Merge branch 'master' into feat/math
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
// http://officeopenxml.com/WPalignment.php
|
||||
// http://officeopenxml.com/WPtableAlignment.php
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
export enum AlignmentType {
|
||||
|
@ -7,6 +7,7 @@ export interface IIndentAttributesProperties {
|
||||
readonly firstLine?: number;
|
||||
readonly start?: number;
|
||||
readonly end?: number;
|
||||
readonly right?: number;
|
||||
}
|
||||
|
||||
class IndentAttributes extends XmlAttributeComponent<IIndentAttributesProperties> {
|
||||
@ -16,6 +17,7 @@ class IndentAttributes extends XmlAttributeComponent<IIndentAttributesProperties
|
||||
firstLine: "w:firstLine",
|
||||
start: "w:start",
|
||||
end: "w:end",
|
||||
right: "w:end", // alias
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -11,11 +11,8 @@ export enum HeadingLevel {
|
||||
}
|
||||
|
||||
export class Style extends XmlComponent {
|
||||
public readonly styleId: string;
|
||||
|
||||
constructor(styleId: string) {
|
||||
super("w:pStyle");
|
||||
this.styleId = styleId;
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: styleId,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Attributes, XmlComponent } from "file/xml-components";
|
||||
|
||||
export class NumberProperties extends XmlComponent {
|
||||
constructor(numberId: number, indentLevel: number) {
|
||||
constructor(numberId: number | string, indentLevel: number) {
|
||||
super("w:numPr");
|
||||
this.root.push(new IndentLevel(indentLevel));
|
||||
this.root.push(new NumberId(numberId));
|
||||
@ -20,11 +20,11 @@ class IndentLevel extends XmlComponent {
|
||||
}
|
||||
|
||||
class NumberId extends XmlComponent {
|
||||
constructor(id: number) {
|
||||
constructor(id: number | string) {
|
||||
super("w:numId");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: id,
|
||||
val: typeof id === "string" ? `{${id}}` : id,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { assert } from "chai";
|
||||
import { assert, expect } from "chai";
|
||||
|
||||
import { Utility } from "tests/utility";
|
||||
|
||||
@ -8,7 +8,7 @@ describe("Bookmark", () => {
|
||||
let bookmark: Bookmark;
|
||||
|
||||
beforeEach(() => {
|
||||
bookmark = new Bookmark("anchor", "Internal Link", 0);
|
||||
bookmark = new Bookmark("anchor", "Internal Link");
|
||||
});
|
||||
|
||||
it("should create a bookmark with three root elements", () => {
|
||||
@ -21,11 +21,8 @@ describe("Bookmark", () => {
|
||||
|
||||
it("should create a bookmark with the correct attributes on the bookmark start element", () => {
|
||||
const newJson = Utility.jsonify(bookmark);
|
||||
const attributes = {
|
||||
name: "anchor",
|
||||
id: "1",
|
||||
};
|
||||
assert.equal(JSON.stringify(newJson.start.root[0].root), JSON.stringify(attributes));
|
||||
|
||||
assert.equal(newJson.start.root[0].root.name, "anchor");
|
||||
});
|
||||
|
||||
it("should create a bookmark with the correct attributes on the text element", () => {
|
||||
@ -35,9 +32,6 @@ describe("Bookmark", () => {
|
||||
|
||||
it("should create a bookmark with the correct attributes on the bookmark end element", () => {
|
||||
const newJson = Utility.jsonify(bookmark);
|
||||
const attributes = {
|
||||
id: "1",
|
||||
};
|
||||
assert.equal(JSON.stringify(newJson.end.root[0].root), JSON.stringify(attributes));
|
||||
expect(newJson.end.root[0].root.id).to.be.a("string");
|
||||
});
|
||||
});
|
||||
|
@ -1,49 +1,41 @@
|
||||
// http://officeopenxml.com/WPbookmark.php
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import * as shortid from "shortid";
|
||||
import { TextRun } from "../run";
|
||||
import { BookmarkEndAttributes, BookmarkStartAttributes } from "./bookmark-attributes";
|
||||
|
||||
export class Bookmark {
|
||||
public readonly linkId: number;
|
||||
public readonly start: BookmarkStart;
|
||||
public readonly text: TextRun;
|
||||
public readonly end: BookmarkEnd;
|
||||
|
||||
constructor(name: string, text: string, relationshipsCount: number) {
|
||||
this.linkId = relationshipsCount + 1;
|
||||
constructor(name: string, text: string) {
|
||||
const linkId = shortid.generate().toLowerCase();
|
||||
|
||||
this.start = new BookmarkStart(name, this.linkId);
|
||||
this.start = new BookmarkStart(name, linkId);
|
||||
this.text = new TextRun(text);
|
||||
this.end = new BookmarkEnd(this.linkId);
|
||||
this.end = new BookmarkEnd(linkId);
|
||||
}
|
||||
}
|
||||
|
||||
export class BookmarkStart extends XmlComponent {
|
||||
public readonly linkId: number;
|
||||
|
||||
constructor(name: string, relationshipsCount: number) {
|
||||
constructor(name: string, linkId: string) {
|
||||
super("w:bookmarkStart");
|
||||
|
||||
this.linkId = relationshipsCount;
|
||||
const id = `${this.linkId}`;
|
||||
const attributes = new BookmarkStartAttributes({
|
||||
name,
|
||||
id,
|
||||
id: linkId,
|
||||
});
|
||||
this.root.push(attributes);
|
||||
}
|
||||
}
|
||||
|
||||
export class BookmarkEnd extends XmlComponent {
|
||||
public readonly linkId: number;
|
||||
|
||||
constructor(relationshipsCount: number) {
|
||||
constructor(linkId: string) {
|
||||
super("w:bookmarkEnd");
|
||||
|
||||
this.linkId = relationshipsCount;
|
||||
const id = `${this.linkId}`;
|
||||
const attributes = new BookmarkEndAttributes({
|
||||
id,
|
||||
id: linkId,
|
||||
});
|
||||
this.root.push(attributes);
|
||||
}
|
||||
|
@ -3,12 +3,13 @@ import { expect } from "chai";
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { Hyperlink } from "./";
|
||||
import { HyperlinkRef } from "./hyperlink";
|
||||
|
||||
describe("Hyperlink", () => {
|
||||
let hyperlink: Hyperlink;
|
||||
|
||||
beforeEach(() => {
|
||||
hyperlink = new Hyperlink("https://example.com", 0);
|
||||
hyperlink = new Hyperlink("https://example.com", "superid");
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
@ -19,7 +20,7 @@ describe("Hyperlink", () => {
|
||||
{
|
||||
_attr: {
|
||||
"w:history": 1,
|
||||
"r:id": "rId1",
|
||||
"r:id": "rIdsuperid",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -34,7 +35,7 @@ describe("Hyperlink", () => {
|
||||
|
||||
describe("with optional anchor parameter", () => {
|
||||
beforeEach(() => {
|
||||
hyperlink = new Hyperlink("Anchor Text", 0, "anchor");
|
||||
hyperlink = new Hyperlink("Anchor Text", "superid2", "anchor");
|
||||
});
|
||||
|
||||
it("should create an internal link with anchor tag", () => {
|
||||
@ -59,3 +60,11 @@ describe("Hyperlink", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("HyperlinkRef", () => {
|
||||
describe("#constructor()", () => {
|
||||
const hyperlinkRef = new HyperlinkRef("test-id");
|
||||
|
||||
expect(hyperlinkRef.id).to.equal("test-id");
|
||||
});
|
||||
});
|
||||
|
@ -3,14 +3,23 @@ import { XmlComponent } from "file/xml-components";
|
||||
import { TextRun } from "../run";
|
||||
import { HyperlinkAttributes, IHyperlinkAttributesProperties } from "./hyperlink-attributes";
|
||||
|
||||
export enum HyperlinkType {
|
||||
INTERNAL = "INTERNAL",
|
||||
EXTERNAL = "EXTERNAL",
|
||||
}
|
||||
|
||||
export class HyperlinkRef {
|
||||
constructor(public readonly id: string) {}
|
||||
}
|
||||
|
||||
export class Hyperlink extends XmlComponent {
|
||||
public readonly linkId: number;
|
||||
public readonly linkId: string;
|
||||
private readonly textRun: TextRun;
|
||||
|
||||
constructor(text: string, relationshipsCount: number, anchor?: string) {
|
||||
constructor(text: string, relationshipId: string, anchor?: string) {
|
||||
super("w:hyperlink");
|
||||
|
||||
this.linkId = relationshipsCount + 1;
|
||||
this.linkId = relationshipId;
|
||||
|
||||
const props: IHyperlinkAttributesProperties = {
|
||||
history: 1,
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { assert, expect } from "chai";
|
||||
import * as shortid from "shortid";
|
||||
import { stub } from "sinon";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { EMPTY_OBJECT } from "file/xml-components";
|
||||
|
||||
import { Numbering } from "../numbering";
|
||||
import { AlignmentType, HeadingLevel, LeaderType, PageBreak, TabStopPosition, TabStopType } from "./formatting";
|
||||
import { Bookmark } from "./links";
|
||||
import { Paragraph } from "./paragraph";
|
||||
|
||||
describe("Paragraph", () => {
|
||||
@ -540,14 +542,8 @@ describe("Paragraph", () => {
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree)
|
||||
.to.have.property("w:p")
|
||||
.which.is.an("array")
|
||||
.which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0])
|
||||
.to.have.property("w:pPr")
|
||||
.which.is.an("array")
|
||||
.which.has.length.at.least(1);
|
||||
expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]["w:pPr"][0]).to.deep.equal({
|
||||
"w:pStyle": { _attr: { "w:val": "ListParagraph" } },
|
||||
});
|
||||
@ -560,14 +556,8 @@ describe("Paragraph", () => {
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree)
|
||||
.to.have.property("w:p")
|
||||
.which.is.an("array")
|
||||
.which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0])
|
||||
.to.have.property("w:pPr")
|
||||
.which.is.an("array")
|
||||
.which.has.length.at.least(1);
|
||||
expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]["w:pPr"][0]).to.deep.equal({
|
||||
"w:pStyle": { _attr: { "w:val": "ListParagraph" } },
|
||||
});
|
||||
@ -580,14 +570,8 @@ describe("Paragraph", () => {
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree)
|
||||
.to.have.property("w:p")
|
||||
.which.is.an("array")
|
||||
.which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0])
|
||||
.to.have.property("w:pPr")
|
||||
.which.is.an("array")
|
||||
.which.has.length.at.least(2);
|
||||
expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(2);
|
||||
expect(tree["w:p"][0]["w:pPr"][1]).to.deep.equal({
|
||||
"w:numPr": [{ "w:ilvl": { _attr: { "w:val": 1 } } }, { "w:numId": { _attr: { "w:val": 1 } } }],
|
||||
});
|
||||
@ -596,40 +580,24 @@ describe("Paragraph", () => {
|
||||
|
||||
describe("#setNumbering", () => {
|
||||
it("should add list paragraph style to JSON", () => {
|
||||
const numbering = new Numbering();
|
||||
const numberedAbstract = numbering.createAbstractNumbering();
|
||||
numberedAbstract.createLevel(0, "lowerLetter", "%1)", "start");
|
||||
const letterNumbering = numbering.createConcreteNumbering(numberedAbstract);
|
||||
|
||||
const paragraph = new Paragraph({
|
||||
numbering: {
|
||||
num: letterNumbering,
|
||||
reference: "test id",
|
||||
level: 0,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree)
|
||||
.to.have.property("w:p")
|
||||
.which.is.an("array")
|
||||
.which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0])
|
||||
.to.have.property("w:pPr")
|
||||
.which.is.an("array")
|
||||
.which.has.length.at.least(1);
|
||||
expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]["w:pPr"][0]).to.deep.equal({
|
||||
"w:pStyle": { _attr: { "w:val": "ListParagraph" } },
|
||||
});
|
||||
});
|
||||
|
||||
it("it should add numbered properties", () => {
|
||||
const numbering = new Numbering();
|
||||
const numberedAbstract = numbering.createAbstractNumbering();
|
||||
numberedAbstract.createLevel(0, "lowerLetter", "%1)", "start");
|
||||
const letterNumbering = numbering.createConcreteNumbering(numberedAbstract);
|
||||
|
||||
const paragraph = new Paragraph({
|
||||
numbering: {
|
||||
num: letterNumbering,
|
||||
reference: "test id",
|
||||
level: 0,
|
||||
},
|
||||
});
|
||||
@ -640,10 +608,7 @@ describe("Paragraph", () => {
|
||||
"w:pPr": [
|
||||
{ "w:pStyle": { _attr: { "w:val": "ListParagraph" } } },
|
||||
{
|
||||
"w:numPr": [
|
||||
{ "w:ilvl": { _attr: { "w:val": 0 } } },
|
||||
{ "w:numId": { _attr: { "w:val": letterNumbering.id } } },
|
||||
],
|
||||
"w:numPr": [{ "w:ilvl": { _attr: { "w:val": 0 } } }, { "w:numId": { _attr: { "w:val": "{test id}" } } }],
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -652,6 +617,49 @@ describe("Paragraph", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("it should add bookmark", () => {
|
||||
stub(shortid, "generate").callsFake(() => {
|
||||
return "test-unique-id";
|
||||
});
|
||||
const paragraph = new Paragraph({
|
||||
children: [new Bookmark("test-id", "test")],
|
||||
});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:bookmarkStart": {
|
||||
_attr: {
|
||||
"w:id": "test-unique-id",
|
||||
"w:name": "test-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:r": [
|
||||
{
|
||||
"w:t": [
|
||||
{
|
||||
_attr: {
|
||||
"xml:space": "preserve",
|
||||
},
|
||||
},
|
||||
"test",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"w:bookmarkEnd": {
|
||||
_attr: {
|
||||
"w:id": "test-unique-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
describe("#style", () => {
|
||||
it("should set the paragraph style to the given styleId", () => {
|
||||
const paragraph = new Paragraph({
|
||||
|
@ -1,52 +1,30 @@
|
||||
// http://officeopenxml.com/WPparagraph.php
|
||||
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
||||
import { Num } from "file/numbering/num";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
||||
|
||||
import { Alignment, AlignmentType } from "./formatting/alignment";
|
||||
import { Bidirectional } from "./formatting/bidirectional";
|
||||
import { IBorderOptions, ThematicBreak } from "./formatting/border";
|
||||
import { IIndentAttributesProperties, Indent } from "./formatting/indent";
|
||||
import { KeepLines, KeepNext } from "./formatting/keep";
|
||||
import { PageBreak, PageBreakBefore } from "./formatting/page-break";
|
||||
import { ContextualSpacing, 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 { Bookmark, Hyperlink, OutlineLevel } from "./links";
|
||||
import { PageBreak } from "./formatting/page-break";
|
||||
import { Bookmark, HyperlinkRef } from "./links";
|
||||
import { Math } from "./math";
|
||||
import { ParagraphProperties } from "./properties";
|
||||
import { File } from "../file";
|
||||
import { InsertedTextRun, DeletedTextRun } from "../track-revision";
|
||||
import { IParagraphPropertiesOptions, ParagraphProperties } from "./properties";
|
||||
import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run";
|
||||
|
||||
export interface IParagraphOptions {
|
||||
export interface IParagraphOptions extends IParagraphPropertiesOptions {
|
||||
readonly text?: string;
|
||||
readonly border?: IBorderOptions;
|
||||
readonly spacing?: ISpacingProperties;
|
||||
readonly outlineLevel?: number;
|
||||
readonly alignment?: AlignmentType;
|
||||
readonly heading?: HeadingLevel;
|
||||
readonly bidirectional?: boolean;
|
||||
readonly thematicBreak?: boolean;
|
||||
readonly pageBreakBefore?: boolean;
|
||||
readonly contextualSpacing?: boolean;
|
||||
readonly indent?: IIndentAttributesProperties;
|
||||
readonly keepLines?: boolean;
|
||||
readonly keepNext?: boolean;
|
||||
readonly tabStops?: Array<{
|
||||
readonly position: number | TabStopPosition;
|
||||
readonly type: TabStopType;
|
||||
readonly leader?: LeaderType;
|
||||
}>;
|
||||
readonly style?: string;
|
||||
readonly bullet?: {
|
||||
readonly level: number;
|
||||
};
|
||||
readonly numbering?: {
|
||||
readonly num: Num;
|
||||
readonly level: number;
|
||||
readonly custom?: boolean;
|
||||
};
|
||||
readonly children?: Array<TextRun | PictureRun | Hyperlink | SymbolRun | Bookmark | PageBreak | SequentialIdentifier | Math>;
|
||||
readonly children?: (
|
||||
| TextRun
|
||||
| PictureRun
|
||||
| SymbolRun
|
||||
| Bookmark
|
||||
| PageBreak
|
||||
| SequentialIdentifier
|
||||
| FootnoteReferenceRun
|
||||
| HyperlinkRef
|
||||
| InsertedTextRun
|
||||
| DeletedTextRun
|
||||
| Math
|
||||
)[];
|
||||
}
|
||||
|
||||
export class Paragraph extends XmlComponent {
|
||||
@ -69,9 +47,7 @@ export class Paragraph extends XmlComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
this.properties = new ParagraphProperties({
|
||||
border: options.border,
|
||||
});
|
||||
this.properties = new ParagraphProperties(options);
|
||||
|
||||
this.root.push(this.properties);
|
||||
|
||||
@ -79,72 +55,6 @@ export class Paragraph extends XmlComponent {
|
||||
this.root.push(new TextRun(options.text));
|
||||
}
|
||||
|
||||
if (options.spacing) {
|
||||
this.properties.push(new Spacing(options.spacing));
|
||||
}
|
||||
|
||||
if (options.outlineLevel !== undefined) {
|
||||
this.properties.push(new OutlineLevel(options.outlineLevel));
|
||||
}
|
||||
|
||||
if (options.alignment) {
|
||||
this.properties.push(new Alignment(options.alignment));
|
||||
}
|
||||
|
||||
if (options.heading) {
|
||||
this.properties.push(new Style(options.heading));
|
||||
}
|
||||
|
||||
if (options.bidirectional) {
|
||||
this.properties.push(new Bidirectional());
|
||||
}
|
||||
|
||||
if (options.thematicBreak) {
|
||||
this.properties.push(new ThematicBreak());
|
||||
}
|
||||
|
||||
if (options.pageBreakBefore) {
|
||||
this.properties.push(new PageBreakBefore());
|
||||
}
|
||||
|
||||
if (options.contextualSpacing) {
|
||||
this.properties.push(new ContextualSpacing(options.contextualSpacing));
|
||||
}
|
||||
|
||||
if (options.indent) {
|
||||
this.properties.push(new Indent(options.indent));
|
||||
}
|
||||
|
||||
if (options.keepLines) {
|
||||
this.properties.push(new KeepLines());
|
||||
}
|
||||
|
||||
if (options.keepNext) {
|
||||
this.properties.push(new KeepNext());
|
||||
}
|
||||
|
||||
if (options.tabStops) {
|
||||
for (const tabStop of options.tabStops) {
|
||||
this.properties.push(new TabStop(tabStop.type, tabStop.position, tabStop.leader));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.style) {
|
||||
this.properties.push(new Style(options.style));
|
||||
}
|
||||
|
||||
if (options.bullet) {
|
||||
this.properties.push(new Style("ListParagraph"));
|
||||
this.properties.push(new NumberProperties(1, options.bullet.level));
|
||||
}
|
||||
|
||||
if (options.numbering) {
|
||||
if (!options.numbering.custom) {
|
||||
this.properties.push(new Style("ListParagraph"));
|
||||
}
|
||||
this.properties.push(new NumberProperties(options.numbering.num.id, options.numbering.level));
|
||||
}
|
||||
|
||||
if (options.children) {
|
||||
for (const child of options.children) {
|
||||
if (child instanceof Bookmark) {
|
||||
@ -159,9 +69,15 @@ export class Paragraph extends XmlComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public referenceFootnote(id: number): Paragraph {
|
||||
this.root.push(new FootnoteReferenceRun(id));
|
||||
return this;
|
||||
public prepForXml(file: File): IXmlableObject | undefined {
|
||||
for (const element of this.root) {
|
||||
if (element instanceof HyperlinkRef) {
|
||||
const index = this.root.indexOf(element);
|
||||
this.root[index] = file.HyperlinkCache[element.id];
|
||||
}
|
||||
}
|
||||
|
||||
return super.prepForXml();
|
||||
}
|
||||
|
||||
public addRunToFront(run: Run): Paragraph {
|
||||
|
@ -1,19 +1,136 @@
|
||||
// http://officeopenxml.com/WPparagraphProperties.php
|
||||
import { IgnoreIfEmptyXmlComponent, XmlComponent } from "file/xml-components";
|
||||
import { Alignment, AlignmentType } from "./formatting/alignment";
|
||||
import { Bidirectional } from "./formatting/bidirectional";
|
||||
import { Border, IBorderOptions, 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 { HeadingLevel, Style } from "./formatting/style";
|
||||
import { LeaderType, TabStop, TabStopPosition, TabStopType } from "./formatting/tab-stop";
|
||||
import { NumberProperties } from "./formatting/unordered-list";
|
||||
import { OutlineLevel } from "./links";
|
||||
|
||||
import { Border, IBorderOptions } from "./formatting/border";
|
||||
export interface IParagraphStylePropertiesOptions {
|
||||
readonly alignment?: AlignmentType;
|
||||
readonly thematicBreak?: boolean;
|
||||
readonly contextualSpacing?: boolean;
|
||||
readonly rightTabStop?: number;
|
||||
readonly leftTabStop?: number;
|
||||
readonly indent?: IIndentAttributesProperties;
|
||||
readonly spacing?: ISpacingProperties;
|
||||
readonly keepNext?: boolean;
|
||||
readonly keepLines?: boolean;
|
||||
readonly outlineLevel?: number;
|
||||
}
|
||||
|
||||
interface IParagraphPropertiesOptions {
|
||||
export interface IParagraphPropertiesOptions extends IParagraphStylePropertiesOptions {
|
||||
readonly border?: IBorderOptions;
|
||||
readonly heading?: HeadingLevel;
|
||||
readonly bidirectional?: boolean;
|
||||
readonly pageBreakBefore?: boolean;
|
||||
readonly tabStops?: {
|
||||
readonly position: number | TabStopPosition;
|
||||
readonly type: TabStopType;
|
||||
readonly leader?: LeaderType;
|
||||
}[];
|
||||
readonly style?: string;
|
||||
readonly bullet?: {
|
||||
readonly level: number;
|
||||
};
|
||||
readonly numbering?: {
|
||||
readonly reference: string;
|
||||
readonly level: number;
|
||||
readonly custom?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export class ParagraphProperties extends IgnoreIfEmptyXmlComponent {
|
||||
constructor(options: IParagraphPropertiesOptions) {
|
||||
constructor(options?: IParagraphPropertiesOptions) {
|
||||
super("w:pPr");
|
||||
|
||||
if (!options) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.border) {
|
||||
this.push(new Border(options.border));
|
||||
}
|
||||
|
||||
if (options.spacing) {
|
||||
this.push(new Spacing(options.spacing));
|
||||
}
|
||||
|
||||
if (options.outlineLevel !== undefined) {
|
||||
this.push(new OutlineLevel(options.outlineLevel));
|
||||
}
|
||||
|
||||
if (options.alignment) {
|
||||
this.push(new Alignment(options.alignment));
|
||||
}
|
||||
|
||||
if (options.heading) {
|
||||
this.push(new Style(options.heading));
|
||||
}
|
||||
|
||||
if (options.bidirectional) {
|
||||
this.push(new Bidirectional());
|
||||
}
|
||||
|
||||
if (options.thematicBreak) {
|
||||
this.push(new ThematicBreak());
|
||||
}
|
||||
|
||||
if (options.pageBreakBefore) {
|
||||
this.push(new PageBreakBefore());
|
||||
}
|
||||
|
||||
if (options.contextualSpacing) {
|
||||
this.push(new ContextualSpacing(options.contextualSpacing));
|
||||
}
|
||||
|
||||
if (options.indent) {
|
||||
this.push(new Indent(options.indent));
|
||||
}
|
||||
|
||||
if (options.keepLines) {
|
||||
this.push(new KeepLines());
|
||||
}
|
||||
|
||||
if (options.keepNext) {
|
||||
this.push(new KeepNext());
|
||||
}
|
||||
|
||||
if (options.tabStops) {
|
||||
for (const tabStop of options.tabStops) {
|
||||
this.push(new TabStop(tabStop.type, tabStop.position, tabStop.leader));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.style) {
|
||||
this.push(new Style(options.style));
|
||||
}
|
||||
|
||||
if (options.bullet) {
|
||||
this.push(new Style("ListParagraph"));
|
||||
this.push(new NumberProperties(1, options.bullet.level));
|
||||
}
|
||||
|
||||
if (options.numbering) {
|
||||
if (!options.numbering.custom) {
|
||||
this.push(new Style("ListParagraph"));
|
||||
}
|
||||
this.push(new NumberProperties(options.numbering.reference, options.numbering.level));
|
||||
}
|
||||
|
||||
if (options.rightTabStop) {
|
||||
this.push(new TabStop(TabStopType.RIGHT, options.rightTabStop));
|
||||
}
|
||||
|
||||
if (options.leftTabStop) {
|
||||
this.push(new TabStop(TabStopType.LEFT, options.leftTabStop));
|
||||
}
|
||||
}
|
||||
|
||||
public push(item: XmlComponent): void {
|
||||
|
@ -1,13 +0,0 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
export class SmallCaps extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:smallCaps");
|
||||
}
|
||||
}
|
||||
|
||||
export class Caps extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:caps");
|
||||
}
|
||||
}
|
29
src/file/paragraph/run/emphasis-mark.spec.ts
Normal file
29
src/file/paragraph/run/emphasis-mark.spec.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import * as em from "./emphasis-mark";
|
||||
|
||||
describe("EmphasisMark", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a new EmphasisMark object with w:em as the rootKey", () => {
|
||||
const emphasisMark = new em.EmphasisMark();
|
||||
const tree = new Formatter().format(emphasisMark);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:em": { _attr: { "w:val": "dot" } },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("DotEmphasisMark", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should put value in attribute", () => {
|
||||
const emphasisMark = new em.DotEmphasisMark();
|
||||
const tree = new Formatter().format(emphasisMark);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:em": { _attr: { "w:val": "dot" } },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
28
src/file/paragraph/run/emphasis-mark.ts
Normal file
28
src/file/paragraph/run/emphasis-mark.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { Attributes, XmlComponent } from "file/xml-components";
|
||||
|
||||
export enum EmphasisMarkType {
|
||||
DOT = "dot",
|
||||
}
|
||||
|
||||
export abstract class BaseEmphasisMark extends XmlComponent {
|
||||
protected constructor(emphasisMarkType: EmphasisMarkType) {
|
||||
super("w:em");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: emphasisMarkType,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class EmphasisMark extends BaseEmphasisMark {
|
||||
constructor(emphasisMarkType: EmphasisMarkType = EmphasisMarkType.DOT) {
|
||||
super(emphasisMarkType);
|
||||
}
|
||||
}
|
||||
|
||||
export class DotEmphasisMark extends BaseEmphasisMark {
|
||||
constructor() {
|
||||
super(EmphasisMarkType.DOT);
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
import { Attributes, XmlComponent } from "file/xml-components";
|
||||
|
||||
export { Underline } from "./underline";
|
||||
export { EmphasisMark } from "./emphasis-mark";
|
||||
export { SubScript, SuperScript } from "./script";
|
||||
export { RunFonts } from "./run-fonts";
|
||||
export { RunFonts, IFontAttributesProperties } from "./run-fonts";
|
||||
|
||||
export class Bold extends XmlComponent {
|
||||
constructor() {
|
||||
@ -113,17 +115,6 @@ export class Imprint extends XmlComponent {
|
||||
}
|
||||
}
|
||||
|
||||
/* export class Shadow extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:shadow");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
val: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
} */
|
||||
|
||||
export class SmallCaps extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:smallCaps");
|
||||
|
@ -1,7 +1,10 @@
|
||||
export * from "./run";
|
||||
export * from "./properties";
|
||||
export * from "./text-run";
|
||||
export * from "./symbol-run";
|
||||
export * from "./picture-run";
|
||||
export * from "./run-fonts";
|
||||
export * from "./sequential-identifier";
|
||||
export * from "./underline";
|
||||
export * from "./emphasis-mark";
|
||||
export * from "./tab";
|
||||
|
@ -7,10 +7,6 @@ export class PictureRun extends Run {
|
||||
constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) {
|
||||
super({});
|
||||
|
||||
if (imageData === undefined) {
|
||||
throw new Error("imageData cannot be undefined");
|
||||
}
|
||||
|
||||
const drawing = new Drawing(imageData, drawingOptions);
|
||||
|
||||
this.root.push(drawing);
|
||||
|
@ -1,8 +1,183 @@
|
||||
import { ShadingType } from "file/table";
|
||||
import { IgnoreIfEmptyXmlComponent, XmlComponent } from "file/xml-components";
|
||||
import { EmphasisMark, EmphasisMarkType } from "./emphasis-mark";
|
||||
import {
|
||||
Bold,
|
||||
BoldComplexScript,
|
||||
Caps,
|
||||
CharacterSpacing,
|
||||
Color,
|
||||
DoubleStrike,
|
||||
Highlight,
|
||||
HighlightComplexScript,
|
||||
Italics,
|
||||
ItalicsComplexScript,
|
||||
RightToLeft,
|
||||
Shading,
|
||||
ShadowComplexScript,
|
||||
Size,
|
||||
SizeComplexScript,
|
||||
SmallCaps,
|
||||
Strike,
|
||||
} from "./formatting";
|
||||
import { IFontAttributesProperties, RunFonts } from "./run-fonts";
|
||||
import { SubScript, SuperScript } from "./script";
|
||||
import { Style } from "./style";
|
||||
import { Underline, UnderlineType } from "./underline";
|
||||
|
||||
interface IFontOptions {
|
||||
readonly name: string;
|
||||
readonly hint?: string;
|
||||
}
|
||||
|
||||
export interface IRunStylePropertiesOptions {
|
||||
readonly bold?: boolean;
|
||||
readonly boldComplexScript?: boolean;
|
||||
readonly italics?: boolean;
|
||||
readonly italicsComplexScript?: boolean;
|
||||
readonly underline?: {
|
||||
readonly color?: string;
|
||||
readonly type?: UnderlineType;
|
||||
};
|
||||
readonly emphasisMark?: {
|
||||
readonly type?: EmphasisMarkType;
|
||||
};
|
||||
readonly color?: string;
|
||||
readonly size?: number;
|
||||
readonly sizeComplexScript?: boolean | number;
|
||||
readonly rightToLeft?: boolean;
|
||||
readonly smallCaps?: boolean;
|
||||
readonly allCaps?: boolean;
|
||||
readonly strike?: boolean;
|
||||
readonly doubleStrike?: boolean;
|
||||
readonly subScript?: boolean;
|
||||
readonly superScript?: boolean;
|
||||
readonly font?: string | IFontOptions | IFontAttributesProperties;
|
||||
readonly highlight?: string;
|
||||
readonly highlightComplexScript?: boolean | string;
|
||||
readonly characterSpacing?: number;
|
||||
readonly shading?: {
|
||||
readonly type: ShadingType;
|
||||
readonly fill: string;
|
||||
readonly color: string;
|
||||
};
|
||||
readonly shadingComplexScript?: boolean | IRunStylePropertiesOptions["shading"];
|
||||
readonly shadow?: IRunStylePropertiesOptions["shading"];
|
||||
}
|
||||
|
||||
export interface IRunPropertiesOptions extends IRunStylePropertiesOptions {
|
||||
readonly style?: string;
|
||||
}
|
||||
|
||||
export class RunProperties extends IgnoreIfEmptyXmlComponent {
|
||||
constructor() {
|
||||
constructor(options?: IRunPropertiesOptions) {
|
||||
super("w:rPr");
|
||||
|
||||
if (!options) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.bold) {
|
||||
this.push(new Bold());
|
||||
}
|
||||
if ((options.boldComplexScript === undefined && options.bold) || options.boldComplexScript) {
|
||||
this.push(new BoldComplexScript());
|
||||
}
|
||||
|
||||
if (options.italics) {
|
||||
this.push(new Italics());
|
||||
}
|
||||
if ((options.italicsComplexScript === undefined && options.italics) || options.italicsComplexScript) {
|
||||
this.push(new ItalicsComplexScript());
|
||||
}
|
||||
|
||||
if (options.underline) {
|
||||
this.push(new Underline(options.underline.type, options.underline.color));
|
||||
}
|
||||
|
||||
if (options.emphasisMark) {
|
||||
this.push(new EmphasisMark(options.emphasisMark.type));
|
||||
}
|
||||
|
||||
if (options.color) {
|
||||
this.push(new Color(options.color));
|
||||
}
|
||||
|
||||
if (options.size) {
|
||||
this.push(new Size(options.size));
|
||||
}
|
||||
const szCs =
|
||||
options.sizeComplexScript === undefined || options.sizeComplexScript === true ? options.size : options.sizeComplexScript;
|
||||
if (szCs) {
|
||||
this.push(new SizeComplexScript(szCs));
|
||||
}
|
||||
|
||||
if (options.rightToLeft) {
|
||||
this.push(new RightToLeft());
|
||||
}
|
||||
|
||||
if (options.smallCaps) {
|
||||
this.push(new SmallCaps());
|
||||
}
|
||||
|
||||
if (options.allCaps) {
|
||||
this.push(new Caps());
|
||||
}
|
||||
|
||||
if (options.strike) {
|
||||
this.push(new Strike());
|
||||
}
|
||||
|
||||
if (options.doubleStrike) {
|
||||
this.push(new DoubleStrike());
|
||||
}
|
||||
|
||||
if (options.subScript) {
|
||||
this.push(new SubScript());
|
||||
}
|
||||
|
||||
if (options.superScript) {
|
||||
this.push(new SuperScript());
|
||||
}
|
||||
|
||||
if (options.style) {
|
||||
this.push(new Style(options.style));
|
||||
}
|
||||
|
||||
if (options.font) {
|
||||
if (typeof options.font === "string") {
|
||||
this.push(new RunFonts(options.font));
|
||||
} else if ("name" in options.font) {
|
||||
this.push(new RunFonts(options.font.name, options.font.hint));
|
||||
} else {
|
||||
this.push(new RunFonts(options.font));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.highlight) {
|
||||
this.push(new Highlight(options.highlight));
|
||||
}
|
||||
const highlightCs =
|
||||
options.highlightComplexScript === undefined || options.highlightComplexScript === true
|
||||
? options.highlight
|
||||
: options.highlightComplexScript;
|
||||
if (highlightCs) {
|
||||
this.push(new HighlightComplexScript(highlightCs));
|
||||
}
|
||||
|
||||
if (options.characterSpacing) {
|
||||
this.push(new CharacterSpacing(options.characterSpacing));
|
||||
}
|
||||
|
||||
const shading = options.shading || options.shadow;
|
||||
if (shading) {
|
||||
this.push(new Shading(shading.type, shading.fill, shading.color));
|
||||
}
|
||||
const shdCs =
|
||||
options.shadingComplexScript === undefined || options.shadingComplexScript === true ? shading : options.shadingComplexScript;
|
||||
if (shdCs) {
|
||||
this.push(new ShadowComplexScript(shdCs.type, shdCs.fill, shdCs.color));
|
||||
}
|
||||
}
|
||||
|
||||
public push(item: XmlComponent): void {
|
||||
|
@ -6,12 +6,6 @@ import { Text } from "./text";
|
||||
|
||||
describe("Text", () => {
|
||||
describe("#constructor", () => {
|
||||
it("creates an empty text run if no text is given", () => {
|
||||
const t = new Text("");
|
||||
const f = new Formatter().format(t);
|
||||
expect(f).to.deep.equal({ "w:t": { _attr: { "xml:space": "preserve" } } });
|
||||
});
|
||||
|
||||
it("adds the passed in text to the component", () => {
|
||||
const t = new Text(" this is\n text");
|
||||
const f = new Formatter().format(t);
|
||||
|
@ -9,8 +9,7 @@ export class Text extends XmlComponent {
|
||||
constructor(text: string) {
|
||||
super("w:t");
|
||||
this.root.push(new TextAttributes({ space: SpaceType.PRESERVE }));
|
||||
if (text) {
|
||||
this.root.push(text);
|
||||
}
|
||||
|
||||
this.root.push(text);
|
||||
}
|
||||
}
|
||||
|
@ -21,5 +21,12 @@ describe("RunFonts", () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("uses the font attrs for ascii and eastAsia", () => {
|
||||
const tree = new Formatter().format(new RunFonts({ ascii: "Times", eastAsia: "KaiTi" }));
|
||||
expect(tree).to.deep.equal({
|
||||
"w:rFonts": { _attr: { "w:ascii": "Times", "w:eastAsia": "KaiTi" } },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
interface IRunFontAttributesProperties {
|
||||
readonly ascii: string;
|
||||
readonly cs: string;
|
||||
readonly eastAsia: string;
|
||||
readonly hAnsi: string;
|
||||
export interface IFontAttributesProperties {
|
||||
readonly ascii?: string;
|
||||
readonly cs?: string;
|
||||
readonly eastAsia?: string;
|
||||
readonly hAnsi?: string;
|
||||
readonly hint?: string;
|
||||
}
|
||||
|
||||
class RunFontAttributes extends XmlAttributeComponent<IRunFontAttributesProperties> {
|
||||
class RunFontAttributes extends XmlAttributeComponent<IFontAttributesProperties> {
|
||||
protected readonly xmlKeys = {
|
||||
ascii: "w:ascii",
|
||||
cs: "w:cs",
|
||||
@ -19,16 +19,26 @@ class RunFontAttributes extends XmlAttributeComponent<IRunFontAttributesProperti
|
||||
}
|
||||
|
||||
export class RunFonts extends XmlComponent {
|
||||
constructor(ascii: string, hint?: string) {
|
||||
constructor(name: string, hint?: string);
|
||||
constructor(attrs: string | IFontAttributesProperties);
|
||||
constructor(nameOrAttrs: string | IFontAttributesProperties, hint?: string) {
|
||||
super("w:rFonts");
|
||||
this.root.push(
|
||||
new RunFontAttributes({
|
||||
ascii: ascii,
|
||||
cs: ascii,
|
||||
eastAsia: ascii,
|
||||
hAnsi: ascii,
|
||||
hint: hint,
|
||||
}),
|
||||
);
|
||||
if (typeof nameOrAttrs === "string") {
|
||||
// use constructor(name: string, hint?: string);
|
||||
const name = nameOrAttrs;
|
||||
this.root.push(
|
||||
new RunFontAttributes({
|
||||
ascii: name,
|
||||
cs: name,
|
||||
eastAsia: name,
|
||||
hAnsi: name,
|
||||
hint: hint,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
// use constructor(attrs: IRunFontAttributesProperties);
|
||||
const attrs = nameOrAttrs;
|
||||
this.root.push(new RunFontAttributes(attrs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
// import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
||||
import { ShadingType } from "file/table";
|
||||
|
||||
import { Run } from "./";
|
||||
import { EmphasisMarkType } from "./emphasis-mark";
|
||||
import { PageNumber } from "./run";
|
||||
import { UnderlineType } from "./underline";
|
||||
|
||||
describe("Run", () => {
|
||||
@ -82,6 +85,30 @@ describe("Run", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#emphasisMark()", () => {
|
||||
it("should default to 'dot'", () => {
|
||||
const run = new Run({
|
||||
emphasisMark: {},
|
||||
});
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [{ "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }] }],
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the style type if given", () => {
|
||||
const run = new Run({
|
||||
emphasisMark: {
|
||||
type: EmphasisMarkType.DOT,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [{ "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }] }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#smallCaps()", () => {
|
||||
it("it should add smallCaps to the properties", () => {
|
||||
const run = new Run({
|
||||
@ -89,7 +116,7 @@ describe("Run", () => {
|
||||
});
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [{ "w:rPr": [{ "w:smallCaps": {} }] }],
|
||||
"w:r": [{ "w:rPr": [{ "w:smallCaps": { _attr: { "w:val": true } } }] }],
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -101,7 +128,7 @@ describe("Run", () => {
|
||||
});
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [{ "w:rPr": [{ "w:caps": {} }] }],
|
||||
"w:r": [{ "w:rPr": [{ "w:caps": { _attr: { "w:val": true } } }] }],
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -130,6 +157,30 @@ describe("Run", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#subScript()", () => {
|
||||
it("it should add subScript to the properties", () => {
|
||||
const run = new Run({
|
||||
subScript: true,
|
||||
});
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [{ "w:rPr": [{ "w:vertAlign": { _attr: { "w:val": "subscript" } } }] }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#superScript()", () => {
|
||||
it("it should add superScript to the properties", () => {
|
||||
const run = new Run({
|
||||
superScript: true,
|
||||
});
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [{ "w:rPr": [{ "w:vertAlign": { _attr: { "w:val": "superscript" } } }] }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#highlight()", () => {
|
||||
it("it should add highlight to the properties", () => {
|
||||
const run = new Run({
|
||||
@ -197,17 +248,6 @@ describe("Run", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#tab()", () => {
|
||||
it("it should add break to the run", () => {
|
||||
const run = new Run({});
|
||||
run.tab();
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [{ "w:tab": {} }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#font()", () => {
|
||||
it("should set the font as named", () => {
|
||||
const run = new Run({
|
||||
@ -220,7 +260,42 @@ describe("Run", () => {
|
||||
"w:r": [
|
||||
{
|
||||
"w:rPr": [
|
||||
{ "w:rFonts": { _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } } },
|
||||
{
|
||||
"w:rFonts": {
|
||||
_attr: {
|
||||
"w:ascii": "Times",
|
||||
"w:cs": "Times",
|
||||
"w:eastAsia": "Times",
|
||||
"w:hAnsi": "Times",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the font for ascii and eastAsia", () => {
|
||||
const run = new Run({
|
||||
font: {
|
||||
ascii: "Times",
|
||||
eastAsia: "KaiTi",
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [
|
||||
{
|
||||
"w:rPr": [
|
||||
{
|
||||
"w:rFonts": {
|
||||
_attr: {
|
||||
"w:ascii": "Times",
|
||||
"w:eastAsia": "KaiTi",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@ -270,8 +345,10 @@ describe("Run", () => {
|
||||
|
||||
describe("#numberOfTotalPages", () => {
|
||||
it("should set the run to the RTL mode", () => {
|
||||
const run = new Run({});
|
||||
run.numberOfTotalPages();
|
||||
const run = new Run({
|
||||
children: [PageNumber.TOTAL_PAGES],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [
|
||||
@ -286,8 +363,10 @@ describe("Run", () => {
|
||||
|
||||
describe("#numberOfTotalPagesSection", () => {
|
||||
it("should set the run to the RTL mode", () => {
|
||||
const run = new Run({});
|
||||
run.numberOfTotalPagesSection();
|
||||
const run = new Run({
|
||||
children: [PageNumber.TOTAL_PAGES_IN_SECTION],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [
|
||||
@ -302,8 +381,9 @@ describe("Run", () => {
|
||||
|
||||
describe("#pageNumber", () => {
|
||||
it("should set the run to the RTL mode", () => {
|
||||
const run = new Run({});
|
||||
run.pageNumber();
|
||||
const run = new Run({
|
||||
children: [PageNumber.CURRENT],
|
||||
});
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [
|
||||
|
@ -1,63 +1,23 @@
|
||||
// http://officeopenxml.com/WPtext.php
|
||||
import { ShadingType } from "file/table";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
||||
import { FieldInstruction } from "file/table-of-contents/field-instruction";
|
||||
import { Break } from "./break";
|
||||
import { Caps, SmallCaps } from "./caps";
|
||||
import { Begin, End, Separate } from "./field";
|
||||
import {
|
||||
Bold,
|
||||
BoldComplexScript,
|
||||
Color,
|
||||
DoubleStrike,
|
||||
Highlight,
|
||||
HighlightComplexScript,
|
||||
Italics,
|
||||
ItalicsComplexScript,
|
||||
RightToLeft,
|
||||
Shading,
|
||||
ShadowComplexScript,
|
||||
Size,
|
||||
SizeComplexScript,
|
||||
Strike,
|
||||
} from "./formatting";
|
||||
import { NumberOfPages, NumberOfPagesSection, Page } from "./page-number";
|
||||
import { RunProperties } from "./properties";
|
||||
import { RunFonts } from "./run-fonts";
|
||||
import { SubScript, SuperScript } from "./script";
|
||||
import { Style } from "./style";
|
||||
import { Tab } from "./tab";
|
||||
import { Underline, UnderlineType } from "./underline";
|
||||
import { IRunPropertiesOptions, RunProperties } from "./properties";
|
||||
import { Text } from "./run-components/text";
|
||||
|
||||
export interface IRunOptions {
|
||||
readonly bold?: true;
|
||||
readonly italics?: true;
|
||||
readonly underline?: {
|
||||
readonly color?: string;
|
||||
readonly type?: UnderlineType;
|
||||
};
|
||||
readonly color?: string;
|
||||
readonly size?: number;
|
||||
readonly rightToLeft?: boolean;
|
||||
readonly smallCaps?: boolean;
|
||||
readonly allCaps?: boolean;
|
||||
readonly strike?: boolean;
|
||||
readonly doubleStrike?: boolean;
|
||||
readonly subScript?: boolean;
|
||||
readonly superScript?: boolean;
|
||||
readonly style?: string;
|
||||
readonly font?: {
|
||||
readonly name: string;
|
||||
readonly hint?: string;
|
||||
};
|
||||
readonly highlight?: string;
|
||||
readonly shading?: {
|
||||
readonly type: ShadingType;
|
||||
readonly fill: string;
|
||||
readonly color: string;
|
||||
};
|
||||
readonly children?: Array<Begin | FieldInstruction | Separate | End>;
|
||||
export interface IRunOptions extends IRunPropertiesOptions {
|
||||
readonly children?: (Begin | FieldInstruction | Separate | End | PageNumber | FootnoteReferenceRun | string)[];
|
||||
readonly text?: string;
|
||||
}
|
||||
|
||||
export enum PageNumber {
|
||||
CURRENT = "CURRENT",
|
||||
TOTAL_PAGES = "TOTAL_PAGES",
|
||||
TOTAL_PAGES_IN_SECTION = "TOTAL_PAGES_IN_SECTION",
|
||||
}
|
||||
|
||||
export class Run extends XmlComponent {
|
||||
@ -65,82 +25,42 @@ export class Run extends XmlComponent {
|
||||
|
||||
constructor(options: IRunOptions) {
|
||||
super("w:r");
|
||||
this.properties = new RunProperties();
|
||||
this.properties = new RunProperties(options);
|
||||
this.root.push(this.properties);
|
||||
|
||||
if (options.bold) {
|
||||
this.properties.push(new Bold());
|
||||
this.properties.push(new BoldComplexScript());
|
||||
}
|
||||
|
||||
if (options.italics) {
|
||||
this.properties.push(new Italics());
|
||||
this.properties.push(new ItalicsComplexScript());
|
||||
}
|
||||
|
||||
if (options.underline) {
|
||||
this.properties.push(new Underline(options.underline.type, options.underline.color));
|
||||
}
|
||||
|
||||
if (options.color) {
|
||||
this.properties.push(new Color(options.color));
|
||||
}
|
||||
|
||||
if (options.size) {
|
||||
this.properties.push(new Size(options.size));
|
||||
this.properties.push(new SizeComplexScript(options.size));
|
||||
}
|
||||
|
||||
if (options.rightToLeft) {
|
||||
this.properties.push(new RightToLeft());
|
||||
}
|
||||
|
||||
if (options.smallCaps) {
|
||||
this.properties.push(new SmallCaps());
|
||||
}
|
||||
|
||||
if (options.allCaps) {
|
||||
this.properties.push(new Caps());
|
||||
}
|
||||
|
||||
if (options.strike) {
|
||||
this.properties.push(new Strike());
|
||||
}
|
||||
|
||||
if (options.doubleStrike) {
|
||||
this.properties.push(new DoubleStrike());
|
||||
}
|
||||
|
||||
if (options.subScript) {
|
||||
this.properties.push(new SubScript());
|
||||
}
|
||||
|
||||
if (options.superScript) {
|
||||
this.properties.push(new SuperScript());
|
||||
}
|
||||
|
||||
if (options.style) {
|
||||
this.properties.push(new Style(options.style));
|
||||
}
|
||||
|
||||
if (options.font) {
|
||||
this.properties.push(new RunFonts(options.font.name, options.font.hint));
|
||||
}
|
||||
|
||||
if (options.highlight) {
|
||||
this.properties.push(new Highlight(options.highlight));
|
||||
this.properties.push(new HighlightComplexScript(options.highlight));
|
||||
}
|
||||
|
||||
if (options.shading) {
|
||||
this.properties.push(new Shading(options.shading.type, options.shading.fill, options.shading.color));
|
||||
this.properties.push(new ShadowComplexScript(options.shading.type, options.shading.fill, options.shading.color));
|
||||
}
|
||||
|
||||
if (options.children) {
|
||||
for (const child of options.children) {
|
||||
if (typeof child === "string") {
|
||||
switch (child) {
|
||||
case PageNumber.CURRENT:
|
||||
this.root.push(new Begin());
|
||||
this.root.push(new Page());
|
||||
this.root.push(new Separate());
|
||||
this.root.push(new End());
|
||||
break;
|
||||
case PageNumber.TOTAL_PAGES:
|
||||
this.root.push(new Begin());
|
||||
this.root.push(new NumberOfPages());
|
||||
this.root.push(new Separate());
|
||||
this.root.push(new End());
|
||||
break;
|
||||
case PageNumber.TOTAL_PAGES_IN_SECTION:
|
||||
this.root.push(new Begin());
|
||||
this.root.push(new NumberOfPagesSection());
|
||||
this.root.push(new Separate());
|
||||
this.root.push(new End());
|
||||
break;
|
||||
default:
|
||||
this.root.push(new Text(child));
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
this.root.push(child);
|
||||
}
|
||||
} else if (options.text) {
|
||||
this.root.push(new Text(options.text));
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,33 +68,4 @@ export class Run extends XmlComponent {
|
||||
this.root.splice(1, 0, new Break());
|
||||
return this;
|
||||
}
|
||||
|
||||
public tab(): Run {
|
||||
this.root.splice(1, 0, new Tab());
|
||||
return this;
|
||||
}
|
||||
|
||||
public pageNumber(): Run {
|
||||
this.root.push(new Begin());
|
||||
this.root.push(new Page());
|
||||
this.root.push(new Separate());
|
||||
this.root.push(new End());
|
||||
return this;
|
||||
}
|
||||
|
||||
public numberOfTotalPages(): Run {
|
||||
this.root.push(new Begin());
|
||||
this.root.push(new NumberOfPages());
|
||||
this.root.push(new Separate());
|
||||
this.root.push(new End());
|
||||
return this;
|
||||
}
|
||||
|
||||
public numberOfTotalPagesSection(): Run {
|
||||
this.root.push(new Begin());
|
||||
this.root.push(new NumberOfPagesSection());
|
||||
this.root.push(new Separate());
|
||||
this.root.push(new End());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { EmphasisMarkType } from "./emphasis-mark";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { UnderlineType } from "./underline";
|
||||
@ -44,6 +46,9 @@ describe("SymbolRun", () => {
|
||||
color: "red",
|
||||
type: UnderlineType.DOUBLE,
|
||||
},
|
||||
emphasisMark: {
|
||||
type: EmphasisMarkType.DOT,
|
||||
},
|
||||
color: "green",
|
||||
size: 40,
|
||||
highlight: "yellow",
|
||||
@ -59,6 +64,7 @@ describe("SymbolRun", () => {
|
||||
{ "w:i": { _attr: { "w:val": true } } },
|
||||
{ "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:sz": { _attr: { "w:val": 40 } } },
|
||||
{ "w:szCs": { _attr: { "w:val": 40 } } },
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
||||
|
||||
import { TextRun } from "./text-run";
|
||||
|
||||
@ -19,9 +20,11 @@ describe("TextRun", () => {
|
||||
|
||||
describe("#referenceFootnote()", () => {
|
||||
it("should add a valid footnote reference", () => {
|
||||
run = new TextRun("test");
|
||||
run.referenceFootnote(1);
|
||||
run = new TextRun({
|
||||
children: ["test", new FootnoteReferenceRun(1)],
|
||||
});
|
||||
const tree = new Formatter().format(run);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [
|
||||
{ "w:t": [{ _attr: { "xml:space": "preserve" } }, "test"] },
|
||||
|
@ -1,13 +1,8 @@
|
||||
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
||||
import { IRunOptions, Run } from "./run";
|
||||
import { Text } from "./run-components/text";
|
||||
|
||||
export interface ITextRunOptions extends IRunOptions {
|
||||
readonly text: string;
|
||||
}
|
||||
|
||||
export class TextRun extends Run {
|
||||
constructor(options: ITextRunOptions | string) {
|
||||
constructor(options: IRunOptions | string) {
|
||||
if (typeof options === "string") {
|
||||
super({});
|
||||
this.root.push(new Text(options));
|
||||
@ -15,11 +10,5 @@ export class TextRun extends Run {
|
||||
}
|
||||
|
||||
super(options);
|
||||
this.root.push(new Text(options.text));
|
||||
}
|
||||
|
||||
public referenceFootnote(id: number): TextRun {
|
||||
this.root.push(new FootnoteReferenceRun(id));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user