From c1cc211c7f84b9a675a8dd86c00b0ffc50ac636d Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Fri, 27 Aug 2021 16:53:11 -0600 Subject: [PATCH 1/4] Add children to hyperlink --- src/file/paragraph/links/hyperlink.spec.ts | 22 +++++++++++++--------- src/file/paragraph/links/hyperlink.ts | 10 ++++++---- src/file/paragraph/paragraph.spec.ts | 2 +- src/file/paragraph/paragraph.ts | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/file/paragraph/links/hyperlink.spec.ts b/src/file/paragraph/links/hyperlink.spec.ts index 50d6aa76aa..8b6fefb691 100644 --- a/src/file/paragraph/links/hyperlink.spec.ts +++ b/src/file/paragraph/links/hyperlink.spec.ts @@ -10,10 +10,12 @@ describe("ConcreteHyperlink", () => { beforeEach(() => { hyperlink = new ConcreteHyperlink( - new TextRun({ - text: "https://example.com", - style: "Hyperlink", - }), + [ + new TextRun({ + text: "https://example.com", + style: "Hyperlink", + }), + ], "superid", ); }); @@ -42,10 +44,12 @@ describe("ConcreteHyperlink", () => { describe("with optional anchor parameter", () => { beforeEach(() => { hyperlink = new ConcreteHyperlink( - new TextRun({ - text: "Anchor Text", - style: "Hyperlink", - }), + [ + new TextRun({ + text: "Anchor Text", + style: "Hyperlink", + }), + ], "superid2", "anchor", ); @@ -78,7 +82,7 @@ describe("ExternalHyperlink", () => { describe("#constructor()", () => { it("should create", () => { const externalHyperlink = new ExternalHyperlink({ - child: new TextRun("test"), + children: [new TextRun("test")], link: "http://www.google.com", }); diff --git a/src/file/paragraph/links/hyperlink.ts b/src/file/paragraph/links/hyperlink.ts index 7ced10d07c..7ee4409298 100644 --- a/src/file/paragraph/links/hyperlink.ts +++ b/src/file/paragraph/links/hyperlink.ts @@ -13,7 +13,7 @@ export enum HyperlinkType { export class ConcreteHyperlink extends XmlComponent { public readonly linkId: string; - constructor(child: ParagraphChild, relationshipId: string, anchor?: string) { + constructor(children: ParagraphChild[], relationshipId: string, anchor?: string) { super("w:hyperlink"); this.linkId = relationshipId; @@ -26,16 +26,18 @@ export class ConcreteHyperlink extends XmlComponent { const attributes = new HyperlinkAttributes(props); this.root.push(attributes); - this.root.push(child); + children.forEach((child) => { + this.root.push(child); + }); } } export class InternalHyperlink extends ConcreteHyperlink { constructor(options: { readonly child: ParagraphChild; readonly anchor: string }) { - super(options.child, uniqueId(), options.anchor); + super([options.child], uniqueId(), options.anchor); } } export class ExternalHyperlink { - constructor(public readonly options: { readonly child: ParagraphChild; readonly link: string }) {} + constructor(public readonly options: { readonly children: ParagraphChild[]; readonly link: string }) {} } diff --git a/src/file/paragraph/paragraph.spec.ts b/src/file/paragraph/paragraph.spec.ts index 90c6c8bedd..ab06d59ac1 100644 --- a/src/file/paragraph/paragraph.spec.ts +++ b/src/file/paragraph/paragraph.spec.ts @@ -927,7 +927,7 @@ describe("Paragraph", () => { const paragraph = new Paragraph({ children: [ new ExternalHyperlink({ - child: new TextRun("test"), + children: [new TextRun("test")], link: "http://www.google.com", }), ], diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index afd9da1b7d..2f73f7cc65 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -75,7 +75,7 @@ export class Paragraph extends XmlComponent { for (const element of this.root) { if (element instanceof ExternalHyperlink) { const index = this.root.indexOf(element); - const concreteHyperlink = new ConcreteHyperlink(element.options.child, uniqueId()); + const concreteHyperlink = new ConcreteHyperlink(element.options.children, uniqueId()); context.viewWrapper.Relationships.createRelationship( concreteHyperlink.linkId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", From 243d73542f9a29662fdbcb737350379f3b1752e3 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 31 Aug 2021 18:55:38 -0600 Subject: [PATCH 2/4] Update demo 35 with new API --- demo/35-hyperlinks.ts | 101 +++++++++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 27 deletions(-) diff --git a/demo/35-hyperlinks.ts b/demo/35-hyperlinks.ts index f8aca4f622..6039e6f443 100644 --- a/demo/35-hyperlinks.ts +++ b/demo/35-hyperlinks.ts @@ -11,10 +11,12 @@ const doc = new Document({ children: [ new TextRun("Click here for the "), new ExternalHyperlink({ - child: new TextRun({ - text: "Footnotes external hyperlink", - style: "Hyperlink", - }), + children: [ + new TextRun({ + text: "Footnotes external hyperlink", + style: "Hyperlink", + }), + ], link: "http://www.example.com", }), ], @@ -31,10 +33,12 @@ const doc = new Document({ children: [ new TextRun("Click here for the "), new ExternalHyperlink({ - child: new TextRun({ - text: "Footer external hyperlink", - style: "Hyperlink", - }), + children: [ + new TextRun({ + text: "Footer external hyperlink", + style: "Hyperlink", + }), + ], link: "http://www.example.com", }), ], @@ -49,10 +53,12 @@ const doc = new Document({ children: [ new TextRun("Click here for the "), new ExternalHyperlink({ - child: new TextRun({ - text: "Header external hyperlink", - style: "Hyperlink", - }), + children: [ + new TextRun({ + text: "Header external hyperlink", + style: "Hyperlink", + }), + ], link: "http://www.google.com", }), ], @@ -64,10 +70,12 @@ const doc = new Document({ new Paragraph({ children: [ new ExternalHyperlink({ - child: new TextRun({ - text: "Anchor Text", - style: "Hyperlink", - }), + children: [ + new TextRun({ + text: "Anchor Text", + style: "Hyperlink", + }), + ], link: "http://www.example.com", }), new FootnoteReferenceRun(1), @@ -76,24 +84,63 @@ const doc = new Document({ new Paragraph({ children: [ new ExternalHyperlink({ - child: new ImageRun({ - data: fs.readFileSync("./demo/images/image1.jpeg"), - transformation: { - width: 100, - height: 100, - }, - }), + children: [ + new ImageRun({ + data: fs.readFileSync("./demo/images/image1.jpeg"), + transformation: { + width: 100, + height: 100, + }, + }), + ], link: "http://www.google.com", }), new ExternalHyperlink({ - child: new TextRun({ - text: "BBC News Link", - style: "Hyperlink", - }), + children: [ + new TextRun({ + text: "BBC News Link", + style: "Hyperlink", + }), + ], link: "https://www.bbc.co.uk/news", }), ], }), + new Paragraph({ + children: [ + new TextRun({ + text: "This is a hyperlink with formatting: ", + }), + new ExternalHyperlink({ + children: [ + new TextRun({ + text: "A ", + style: "Hyperlink", + }), + new TextRun({ + text: "single ", + bold: true, + style: "Hyperlink", + }), + new TextRun({ + text: "link", + doubleStrike: true, + style: "Hyperlink", + }), + new TextRun({ + text: "1", + superScript: true, + style: "Hyperlink", + }), + new TextRun({ + text: "!", + style: "Hyperlink", + }), + ], + link: "http://www.example.com", + }), + ], + }), ], }, ], From 41f516d64b76a4561364602c4696287afb122808 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 31 Aug 2021 19:54:33 -0600 Subject: [PATCH 3/4] Make the internal hyperlink consistent --- demo/21-bookmarks.ts | 30 +++++++++++++--------- src/file/paragraph/links/hyperlink.spec.ts | 2 +- src/file/paragraph/links/hyperlink.ts | 4 +-- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/demo/21-bookmarks.ts b/demo/21-bookmarks.ts index 6c673f1520..56343c94cd 100644 --- a/demo/21-bookmarks.ts +++ b/demo/21-bookmarks.ts @@ -18,10 +18,12 @@ const doc = new Document({ new Paragraph({ children: [ new InternalHyperlink({ - child: new TextRun({ - text: "Click here!", - style: "Hyperlink", - }), + children: [ + new TextRun({ + text: "Click here!", + style: "Hyperlink", + }), + ], anchor: "myAnchorId", }), ], @@ -47,19 +49,23 @@ const doc = new Document({ new Paragraph({ children: [ new InternalHyperlink({ - child: new TextRun({ - text: "Anchor Text", - style: "Hyperlink", - }), + children: [ + new TextRun({ + text: "Styled", + bold: true, + style: "Hyperlink", + }), + new TextRun({ + text: " Anchor Text", + style: "Hyperlink", + }), + ], anchor: "myAnchorId", }), ], }), new Paragraph({ - children: [ - new TextRun("The bookmark can be seen on page "), - new PageRef("myAnchorId"), - ] + children: [new TextRun("The bookmark can be seen on page "), new PageRef("myAnchorId")], }), ], }, diff --git a/src/file/paragraph/links/hyperlink.spec.ts b/src/file/paragraph/links/hyperlink.spec.ts index 8b6fefb691..9f79a19ff1 100644 --- a/src/file/paragraph/links/hyperlink.spec.ts +++ b/src/file/paragraph/links/hyperlink.spec.ts @@ -95,7 +95,7 @@ describe("InternalHyperlink", () => { describe("#constructor()", () => { it("should create", () => { const internalHyperlink = new InternalHyperlink({ - child: new TextRun("test"), + children: [new TextRun("test")], anchor: "test-id", }); diff --git a/src/file/paragraph/links/hyperlink.ts b/src/file/paragraph/links/hyperlink.ts index 7ee4409298..2c39997908 100644 --- a/src/file/paragraph/links/hyperlink.ts +++ b/src/file/paragraph/links/hyperlink.ts @@ -33,8 +33,8 @@ export class ConcreteHyperlink extends XmlComponent { } export class InternalHyperlink extends ConcreteHyperlink { - constructor(options: { readonly child: ParagraphChild; readonly anchor: string }) { - super([options.child], uniqueId(), options.anchor); + constructor(options: { readonly children: ParagraphChild[]; readonly anchor: string }) { + super(options.children, uniqueId(), options.anchor); } } From 727e741b08a71cba8b4737e9b25e51d7b98e5b3b Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 31 Aug 2021 19:54:57 -0600 Subject: [PATCH 4/4] Hyperlink documentation --- docs/_sidebar.md | 1 + docs/usage/hyperlinks.md | 86 +++++++++++++++++++++++++++++----------- 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 7fa4e9f745..356f64239a 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -15,6 +15,7 @@ * [Image](usage/images.md) * [Headers & Footers](usage/headers-and-footers.md) * [Bullet Points](usage/bullet-points.md) + * [Hyperlinks](usage/hyperlinks.md) * [Numbering](usage/numbering.md) * [Tables](usage/tables.md) * [Tab Stops](usage/tab-stops.md) diff --git a/docs/usage/hyperlinks.md b/docs/usage/hyperlinks.md index f8d53416ee..d49d9aa0a2 100644 --- a/docs/usage/hyperlinks.md +++ b/docs/usage/hyperlinks.md @@ -1,58 +1,98 @@ # Hyperlinks +!> Hyperlinks require an understanding of [Paragraphs](usage/paragraph.md) and [Text](usage/text.md). + There are two types of hyperlinks: internal (pointing to a bookmark inside the document) and external (pointing to an external url). ## Internal -To create an internal hyperlink you need first to create a bookmark (the paragraph that will be the destination of the hyperlink) with `doc.createBookmark(anchor, text)`. +To create an internal hyperlink you need first to create a `Bookmark`, which contains the content that will be the destination of the hyperlink. -A bookmark is composed of an anchor (an identifier) and the text displayed. After creating a bookmark just add it to a paragraph with `paragraph.addBookmark(bookmark)` - -For example: +A bookmark is composed of an anchor (an identifier) and the text displayed. After creating a bookmark just add it to a paragraph. For example, creating a bookmarked heading: ```ts -const paragraph = this.doc.createParagraph(); -const bookmark = this.doc.createBookmark('anchorForChapter1', 'This is chapter1'); -paragraph.addBookmark(bookmark); +const chapter1 = new Paragraph({ + heading: HeadingLevel.HEADING_1, + children: [ + new Bookmark({ + id: "anchorForChapter1", + children: [ + new TextRun("Chapter 1"), + ], + }), + ], +}) ``` -Then you can create an hyperlink pointing to that bookmark with `doc.createInternalHyperLink(anchor,text)`: +Then you can create an hyperlink pointing to that bookmark with an `InternalHyperLink`: ```ts -const paragraph = this.doc.createParagraph(); -const link = this.doc.createInternalHyperLink('anchorForChapter1', 'This is a link to chapter1'); -paragraph.addHyperLink(link); +const link = new InternalHyperlink({ + children: [ + new TextRun({ + text: "See Chapter 1", + style: "Hyperlink", + }), + ], + anchor: "anchorForChapter1", +}) ``` You can also get the page number of the bookmark by creating a page reference to it: ```ts -new Paragraph({ +const paragraph = new Paragraph({ children: [ - new TextRun("The chapter1 can be seen on page "), + new TextRun("Chapter 1 can be seen on page "), new PageRef("anchorForChapter1"), - ] -}) + ], +}); ``` ## 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: ```ts -const paragraph = this.doc.createParagraph(); -const link = this.doc.createHyperlink('https://docx.js.org', 'This is an external link'); -paragraph.addHyperLink(link); +const paragraph = new Paragraph({ + children: [ + new ExternalHyperlink({ + children: [ + new TextRun({ + text: "This is an external link!", + style: "Hyperlink", + }), + ], + link: "https://docx.js.org", + }), + ], +}); ``` -## Styling an hyperlink +## Styling hyperlinks -It is possible to set the style of the text of an hyperlink. This can be done applying run formatting on `TextRun` property of the hyperlink. +It is possible to set the style of the text of both internal and external hyperlinks. This can be done applying run formatting on any of the `TextRun` children of the hyperlink. Use the `style: "Hyperlink"` property to show the default link styles, which can be combined with any other style. Example: ```ts -const link = this.doc.createHyperlink('https://docx.js.org', 'This is an external link'); -link.TextRun.bold().italics() +const styledLink = new ExternalHyperlink({ + children: [ + new TextRun({ + text: "This is a ", + style: "Hyperlink", + }), + new TextRun({ + text: "bold", + bold: true, + style: "Hyperlink", + }), + new TextRun({ + text: " link!", + style: "Hyperlink", + }), + ], + link: "https://docx.js.org", +}); ```