Make internal hyperlink declarative

This commit is contained in:
Dolan Miu
2019-12-21 03:31:09 +00:00
parent c68dc8c52a
commit 3fdbca939e
7 changed files with 52 additions and 27 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 { Document, HeadingLevel, Packer, PageBreak, Paragraph } from "../build"; import { Document, HeadingLevel, HyperlinkRef, HyperlinkType, Packer, PageBreak, Paragraph } 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.";
@ -10,13 +10,16 @@ const doc = new Document({
creator: "Clippy", creator: "Clippy",
title: "Sample Document", title: "Sample Document",
description: "A brief example of using docx with bookmarks and internal hyperlinks", 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 // First create the bookmark
const bookmark = doc.createBookmark(anchorId, "Lorem Ipsum"); const bookmark = doc.createBookmark("myAnchorId", "Lorem Ipsum");
const hyperlink = doc.createInternalHyperLink(anchorId, `Click me!`);
doc.addSection({ doc.addSection({
children: [ children: [
@ -30,7 +33,7 @@ doc.addSection({
children: [new PageBreak()], children: [new PageBreak()],
}), }),
new Paragraph({ new Paragraph({
children: [hyperlink], children: [new HyperlinkRef("myAnchorId")],
}), }),
], ],
}); });

View File

@ -1,13 +1,14 @@
// Example on how to add hyperlinks to websites // Example on how to add hyperlinks to websites
// 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 { Document, HyperlinkRef, Packer, Paragraph } from "../build"; import { Document, HyperlinkRef, HyperlinkType, Packer, Paragraph } from "../build";
const doc = new Document({ const doc = new Document({
hyperlinks: { hyperlinks: {
myCoolLink: { myCoolLink: {
link: "http://www.example.com", link: "http://www.example.com",
text: "Hyperlink", text: "Hyperlink",
type: HyperlinkType.EXTERNAL,
}, },
}, },
}); });

View File

@ -2,10 +2,21 @@ import { XmlComponent } from "file/xml-components";
import { DocumentAttributes } from "../document/document-attributes"; import { DocumentAttributes } from "../document/document-attributes";
import { INumberingOptions } from "../numbering"; import { INumberingOptions } from "../numbering";
import { Paragraph } from "../paragraph"; import { HyperlinkType, Paragraph } from "../paragraph";
import { IStylesOptions } from "../styles"; import { IStylesOptions } from "../styles";
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components"; 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 { export interface IPropertiesOptions {
readonly title?: string; readonly title?: string;
readonly subject?: string; readonly subject?: string;
@ -19,10 +30,7 @@ export interface IPropertiesOptions {
readonly numbering?: INumberingOptions; readonly numbering?: INumberingOptions;
readonly footnotes?: Paragraph[]; readonly footnotes?: Paragraph[];
readonly hyperlinks?: { readonly hyperlinks?: {
readonly [key: string]: { readonly [key: string]: IInternalHyperlinkDefinition | IExternalHyperlinkDefinition;
readonly link: string;
readonly text: string;
};
}; };
} }

View File

@ -17,7 +17,7 @@ import { Footer, Header } from "./header";
import { HeaderWrapper, IDocumentHeader } from "./header-wrapper"; import { HeaderWrapper, IDocumentHeader } from "./header-wrapper";
import { Media } from "./media"; import { Media } from "./media";
import { Numbering } from "./numbering"; import { Numbering } from "./numbering";
import { Bookmark, Hyperlink, HyperlinkRef, Paragraph } from "./paragraph"; import { Bookmark, Hyperlink, HyperlinkRef, HyperlinkType, Paragraph } from "./paragraph";
import { Relationships } from "./relationships"; import { Relationships } from "./relationships";
import { TargetModeType } from "./relationships/relationship/relationship"; import { TargetModeType } from "./relationships/relationship/relationship";
import { Settings } from "./settings"; import { Settings } from "./settings";
@ -158,7 +158,13 @@ export class File {
continue; 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; 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 { public createBookmark(name: string, text: string = name): Bookmark {
return new Bookmark(name, text, this.docRelationships.RelationshipCount); return new Bookmark(name, text, this.docRelationships.RelationshipCount);
} }
@ -219,9 +217,8 @@ export class File {
} }
} }
private createHyperlink(link: string, text?: string): Hyperlink { private createHyperlink(link: string, text: string = link): Hyperlink {
const newText = text === undefined ? link : text; const hyperlink = new Hyperlink(text, shortid.generate().toLowerCase());
const hyperlink = new Hyperlink(newText, shortid.generate().toLowerCase());
this.docRelationships.createRelationship( this.docRelationships.createRelationship(
hyperlink.linkId, hyperlink.linkId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
@ -231,6 +228,13 @@ export class File {
return hyperlink; 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 { private createHeader(header: Header): HeaderWrapper {
const wrapper = new HeaderWrapper(this.media, this.currentRelationshipId++); const wrapper = new HeaderWrapper(this.media, this.currentRelationshipId++);

View File

@ -3,6 +3,10 @@ import { XmlComponent } from "file/xml-components";
import { TextRun } from "../run"; import { TextRun } from "../run";
import { BookmarkEndAttributes, BookmarkStartAttributes } from "./bookmark-attributes"; import { BookmarkEndAttributes, BookmarkStartAttributes } from "./bookmark-attributes";
export class BookmarkRef {
constructor(public readonly name: string, public readonly text: string) {}
}
export class Bookmark { export class Bookmark {
public readonly linkId: number; public readonly linkId: number;
public readonly start: BookmarkStart; public readonly start: BookmarkStart;

View File

@ -3,6 +3,11 @@ import { XmlComponent } from "file/xml-components";
import { TextRun } from "../run"; import { TextRun } from "../run";
import { HyperlinkAttributes, IHyperlinkAttributesProperties } from "./hyperlink-attributes"; import { HyperlinkAttributes, IHyperlinkAttributesProperties } from "./hyperlink-attributes";
export enum HyperlinkType {
INTERNAL = "INTERNAL",
EXTERNAL = "EXTERNAL",
}
export class HyperlinkRef { export class HyperlinkRef {
constructor(public readonly id: string) {} constructor(public readonly id: string) {}
} }

View File

@ -13,7 +13,7 @@ import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spa
import { HeadingLevel, Style } from "./formatting/style"; import { HeadingLevel, Style } from "./formatting/style";
import { LeaderType, TabStop, TabStopPosition, TabStopType } from "./formatting/tab-stop"; import { LeaderType, TabStop, TabStopPosition, TabStopType } from "./formatting/tab-stop";
import { NumberProperties } from "./formatting/unordered-list"; import { NumberProperties } from "./formatting/unordered-list";
import { Bookmark, HyperlinkRef, OutlineLevel } from "./links"; import { Bookmark, BookmarkRef, HyperlinkRef, OutlineLevel } from "./links";
import { ParagraphProperties } from "./properties"; import { ParagraphProperties } from "./properties";
import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run"; import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run";
@ -46,7 +46,7 @@ export interface IParagraphOptions {
readonly custom?: boolean; readonly custom?: boolean;
}; };
readonly children?: Array< readonly children?: Array<
TextRun | PictureRun | SymbolRun | Bookmark | PageBreak | SequentialIdentifier | FootnoteReferenceRun | HyperlinkRef TextRun | PictureRun | SymbolRun | Bookmark | PageBreak | SequentialIdentifier | FootnoteReferenceRun | HyperlinkRef | BookmarkRef
>; >;
} }