diff --git a/demo/21-bookmarks.ts b/demo/21-bookmarks.ts index cc0bac5517..d104ca7574 100644 --- a/demo/21-bookmarks.ts +++ b/demo/21-bookmarks.ts @@ -1,7 +1,7 @@ // 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 * as fs from "fs"; -import { Document, HeadingLevel, Packer, PageBreak, Paragraph } from "../build"; +import { Document, HeadingLevel, HyperlinkRef, HyperlinkType, Packer, PageBreak, Paragraph } from "../build"; 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."; @@ -10,13 +10,16 @@ const doc = new Document({ creator: "Clippy", title: "Sample Document", description: "A brief example of using docx with bookmarks and internal hyperlinks", + hyperlinks: { + myAnchorId: { + text: "Hyperlink", + type: HyperlinkType.INTERNAL, + }, + }, }); -const anchorId = "anchorID"; - // First create the bookmark -const bookmark = doc.createBookmark(anchorId, "Lorem Ipsum"); -const hyperlink = doc.createInternalHyperLink(anchorId, `Click me!`); +const bookmark = doc.createBookmark("myAnchorId", "Lorem Ipsum"); doc.addSection({ children: [ @@ -30,7 +33,7 @@ doc.addSection({ children: [new PageBreak()], }), new Paragraph({ - children: [hyperlink], + children: [new HyperlinkRef("myAnchorId")], }), ], }); diff --git a/demo/35-hyperlinks.ts b/demo/35-hyperlinks.ts index 9d2bd5062e..fb84f13099 100644 --- a/demo/35-hyperlinks.ts +++ b/demo/35-hyperlinks.ts @@ -1,13 +1,14 @@ // Example on how to add hyperlinks to websites // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, HyperlinkRef, Packer, Paragraph } from "../build"; +import { Document, HyperlinkRef, HyperlinkType, Packer, Paragraph } from "../build"; const doc = new Document({ hyperlinks: { myCoolLink: { link: "http://www.example.com", text: "Hyperlink", + type: HyperlinkType.EXTERNAL, }, }, }); diff --git a/src/file/core-properties/properties.ts b/src/file/core-properties/properties.ts index 3fb7bf45a4..ceddff39e0 100644 --- a/src/file/core-properties/properties.ts +++ b/src/file/core-properties/properties.ts @@ -2,10 +2,21 @@ import { XmlComponent } from "file/xml-components"; import { DocumentAttributes } from "../document/document-attributes"; import { INumberingOptions } from "../numbering"; -import { Paragraph } from "../paragraph"; +import { HyperlinkType, Paragraph } from "../paragraph"; import { IStylesOptions } from "../styles"; import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components"; +export interface IInternalHyperlinkDefinition { + readonly text: string; + readonly type: HyperlinkType.INTERNAL; +} + +export interface IExternalHyperlinkDefinition { + readonly link: string; + readonly text: string; + readonly type: HyperlinkType.EXTERNAL; +} + export interface IPropertiesOptions { readonly title?: string; readonly subject?: string; @@ -19,10 +30,7 @@ export interface IPropertiesOptions { readonly numbering?: INumberingOptions; readonly footnotes?: Paragraph[]; readonly hyperlinks?: { - readonly [key: string]: { - readonly link: string; - readonly text: string; - }; + readonly [key: string]: IInternalHyperlinkDefinition | IExternalHyperlinkDefinition; }; } diff --git a/src/file/file.ts b/src/file/file.ts index 14f6382b9f..21a8487d71 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -17,7 +17,7 @@ import { Footer, Header } from "./header"; import { HeaderWrapper, IDocumentHeader } from "./header-wrapper"; import { Media } from "./media"; import { Numbering } from "./numbering"; -import { Bookmark, Hyperlink, HyperlinkRef, Paragraph } from "./paragraph"; +import { Bookmark, Hyperlink, HyperlinkRef, HyperlinkType, Paragraph } from "./paragraph"; import { Relationships } from "./relationships"; import { TargetModeType } from "./relationships/relationship/relationship"; import { Settings } from "./settings"; @@ -158,7 +158,13 @@ export class File { continue; } - const hyperlink = this.createHyperlink(options.hyperlinks[key].link, options.hyperlinks[key].text); + const hyperlinkRef = options.hyperlinks[key]; + + const hyperlink = + hyperlinkRef.type === HyperlinkType.EXTERNAL + ? this.createHyperlink(hyperlinkRef.link, hyperlinkRef.text) + : this.createInternalHyperLink(key, hyperlinkRef.text); + cache[key] = hyperlink; } @@ -166,14 +172,6 @@ export class File { } } - public createInternalHyperLink(anchor: string, text?: string): Hyperlink { - const newText = text === undefined ? anchor : text; - const hyperlink = new Hyperlink(newText, shortid.generate().toLowerCase(), anchor); - // NOTE: unlike File#createHyperlink(), since the link is to an internal bookmark - // we don't need to create a new relationship. - return hyperlink; - } - public createBookmark(name: string, text: string = name): Bookmark { return new Bookmark(name, text, this.docRelationships.RelationshipCount); } @@ -219,9 +217,8 @@ export class File { } } - private createHyperlink(link: string, text?: string): Hyperlink { - const newText = text === undefined ? link : text; - const hyperlink = new Hyperlink(newText, shortid.generate().toLowerCase()); + private createHyperlink(link: string, text: string = link): Hyperlink { + const hyperlink = new Hyperlink(text, shortid.generate().toLowerCase()); this.docRelationships.createRelationship( hyperlink.linkId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", @@ -231,6 +228,13 @@ export class File { return hyperlink; } + private createInternalHyperLink(anchor: string, text: string = anchor): Hyperlink { + const hyperlink = new Hyperlink(text, shortid.generate().toLowerCase(), anchor); + // NOTE: unlike File#createHyperlink(), since the link is to an internal bookmark + // we don't need to create a new relationship. + return hyperlink; + } + private createHeader(header: Header): HeaderWrapper { const wrapper = new HeaderWrapper(this.media, this.currentRelationshipId++); diff --git a/src/file/paragraph/links/bookmark.ts b/src/file/paragraph/links/bookmark.ts index c8c339e578..5ef567899b 100644 --- a/src/file/paragraph/links/bookmark.ts +++ b/src/file/paragraph/links/bookmark.ts @@ -3,6 +3,10 @@ import { XmlComponent } from "file/xml-components"; import { TextRun } from "../run"; import { BookmarkEndAttributes, BookmarkStartAttributes } from "./bookmark-attributes"; +export class BookmarkRef { + constructor(public readonly name: string, public readonly text: string) {} +} + export class Bookmark { public readonly linkId: number; public readonly start: BookmarkStart; diff --git a/src/file/paragraph/links/hyperlink.ts b/src/file/paragraph/links/hyperlink.ts index ed69331863..302acfd603 100644 --- a/src/file/paragraph/links/hyperlink.ts +++ b/src/file/paragraph/links/hyperlink.ts @@ -3,6 +3,11 @@ 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) {} } diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index c97d8d34fd..c1a8861568 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -13,7 +13,7 @@ import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spa import { HeadingLevel, Style } from "./formatting/style"; import { LeaderType, TabStop, TabStopPosition, TabStopType } from "./formatting/tab-stop"; import { NumberProperties } from "./formatting/unordered-list"; -import { Bookmark, HyperlinkRef, OutlineLevel } from "./links"; +import { Bookmark, BookmarkRef, HyperlinkRef, OutlineLevel } from "./links"; import { ParagraphProperties } from "./properties"; import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run"; @@ -46,7 +46,7 @@ export interface IParagraphOptions { readonly custom?: boolean; }; readonly children?: Array< - TextRun | PictureRun | SymbolRun | Bookmark | PageBreak | SequentialIdentifier | FootnoteReferenceRun | HyperlinkRef + TextRun | PictureRun | SymbolRun | Bookmark | PageBreak | SequentialIdentifier | FootnoteReferenceRun | HyperlinkRef | BookmarkRef >; }