Merge pull request #1074 from LeSuisse/pageref-element

Add the pageref element
This commit is contained in:
Dolan
2021-08-06 04:02:37 +01:00
committed by GitHub
8 changed files with 173 additions and 1 deletions

View File

@ -1,7 +1,7 @@
// This demo shows how to create bookmarks then link to them with internal hyperlinks // This demo shows how to create bookmarks then link to them with internal hyperlinks
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; import * as fs from "fs";
import { Bookmark, Document, Footer, HeadingLevel, InternalHyperlink, Packer, PageBreak, Paragraph, TextRun } from "../build"; import { Bookmark, Document, Footer, HeadingLevel, InternalHyperlink, Packer, PageBreak, Paragraph, TextRun, PageRef } from "../build";
const LOREM_IPSUM = const LOREM_IPSUM =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mi velit, convallis convallis scelerisque nec, faucibus nec leo. Phasellus at posuere mauris, tempus dignissim velit. Integer et tortor dolor. Duis auctor efficitur mattis. Vivamus ut metus accumsan tellus auctor sollicitudin venenatis et nibh. Cras quis massa ac metus fringilla venenatis. Proin rutrum mauris purus, ut suscipit magna consectetur id. Integer consectetur sollicitudin ante, vitae faucibus neque efficitur in. Praesent ultricies nibh lectus. Mauris pharetra id odio eget iaculis. Duis dictum, risus id pellentesque rutrum, lorem quam malesuada massa, quis ullamcorper turpis urna a diam. Cras vulputate metus vel massa porta ullamcorper. Etiam porta condimentum nulla nec tristique. Sed nulla urna, pharetra non tortor sed, sollicitudin molestie diam. Maecenas enim leo, feugiat eget vehicula id, sollicitudin vitae ante."; "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mi velit, convallis convallis scelerisque nec, faucibus nec leo. Phasellus at posuere mauris, tempus dignissim velit. Integer et tortor dolor. Duis auctor efficitur mattis. Vivamus ut metus accumsan tellus auctor sollicitudin venenatis et nibh. Cras quis massa ac metus fringilla venenatis. Proin rutrum mauris purus, ut suscipit magna consectetur id. Integer consectetur sollicitudin ante, vitae faucibus neque efficitur in. Praesent ultricies nibh lectus. Mauris pharetra id odio eget iaculis. Duis dictum, risus id pellentesque rutrum, lorem quam malesuada massa, quis ullamcorper turpis urna a diam. Cras vulputate metus vel massa porta ullamcorper. Etiam porta condimentum nulla nec tristique. Sed nulla urna, pharetra non tortor sed, sollicitudin molestie diam. Maecenas enim leo, feugiat eget vehicula id, sollicitudin vitae ante.";
@ -55,6 +55,12 @@ const doc = new Document({
}), }),
], ],
}), }),
new Paragraph({
children: [
new TextRun("The bookmark can be seen on page "),
new PageRef("myAnchorId"),
]
}),
], ],
}, },
], ],

View File

@ -24,6 +24,17 @@ const link = this.doc.createInternalHyperLink('anchorForChapter1', 'This is a li
paragraph.addHyperLink(link); paragraph.addHyperLink(link);
``` ```
You can also get the page number of the bookmark by creating a page reference to it:
```ts
new Paragraph({
children: [
new TextRun("The chapter1 can be seen on page "),
new PageRef("anchorForChapter1"),
]
})
```
## External ## External
To create an external hyperlink you just need to specify the url and the text of the link, then add it to a paragraph with `doc.createHyperlink(url, text)`: To create an external hyperlink you just need to specify the url and the text of the link, then add it to a paragraph with `doc.createHyperlink(url, text)`:

View File

@ -1,3 +1,4 @@
export * from "./hyperlink"; export * from "./hyperlink";
export * from "./bookmark"; export * from "./bookmark";
export * from "./outline-level"; 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()],
});
}
}