Declarative hyperlinks, bookmarks, tab stops and page breaks

This commit is contained in:
Dolan
2019-09-30 22:56:21 +01:00
parent d2dded860d
commit 04b6d8e54a
20 changed files with 207 additions and 165 deletions

View File

@ -44,7 +44,8 @@ export class FootNotes extends XmlComponent {
line: 240,
lineRule: "auto",
},
}).addRun(new SeperatorRun()),
children: [new SeperatorRun()],
}),
);
this.root.push(begin);
@ -56,7 +57,8 @@ export class FootNotes extends XmlComponent {
line: 240,
lineRule: "auto",
},
}).addRun(new ContinuationSeperatorRun()),
children: [new ContinuationSeperatorRun()],
}),
);
this.root.push(spacing);
}

View File

@ -8,8 +8,9 @@ import {
KeepLines,
KeepNext,
LeftTabStop,
MaxRightTabStop,
RightTabStop,
Spacing,
TabStopPosition,
ThematicBreak,
} from "../paragraph/formatting";
import { ParagraphProperties } from "../paragraph/properties";
@ -235,9 +236,8 @@ export class LevelBase extends XmlComponent {
return this;
}
public maxRightTabStop(): Level {
this.addParagraphProperty(new MaxRightTabStop());
return this;
public rightTabStop(position: number): Level {
return this.addParagraphProperty(new RightTabStop(position));
}
public leftTabStop(position: number): Level {

View File

@ -8,6 +8,7 @@ import { Num } from "./num";
import { Numbering } from "./numbering";
import { EMPTY_OBJECT } from "file/xml-components";
import { TabStopPosition } from "../paragraph";
describe("Numbering", () => {
let numbering: Numbering;
@ -202,7 +203,7 @@ describe("AbstractNumbering", () => {
it("#maxRightTabStop", () => {
const abstractNumbering = new AbstractNumbering(1);
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").maxRightTabStop();
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").rightTabStop(TabStopPosition.MAX);
const tree = new Formatter().format(level);
expect(tree["w:lvl"]).to.include({
"w:pPr": [

View File

@ -2,7 +2,7 @@ import { assert } from "chai";
import { Utility } from "tests/utility";
import { LeaderType, LeftTabStop, MaxRightTabStop, RightTabStop } from "./tab-stop";
import { LeaderType, LeftTabStop, RightTabStop } from "./tab-stop";
describe("LeftTabStop", () => {
let tabStop: LeftTabStop;
@ -52,28 +52,3 @@ describe("RightTabStop", () => {
});
});
});
describe("MaxRightTabStop", () => {
let tabStop: MaxRightTabStop;
beforeEach(() => {
tabStop = new MaxRightTabStop();
});
describe("#constructor()", () => {
it("should create a Tab Stop with correct attributes", () => {
const newJson = Utility.jsonify(tabStop);
const attributes = {
val: "right",
pos: 9026,
};
assert.equal(JSON.stringify(newJson.root[0].root[0].root), JSON.stringify(attributes));
});
it("should create a Tab Stop with w:tab", () => {
const newJson = Utility.jsonify(tabStop);
assert.equal(newJson.root[0].rootKey, "w:tab");
});
});
});

View File

@ -28,6 +28,10 @@ export enum LeaderType {
UNDERSCORE = "underscore",
}
export enum TabStopPosition {
MAX = 9026,
}
export class TabAttributes extends XmlAttributeComponent<{
readonly val: TabValue;
readonly pos: string | number;
@ -49,12 +53,6 @@ export class TabStopItem extends XmlComponent {
}
}
export class MaxRightTabStop extends TabStop {
constructor(leader?: LeaderType) {
super(new TabStopItem(TabValue.RIGHT, 9026, leader));
}
}
export class LeftTabStop extends TabStop {
constructor(position: number, leader?: LeaderType) {
super(new TabStopItem(TabValue.LEFT, position, leader));

View File

@ -4,7 +4,7 @@ import { Formatter } from "export/formatter";
import { EMPTY_OBJECT } from "file/xml-components";
import { Numbering } from "../numbering";
import { AlignmentType, HeadingLevel, LeaderType } from "./formatting";
import { AlignmentType, HeadingLevel, LeaderType, PageBreak, TabStopPosition } from "./formatting";
import { Paragraph } from "./paragraph";
describe("Paragraph", () => {
@ -254,10 +254,12 @@ describe("Paragraph", () => {
});
describe("#maxRightTabStop()", () => {
it("should add maxRightTabStop to JSON", () => {
it("should add right tab stop to JSON", () => {
const paragraph = new Paragraph({
tabStop: {
maxRight: {},
right: {
position: TabStopPosition.MAX,
},
},
});
const tree = new Formatter().format(paragraph);
@ -492,8 +494,9 @@ describe("Paragraph", () => {
describe("#pageBreak()", () => {
it("should add page break to JSON", () => {
const paragraph = new Paragraph({});
paragraph.pageBreak();
const paragraph = new Paragraph({
children: [new PageBreak()],
});
const tree = new Formatter().format(paragraph);
expect(tree).to.deep.equal({
"w:p": [

View File

@ -11,14 +11,14 @@ 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 { CenterTabStop, LeaderType, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop";
import { CenterTabStop, LeaderType, LeftTabStop, RightTabStop, TabStopPosition } from "./formatting/tab-stop";
import { NumberProperties } from "./formatting/unordered-list";
import { Bookmark, Hyperlink, OutlineLevel } from "./links";
import { ParagraphProperties } from "./properties";
import { PictureRun, Run, SequentialIdentifier, TextRun } from "./run";
interface ITabStopOptions {
readonly position: number;
readonly position: number | TabStopPosition;
readonly leader?: LeaderType;
}
@ -39,9 +39,6 @@ export interface IParagraphOptions {
readonly tabStop?: {
readonly left?: ITabStopOptions;
readonly right?: ITabStopOptions;
readonly maxRight?: {
readonly leader?: LeaderType;
};
readonly center?: ITabStopOptions;
};
readonly style?: string;
@ -53,7 +50,7 @@ export interface IParagraphOptions {
readonly level: number;
readonly custom?: boolean;
};
readonly children?: Array<TextRun | PictureRun | Hyperlink>;
readonly children?: Array<TextRun | PictureRun | Hyperlink | Bookmark | PageBreak>;
}
export class Paragraph extends XmlComponent {
@ -139,10 +136,6 @@ export class Paragraph extends XmlComponent {
this.properties.push(new RightTabStop(options.tabStop.right.position, options.tabStop.right.leader));
}
if (options.tabStop.maxRight) {
this.properties.push(new MaxRightTabStop(options.tabStop.maxRight.leader));
}
if (options.tabStop.center) {
this.properties.push(new CenterTabStop(options.tabStop.center.position, options.tabStop.center.leader));
}
@ -166,34 +159,18 @@ export class Paragraph extends XmlComponent {
if (options.children) {
for (const child of options.children) {
if (child instanceof Bookmark) {
this.root.push(child.start);
this.root.push(child.text);
this.root.push(child.end);
continue;
}
this.root.push(child);
}
}
}
public addRun(run: Run): Paragraph {
this.root.push(run);
return this;
}
public addHyperLink(hyperlink: Hyperlink): Paragraph {
this.root.push(hyperlink);
return this;
}
public addBookmark(bookmark: Bookmark): Paragraph {
// Bookmarks by spec have three components, a start, text, and end
this.root.push(bookmark.start);
this.root.push(bookmark.text);
this.root.push(bookmark.end);
return this;
}
public pageBreak(): Paragraph {
this.root.push(new PageBreak());
return this;
}
public referenceFootnote(id: number): Paragraph {
this.root.push(new FootnoteReferenceRun(id));
return this;

View File

@ -2,6 +2,7 @@
import { ShadingType } from "file/table";
import { XmlComponent } from "file/xml-components";
import { FieldInstruction } from "file/table-of-contents/field-instruction";
import { Break } from "./break";
import { Caps, SmallCaps } from "./caps";
import { Begin, End, Separate } from "./field";
@ -56,6 +57,7 @@ export interface IRunOptions {
readonly fill: string;
readonly color: string;
};
readonly children?: Array<Begin | FieldInstruction | Separate | End>;
}
export class Run extends XmlComponent {
@ -134,6 +136,12 @@ export class Run extends XmlComponent {
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) {
this.root.push(child);
}
}
}
public break(): Run {

View File

@ -1,11 +1,11 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { TabStopPosition } from "file/paragraph";
import { EMPTY_OBJECT } from "file/xml-components";
import { ParagraphStyle } from "./paragraph-style";
import { EMPTY_OBJECT } from "file/xml-components";
describe("ParagraphStyle", () => {
describe("#constructor", () => {
it("should set the style type to paragraph and use the given style id", () => {
@ -198,7 +198,7 @@ describe("ParagraphStyle", () => {
});
it("#maxRightTabStop", () => {
const style = new ParagraphStyle("myStyleId").maxRightTabStop();
const style = new ParagraphStyle("myStyleId").rightTabStop(TabStopPosition.MAX);
const tree = new Formatter().format(style);
expect(tree).to.deep.equal({
"w:style": [

View File

@ -6,12 +6,12 @@ import {
KeepLines,
KeepNext,
LeftTabStop,
MaxRightTabStop,
OutlineLevel,
ParagraphProperties,
Spacing,
ThematicBreak,
} from "file/paragraph";
import { RightTabStop } from "file/paragraph/formatting";
import * as formatting from "file/paragraph/run/formatting";
import { RunProperties } from "file/paragraph/run/properties";
import { XmlComponent } from "file/xml-components";
@ -144,8 +144,8 @@ export class ParagraphStyle extends Style {
return this.addParagraphProperty(new ThematicBreak());
}
public maxRightTabStop(): ParagraphStyle {
return this.addParagraphProperty(new MaxRightTabStop());
public rightTabStop(position: number): ParagraphStyle {
return this.addParagraphProperty(new RightTabStop(position));
}
public leftTabStop(position: number): ParagraphStyle {

View File

@ -16,18 +16,24 @@ export class TableOfContents extends XmlComponent {
const content = new StructuredDocumentTagContent();
const beginParagraph = new Paragraph({});
const beginRun = new Run({});
beginRun.addChildElement(new Begin(true));
beginRun.addChildElement(new FieldInstruction(properties));
beginRun.addChildElement(new Separate());
beginParagraph.addRun(beginRun);
const beginParagraph = new Paragraph({
children: [
new Run({
children: [new Begin(true), new FieldInstruction(properties), new Separate()],
}),
],
});
content.addChildElement(beginParagraph);
const endParagraph = new Paragraph({});
const endRun = new Run({});
endRun.addChildElement(new End());
endParagraph.addRun(endRun);
const endParagraph = new Paragraph({
children: [
new Run({
children: [new End()],
}),
],
});
content.addChildElement(endParagraph);
this.root.push(content);