From ce2a0fb864bc5be41c94ac9012e16a9a10aec6c0 Mon Sep 17 00:00:00 2001 From: Tom Hunkapiller Date: Mon, 24 May 2021 11:28:10 +0300 Subject: [PATCH] remove more duplicate classes; add additional values functions; clean up tests --- src/export/formatter.spec.ts | 12 +-- src/file/border/border.ts | 4 +- src/file/numbering/abstract-numbering.spec.ts | 20 ++--- .../formatting/bidirectional.spec.ts | 15 ---- .../paragraph/formatting/bidirectional.ts | 7 -- src/file/paragraph/formatting/index.ts | 1 - src/file/paragraph/formatting/keep.ts | 13 ---- src/file/paragraph/formatting/spacing.spec.ts | 22 +----- src/file/paragraph/formatting/spacing.ts | 13 +--- .../formatting/widow-control.spec.ts | 20 ----- .../paragraph/formatting/widow-control.ts | 13 ---- src/file/paragraph/paragraph.spec.ts | 17 +++- src/file/paragraph/properties.spec.ts | 6 +- src/file/paragraph/properties.ts | 27 +++---- src/file/paragraph/run/properties.ts | 47 +++++------ src/file/paragraph/run/run.spec.ts | 30 +++---- src/file/paragraph/run/symbol-run.spec.ts | 8 +- src/file/styles/style/character-style.spec.ts | 20 ++--- src/file/styles/style/paragraph-style.spec.ts | 26 +++---- src/file/table/grid.ts | 19 ++++- .../table-float-properties.ts | 13 ++++ .../table/table-properties/table-layout.ts | 9 +++ .../table/table-properties/table-overlap.ts | 10 +++ .../table-properties/table-properties.ts | 10 +-- .../table-properties/table-style.spec.ts | 22 ------ .../table/table-properties/table-style.ts | 13 ---- .../visually-right-to-left.spec.ts | 14 ---- .../visually-right-to-left.ts | 8 -- src/file/table/table-row/table-row-height.ts | 19 ++++- .../table-row/table-row-properties.spec.ts | 4 +- .../table/table-row/table-row-properties.ts | 62 ++++++++------- src/file/table/table-row/table-row.spec.ts | 18 +---- src/file/table/table-width.ts | 3 +- src/file/table/table.spec.ts | 2 +- .../deleted-text-run.spec.ts | 12 +-- src/file/values.spec.ts | 15 ++++ src/file/values.ts | 78 +++++++++++++++---- src/file/xml-components/simple-elements.ts | 21 ++++- 38 files changed, 311 insertions(+), 362 deletions(-) delete mode 100644 src/file/paragraph/formatting/bidirectional.spec.ts delete mode 100644 src/file/paragraph/formatting/bidirectional.ts delete mode 100644 src/file/paragraph/formatting/keep.ts delete mode 100644 src/file/paragraph/formatting/widow-control.spec.ts delete mode 100644 src/file/paragraph/formatting/widow-control.ts delete mode 100644 src/file/table/table-properties/table-style.spec.ts delete mode 100644 src/file/table/table-properties/table-style.ts delete mode 100644 src/file/table/table-properties/visually-right-to-left.spec.ts delete mode 100644 src/file/table/table-properties/visually-right-to-left.ts diff --git a/src/export/formatter.spec.ts b/src/export/formatter.spec.ts index e79cf7a9cc..463ec38c7f 100644 --- a/src/export/formatter.spec.ts +++ b/src/export/formatter.spec.ts @@ -45,18 +45,10 @@ describe("Formatter", () => { { "w:rPr": [ { - "w:b": { - _attr: { - "w:val": true, - }, - }, + "w:b": {}, }, { - "w:bCs": { - _attr: { - "w:val": true, - }, - }, + "w:bCs": {}, }, ], }, diff --git a/src/file/border/border.ts b/src/file/border/border.ts index 583c513f30..b10d5a72e1 100644 --- a/src/file/border/border.ts +++ b/src/file/border/border.ts @@ -33,7 +33,7 @@ export class BorderElement extends XmlComponent { constructor(elementName: string, { color, ...options }: IBorderOptions) { super(elementName); this.root.push( - new TableBordersAttributes({ + new BordersAttributes({ ...options, color: color === undefined ? color : hexColorValue(color), }), @@ -41,7 +41,7 @@ export class BorderElement extends XmlComponent { } } -class TableBordersAttributes extends XmlAttributeComponent { +class BordersAttributes extends XmlAttributeComponent { protected readonly xmlKeys = { style: "w:val", color: "w:color", diff --git a/src/file/numbering/abstract-numbering.spec.ts b/src/file/numbering/abstract-numbering.spec.ts index 746fb3f6d5..b332e0d94a 100644 --- a/src/file/numbering/abstract-numbering.spec.ts +++ b/src/file/numbering/abstract-numbering.spec.ts @@ -351,7 +351,7 @@ describe("AbstractNumbering", () => { ]); const tree = new Formatter().format(abstractNumbering); expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ - "w:rPr": [{ "w:smallCaps": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:smallCaps": {} }], }); }); @@ -370,7 +370,7 @@ describe("AbstractNumbering", () => { ]); const tree = new Formatter().format(abstractNumbering); expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ - "w:rPr": [{ "w:caps": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:caps": {} }], }); }); @@ -390,7 +390,7 @@ describe("AbstractNumbering", () => { const tree = new Formatter().format(abstractNumbering); expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ - "w:rPr": [{ "w:strike": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:strike": {} }], }); }); @@ -409,7 +409,7 @@ describe("AbstractNumbering", () => { ]); const tree = new Formatter().format(abstractNumbering); expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ - "w:rPr": [{ "w:dstrike": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:dstrike": {} }], }); }); @@ -515,17 +515,17 @@ describe("AbstractNumbering", () => { const boldTests = [ { bold: true, - expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + expected: [{ "w:b": {} }, { "w:bCs": {} }], }, { bold: true, boldComplexScript: true, - expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + expected: [{ "w:b": {} }, { "w:bCs": {} }], }, { bold: true, boldComplexScript: false, - expected: [{ "w:b": { _attr: { "w:val": true } } }], + expected: [{ "w:b": {} }], }, ]; boldTests.forEach(({ bold, boldComplexScript, expected }) => { @@ -548,17 +548,17 @@ describe("AbstractNumbering", () => { const italicsTests = [ { italics: true, - expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + expected: [{ "w:i": {} }, { "w:iCs": {} }], }, { italics: true, italicsComplexScript: true, - expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + expected: [{ "w:i": {} }, { "w:iCs": {} }], }, { italics: true, italicsComplexScript: false, - expected: [{ "w:i": { _attr: { "w:val": true } } }], + expected: [{ "w:i": {} }], }, ]; italicsTests.forEach(({ italics, italicsComplexScript, expected }) => { diff --git a/src/file/paragraph/formatting/bidirectional.spec.ts b/src/file/paragraph/formatting/bidirectional.spec.ts deleted file mode 100644 index a197ada54e..0000000000 --- a/src/file/paragraph/formatting/bidirectional.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { expect } from "chai"; - -import { Formatter } from "export/formatter"; - -import { Bidirectional } from "./bidirectional"; - -describe("Bidirectional", () => { - it("should create", () => { - const bidirectional = new Bidirectional(); - const tree = new Formatter().format(bidirectional); - expect(tree).to.deep.equal({ - "w:bidi": {}, - }); - }); -}); diff --git a/src/file/paragraph/formatting/bidirectional.ts b/src/file/paragraph/formatting/bidirectional.ts deleted file mode 100644 index 4083247e78..0000000000 --- a/src/file/paragraph/formatting/bidirectional.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { XmlComponent } from "file/xml-components"; - -export class Bidirectional extends XmlComponent { - constructor() { - super("w:bidi"); - } -} diff --git a/src/file/paragraph/formatting/index.ts b/src/file/paragraph/formatting/index.ts index 2c8829ee9d..0d83804dc6 100644 --- a/src/file/paragraph/formatting/index.ts +++ b/src/file/paragraph/formatting/index.ts @@ -1,7 +1,6 @@ export * from "./alignment"; export * from "./border"; export * from "./indent"; -export * from "./keep"; export * from "./page-break"; export * from "./spacing"; export * from "./style"; diff --git a/src/file/paragraph/formatting/keep.ts b/src/file/paragraph/formatting/keep.ts deleted file mode 100644 index 5f1abb53f8..0000000000 --- a/src/file/paragraph/formatting/keep.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { XmlComponent } from "file/xml-components"; - -export class KeepLines extends XmlComponent { - constructor() { - super("w:keepLines"); - } -} - -export class KeepNext extends XmlComponent { - constructor() { - super("w:keepNext"); - } -} diff --git a/src/file/paragraph/formatting/spacing.spec.ts b/src/file/paragraph/formatting/spacing.spec.ts index 8241fb282c..09d88dc31c 100644 --- a/src/file/paragraph/formatting/spacing.spec.ts +++ b/src/file/paragraph/formatting/spacing.spec.ts @@ -2,7 +2,7 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; -import { ContextualSpacing, Spacing } from "./spacing"; +import { Spacing } from "./spacing"; describe("Spacing", () => { describe("#constructor", () => { @@ -23,23 +23,3 @@ describe("Spacing", () => { }); }); }); - -describe("ContextualSpacing", () => { - describe("#constructor", () => { - it("should create", () => { - const spacing = new ContextualSpacing(true); - const tree = new Formatter().format(spacing); - expect(tree).to.deep.equal({ - "w:contextualSpacing": { _attr: { "w:val": 1 } }, - }); - }); - - it("should create with value of 0 if param is false", () => { - const spacing = new ContextualSpacing(false); - const tree = new Formatter().format(spacing); - expect(tree).to.deep.equal({ - "w:contextualSpacing": { _attr: { "w:val": 0 } }, - }); - }); - }); -}); diff --git a/src/file/paragraph/formatting/spacing.ts b/src/file/paragraph/formatting/spacing.ts index 7eac5cea72..bac1a17049 100644 --- a/src/file/paragraph/formatting/spacing.ts +++ b/src/file/paragraph/formatting/spacing.ts @@ -1,5 +1,5 @@ // http://officeopenxml.com/WPspacing.php -import { Attributes, XmlAttributeComponent, XmlComponent } from "file/xml-components"; +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; export enum LineRuleType { AT_LEAST = "atLeast", @@ -30,14 +30,3 @@ export class Spacing extends XmlComponent { this.root.push(new SpacingAttributes(options)); } } - -export class ContextualSpacing extends XmlComponent { - constructor(value: boolean) { - super("w:contextualSpacing"); - this.root.push( - new Attributes({ - val: value === false ? 0 : 1, - }), - ); - } -} diff --git a/src/file/paragraph/formatting/widow-control.spec.ts b/src/file/paragraph/formatting/widow-control.spec.ts deleted file mode 100644 index e6e50fb13c..0000000000 --- a/src/file/paragraph/formatting/widow-control.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { expect } from "chai"; - -import { Formatter } from "export/formatter"; - -import { WidowControl } from "./widow-control"; - -describe("WidowControl", () => { - it("should create", () => { - const widowControl = new WidowControl(true); - const tree = new Formatter().format(widowControl); - - expect(tree).to.deep.equal({ - "w:widowControl": { - _attr: { - "w:val": true, - }, - }, - }); - }); -}); diff --git a/src/file/paragraph/formatting/widow-control.ts b/src/file/paragraph/formatting/widow-control.ts deleted file mode 100644 index cbfc125564..0000000000 --- a/src/file/paragraph/formatting/widow-control.ts +++ /dev/null @@ -1,13 +0,0 @@ -// http://www.datypic.com/sc/ooxml/e-w_widowControl-1.html -import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; - -export class WidowControlAttributes extends XmlAttributeComponent<{ readonly val: boolean }> { - protected readonly xmlKeys = { val: "w:val" }; -} - -export class WidowControl extends XmlComponent { - constructor(value: boolean) { - super("w:widowControl"); - this.root.push(new WidowControlAttributes({ val: value })); - } -} diff --git a/src/file/paragraph/paragraph.spec.ts b/src/file/paragraph/paragraph.spec.ts index 9dfaad18c8..ae6107f6e1 100644 --- a/src/file/paragraph/paragraph.spec.ts +++ b/src/file/paragraph/paragraph.spec.ts @@ -416,7 +416,7 @@ describe("Paragraph", () => { }); describe("#contextualSpacing()", () => { - it("should add contextualSpacing to JSON, and set 1 if true", () => { + it("should add contextualSpacing", () => { const paragraph = new Paragraph({ contextualSpacing: true, }); @@ -424,7 +424,20 @@ describe("Paragraph", () => { expect(tree).to.deep.equal({ "w:p": [ { - "w:pPr": [{ "w:contextualSpacing": { _attr: { "w:val": 1 } } }], + "w:pPr": [{ "w:contextualSpacing": {} }], + }, + ], + }); + }); + it("should remove contextualSpacing", () => { + const paragraph = new Paragraph({ + contextualSpacing: false, + }); + const tree = new Formatter().format(paragraph); + expect(tree).to.deep.equal({ + "w:p": [ + { + "w:pPr": [{ "w:contextualSpacing": { _attr: { "w:val": false } } }], }, ], }); diff --git a/src/file/paragraph/properties.spec.ts b/src/file/paragraph/properties.spec.ts index deb7f416c2..e8961ceea6 100644 --- a/src/file/paragraph/properties.spec.ts +++ b/src/file/paragraph/properties.spec.ts @@ -86,11 +86,7 @@ describe("ParagraphProperties", () => { expect(tree).to.deep.equal({ "w:pPr": [ { - "w:widowControl": { - _attr: { - "w:val": true, - }, - }, + "w:widowControl": {}, }, ], }); diff --git a/src/file/paragraph/properties.ts b/src/file/paragraph/properties.ts index 40491109e5..d3cb2081e9 100644 --- a/src/file/paragraph/properties.ts +++ b/src/file/paragraph/properties.ts @@ -1,18 +1,15 @@ // http://officeopenxml.com/WPparagraphProperties.php -import { IContext, IgnoreIfEmptyXmlComponent, IXmlableObject, XmlComponent } from "file/xml-components"; +import { IContext, IgnoreIfEmptyXmlComponent, IXmlableObject, OnOffElement, XmlComponent } from "file/xml-components"; import { DocumentWrapper } from "../document-wrapper"; import { IShadingAttributesProperties, Shading } from "../shading"; import { Alignment, AlignmentType } from "./formatting/alignment"; -import { Bidirectional } from "./formatting/bidirectional"; import { Border, IBordersOptions, ThematicBreak } from "./formatting/border"; import { IIndentAttributesProperties, Indent } from "./formatting/indent"; -import { KeepLines, KeepNext } from "./formatting/keep"; import { PageBreakBefore } from "./formatting/page-break"; -import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spacing"; +import { ISpacingProperties, Spacing } from "./formatting/spacing"; import { HeadingLevel, Style } from "./formatting/style"; import { LeaderType, TabStop, TabStopPosition, TabStopType } from "./formatting/tab-stop"; import { NumberProperties } from "./formatting/unordered-list"; -import { WidowControl } from "./formatting/widow-control"; import { FrameProperties, IFrameOptions } from "./frame/frame-properties"; import { OutlineLevel } from "./links"; @@ -84,12 +81,12 @@ export class ParagraphProperties extends IgnoreIfEmptyXmlComponent { this.push(new Style(options.style)); } - if (options.keepNext) { - this.push(new KeepNext()); + if (options.keepNext !== undefined) { + this.push(new OnOffElement("w:keepNext", options.keepNext)); } - if (options.keepLines) { - this.push(new KeepLines()); + if (options.keepLines !== undefined) { + this.push(new OnOffElement("w:keepLines", options.keepLines)); } if (options.pageBreakBefore) { @@ -100,8 +97,8 @@ export class ParagraphProperties extends IgnoreIfEmptyXmlComponent { this.push(new FrameProperties(options.frame)); } - if (options.widowControl) { - this.push(new WidowControl(options.widowControl)); + if (options.widowControl !== undefined) { + this.push(new OnOffElement("w:widowControl", options.widowControl)); } if (options.bullet) { @@ -143,8 +140,8 @@ export class ParagraphProperties extends IgnoreIfEmptyXmlComponent { this.push(new TabStop(TabStopType.LEFT, options.leftTabStop)); } - if (options.bidirectional) { - this.push(new Bidirectional()); + if (options.bidirectional !== undefined) { + this.push(new OnOffElement("w:bidi", options.contextualSpacing)); } if (options.spacing) { @@ -155,8 +152,8 @@ export class ParagraphProperties extends IgnoreIfEmptyXmlComponent { this.push(new Indent(options.indent)); } - if (options.contextualSpacing) { - this.push(new ContextualSpacing(options.contextualSpacing)); + if (options.contextualSpacing !== undefined) { + this.push(new OnOffElement("w:contextualSpacing", options.contextualSpacing)); } if (options.alignment) { diff --git a/src/file/paragraph/run/properties.ts b/src/file/paragraph/run/properties.ts index 277c540619..89be41619e 100644 --- a/src/file/paragraph/run/properties.ts +++ b/src/file/paragraph/run/properties.ts @@ -98,18 +98,19 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent { return; } - if (options.bold) { - this.push(new OnOffElement("w:b")); + if (options.bold !== undefined) { + this.push(new OnOffElement("w:b", options.bold)); } - if ((options.boldComplexScript === undefined && options.bold) || options.boldComplexScript) { - this.push(new OnOffElement("w:bCs")); + if ((options.boldComplexScript === undefined && options.bold !== undefined) || options.boldComplexScript) { + this.push(new OnOffElement("w:bCs", options.boldComplexScript ?? options.bold)); } - if (options.italics) { - this.push(new OnOffElement("w:i")); + if (options.italics !== undefined) { + this.push(new OnOffElement("w:i", options.italics)); } - if ((options.italicsComplexScript === undefined && options.italics) || options.italicsComplexScript) { - this.push(new OnOffElement("w:iCs")); + + if ((options.italicsComplexScript === undefined && options.italics !== undefined) || options.italicsComplexScript) { + this.push(new OnOffElement("w:iCs", options.italicsComplexScript ?? options.italics)); } if (options.underline) { @@ -124,7 +125,7 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent { this.push(new Color(options.color)); } - if (options.size) { + if (options.size !== undefined) { this.push(new HpsMeasureElement("w:sz", options.size)); } const szCs = @@ -133,23 +134,23 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent { this.push(new HpsMeasureElement("w:szCs", szCs)); } - if (options.rightToLeft) { - this.push(new OnOffElement("w:rtl")); + if (options.rightToLeft !== undefined) { + this.push(new OnOffElement("w:rtl", options.rightToLeft)); } // These two are mutually exclusive - if (options.smallCaps) { - this.push(new OnOffElement("w:smallCaps")); - } else if (options.allCaps) { - this.push(new OnOffElement("w:caps")); + if (options.smallCaps !== undefined) { + this.push(new OnOffElement("w:smallCaps", options.smallCaps)); + } else if (options.allCaps !== undefined) { + this.push(new OnOffElement("w:caps", options.allCaps)); } - if (options.strike) { - this.push(new OnOffElement("w:strike")); + if (options.strike !== undefined) { + this.push(new OnOffElement("w:strike", options.strike)); } - if (options.doubleStrike) { - this.push(new OnOffElement("w:dstrike")); + if (options.doubleStrike !== undefined) { + this.push(new OnOffElement("w:dstrike", options.doubleStrike)); } if (options.subScript) { @@ -189,12 +190,12 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent { this.push(new CharacterSpacing(options.characterSpacing)); } - if (options.emboss) { - this.push(new OnOffElement("w:emboss")); + if (options.emboss !== undefined) { + this.push(new OnOffElement("w:emboss", options.emboss)); } - if (options.imprint) { - this.push(new OnOffElement("w:imprint")); + if (options.imprint !== undefined) { + this.push(new OnOffElement("w:imprint", options.imprint)); } if (options.shading) { diff --git a/src/file/paragraph/run/run.spec.ts b/src/file/paragraph/run/run.spec.ts index aad96fd39c..a3178df35e 100644 --- a/src/file/paragraph/run/run.spec.ts +++ b/src/file/paragraph/run/run.spec.ts @@ -20,13 +20,9 @@ describe("Run", () => { "w:r": [ { "w:rPr": [ - { "w:b": { _attr: { "w:val": true } } }, + { "w:b": {} }, { - "w:bCs": { - _attr: { - "w:val": true, - }, - }, + "w:bCs": {}, }, ], }, @@ -45,13 +41,9 @@ describe("Run", () => { "w:r": [ { "w:rPr": [ - { "w:i": { _attr: { "w:val": true } } }, + { "w:i": {} }, { - "w:iCs": { - _attr: { - "w:val": true, - }, - }, + "w:iCs": {}, }, ], }, @@ -116,7 +108,7 @@ describe("Run", () => { }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:rPr": [{ "w:smallCaps": { _attr: { "w:val": true } } }] }], + "w:r": [{ "w:rPr": [{ "w:smallCaps": {} }] }], }); }); }); @@ -128,7 +120,7 @@ describe("Run", () => { }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:rPr": [{ "w:caps": { _attr: { "w:val": true } } }] }], + "w:r": [{ "w:rPr": [{ "w:caps": {} }] }], }); }); }); @@ -140,7 +132,7 @@ describe("Run", () => { }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:rPr": [{ "w:strike": { _attr: { "w:val": true } } }] }], + "w:r": [{ "w:rPr": [{ "w:strike": {} }] }], }); }); }); @@ -152,7 +144,7 @@ describe("Run", () => { }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:rPr": [{ "w:dstrike": { _attr: { "w:val": true } } }] }], + "w:r": [{ "w:rPr": [{ "w:dstrike": {} }] }], }); }); }); @@ -164,7 +156,7 @@ describe("Run", () => { }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:rPr": [{ "w:emboss": { _attr: { "w:val": true } } }] }], + "w:r": [{ "w:rPr": [{ "w:emboss": {} }] }], }); }); }); @@ -176,7 +168,7 @@ describe("Run", () => { }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:rPr": [{ "w:imprint": { _attr: { "w:val": true } } }] }], + "w:r": [{ "w:rPr": [{ "w:imprint": {} }] }], }); }); }); @@ -367,7 +359,7 @@ describe("Run", () => { }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:rPr": [{ "w:rtl": { _attr: { "w:val": true } } }] }], + "w:r": [{ "w:rPr": [{ "w:rtl": {} }] }], }); }); }); diff --git a/src/file/paragraph/run/symbol-run.spec.ts b/src/file/paragraph/run/symbol-run.spec.ts index c249c63082..06e98a4373 100644 --- a/src/file/paragraph/run/symbol-run.spec.ts +++ b/src/file/paragraph/run/symbol-run.spec.ts @@ -59,10 +59,10 @@ describe("SymbolRun", () => { "w:r": [ { "w:rPr": [ - { "w:b": { _attr: { "w:val": true } } }, - { "w:bCs": { _attr: { "w:val": true } } }, - { "w:i": { _attr: { "w:val": true } } }, - { "w:iCs": { _attr: { "w:val": true } } }, + { "w:b": {} }, + { "w:bCs": {} }, + { "w:i": {} }, + { "w:iCs": {} }, { "w:u": { _attr: { "w:val": "double", "w:color": "ff0000" } } }, { "w:em": { _attr: { "w:val": "dot" } } }, { "w:color": { _attr: { "w:val": "00FF00" } } }, diff --git a/src/file/styles/style/character-style.spec.ts b/src/file/styles/style/character-style.spec.ts index 05715ea982..f6def753b3 100644 --- a/src/file/styles/style/character-style.spec.ts +++ b/src/file/styles/style/character-style.spec.ts @@ -66,7 +66,7 @@ describe("CharacterStyle", () => { "w:style": [ { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, { - "w:rPr": [{ "w:smallCaps": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:smallCaps": {} }], }, { "w:uiPriority": { @@ -94,7 +94,7 @@ describe("CharacterStyle", () => { "w:style": [ { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, { - "w:rPr": [{ "w:caps": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:caps": {} }], }, { "w:uiPriority": { @@ -122,7 +122,7 @@ describe("CharacterStyle", () => { "w:style": [ { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, { - "w:rPr": [{ "w:strike": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:strike": {} }], }, { "w:uiPriority": { @@ -150,7 +150,7 @@ describe("CharacterStyle", () => { "w:style": [ { _attr: { "w:type": "character", "w:styleId": "myStyleId" } }, { - "w:rPr": [{ "w:dstrike": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:dstrike": {} }], }, { "w:uiPriority": { @@ -601,17 +601,17 @@ describe("CharacterStyle", () => { const boldTests = [ { bold: true, - expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + expected: [{ "w:b": {} }, { "w:bCs": {} }], }, { bold: true, boldComplexScript: true, - expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + expected: [{ "w:b": {} }, { "w:bCs": {} }], }, { bold: true, boldComplexScript: false, - expected: [{ "w:b": { _attr: { "w:val": true } } }], + expected: [{ "w:b": {} }], }, ]; boldTests.forEach(({ bold, boldComplexScript, expected }) => { @@ -645,17 +645,17 @@ describe("CharacterStyle", () => { const italicsTests = [ { italics: true, - expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + expected: [{ "w:i": {} }, { "w:iCs": {} }], }, { italics: true, italicsComplexScript: true, - expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + expected: [{ "w:i": {} }, { "w:iCs": {} }], }, { italics: true, italicsComplexScript: false, - expected: [{ "w:i": { _attr: { "w:val": true } } }], + expected: [{ "w:i": {} }], }, ]; italicsTests.forEach(({ italics, italicsComplexScript, expected }) => { diff --git a/src/file/styles/style/paragraph-style.spec.ts b/src/file/styles/style/paragraph-style.spec.ts index ad0e7f989d..da24b63d5c 100644 --- a/src/file/styles/style/paragraph-style.spec.ts +++ b/src/file/styles/style/paragraph-style.spec.ts @@ -242,11 +242,7 @@ describe("ParagraphStyle", () => { { "w:pPr": [ { - "w:contextualSpacing": { - _attr: { - "w:val": 1, - }, - }, + "w:contextualSpacing": {}, }, ], }, @@ -404,7 +400,7 @@ describe("ParagraphStyle", () => { "w:style": [ { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { - "w:rPr": [{ "w:smallCaps": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:smallCaps": {} }], }, ], }); @@ -422,7 +418,7 @@ describe("ParagraphStyle", () => { "w:style": [ { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { - "w:rPr": [{ "w:caps": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:caps": {} }], }, ], }); @@ -440,7 +436,7 @@ describe("ParagraphStyle", () => { "w:style": [ { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { - "w:rPr": [{ "w:strike": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:strike": {} }], }, ], }); @@ -458,7 +454,7 @@ describe("ParagraphStyle", () => { "w:style": [ { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { - "w:rPr": [{ "w:dstrike": { _attr: { "w:val": true } } }], + "w:rPr": [{ "w:dstrike": {} }], }, ], }); @@ -562,17 +558,17 @@ describe("ParagraphStyle", () => { const boldTests = [ { bold: true, - expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + expected: [{ "w:b": {} }, { "w:bCs": {} }], }, { bold: true, boldComplexScript: true, - expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }], + expected: [{ "w:b": {} }, { "w:bCs": {} }], }, { bold: true, boldComplexScript: false, - expected: [{ "w:b": { _attr: { "w:val": true } } }], + expected: [{ "w:b": {} }], }, ]; boldTests.forEach(({ bold, boldComplexScript, expected }) => { @@ -591,17 +587,17 @@ describe("ParagraphStyle", () => { const italicsTests = [ { italics: true, - expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + expected: [{ "w:i": {} }, { "w:iCs": {} }], }, { italics: true, italicsComplexScript: true, - expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }], + expected: [{ "w:i": {} }, { "w:iCs": {} }], }, { italics: true, italicsComplexScript: false, - expected: [{ "w:i": { _attr: { "w:val": true } } }], + expected: [{ "w:i": {} }], }, ]; italicsTests.forEach(({ italics, italicsComplexScript, expected }) => { diff --git a/src/file/table/grid.ts b/src/file/table/grid.ts index 5ce6486fcc..b8a683f255 100644 --- a/src/file/table/grid.ts +++ b/src/file/table/grid.ts @@ -1,8 +1,19 @@ // http://officeopenxml.com/WPtableGrid.php + +// +// +// +// +// +// +// +// + +import { twipsMeasureValue } from "file/values"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; export class TableGrid extends XmlComponent { - constructor(widths: number[]) { + constructor(widths: number[] | string[]) { super("w:tblGrid"); for (const width of widths) { this.root.push(new GridCol(width)); @@ -10,15 +21,15 @@ export class TableGrid extends XmlComponent { } } -class GridColAttributes extends XmlAttributeComponent<{ readonly w: number }> { +class GridColAttributes extends XmlAttributeComponent<{ readonly w: number | string }> { protected readonly xmlKeys = { w: "w:w" }; } export class GridCol extends XmlComponent { - constructor(width?: number) { + constructor(width?: number | string) { super("w:gridCol"); if (width !== undefined) { - this.root.push(new GridColAttributes({ w: width })); + this.root.push(new GridColAttributes({ w: 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 2b97d86c1c..93bdd1a882 100644 --- a/src/file/table/table-properties/table-float-properties.ts +++ b/src/file/table/table-properties/table-float-properties.ts @@ -129,6 +129,19 @@ export class TableFloatOptionsAttributes extends XmlAttributeComponent +// +// +// +// +// +// +// +// +// +// +// + export class TableFloatProperties extends XmlComponent { constructor(options: ITableFloatOptions) { super("w:tblpPr"); diff --git a/src/file/table/table-properties/table-layout.ts b/src/file/table/table-properties/table-layout.ts index 58fc14f4ec..45fe1e6d5a 100644 --- a/src/file/table/table-properties/table-layout.ts +++ b/src/file/table/table-properties/table-layout.ts @@ -9,6 +9,15 @@ class TableLayoutAttributes extends XmlAttributeComponent<{ readonly type: Table protected readonly xmlKeys = { type: "w:type" }; } +// +// +// +// +// +// +// +// +// export class TableLayout extends XmlComponent { constructor(type: TableLayoutType) { super("w:tblLayout"); diff --git a/src/file/table/table-properties/table-overlap.ts b/src/file/table/table-properties/table-overlap.ts index 387cf27943..fbc8fb65fb 100644 --- a/src/file/table/table-properties/table-overlap.ts +++ b/src/file/table/table-properties/table-overlap.ts @@ -5,6 +5,16 @@ export enum OverlapType { OVERLAP = "overlap", } +// +// +// +// +// +// +// +// +// + class TableOverlapAttributes extends XmlAttributeComponent<{ readonly val: OverlapType }> { protected readonly xmlKeys = { val: "w:val" }; } diff --git a/src/file/table/table-properties/table-properties.ts b/src/file/table/table-properties/table-properties.ts index a615584ce2..5e46cfa92a 100644 --- a/src/file/table/table-properties/table-properties.ts +++ b/src/file/table/table-properties/table-properties.ts @@ -21,7 +21,7 @@ // // // -import { IgnoreIfEmptyXmlComponent } from "file/xml-components"; +import { IgnoreIfEmptyXmlComponent, OnOffElement, StringValueElement } from "file/xml-components"; import { Alignment, AlignmentType } from "../../paragraph"; import { IShadingAttributesProperties, Shading } from "../../shading"; @@ -30,8 +30,6 @@ import { ITableBordersOptions, TableBorders } from "./table-borders"; import { ITableCellMarginOptions, TableCellMargin, TableCellMarginElementType } from "./table-cell-margin"; import { ITableFloatOptions, TableFloatProperties } from "./table-float-properties"; import { TableLayout, TableLayoutType } from "./table-layout"; -import { TableStyle } from "./table-style"; -import { VisuallyRightToLeft } from "./visually-right-to-left"; export interface ITablePropertiesOptions { readonly width?: ITableWidthProperties; @@ -51,15 +49,15 @@ export class TableProperties extends IgnoreIfEmptyXmlComponent { super("w:tblPr"); if (options.style) { - this.root.push(new TableStyle(options.style)); + this.root.push(new StringValueElement("w:tblStyle", options.style)); } if (options.float) { this.root.push(new TableFloatProperties(options.float)); } - if (options.visuallyRightToLeft) { - this.root.push(new VisuallyRightToLeft()); + if (options.visuallyRightToLeft !== undefined) { + this.root.push(new OnOffElement("w:bidiVisual", options.visuallyRightToLeft)); } if (options.width) { diff --git a/src/file/table/table-properties/table-style.spec.ts b/src/file/table/table-properties/table-style.spec.ts deleted file mode 100644 index 1b9b0e9748..0000000000 --- a/src/file/table/table-properties/table-style.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { expect } from "chai"; - -import { Formatter } from "export/formatter"; - -import { TableStyle } from "./table-style"; - -describe("TableStyle", () => { - describe("#constructor", () => { - it("should create", () => { - const tableStyle = new TableStyle("test-id"); - const tree = new Formatter().format(tableStyle); - - expect(tree).to.deep.equal({ - "w:tblStyle": { - _attr: { - "w:val": "test-id", - }, - }, - }); - }); - }); -}); diff --git a/src/file/table/table-properties/table-style.ts b/src/file/table/table-properties/table-style.ts deleted file mode 100644 index 22b4dc5e89..0000000000 --- a/src/file/table/table-properties/table-style.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Attributes, XmlComponent } from "file/xml-components"; - -export class TableStyle extends XmlComponent { - constructor(styleId: string) { - super("w:tblStyle"); - - this.root.push( - new Attributes({ - val: styleId, - }), - ); - } -} diff --git a/src/file/table/table-properties/visually-right-to-left.spec.ts b/src/file/table/table-properties/visually-right-to-left.spec.ts deleted file mode 100644 index 792c90194b..0000000000 --- a/src/file/table/table-properties/visually-right-to-left.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -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": {}, - }); - }); -}); diff --git a/src/file/table/table-properties/visually-right-to-left.ts b/src/file/table/table-properties/visually-right-to-left.ts deleted file mode 100644 index c0598a5a26..0000000000 --- a/src/file/table/table-properties/visually-right-to-left.ts +++ /dev/null @@ -1,8 +0,0 @@ -// 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"); - } -} diff --git a/src/file/table/table-row/table-row-height.ts b/src/file/table/table-row/table-row-height.ts index 6803d9b17e..84d696b63b 100644 --- a/src/file/table/table-row/table-row-height.ts +++ b/src/file/table/table-row/table-row-height.ts @@ -1,5 +1,18 @@ +import { twipsMeasureValue } from "file/values"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; +// +// +// +// + +// +// +// +// +// +// +// export enum HeightRule { /** Height is determined based on the content, so value is ignored. */ AUTO = "auto", @@ -10,19 +23,19 @@ export enum HeightRule { } export class TableRowHeightAttributes extends XmlAttributeComponent<{ - readonly value: number; + readonly value: number | string; readonly rule: HeightRule; }> { protected readonly xmlKeys = { value: "w:val", rule: "w:hRule" }; } export class TableRowHeight extends XmlComponent { - constructor(value: number, rule: HeightRule) { + constructor(value: number | string, rule: HeightRule) { super("w:trHeight"); this.root.push( new TableRowHeightAttributes({ - value: value, + value: twipsMeasureValue(value), rule: rule, }), ); diff --git a/src/file/table/table-row/table-row-properties.spec.ts b/src/file/table/table-row/table-row-properties.spec.ts index 097c57a529..3f008ce77e 100644 --- a/src/file/table/table-row/table-row-properties.spec.ts +++ b/src/file/table/table-row/table-row-properties.spec.ts @@ -17,13 +17,13 @@ describe("TableRowProperties", () => { it("sets cantSplit to avoid row been paginated", () => { const rowProperties = new TableRowProperties({ cantSplit: true }); const tree = new Formatter().format(rowProperties); - expect(tree).to.deep.equal({ "w:trPr": [{ "w:cantSplit": { _attr: { "w:val": true } } }] }); + expect(tree).to.deep.equal({ "w:trPr": [{ "w:cantSplit": {} }] }); }); it("sets row as table header (repeat row on each page of table)", () => { const rowProperties = new TableRowProperties({ tableHeader: true }); const tree = new Formatter().format(rowProperties); - expect(tree).to.deep.equal({ "w:trPr": [{ "w:tblHeader": { _attr: { "w:val": true } } }] }); + expect(tree).to.deep.equal({ "w:trPr": [{ "w:tblHeader": {} }] }); }); it("sets row height exact", () => { diff --git a/src/file/table/table-row/table-row-properties.ts b/src/file/table/table-row/table-row-properties.ts index 91d0cf2ae4..2168d0774a 100644 --- a/src/file/table/table-row/table-row-properties.ts +++ b/src/file/table/table-row/table-row-properties.ts @@ -1,5 +1,33 @@ // http://officeopenxml.com/WPtableRowProperties.php -import { IgnoreIfEmptyXmlComponent, XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +import { IgnoreIfEmptyXmlComponent, OnOffElement } from "file/xml-components"; import { HeightRule, TableRowHeight } from "./table-row-height"; @@ -7,7 +35,7 @@ export interface ITableRowPropertiesOptions { readonly cantSplit?: boolean; readonly tableHeader?: boolean; readonly height?: { - readonly value: number; + readonly value: number | string; readonly rule: HeightRule; }; } @@ -16,12 +44,12 @@ export class TableRowProperties extends IgnoreIfEmptyXmlComponent { constructor(options: ITableRowPropertiesOptions) { super("w:trPr"); - if (options.cantSplit) { - this.root.push(new CantSplit()); + if (options.cantSplit !== undefined) { + this.root.push(new OnOffElement("w:cantSplit", options.cantSplit)); } - if (options.tableHeader) { - this.root.push(new TableHeader()); + if (options.tableHeader !== undefined) { + this.root.push(new OnOffElement("w:tblHeader", options.tableHeader)); } if (options.height) { @@ -29,25 +57,3 @@ export class TableRowProperties extends IgnoreIfEmptyXmlComponent { } } } - -class CantSplitAttributes extends XmlAttributeComponent<{ readonly val: boolean }> { - protected readonly xmlKeys = { val: "w:val" }; -} - -export class CantSplit extends XmlComponent { - constructor() { - super("w:cantSplit"); - this.root.push(new CantSplitAttributes({ val: true })); - } -} - -class TableHeaderAttributes extends XmlAttributeComponent<{ readonly val: boolean }> { - protected readonly xmlKeys = { val: "w:val" }; -} - -export class TableHeader extends XmlComponent { - constructor() { - super("w:tblHeader"); - this.root.push(new TableHeaderAttributes({ val: true })); - } -} diff --git a/src/file/table/table-row/table-row.spec.ts b/src/file/table/table-row/table-row.spec.ts index 16a08e10ae..f1bcbb1aaf 100644 --- a/src/file/table/table-row/table-row.spec.ts +++ b/src/file/table/table-row/table-row.spec.ts @@ -53,11 +53,7 @@ describe("TableRow", () => { { "w:trPr": [ { - "w:cantSplit": { - _attr: { - "w:val": true, - }, - }, + "w:cantSplit": {}, }, ], }, @@ -76,11 +72,7 @@ describe("TableRow", () => { { "w:trPr": [ { - "w:tblHeader": { - _attr: { - "w:val": true, - }, - }, + "w:tblHeader": {}, }, ], }, @@ -141,11 +133,7 @@ describe("TableRow", () => { { "w:trPr": [ { - "w:tblHeader": { - _attr: { - "w:val": true, - }, - }, + "w:tblHeader": {}, }, ], }, diff --git a/src/file/table/table-width.ts b/src/file/table/table-width.ts index d25fa69276..ff203506eb 100644 --- a/src/file/table/table-width.ts +++ b/src/file/table/table-width.ts @@ -1,4 +1,5 @@ // http://officeopenxml.com/WPtableWidth.php +import { measurementOrPercentValue } from "file/values"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; // @@ -37,6 +38,6 @@ export class TableWidthElement extends XmlComponent { constructor(name: string, { type = WidthType.AUTO, size }: ITableWidthProperties) { super(name); // super("w:tblW"); - this.root.push(new TableWidthAttributes({ type: type, size: type === WidthType.PERCENTAGE ? `${size}%` : size })); + this.root.push(new TableWidthAttributes({ type: type, size: measurementOrPercentValue(size) })); } } diff --git a/src/file/table/table.spec.ts b/src/file/table/table.spec.ts index 04020833b4..d3e703decd 100644 --- a/src/file/table/table.spec.ts +++ b/src/file/table/table.spec.ts @@ -282,7 +282,7 @@ describe("Table", () => { "w:tblW": { _attr: { "w:type": "pct", - "w:w": "100%", + "w:w": 100, }, }, }, diff --git a/src/file/track-revision/track-revision-components/deleted-text-run.spec.ts b/src/file/track-revision/track-revision-components/deleted-text-run.spec.ts index 6bd11c24d7..9eacb7c23c 100644 --- a/src/file/track-revision/track-revision-components/deleted-text-run.spec.ts +++ b/src/file/track-revision/track-revision-components/deleted-text-run.spec.ts @@ -54,18 +54,10 @@ describe("DeletedTextRun", () => { { "w:rPr": [ { - "w:b": { - _attr: { - "w:val": true, - }, - }, + "w:b": {}, }, { - "w:bCs": { - _attr: { - "w:val": true, - }, - }, + "w:bCs": {}, }, ], }, diff --git a/src/file/values.spec.ts b/src/file/values.spec.ts index 990107cfd9..9ed751cb51 100644 --- a/src/file/values.spec.ts +++ b/src/file/values.spec.ts @@ -4,6 +4,7 @@ import { hpsMeasureValue, positiveUniversalMeasureValue, signedTwipsMeasureValue, + twipsMeasureValue, universalMeasureValue, unsignedDecimalNumber, } from "./values"; @@ -89,6 +90,20 @@ describe("values", () => { }); }); + describe("twipsMeasureValue", () => { + it("should allow valid values", () => { + expect(twipsMeasureValue(1243)).to.eq(1243); + expect(twipsMeasureValue("5mm")).to.eq("5mm"); + expect(twipsMeasureValue("10.in")).to.eq("10in"); + }); + 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(); + }); + }); + describe("hpsMeasureValue", () => { it("should allow valid values", () => { expect(hpsMeasureValue(1243)).to.eq(1243); diff --git a/src/file/values.ts b/src/file/values.ts index 9d4ce8ff9a..c1b38f4b79 100644 --- a/src/file/values.ts +++ b/src/file/values.ts @@ -1,6 +1,27 @@ // Runtime checks and cleanup for value types in the spec that aren't easily expressed through our type system. // These will help us to prevent silent failures and corrupted documents. +// +// +// +export function decimalNumber(val: number): number { + if (isNaN(val)) { + throw new Error(`Invalid value '${val}' specified. Must be an integer.`); + } + return Math.floor(val); +} + +// +// +// +export function unsignedDecimalNumber(val: number): number { + const value = decimalNumber(val); + if (value < 0) { + throw new Error(`Invalid value '${val}' specified. Must be a positive integer.`); + } + return value; +} + // // // @@ -63,27 +84,11 @@ export function hexColorValue(val: string): string { return color; } -// -// -// -export function unsignedDecimalNumber(val: number): number { - if (isNaN(val) || val < 0) { - throw new Error(`Invalid value '${val}' specified. Must be a positive base10 integer.`); - } - return Math.floor(val); -} - // // // export function signedTwipsMeasureValue(val: string | number): string | number { - if (typeof val === "string") { - return universalMeasureValue(val); - } - if (isNaN(val)) { - throw new Error(`Invalid value '${val}' specified. Expected a valid number.`); - } - return Math.floor(val); + return typeof val === "string" ? universalMeasureValue(val) : decimalNumber(val); } // @@ -92,3 +97,42 @@ export function signedTwipsMeasureValue(val: string | number): string | number { export function hpsMeasureValue(val: string | number): string | number { return typeof val === "string" ? positiveUniversalMeasureValue(val) : unsignedDecimalNumber(val); } + +// +// +// +export function twipsMeasureValue(val: string | number): string | number { + return typeof val === "string" ? positiveUniversalMeasureValue(val) : unsignedDecimalNumber(val); +} + +// +// +// +// +// +export function percentageValue(val: string): string { + if (val.slice(-1) !== "%") { + throw new Error(`Invalid value '${val}'. Expected percentage value (eg '55%')`); + } + 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)}%`; +} + +// +// +// + +// +// +// + +// +// +// + +export function measurementOrPercentValue(val: number | string): number | string { + return typeof val === "number" ? decimalNumber(val) : percentageValue(val); +} diff --git a/src/file/xml-components/simple-elements.ts b/src/file/xml-components/simple-elements.ts index 8fa665a832..64d45819e3 100644 --- a/src/file/xml-components/simple-elements.ts +++ b/src/file/xml-components/simple-elements.ts @@ -4,13 +4,20 @@ import { hpsMeasureValue } from "../values"; // This represents element type CT_OnOff, which indicate a boolean value. // +// A value of 1 or true specifies that the property shall be explicitly applied. +// This is the default value for this attribute, and is implied when the parent +// element is present, but this attribute is omitted. +// A value of 0 or false specifies that the property shall be explicitly turned off. +// // // // export class OnOffElement extends XmlComponent { constructor(name: string, val: boolean | undefined = true) { super(name); - this.root.push(new Attributes({ val })); + if (val !== true) { + this.root.push(new Attributes({ val })); + } } } @@ -25,3 +32,15 @@ export class HpsMeasureElement extends XmlComponent { this.root.push(new Attributes({ val: hpsMeasureValue(val) })); } } + +// This represents element type CT_String, which indicate a string value. +// +// +// +// +export class StringValueElement extends XmlComponent { + constructor(name: string, val: string) { + super(name); + this.root.push(new Attributes({ val })); + } +}