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
// 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")],
}),
],
});

View File

@ -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,
},
},
});

View File

@ -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;
};
}

View File

@ -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++);

View File

@ -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;

View File

@ -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) {}
}

View File

@ -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
>;
}