Simplify run format properties, removing duplicate classes. Add values functions, which check and clean up values for specific defined types from the schema
This commit is contained in:
@ -17,3 +17,4 @@ export * from "./footnotes";
|
||||
export * from "./track-revision";
|
||||
export * from "./shared";
|
||||
export * from "./border";
|
||||
export * from "./values";
|
||||
|
@ -2,18 +2,35 @@ import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { Bold } from "./formatting";
|
||||
import { CharacterSpacing, Color } from "./formatting";
|
||||
|
||||
describe("Bold", () => {
|
||||
describe("CharacterSpacing", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create", () => {
|
||||
const currentBold = new Bold();
|
||||
const element = new CharacterSpacing(32);
|
||||
|
||||
const tree = new Formatter().format(currentBold);
|
||||
const tree = new Formatter().format(element);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:b": {
|
||||
"w:spacing": {
|
||||
_attr: {
|
||||
"w:val": true,
|
||||
"w:val": 32,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Color", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create", () => {
|
||||
const element = new Color("#FFFFFF");
|
||||
|
||||
const tree = new Formatter().format(element);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:color": {
|
||||
_attr: {
|
||||
"w:val": "FFFFFF",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,170 +1,55 @@
|
||||
import { hexColorValue, signedTwipsMeasureValue } from "file/values";
|
||||
import { Attributes, XmlComponent } from "file/xml-components";
|
||||
|
||||
export class Bold extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:b");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BoldComplexScript extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:bCs");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class CharacterSpacing extends XmlComponent {
|
||||
constructor(value: number) {
|
||||
constructor(value: number | string) {
|
||||
super("w:spacing");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: value,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Italics extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:i");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class ItalicsComplexScript extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:iCs");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Caps extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:caps");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
val: signedTwipsMeasureValue(value),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// <xsd:complexType name="CT_Color">
|
||||
// <xsd:attribute name="val" type="ST_HexColor" use="required"/>
|
||||
// <xsd:attribute name="themeColor" type="ST_ThemeColor" use="optional"/>
|
||||
// <xsd:attribute name="themeTint" type="ST_UcharHexNumber" use="optional"/>
|
||||
// <xsd:attribute name="themeShade" type="ST_UcharHexNumber" use="optional"/>
|
||||
// </xsd:complexType>
|
||||
export class Color extends XmlComponent {
|
||||
constructor(color: string) {
|
||||
super("w:color");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: color,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class DoubleStrike extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:dstrike");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Emboss extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:emboss");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Imprint extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:imprint");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class SmallCaps extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:smallCaps");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Strike extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:strike");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Size extends XmlComponent {
|
||||
constructor(size: number) {
|
||||
super("w:sz");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: size,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class SizeComplexScript extends XmlComponent {
|
||||
constructor(size: number) {
|
||||
super("w:szCs");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: size,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class RightToLeft extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:rtl");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
val: hexColorValue(color),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// <xsd:simpleType name="ST_HighlightColor">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="black"/>
|
||||
// <xsd:enumeration value="blue"/>
|
||||
// <xsd:enumeration value="cyan"/>
|
||||
// <xsd:enumeration value="green"/>
|
||||
// <xsd:enumeration value="magenta"/>
|
||||
// <xsd:enumeration value="red"/>
|
||||
// <xsd:enumeration value="yellow"/>
|
||||
// <xsd:enumeration value="white"/>
|
||||
// <xsd:enumeration value="darkBlue"/>
|
||||
// <xsd:enumeration value="darkCyan"/>
|
||||
// <xsd:enumeration value="darkGreen"/>
|
||||
// <xsd:enumeration value="darkMagenta"/>
|
||||
// <xsd:enumeration value="darkRed"/>
|
||||
// <xsd:enumeration value="darkYellow"/>
|
||||
// <xsd:enumeration value="darkGray"/>
|
||||
// <xsd:enumeration value="lightGray"/>
|
||||
// <xsd:enumeration value="none"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export class Highlight extends XmlComponent {
|
||||
constructor(color: string) {
|
||||
super("w:highlight");
|
||||
|
@ -1,25 +1,7 @@
|
||||
import { IShadingAttributesProperties, Shading } from "file/shading";
|
||||
import { IgnoreIfEmptyXmlComponent, XmlComponent } from "file/xml-components";
|
||||
import { HpsMeasureElement, IgnoreIfEmptyXmlComponent, OnOffElement, XmlComponent } from "file/xml-components";
|
||||
import { EmphasisMark, EmphasisMarkType } from "./emphasis-mark";
|
||||
import {
|
||||
Bold,
|
||||
BoldComplexScript,
|
||||
Caps,
|
||||
CharacterSpacing,
|
||||
Color,
|
||||
DoubleStrike,
|
||||
Emboss,
|
||||
Highlight,
|
||||
HighlightComplexScript,
|
||||
Imprint,
|
||||
Italics,
|
||||
ItalicsComplexScript,
|
||||
RightToLeft,
|
||||
Size,
|
||||
SizeComplexScript,
|
||||
SmallCaps,
|
||||
Strike,
|
||||
} from "./formatting";
|
||||
import { CharacterSpacing, Color, Highlight, HighlightComplexScript } from "./formatting";
|
||||
import { IFontAttributesProperties, RunFonts } from "./run-fonts";
|
||||
import { SubScript, SuperScript } from "./script";
|
||||
import { Style } from "./style";
|
||||
@ -43,8 +25,8 @@ export interface IRunStylePropertiesOptions {
|
||||
readonly type?: EmphasisMarkType;
|
||||
};
|
||||
readonly color?: string;
|
||||
readonly size?: number;
|
||||
readonly sizeComplexScript?: boolean | number;
|
||||
readonly size?: number | string;
|
||||
readonly sizeComplexScript?: boolean | number | string;
|
||||
readonly rightToLeft?: boolean;
|
||||
readonly smallCaps?: boolean;
|
||||
readonly allCaps?: boolean;
|
||||
@ -65,6 +47,49 @@ export interface IRunPropertiesOptions extends IRunStylePropertiesOptions {
|
||||
readonly style?: string;
|
||||
}
|
||||
|
||||
// <xsd:group name="EG_RPrBase">
|
||||
// <xsd:choice>
|
||||
// <xsd:element name="rStyle" type="CT_String"/>
|
||||
// <xsd:element name="rFonts" type="CT_Fonts"/>
|
||||
// <xsd:element name="b" type="CT_OnOff"/>
|
||||
// <xsd:element name="bCs" type="CT_OnOff"/>
|
||||
// <xsd:element name="i" type="CT_OnOff"/>
|
||||
// <xsd:element name="iCs" type="CT_OnOff"/>
|
||||
// <xsd:element name="caps" type="CT_OnOff"/>
|
||||
// <xsd:element name="smallCaps" type="CT_OnOff"/>
|
||||
// <xsd:element name="strike" type="CT_OnOff"/>
|
||||
// <xsd:element name="dstrike" type="CT_OnOff"/>
|
||||
// <xsd:element name="outline" type="CT_OnOff"/>
|
||||
// <xsd:element name="shadow" type="CT_OnOff"/>
|
||||
// <xsd:element name="emboss" type="CT_OnOff"/>
|
||||
// <xsd:element name="imprint" type="CT_OnOff"/>
|
||||
// <xsd:element name="noProof" type="CT_OnOff"/>
|
||||
// <xsd:element name="snapToGrid" type="CT_OnOff"/>
|
||||
// <xsd:element name="vanish" type="CT_OnOff"/>
|
||||
// <xsd:element name="webHidden" type="CT_OnOff"/>
|
||||
// <xsd:element name="color" type="CT_Color"/>
|
||||
// <xsd:element name="spacing" type="CT_SignedTwipsMeasure"/>
|
||||
// <xsd:element name="w" type="CT_TextScale"/>
|
||||
// <xsd:element name="kern" type="CT_HpsMeasure"/>
|
||||
// <xsd:element name="position" type="CT_SignedHpsMeasure"/>
|
||||
// <xsd:element name="sz" type="CT_HpsMeasure"/>
|
||||
// <xsd:element name="szCs" type="CT_HpsMeasure"/>
|
||||
// <xsd:element name="highlight" type="CT_Highlight"/>
|
||||
// <xsd:element name="u" type="CT_Underline"/>
|
||||
// <xsd:element name="effect" type="CT_TextEffect"/>
|
||||
// <xsd:element name="bdr" type="CT_Border"/>
|
||||
// <xsd:element name="shd" type="CT_Shd"/>
|
||||
// <xsd:element name="fitText" type="CT_FitText"/>
|
||||
// <xsd:element name="vertAlign" type="CT_VerticalAlignRun"/>
|
||||
// <xsd:element name="rtl" type="CT_OnOff"/>
|
||||
// <xsd:element name="cs" type="CT_OnOff"/>
|
||||
// <xsd:element name="em" type="CT_Em"/>
|
||||
// <xsd:element name="lang" type="CT_Language"/>
|
||||
// <xsd:element name="eastAsianLayout" type="CT_EastAsianLayout"/>
|
||||
// <xsd:element name="specVanish" type="CT_OnOff"/>
|
||||
// <xsd:element name="oMath" type="CT_OnOff"/>
|
||||
// </xsd:choice>
|
||||
// </xsd:group>
|
||||
export class RunProperties extends IgnoreIfEmptyXmlComponent {
|
||||
constructor(options?: IRunPropertiesOptions) {
|
||||
super("w:rPr");
|
||||
@ -74,17 +99,17 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent {
|
||||
}
|
||||
|
||||
if (options.bold) {
|
||||
this.push(new Bold());
|
||||
this.push(new OnOffElement("w:b"));
|
||||
}
|
||||
if ((options.boldComplexScript === undefined && options.bold) || options.boldComplexScript) {
|
||||
this.push(new BoldComplexScript());
|
||||
this.push(new OnOffElement("w:bCs"));
|
||||
}
|
||||
|
||||
if (options.italics) {
|
||||
this.push(new Italics());
|
||||
this.push(new OnOffElement("w:i"));
|
||||
}
|
||||
if ((options.italicsComplexScript === undefined && options.italics) || options.italicsComplexScript) {
|
||||
this.push(new ItalicsComplexScript());
|
||||
this.push(new OnOffElement("w:iCs"));
|
||||
}
|
||||
|
||||
if (options.underline) {
|
||||
@ -100,32 +125,31 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent {
|
||||
}
|
||||
|
||||
if (options.size) {
|
||||
this.push(new Size(options.size));
|
||||
this.push(new HpsMeasureElement("w:sz", options.size));
|
||||
}
|
||||
const szCs =
|
||||
options.sizeComplexScript === undefined || options.sizeComplexScript === true ? options.size : options.sizeComplexScript;
|
||||
if (szCs) {
|
||||
this.push(new SizeComplexScript(szCs));
|
||||
this.push(new HpsMeasureElement("w:szCs", szCs));
|
||||
}
|
||||
|
||||
if (options.rightToLeft) {
|
||||
this.push(new RightToLeft());
|
||||
this.push(new OnOffElement("w:rtl"));
|
||||
}
|
||||
|
||||
// These two are mutually exclusive
|
||||
if (options.smallCaps) {
|
||||
this.push(new SmallCaps());
|
||||
}
|
||||
|
||||
if (options.allCaps) {
|
||||
this.push(new Caps());
|
||||
this.push(new OnOffElement("w:smallCaps"));
|
||||
} else if (options.allCaps) {
|
||||
this.push(new OnOffElement("w:caps"));
|
||||
}
|
||||
|
||||
if (options.strike) {
|
||||
this.push(new Strike());
|
||||
this.push(new OnOffElement("w:strike"));
|
||||
}
|
||||
|
||||
if (options.doubleStrike) {
|
||||
this.push(new DoubleStrike());
|
||||
this.push(new OnOffElement("w:dstrike"));
|
||||
}
|
||||
|
||||
if (options.subScript) {
|
||||
@ -166,11 +190,11 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent {
|
||||
}
|
||||
|
||||
if (options.emboss) {
|
||||
this.push(new Emboss());
|
||||
this.push(new OnOffElement("w:emboss"));
|
||||
}
|
||||
|
||||
if (options.imprint) {
|
||||
this.push(new Imprint());
|
||||
this.push(new OnOffElement("w:imprint"));
|
||||
}
|
||||
|
||||
if (options.shading) {
|
||||
|
@ -1,47 +0,0 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { DoubleStrike, Strike } from "./formatting";
|
||||
|
||||
describe("Strike", () => {
|
||||
let strike: Strike;
|
||||
|
||||
beforeEach(() => {
|
||||
strike = new Strike();
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Strike with correct root key", () => {
|
||||
const tree = new Formatter().format(strike);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:strike": {
|
||||
_attr: {
|
||||
"w:val": true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("DoubleStrike", () => {
|
||||
let strike: DoubleStrike;
|
||||
|
||||
beforeEach(() => {
|
||||
strike = new DoubleStrike();
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Double Strike with correct root key", () => {
|
||||
const tree = new Formatter().format(strike);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:dstrike": {
|
||||
_attr: {
|
||||
"w:val": true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -49,7 +49,7 @@ describe("SymbolRun", () => {
|
||||
emphasisMark: {
|
||||
type: EmphasisMarkType.DOT,
|
||||
},
|
||||
color: "green",
|
||||
color: "00FF00",
|
||||
size: 40,
|
||||
highlight: "yellow",
|
||||
});
|
||||
@ -65,7 +65,7 @@ describe("SymbolRun", () => {
|
||||
{ "w:iCs": { _attr: { "w:val": true } } },
|
||||
{ "w:u": { _attr: { "w:val": "double", "w:color": "red" } } },
|
||||
{ "w:em": { _attr: { "w:val": "dot" } } },
|
||||
{ "w:color": { _attr: { "w:val": "green" } } },
|
||||
{ "w:color": { _attr: { "w:val": "00FF00" } } },
|
||||
{ "w:sz": { _attr: { "w:val": 40 } } },
|
||||
{ "w:szCs": { _attr: { "w:val": 40 } } },
|
||||
{ "w:highlight": { _attr: { "w:val": "yellow" } } },
|
||||
|
@ -21,7 +21,7 @@ export enum UnderlineType {
|
||||
}
|
||||
|
||||
export abstract class BaseUnderline extends XmlComponent {
|
||||
constructor(underlineType: string, color?: string) {
|
||||
constructor(underlineType: UnderlineType, color?: string) {
|
||||
super("w:u");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
@ -40,96 +40,96 @@ export class Underline extends BaseUnderline {
|
||||
|
||||
export class DashUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("dash");
|
||||
super(UnderlineType.DASH);
|
||||
}
|
||||
}
|
||||
|
||||
export class DashDotDotHeavyUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("dashDotDotHeavy");
|
||||
super(UnderlineType.DASHDOTDOTHEAVY);
|
||||
}
|
||||
}
|
||||
|
||||
export class DashDotHeavyUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("dashDotHeavy");
|
||||
super(UnderlineType.DASHDOTHEAVY);
|
||||
}
|
||||
}
|
||||
|
||||
export class DashLongUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("dashLong");
|
||||
super(UnderlineType.DASHLONG);
|
||||
}
|
||||
}
|
||||
|
||||
export class DashLongHeavyUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("dashLongHeavy");
|
||||
super(UnderlineType.DASHLONGHEAVY);
|
||||
}
|
||||
}
|
||||
|
||||
export class DotDashUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("dotDash");
|
||||
super(UnderlineType.DOTDASH);
|
||||
}
|
||||
}
|
||||
|
||||
export class DotDotDashUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("dotDotDash");
|
||||
super(UnderlineType.DOTDOTDASH);
|
||||
}
|
||||
}
|
||||
|
||||
export class DottedUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("dotted");
|
||||
super(UnderlineType.DOTTED);
|
||||
}
|
||||
}
|
||||
|
||||
export class DottedHeavyUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("dottedHeavy");
|
||||
super(UnderlineType.DOTTEDHEAVY);
|
||||
}
|
||||
}
|
||||
|
||||
export class DoubleUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("double");
|
||||
super(UnderlineType.DOUBLE);
|
||||
}
|
||||
}
|
||||
|
||||
export class SingleUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("single");
|
||||
super(UnderlineType.SINGLE);
|
||||
}
|
||||
}
|
||||
|
||||
export class ThickUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("thick");
|
||||
super(UnderlineType.THICK);
|
||||
}
|
||||
}
|
||||
|
||||
export class WaveUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("wave");
|
||||
super(UnderlineType.WAVE);
|
||||
}
|
||||
}
|
||||
|
||||
export class WavyDoubleUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("wavyDouble");
|
||||
super(UnderlineType.WAVYDOUBLE);
|
||||
}
|
||||
}
|
||||
|
||||
export class WavyHeavyUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("wavyHeavy");
|
||||
super(UnderlineType.WAVYHEAVY);
|
||||
}
|
||||
}
|
||||
|
||||
export class WordsUnderline extends BaseUnderline {
|
||||
constructor() {
|
||||
super("words");
|
||||
super(UnderlineType.WORDS);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
// <xsd:attribute name="themeFillShade" type="ST_UcharHexNumber" use="optional"/>
|
||||
// </xsd:complexType>
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
import { hexColorValue } from "../values";
|
||||
|
||||
export interface IShadingAttributesProperties {
|
||||
readonly fill?: string;
|
||||
@ -34,9 +35,15 @@ class ShadingAttributes extends XmlAttributeComponent<IShadingAttributesProperti
|
||||
}
|
||||
|
||||
export class Shading extends XmlComponent {
|
||||
constructor(attrs: IShadingAttributesProperties) {
|
||||
constructor({ fill, color, val }: IShadingAttributesProperties) {
|
||||
super("w:shd");
|
||||
this.root.push(new ShadingAttributes(attrs));
|
||||
this.root.push(
|
||||
new ShadingAttributes({
|
||||
fill: fill === undefined ? fill : hexColorValue(fill),
|
||||
color: color === undefined ? color : hexColorValue(color),
|
||||
val,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,12 +60,12 @@ describe("TableCellProperties", () => {
|
||||
it("sets shading", () => {
|
||||
const properties = new TableCellProperties({
|
||||
shading: {
|
||||
fill: "test",
|
||||
color: "000",
|
||||
fill: "ffffff",
|
||||
color: "000000",
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(tree).to.deep.equal({ "w:tcPr": [{ "w:shd": { _attr: { "w:fill": "test", "w:color": "000" } } }] });
|
||||
expect(tree).to.deep.equal({ "w:tcPr": [{ "w:shd": { _attr: { "w:fill": "ffffff", "w:color": "000000" } } }] });
|
||||
});
|
||||
|
||||
it("should set the TableCellBorders", () => {
|
||||
|
@ -432,8 +432,8 @@ describe("TableCell", () => {
|
||||
const cell = new TableCell({
|
||||
children: [],
|
||||
shading: {
|
||||
fill: "red",
|
||||
color: "blue",
|
||||
fill: "FF0000",
|
||||
color: "0000ff",
|
||||
val: ShadingType.PERCENT_10,
|
||||
},
|
||||
});
|
||||
@ -447,8 +447,8 @@ describe("TableCell", () => {
|
||||
{
|
||||
"w:shd": {
|
||||
_attr: {
|
||||
"w:color": "blue",
|
||||
"w:fill": "red",
|
||||
"w:color": "0000ff",
|
||||
"w:fill": "FF0000",
|
||||
"w:val": "pct10",
|
||||
},
|
||||
},
|
||||
|
94
src/file/values.ts
Normal file
94
src/file/values.ts
Normal file
@ -0,0 +1,94 @@
|
||||
// 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.
|
||||
|
||||
// <xsd:simpleType name="ST_UniversalMeasure">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:pattern value="-?[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export function universalMeasureValue(val: string): string {
|
||||
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 val;
|
||||
}
|
||||
const universalMeasureUnits = ["mm", "cm", "in", "pt", "pc", "pi"];
|
||||
|
||||
// <xsd:simpleType name="ST_PositiveUniversalMeasure">
|
||||
// <xsd:restriction base="ST_UniversalMeasure">
|
||||
// <xsd:pattern value="[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export function positiveUniversalMeasureValue(val: string): string {
|
||||
const value = universalMeasureValue(val);
|
||||
if (parseInt(value, 10) < 0) {
|
||||
throw new Error(`Invalid value '${value}' specified. Expected a positive number.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// <xsd:simpleType name="ST_HexColor">
|
||||
// <xsd:union memberTypes="ST_HexColorAuto s:ST_HexColorRGB"/>
|
||||
// </xsd:simpleType>
|
||||
// <xsd:simpleType name="ST_HexColorAuto">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="auto"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
|
||||
// The xsd:hexBinary type represents binary data as a sequence of binary octets.
|
||||
// It uses hexadecimal encoding, where each binary octet is a two-character hexadecimal number.
|
||||
// Lowercase and uppercase letters A through F are permitted. For example, 0FB8 and 0fb8 are two
|
||||
// equal xsd:hexBinary representations consisting of two octets.
|
||||
// <xsd:simpleType name="ST_HexColorRGB">
|
||||
// <xsd:restriction base="xsd:hexBinary">
|
||||
// <xsd:length value="3" fixed="true"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export function hexColorValue(val: string): string {
|
||||
if (val === "auto") {
|
||||
return val;
|
||||
}
|
||||
// It's super common to see colors prefixed with a pound, but technically invalid here.
|
||||
// Most clients work with it, but strip it off anyway for strict compliance.
|
||||
const color = val.charAt(0) === "#" ? val.substring(1) : val;
|
||||
if (color.length !== 6 || isNaN(Number("0x" + color))) {
|
||||
throw new Error(`Invalid color value '${color}'. Expected six digit hex value (eg FF9900)`);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
// <xsd:simpleType name="ST_UnsignedDecimalNumber">
|
||||
// <xsd:restriction base="xsd:unsignedLong"/>
|
||||
// </xsd:simpleType>
|
||||
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);
|
||||
}
|
||||
|
||||
// <xsd:simpleType name="ST_SignedTwipsMeasure">
|
||||
// <xsd:union memberTypes="xsd:integer s:ST_UniversalMeasure"/>
|
||||
// </xsd:simpleType>
|
||||
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);
|
||||
}
|
||||
|
||||
// <xsd:simpleType name="ST_HpsMeasure">
|
||||
// <xsd:union memberTypes="s:ST_UnsignedDecimalNumber s:ST_PositiveUniversalMeasure"/>
|
||||
// </xsd:simpleType>
|
||||
export function hpsMeasureValue(val: string | number): string | number {
|
||||
return typeof val === "string" ? positiveUniversalMeasureValue(val) : unsignedDecimalNumber(val);
|
||||
}
|
@ -4,4 +4,5 @@ export * from "./default-attributes";
|
||||
export * from "./imported-xml-component";
|
||||
export * from "./xmlable-object";
|
||||
export * from "./initializable-xml-component";
|
||||
export * from "./simple-elements";
|
||||
export * from "./base";
|
||||
|
27
src/file/xml-components/simple-elements.ts
Normal file
27
src/file/xml-components/simple-elements.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { Attributes, XmlComponent } from "file/xml-components";
|
||||
|
||||
import { hpsMeasureValue } from "../values";
|
||||
|
||||
// This represents element type CT_OnOff, which indicate a boolean value.
|
||||
//
|
||||
// <xsd:complexType name="CT_OnOff">
|
||||
// <xsd:attribute name="val" type="s:ST_OnOff"/>
|
||||
// </xsd:complexType>
|
||||
export class OnOffElement extends XmlComponent {
|
||||
constructor(name: string, val: boolean | undefined = true) {
|
||||
super(name);
|
||||
this.root.push(new Attributes({ val }));
|
||||
}
|
||||
}
|
||||
|
||||
// This represents element type CT_HpsMeasure, which indicate an unsigned int or a measurement with unit.
|
||||
//
|
||||
// <xsd:complexType name="CT_HpsMeasure">
|
||||
// <xsd:attribute name="val" type="ST_HpsMeasure" use="required"/>
|
||||
// </xsd:complexType>
|
||||
export class HpsMeasureElement extends XmlComponent {
|
||||
constructor(name: string, val: number | string) {
|
||||
super(name);
|
||||
this.root.push(new Attributes({ val: hpsMeasureValue(val) }));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user