Add the pageref element

This instruction is useful if you want to get the number of the page
containing a specific bookmark.
This commit is contained in:
Thomas Gerbet
2021-08-03 15:58:26 +02:00
parent 14013273af
commit 3f257bf5a4
8 changed files with 173 additions and 1 deletions

View File

@ -1,3 +1,4 @@
export * from "./hyperlink";
export * from "./bookmark";
export * from "./outline-level";
export * from "./pageref";

View File

@ -0,0 +1,24 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { PageRefFieldInstruction } from "./pageref-field-instruction";
describe("PageRef field instruction", () => {
describe("#constructor()", () => {
it("should construct a pageref field instruction without options", () => {
const instruction = new PageRefFieldInstruction("anchor");
const tree = new Formatter().format(instruction);
expect(tree).to.be.deep.equal({
"w:instrText": [
{
_attr: {
"xml:space": "preserve",
},
},
"PAGEREF anchor",
],
});
});
});
});

View File

@ -0,0 +1,25 @@
import { SpaceType } from "file/space-type";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
import { IPageRefOptions } from "./pageref-properties";
class TextAttributes extends XmlAttributeComponent<{ readonly space: SpaceType }> {
protected readonly xmlKeys = { space: "xml:space" };
}
export class PageRefFieldInstruction extends XmlComponent {
constructor(bookmarkId: string, options: IPageRefOptions = {}) {
super("w:instrText");
this.root.push(new TextAttributes({ space: SpaceType.PRESERVE }));
let instruction = `PAGEREF ${bookmarkId}`;
if (options.hyperlink) {
instruction = `${instruction} \\h`;
}
if (options.useRelativePosition) {
instruction = `${instruction} \\p`;
}
this.root.push(instruction);
}
}

View File

@ -0,0 +1,16 @@
// Options according to https://www.ecma-international.org/publications/standards/Ecma-376.htm (at Part 1, Page 1234)
export interface IPageRefOptions {
/**
* \h option - Creates a hyperlink to the bookmarked paragraph.
*/
readonly hyperlink?: boolean;
/**
* \p option - Causes the field to display its position relative to the source
* bookmark. If the PAGEREF field is on the same page as the
* bookmark, it omits "on page #" and returns "above" or "below"
* only. If the PAGEREF field is not on the same page as the
* bookmark, the string "on page #" is used.
*/
readonly useRelativePosition?: boolean;
}

View File

@ -0,0 +1,76 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { PageRef } from "./pageref";
describe("PageRef", () => {
describe("#constructor()", () => {
it("should construct a pageref without options", () => {
const pageref = new PageRef("some_bookmark");
const tree = new Formatter().format(pageref);
expect(tree).to.be.deep.equal({
"w:r": [
{
"w:fldChar": {
_attr: {
"w:dirty": true,
"w:fldCharType": "begin",
},
},
},
{
"w:instrText": [
{
_attr: {
"xml:space": "preserve",
},
},
"PAGEREF some_bookmark",
],
},
{
"w:fldChar": {
_attr: {
"w:fldCharType": "end",
},
},
},
],
});
});
it("should construct a pageref with all the options", () => {
const pageref = new PageRef("some_bookmark", { hyperlink: true, useRelativePosition: true });
const tree = new Formatter().format(pageref);
expect(tree).to.be.deep.equal({
"w:r": [
{
"w:fldChar": {
_attr: {
"w:dirty": true,
"w:fldCharType": "begin",
},
},
},
{
"w:instrText": [
{
_attr: {
"xml:space": "preserve",
},
},
"PAGEREF some_bookmark \\h \\p",
],
},
{
"w:fldChar": {
_attr: {
"w:fldCharType": "end",
},
},
},
],
});
});
});
});

View File

@ -0,0 +1,13 @@
// See https://www.ecma-international.org/publications/standards/Ecma-376.htm (at Part 1, Page 1234)
import { Begin, End } from "file/paragraph/run/field";
import { Run } from "../run";
import { PageRefFieldInstruction } from "./pageref-field-instruction";
import type { IPageRefOptions } from "./pageref-properties";
export class PageRef extends Run {
constructor(bookmarkId: string, options: IPageRefOptions = {}) {
super({
children: [new Begin(true), new PageRefFieldInstruction(bookmarkId, options), new End()],
});
}
}