Merge pull request #784 from dolanmiu/feat/compat-mode
#773 Better hyperlink and bookmark syntax
This commit is contained in:
@ -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, HeadingLevel, HyperlinkRef, HyperlinkType, Packer, PageBreak, Paragraph } from "../build";
|
import { Bookmark, Document, Footer, HeadingLevel, InternalHyperlink, Packer, PageBreak, Paragraph, TextRun } 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,15 +10,26 @@ 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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
|
footers: {
|
||||||
|
default: new Footer({
|
||||||
|
children: [
|
||||||
|
new Paragraph({
|
||||||
|
children: [
|
||||||
|
new InternalHyperlink({
|
||||||
|
child: new TextRun({
|
||||||
|
text: "Click here!",
|
||||||
|
style: "Hyperlink",
|
||||||
|
}),
|
||||||
|
anchor: "myAnchorId",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
},
|
||||||
children: [
|
children: [
|
||||||
new Paragraph({
|
new Paragraph({
|
||||||
heading: HeadingLevel.HEADING_1,
|
heading: HeadingLevel.HEADING_1,
|
||||||
@ -30,7 +41,15 @@ doc.addSection({
|
|||||||
children: [new PageBreak()],
|
children: [new PageBreak()],
|
||||||
}),
|
}),
|
||||||
new Paragraph({
|
new Paragraph({
|
||||||
children: [new HyperlinkRef("myAnchorId")],
|
children: [
|
||||||
|
new InternalHyperlink({
|
||||||
|
child: new TextRun({
|
||||||
|
text: "Anchor Text",
|
||||||
|
style: "Hyperlink",
|
||||||
|
}),
|
||||||
|
anchor: "myAnchorId",
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -1,32 +1,39 @@
|
|||||||
// 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, HyperlinkType, Packer, Paragraph, Media } from "../build";
|
import { ExternalHyperlink, Document, Packer, Paragraph, Media, TextRun } from "../build";
|
||||||
|
|
||||||
const doc = new Document({
|
const doc = new Document({});
|
||||||
hyperlinks: {
|
|
||||||
myCoolLink: {
|
|
||||||
link: "http://www.example.com",
|
|
||||||
text: "Hyperlink",
|
|
||||||
type: HyperlinkType.EXTERNAL,
|
|
||||||
},
|
|
||||||
myOtherLink: {
|
|
||||||
link: "http://www.google.com",
|
|
||||||
text: "Google Link",
|
|
||||||
type: HyperlinkType.EXTERNAL,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const image1 = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
const image1 = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
children: [
|
children: [
|
||||||
new Paragraph({
|
new Paragraph({
|
||||||
children: [new HyperlinkRef("myCoolLink")],
|
children: [
|
||||||
|
new ExternalHyperlink({
|
||||||
|
child: new TextRun({
|
||||||
|
text: "Anchor Text",
|
||||||
|
style: "Hyperlink",
|
||||||
|
}),
|
||||||
|
link: "http://www.example.com",
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
new Paragraph({
|
new Paragraph({
|
||||||
children: [image1, new HyperlinkRef("myOtherLink")],
|
children: [
|
||||||
|
new ExternalHyperlink({
|
||||||
|
child: image1,
|
||||||
|
link: "http://www.google.com",
|
||||||
|
}),
|
||||||
|
new ExternalHyperlink({
|
||||||
|
child: new TextRun({
|
||||||
|
text: "BBC News Link",
|
||||||
|
style: "Hyperlink",
|
||||||
|
}),
|
||||||
|
link: "https://www.bbc.co.uk/news",
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -4884,7 +4884,7 @@
|
|||||||
},
|
},
|
||||||
"jsesc": {
|
"jsesc": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
|
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
|
||||||
"integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
|
"integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
@ -8149,9 +8149,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "2.9.2",
|
"version": "4.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz",
|
||||||
"integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
|
"integrity": "sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
|
@ -91,7 +91,7 @@
|
|||||||
"tslint": "^6.1.3",
|
"tslint": "^6.1.3",
|
||||||
"tslint-immutable": "^6.0.1",
|
"tslint-immutable": "^6.0.1",
|
||||||
"typedoc": "^0.16.11",
|
"typedoc": "^0.16.11",
|
||||||
"typescript": "2.9.2",
|
"typescript": "4.2.2",
|
||||||
"webpack": "^3.10.0"
|
"webpack": "^3.10.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -3,21 +3,10 @@ import { IDocumentBackgroundOptions } from "../document";
|
|||||||
|
|
||||||
import { DocumentAttributes } from "../document/document-attributes";
|
import { DocumentAttributes } from "../document/document-attributes";
|
||||||
import { INumberingOptions } from "../numbering";
|
import { INumberingOptions } from "../numbering";
|
||||||
import { HyperlinkType, Paragraph } from "../paragraph";
|
import { 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;
|
||||||
@ -30,9 +19,6 @@ export interface IPropertiesOptions {
|
|||||||
readonly styles?: IStylesOptions;
|
readonly styles?: IStylesOptions;
|
||||||
readonly numbering?: INumberingOptions;
|
readonly numbering?: INumberingOptions;
|
||||||
readonly footnotes?: Paragraph[];
|
readonly footnotes?: Paragraph[];
|
||||||
readonly hyperlinks?: {
|
|
||||||
readonly [key: string]: IInternalHyperlinkDefinition | IExternalHyperlinkDefinition;
|
|
||||||
};
|
|
||||||
readonly background?: IDocumentBackgroundOptions;
|
readonly background?: IDocumentBackgroundOptions;
|
||||||
readonly features?: {
|
readonly features?: {
|
||||||
readonly trackRevisions?: boolean;
|
readonly trackRevisions?: boolean;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// http://officeopenxml.com/WPdocument.php
|
// http://officeopenxml.com/WPdocument.php
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { Hyperlink, Paragraph } from "../paragraph";
|
import { ConcreteHyperlink, Paragraph } from "../paragraph";
|
||||||
import { Table } from "../table";
|
import { Table } from "../table";
|
||||||
import { TableOfContents } from "../table-of-contents";
|
import { TableOfContents } from "../table-of-contents";
|
||||||
import { Body } from "./body";
|
import { Body } from "./body";
|
||||||
@ -42,7 +42,7 @@ export class Document extends XmlComponent {
|
|||||||
this.root.push(this.body);
|
this.root.push(this.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(item: Paragraph | Table | TableOfContents | Hyperlink): Document {
|
public add(item: Paragraph | Table | TableOfContents | ConcreteHyperlink): Document {
|
||||||
this.body.push(item);
|
this.body.push(item);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import { Formatter } from "export/formatter";
|
|||||||
|
|
||||||
import { File } from "./file";
|
import { File } from "./file";
|
||||||
import { Footer, Header } from "./header";
|
import { Footer, Header } from "./header";
|
||||||
import { HyperlinkRef, HyperlinkType, Paragraph } from "./paragraph";
|
import { Paragraph } from "./paragraph";
|
||||||
import { Table, TableCell, TableRow } from "./table";
|
import { Table, TableCell, TableRow } from "./table";
|
||||||
import { TableOfContents } from "./table-of-contents";
|
import { TableOfContents } from "./table-of-contents";
|
||||||
|
|
||||||
@ -164,16 +164,6 @@ describe("File", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should add hyperlink child", () => {
|
|
||||||
const doc = new File(undefined, undefined, [
|
|
||||||
{
|
|
||||||
children: [new HyperlinkRef("test")],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(doc.HyperlinkCache).to.deep.equal({});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#addSection", () => {
|
describe("#addSection", () => {
|
||||||
@ -187,16 +177,6 @@ describe("File", () => {
|
|||||||
expect(spy.called).to.equal(true);
|
expect(spy.called).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should add hyperlink child", () => {
|
|
||||||
const doc = new File();
|
|
||||||
|
|
||||||
doc.addSection({
|
|
||||||
children: [new HyperlinkRef("test")],
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(doc.HyperlinkCache).to.deep.equal({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the underlying document's add when adding a Table", () => {
|
it("should call the underlying document's add when adding a Table", () => {
|
||||||
const file = new File();
|
const file = new File();
|
||||||
const spy = sinon.spy(file.Document, "add");
|
const spy = sinon.spy(file.Document, "add");
|
||||||
@ -256,29 +236,6 @@ describe("File", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#HyperlinkCache", () => {
|
|
||||||
it("should initially have empty hyperlink cache", () => {
|
|
||||||
const file = new File();
|
|
||||||
|
|
||||||
expect(file.HyperlinkCache).to.deep.equal({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should have hyperlink cache when option is added", () => {
|
|
||||||
const file = new File({
|
|
||||||
hyperlinks: {
|
|
||||||
myCoolLink: {
|
|
||||||
link: "http://www.example.com",
|
|
||||||
text: "Hyperlink",
|
|
||||||
type: HyperlinkType.EXTERNAL,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// tslint:disable-next-line: no-unused-expression no-string-literal
|
|
||||||
expect(file.HyperlinkCache["myCoolLink"]).to.exist;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#createFootnote", () => {
|
describe("#createFootnote", () => {
|
||||||
it("should create footnote", () => {
|
it("should create footnote", () => {
|
||||||
const wrapper = new File({
|
const wrapper = new File({
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import * as shortid from "shortid";
|
|
||||||
import { AppProperties } from "./app-properties/app-properties";
|
import { AppProperties } from "./app-properties/app-properties";
|
||||||
import { ContentTypes } from "./content-types/content-types";
|
import { ContentTypes } from "./content-types/content-types";
|
||||||
import { CoreProperties, IPropertiesOptions } from "./core-properties";
|
import { CoreProperties, IPropertiesOptions } from "./core-properties";
|
||||||
@ -17,9 +16,8 @@ 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 { Hyperlink, HyperlinkRef, HyperlinkType, Paragraph } from "./paragraph";
|
import { Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
import { TargetModeType } from "./relationships/relationship/relationship";
|
|
||||||
import { Settings } from "./settings";
|
import { Settings } from "./settings";
|
||||||
import { Styles } from "./styles";
|
import { Styles } from "./styles";
|
||||||
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
||||||
@ -41,7 +39,7 @@ export interface ISectionOptions {
|
|||||||
readonly size?: IPageSizeAttributes;
|
readonly size?: IPageSizeAttributes;
|
||||||
readonly margins?: IPageMarginAttributes;
|
readonly margins?: IPageMarginAttributes;
|
||||||
readonly properties?: SectionPropertiesOptions;
|
readonly properties?: SectionPropertiesOptions;
|
||||||
readonly children: (Paragraph | Table | TableOfContents | HyperlinkRef)[];
|
readonly children: (Paragraph | Table | TableOfContents)[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class File {
|
export class File {
|
||||||
@ -61,7 +59,6 @@ export class File {
|
|||||||
private readonly contentTypes: ContentTypes;
|
private readonly contentTypes: ContentTypes;
|
||||||
private readonly appProperties: AppProperties;
|
private readonly appProperties: AppProperties;
|
||||||
private readonly styles: Styles;
|
private readonly styles: Styles;
|
||||||
private readonly hyperlinkCache: { readonly [key: string]: Hyperlink } = {};
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
options: IPropertiesOptions = {
|
options: IPropertiesOptions = {
|
||||||
@ -136,12 +133,6 @@ export class File {
|
|||||||
this.document.Body.addSection(section.properties ? section.properties : {});
|
this.document.Body.addSection(section.properties ? section.properties : {});
|
||||||
|
|
||||||
for (const child of section.children) {
|
for (const child of section.children) {
|
||||||
if (child instanceof HyperlinkRef) {
|
|
||||||
const hyperlink = this.hyperlinkCache[child.id];
|
|
||||||
this.document.add(hyperlink);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.document.add(child);
|
this.document.add(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,27 +143,6 @@ export class File {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.hyperlinks) {
|
|
||||||
const cache = {};
|
|
||||||
|
|
||||||
for (const key in options.hyperlinks) {
|
|
||||||
if (!options.hyperlinks[key]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.hyperlinkCache = cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.features) {
|
if (options.features) {
|
||||||
if (options.features.trackRevisions) {
|
if (options.features.trackRevisions) {
|
||||||
this.settings.addTrackRevisions();
|
this.settings.addTrackRevisions();
|
||||||
@ -205,12 +175,6 @@ export class File {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
if (child instanceof HyperlinkRef) {
|
|
||||||
const hyperlink = this.hyperlinkCache[child.id];
|
|
||||||
this.document.add(hyperlink);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.document.add(child);
|
this.document.add(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,24 +185,6 @@ export class File {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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",
|
|
||||||
link,
|
|
||||||
TargetModeType.EXTERNAL,
|
|
||||||
);
|
|
||||||
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++);
|
||||||
|
|
||||||
@ -371,8 +317,4 @@ export class File {
|
|||||||
public get Settings(): Settings {
|
public get Settings(): Settings {
|
||||||
return this.settings;
|
return this.settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get HyperlinkCache(): { readonly [key: string]: Hyperlink } {
|
|
||||||
return this.hyperlinkCache;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ export class Media {
|
|||||||
return imageData;
|
return imageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get Array(): IMediaData[] {
|
public get Array(): readonly IMediaData[] {
|
||||||
const array = new Array<IMediaData>();
|
const array = new Array<IMediaData>();
|
||||||
|
|
||||||
this.map.forEach((data) => {
|
this.map.forEach((data) => {
|
||||||
|
@ -2,14 +2,20 @@ import { expect } from "chai";
|
|||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { Hyperlink } from "./";
|
import { TextRun } from "../run";
|
||||||
import { HyperlinkRef } from "./hyperlink";
|
import { ConcreteHyperlink, ExternalHyperlink, InternalHyperlink } from "./hyperlink";
|
||||||
|
|
||||||
describe("Hyperlink", () => {
|
describe("ConcreteHyperlink", () => {
|
||||||
let hyperlink: Hyperlink;
|
let hyperlink: ConcreteHyperlink;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
hyperlink = new Hyperlink("https://example.com", "superid");
|
hyperlink = new ConcreteHyperlink(
|
||||||
|
new TextRun({
|
||||||
|
text: "https://example.com",
|
||||||
|
style: "Hyperlink",
|
||||||
|
}),
|
||||||
|
"superid",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
@ -35,7 +41,14 @@ describe("Hyperlink", () => {
|
|||||||
|
|
||||||
describe("with optional anchor parameter", () => {
|
describe("with optional anchor parameter", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
hyperlink = new Hyperlink("Anchor Text", "superid2", "anchor");
|
hyperlink = new ConcreteHyperlink(
|
||||||
|
new TextRun({
|
||||||
|
text: "Anchor Text",
|
||||||
|
style: "Hyperlink",
|
||||||
|
}),
|
||||||
|
"superid2",
|
||||||
|
"anchor",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create an internal link with anchor tag", () => {
|
it("should create an internal link with anchor tag", () => {
|
||||||
@ -61,10 +74,53 @@ describe("Hyperlink", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("HyperlinkRef", () => {
|
describe("ExternalHyperlink", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
const hyperlinkRef = new HyperlinkRef("test-id");
|
it("should create", () => {
|
||||||
|
const externalHyperlink = new ExternalHyperlink({
|
||||||
|
child: new TextRun("test"),
|
||||||
|
link: "http://www.google.com",
|
||||||
|
});
|
||||||
|
|
||||||
expect(hyperlinkRef.id).to.equal("test-id");
|
expect(externalHyperlink.options.link).to.equal("http://www.google.com");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("InternalHyperlink", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("should create", () => {
|
||||||
|
const internalHyperlink = new InternalHyperlink({
|
||||||
|
child: new TextRun("test"),
|
||||||
|
anchor: "test-id",
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(internalHyperlink);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:hyperlink": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:anchor": "test-id",
|
||||||
|
"w:history": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:t": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xml:space": "preserve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"test",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
// http://officeopenxml.com/WPhyperlink.php
|
// http://officeopenxml.com/WPhyperlink.php
|
||||||
|
import * as shortid from "shortid";
|
||||||
|
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { TextRun } from "../run";
|
|
||||||
|
import { ParagraphChild } from "../paragraph";
|
||||||
import { HyperlinkAttributes, IHyperlinkAttributesProperties } from "./hyperlink-attributes";
|
import { HyperlinkAttributes, IHyperlinkAttributesProperties } from "./hyperlink-attributes";
|
||||||
|
|
||||||
export enum HyperlinkType {
|
export enum HyperlinkType {
|
||||||
@ -8,15 +11,10 @@ export enum HyperlinkType {
|
|||||||
EXTERNAL = "EXTERNAL",
|
EXTERNAL = "EXTERNAL",
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HyperlinkRef {
|
export class ConcreteHyperlink extends XmlComponent {
|
||||||
constructor(public readonly id: string) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Hyperlink extends XmlComponent {
|
|
||||||
public readonly linkId: string;
|
public readonly linkId: string;
|
||||||
private readonly textRun: TextRun;
|
|
||||||
|
|
||||||
constructor(text: string, relationshipId: string, anchor?: string) {
|
constructor(child: ParagraphChild, relationshipId: string, anchor?: string) {
|
||||||
super("w:hyperlink");
|
super("w:hyperlink");
|
||||||
|
|
||||||
this.linkId = relationshipId;
|
this.linkId = relationshipId;
|
||||||
@ -29,14 +27,16 @@ export class Hyperlink extends XmlComponent {
|
|||||||
|
|
||||||
const attributes = new HyperlinkAttributes(props);
|
const attributes = new HyperlinkAttributes(props);
|
||||||
this.root.push(attributes);
|
this.root.push(attributes);
|
||||||
this.textRun = new TextRun({
|
this.root.push(child);
|
||||||
text: text,
|
}
|
||||||
style: "Hyperlink",
|
|
||||||
});
|
|
||||||
this.root.push(this.textRun);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get TextRun(): TextRun {
|
export class InternalHyperlink extends ConcreteHyperlink {
|
||||||
return this.textRun;
|
constructor(options: { readonly child: ParagraphChild; readonly anchor: string }) {
|
||||||
|
super(options.child, shortid.generate().toLowerCase(), options.anchor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ExternalHyperlink {
|
||||||
|
constructor(public readonly options: { readonly child: ParagraphChild; readonly link: string }) {}
|
||||||
|
}
|
||||||
|
@ -8,8 +8,9 @@ import { EMPTY_OBJECT } from "file/xml-components";
|
|||||||
import { File } from "../file";
|
import { File } from "../file";
|
||||||
import { ShadingType } from "../table/shading";
|
import { ShadingType } from "../table/shading";
|
||||||
import { AlignmentType, HeadingLevel, LeaderType, PageBreak, TabStopPosition, TabStopType } from "./formatting";
|
import { AlignmentType, HeadingLevel, LeaderType, PageBreak, TabStopPosition, TabStopType } from "./formatting";
|
||||||
import { Bookmark, HyperlinkRef } from "./links";
|
import { Bookmark, ExternalHyperlink } from "./links";
|
||||||
import { Paragraph } from "./paragraph";
|
import { Paragraph } from "./paragraph";
|
||||||
|
import { TextRun } from "./run";
|
||||||
|
|
||||||
describe("Paragraph", () => {
|
describe("Paragraph", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
@ -763,7 +764,7 @@ describe("Paragraph", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("#shading", () => {
|
describe("#shading", () => {
|
||||||
it("should set paragraph outline level to the given value", () => {
|
it("should set shading to the given value", () => {
|
||||||
const paragraph = new Paragraph({
|
const paragraph = new Paragraph({
|
||||||
shading: {
|
shading: {
|
||||||
type: ShadingType.REVERSE_DIAGONAL_STRIPE,
|
type: ShadingType.REVERSE_DIAGONAL_STRIPE,
|
||||||
@ -793,20 +794,49 @@ describe("Paragraph", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("#prepForXml", () => {
|
describe("#prepForXml", () => {
|
||||||
it("should set paragraph outline level to the given value", () => {
|
it("should set Internal Hyperlink", () => {
|
||||||
const paragraph = new Paragraph({
|
const paragraph = new Paragraph({
|
||||||
children: [new HyperlinkRef("myAnchorId")],
|
children: [
|
||||||
|
new ExternalHyperlink({
|
||||||
|
child: new TextRun("test"),
|
||||||
|
link: "http://www.google.com",
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
const fileMock = ({
|
const fileMock = ({
|
||||||
HyperlinkCache: {
|
DocumentRelationships: {
|
||||||
myAnchorId: "test",
|
createRelationship: () => ({}),
|
||||||
},
|
},
|
||||||
// tslint:disable-next-line: no-any
|
} as unknown) as File;
|
||||||
} as any) as File;
|
|
||||||
paragraph.prepForXml(fileMock);
|
paragraph.prepForXml(fileMock);
|
||||||
const tree = new Formatter().format(paragraph);
|
const tree = new Formatter().format(paragraph);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:p": ["test"],
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:hyperlink": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rIdtest-unique-id",
|
||||||
|
"w:history": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:t": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xml:space": "preserve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"test",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
// http://officeopenxml.com/WPparagraph.php
|
// http://officeopenxml.com/WPparagraph.php
|
||||||
|
import * as shortid from "shortid";
|
||||||
|
|
||||||
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
||||||
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { File } from "../file";
|
import { File } from "../file";
|
||||||
|
import { TargetModeType } from "../relationships/relationship/relationship";
|
||||||
import { DeletedTextRun, InsertedTextRun } from "../track-revision";
|
import { DeletedTextRun, InsertedTextRun } from "../track-revision";
|
||||||
import { PageBreak } from "./formatting/page-break";
|
import { PageBreak } from "./formatting/page-break";
|
||||||
import { Bookmark, HyperlinkRef } from "./links";
|
import { Bookmark, ConcreteHyperlink, ExternalHyperlink, InternalHyperlink } from "./links";
|
||||||
import { Math } from "./math";
|
import { Math } from "./math";
|
||||||
import { IParagraphPropertiesOptions, ParagraphProperties } from "./properties";
|
import { IParagraphPropertiesOptions, ParagraphProperties } from "./properties";
|
||||||
import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run";
|
import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run";
|
||||||
|
|
||||||
export interface IParagraphOptions extends IParagraphPropertiesOptions {
|
export type ParagraphChild =
|
||||||
readonly text?: string;
|
|
||||||
readonly children?: (
|
|
||||||
| TextRun
|
| TextRun
|
||||||
| PictureRun
|
| PictureRun
|
||||||
| SymbolRun
|
| SymbolRun
|
||||||
@ -20,11 +21,15 @@ export interface IParagraphOptions extends IParagraphPropertiesOptions {
|
|||||||
| PageBreak
|
| PageBreak
|
||||||
| SequentialIdentifier
|
| SequentialIdentifier
|
||||||
| FootnoteReferenceRun
|
| FootnoteReferenceRun
|
||||||
| HyperlinkRef
|
| InternalHyperlink
|
||||||
|
| ExternalHyperlink
|
||||||
| InsertedTextRun
|
| InsertedTextRun
|
||||||
| DeletedTextRun
|
| DeletedTextRun
|
||||||
| Math
|
| Math;
|
||||||
)[];
|
|
||||||
|
export interface IParagraphOptions extends IParagraphPropertiesOptions {
|
||||||
|
readonly text?: string;
|
||||||
|
readonly children?: ParagraphChild[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Paragraph extends XmlComponent {
|
export class Paragraph extends XmlComponent {
|
||||||
@ -71,9 +76,16 @@ export class Paragraph extends XmlComponent {
|
|||||||
|
|
||||||
public prepForXml(file: File): IXmlableObject | undefined {
|
public prepForXml(file: File): IXmlableObject | undefined {
|
||||||
for (const element of this.root) {
|
for (const element of this.root) {
|
||||||
if (element instanceof HyperlinkRef) {
|
if (element instanceof ExternalHyperlink) {
|
||||||
const index = this.root.indexOf(element);
|
const index = this.root.indexOf(element);
|
||||||
this.root[index] = file.HyperlinkCache[element.id];
|
const concreteHyperlink = new ConcreteHyperlink(element.options.child, shortid.generate().toLowerCase());
|
||||||
|
file.DocumentRelationships.createRelationship(
|
||||||
|
concreteHyperlink.linkId,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
||||||
|
element.options.link,
|
||||||
|
TargetModeType.EXTERNAL,
|
||||||
|
);
|
||||||
|
this.root[index] = concreteHyperlink;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user