From 59ca9df66308696246c53b2cc52bbc62ae247bf6 Mon Sep 17 00:00:00 2001 From: amitm02 Date: Tue, 24 Jul 2018 18:58:01 +0300 Subject: [PATCH 1/9] remove post install --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index ce427aa8e9..5d180c2457 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "style": "prettier -l \"src/**/*.ts\"", "style.fix": "prettier \"src/**/*.ts\" --write", "fix-types": "node types-absolute-fixer.js", - "postinstall" : "npm run build" }, "files": [ "src", From 8ceb38963e83e419fd517b5e282e1a5309afc9aa Mon Sep 17 00:00:00 2001 From: Michael Myers Date: Tue, 24 Jul 2018 15:56:13 -0400 Subject: [PATCH 2/9] initial functionality --- src/file/file.ts | 14 ++++- .../paragraph/links/bookmark-attributes.ts | 23 ++++++++ src/file/paragraph/links/bookmark.ts | 57 +++++++++++++++++++ .../paragraph/links/hyperlink-attributes.ts | 2 + src/file/paragraph/links/hyperlink.ts | 18 ++++-- src/file/paragraph/links/index.ts | 1 + src/file/paragraph/paragraph.ts | 10 +++- 7 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 src/file/paragraph/links/bookmark-attributes.ts create mode 100644 src/file/paragraph/links/bookmark.ts diff --git a/src/file/file.ts b/src/file/file.ts index ae9cf9deac..ddc55841b3 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -10,7 +10,7 @@ import { FootNotes } from "./footnotes"; import { HeaderWrapper } from "./header-wrapper"; import { Media } from "./media"; import { Numbering } from "./numbering"; -import { Hyperlink, Paragraph, PictureRun } from "./paragraph"; +import { Bookmark, Hyperlink, Paragraph, PictureRun } from "./paragraph"; import { Relationships } from "./relationships"; import { Styles } from "./styles"; import { ExternalStylesFactory } from "./styles/external-styles-factory"; @@ -157,6 +157,18 @@ export class File { return hyperlink; } + public createInternalHyperLink(anchor: string, text?: string): Hyperlink { + text = text === undefined ? anchor : text; + const hyperlink = new Hyperlink(text, this.docRelationships.RelationshipCount, anchor); + return hyperlink; + } + + public createBookmark(name: string, text?: string): Bookmark { + text = text === undefined ? name : text; + const bookmark = new Bookmark(name, text, this.docRelationships.RelationshipCount); + return bookmark; + } + public addSection(sectionPropertiesOptions: SectionPropertiesOptions): void { this.document.Body.addSection(sectionPropertiesOptions); } diff --git a/src/file/paragraph/links/bookmark-attributes.ts b/src/file/paragraph/links/bookmark-attributes.ts new file mode 100644 index 0000000000..670c462306 --- /dev/null +++ b/src/file/paragraph/links/bookmark-attributes.ts @@ -0,0 +1,23 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IBookmarkStartAttributesProperties { + id: string; + name: string; +} + +export class BookmarkStartAttributes extends XmlAttributeComponent { + protected xmlKeys = { + id: "w:id", + name: "w:name", + }; +} + +export interface IBookmarkEndAttributesProperties { + id: string; +} + +export class BookmarkEndAttributes extends XmlAttributeComponent { + protected xmlKeys = { + id: "w:id", + }; +} diff --git a/src/file/paragraph/links/bookmark.ts b/src/file/paragraph/links/bookmark.ts new file mode 100644 index 0000000000..21a9b7e983 --- /dev/null +++ b/src/file/paragraph/links/bookmark.ts @@ -0,0 +1,57 @@ +// http://officeopenxml.com/WPbookmark.php + +import { XmlComponent } from "file/xml-components"; +import { TextRun } from "../run"; +import { BookmarkEndAttributes, BookmarkStartAttributes } from "./bookmark-attributes"; + +export class Bookmark { + + public linkId: number; + + public readonly start: BookmarkStart; + + public readonly text: TextRun; + + public readonly end: BookmarkEnd; + + constructor(name: string, text: string, relationshipsCount: number) { + this.linkId = relationshipsCount + 1; + + this.start = new BookmarkStart(name, text, this.linkId); + this.text = new TextRun(text); + this.end = new BookmarkEnd(this.linkId); + } +} + +export class BookmarkStart extends XmlComponent { + + public linkId: number; + + constructor(name: string, text: string, relationshipsCount: number) { + super("w:bookmarkStart"); + + this.linkId = relationshipsCount; + const id = `${this.linkId}`; + const attributes = new BookmarkStartAttributes({ + name, + id, + }); + this.root.push(attributes); + } +} + +export class BookmarkEnd extends XmlComponent { + + public linkId: number; + + constructor(relationshipsCount: number) { + super("w:bookmarkEnd"); + + this.linkId = relationshipsCount; + const id = `${this.linkId}`; + const attributes = new BookmarkEndAttributes({ + id, + }); + this.root.push(attributes); + } +} diff --git a/src/file/paragraph/links/hyperlink-attributes.ts b/src/file/paragraph/links/hyperlink-attributes.ts index d51f5a8b65..6d68e265b4 100644 --- a/src/file/paragraph/links/hyperlink-attributes.ts +++ b/src/file/paragraph/links/hyperlink-attributes.ts @@ -2,6 +2,7 @@ import { XmlAttributeComponent } from "file/xml-components"; export interface IHyperlinkAttributesProperties { id?: string; + anchor?: string; history: number; } @@ -9,5 +10,6 @@ export class HyperlinkAttributes extends XmlAttributeComponent Date: Tue, 24 Jul 2018 16:00:55 -0400 Subject: [PATCH 3/9] style fix --- src/file/paragraph/links/bookmark.ts | 3 --- src/file/paragraph/links/index.ts | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/file/paragraph/links/bookmark.ts b/src/file/paragraph/links/bookmark.ts index 21a9b7e983..661ca4118a 100644 --- a/src/file/paragraph/links/bookmark.ts +++ b/src/file/paragraph/links/bookmark.ts @@ -5,7 +5,6 @@ import { TextRun } from "../run"; import { BookmarkEndAttributes, BookmarkStartAttributes } from "./bookmark-attributes"; export class Bookmark { - public linkId: number; public readonly start: BookmarkStart; @@ -24,7 +23,6 @@ export class Bookmark { } export class BookmarkStart extends XmlComponent { - public linkId: number; constructor(name: string, text: string, relationshipsCount: number) { @@ -41,7 +39,6 @@ export class BookmarkStart extends XmlComponent { } export class BookmarkEnd extends XmlComponent { - public linkId: number; constructor(relationshipsCount: number) { diff --git a/src/file/paragraph/links/index.ts b/src/file/paragraph/links/index.ts index 8981572b09..09084aa8c7 100644 --- a/src/file/paragraph/links/index.ts +++ b/src/file/paragraph/links/index.ts @@ -1,2 +1,2 @@ export * from "./hyperlink"; -export * from "./bookmark"; \ No newline at end of file +export * from "./bookmark"; From 985ea30d36fce1b2086855781b2db7ebeaa10880 Mon Sep 17 00:00:00 2001 From: Michael Myers Date: Tue, 24 Jul 2018 16:56:27 -0400 Subject: [PATCH 4/9] tests --- src/file/file.ts | 2 ++ src/file/paragraph/links/bookmark.spec.ts | 42 ++++++++++++++++++++++ src/file/paragraph/links/bookmark.ts | 4 +-- src/file/paragraph/links/hyperlink.spec.ts | 17 ++++++++- 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/file/paragraph/links/bookmark.spec.ts diff --git a/src/file/file.ts b/src/file/file.ts index ddc55841b3..866ddd1480 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -160,6 +160,8 @@ export class File { public createInternalHyperLink(anchor: string, text?: string): Hyperlink { text = text === undefined ? anchor : text; const hyperlink = new Hyperlink(text, this.docRelationships.RelationshipCount, anchor); + // NOTE: unlike File#createHyperlink(), since the link is to an internal bookmark + // we don't need to create a new relationship. return hyperlink; } diff --git a/src/file/paragraph/links/bookmark.spec.ts b/src/file/paragraph/links/bookmark.spec.ts new file mode 100644 index 0000000000..08d0aec91c --- /dev/null +++ b/src/file/paragraph/links/bookmark.spec.ts @@ -0,0 +1,42 @@ +import { assert } from "chai"; + +import { Utility } from "../../../tests/utility"; +import { Bookmark } from "./"; + +describe("Bookmark", () => { + let bookmark: Bookmark; + + beforeEach(() => { + bookmark = new Bookmark("anchor", "Internal Link", 0); + }); + + it("should create a bookmark with three root elements", () => { + const newJson = Utility.jsonify(bookmark); + assert.equal(newJson.rootKey, undefined); + assert.equal(newJson.start.rootKey, "w:bookmarkStart"); + assert.equal(newJson.text.rootKey, "w:r"); + assert.equal(newJson.end.rootKey, "w:bookmarkEnd"); + }); + + it("should create a bookmark with the correct attributes on the bookmark start element", () => { + const newJson = Utility.jsonify(bookmark); + const attributes = { + name: "anchor", + id: "1", + }; + assert.equal(JSON.stringify(newJson.start.root[0].root), JSON.stringify(attributes)); + }); + + it("should create a bookmark with the correct attributes on the text element", () => { + const newJson = Utility.jsonify(bookmark); + assert.equal(JSON.stringify(newJson.text.root[1].root[1]), JSON.stringify("Internal Link")); + }); + + it("should create a bookmark with the correct attributes on the bookmark end element", () => { + const newJson = Utility.jsonify(bookmark); + const attributes = { + id: "1", + }; + assert.equal(JSON.stringify(newJson.end.root[0].root), JSON.stringify(attributes)); + }); +}); diff --git a/src/file/paragraph/links/bookmark.ts b/src/file/paragraph/links/bookmark.ts index 661ca4118a..de4fabdaa2 100644 --- a/src/file/paragraph/links/bookmark.ts +++ b/src/file/paragraph/links/bookmark.ts @@ -16,7 +16,7 @@ export class Bookmark { constructor(name: string, text: string, relationshipsCount: number) { this.linkId = relationshipsCount + 1; - this.start = new BookmarkStart(name, text, this.linkId); + this.start = new BookmarkStart(name, this.linkId); this.text = new TextRun(text); this.end = new BookmarkEnd(this.linkId); } @@ -25,7 +25,7 @@ export class Bookmark { export class BookmarkStart extends XmlComponent { public linkId: number; - constructor(name: string, text: string, relationshipsCount: number) { + constructor(name: string, relationshipsCount: number) { super("w:bookmarkStart"); this.linkId = relationshipsCount; diff --git a/src/file/paragraph/links/hyperlink.spec.ts b/src/file/paragraph/links/hyperlink.spec.ts index e3f0b58c49..d6432b432a 100644 --- a/src/file/paragraph/links/hyperlink.spec.ts +++ b/src/file/paragraph/links/hyperlink.spec.ts @@ -20,8 +20,8 @@ describe("Hyperlink", () => { it("should create a hyperlink with right attributes", () => { const newJson = Utility.jsonify(hyperlink); const attributes = { - id: "rId1", history: 1, + id: "rId1", }; assert.equal(JSON.stringify(newJson.root[0].root), JSON.stringify(attributes)); }); @@ -36,5 +36,20 @@ describe("Hyperlink", () => { }; expect(tree["w:hyperlink"][1]).to.deep.equal(runJson); }); + + describe("with optional anchor parameter", () => { + beforeEach(() => { + hyperlink = new Hyperlink("Anchor Text", 0, "anchor"); + }); + + it("should create an internal link with anchor tag", () => { + const newJson = Utility.jsonify(hyperlink); + const attributes = { + history: 1, + anchor: "anchor", + }; + assert.equal(JSON.stringify(newJson.root[0].root), JSON.stringify(attributes)); + }); + }); }); }); From 305dd847699b94112df4d490f51277ff36e8a25f Mon Sep 17 00:00:00 2001 From: Michael Myers Date: Tue, 24 Jul 2018 17:15:23 -0400 Subject: [PATCH 5/9] adding a demo --- demo/demo21.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 demo/demo21.js diff --git a/demo/demo21.js b/demo/demo21.js new file mode 100644 index 0000000000..fd74e61b31 --- /dev/null +++ b/demo/demo21.js @@ -0,0 +1,31 @@ +/** This demo shows how to create bookmarks then link to them with internal hyperlinks */ + +const docx = require("../build"); + +const loremIpsum = "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."; + +const doc = new docx.Document({ + creator: 'Clippy', + title: 'Sample Document', + description: 'A brief example of using docx with bookmarks and internal hyperlinks', +}); + +const anchorId = "anchorID"; + +// First create the bookmark +const bookmark = doc.createBookmark(anchorId, "Lorem Ipsum"); +// That has header styling +doc.createParagraph().addBookmark(bookmark).heading1(); +doc.createParagraph("\n"); + +doc.createParagraph(loremIpsum); +doc.createParagraph().pageBreak(); + +// Now the link back up to the bookmark +const hyperlink = doc.createInternalHyperLink(anchorId, `Click me!`); +doc.createParagraph().addHyperLink(hyperlink); + +var exporter = new docx.LocalPacker(doc); +exporter.pack("My Document"); + +console.log("Document created successfully at project root!"); From 4168d1a296ffbb056a70475a3e8b539686979ce3 Mon Sep 17 00:00:00 2001 From: amitm02 Date: Wed, 25 Jul 2018 09:28:01 +0300 Subject: [PATCH 6/9] revert --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5d180c2457..2eaf10efab 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "typedoc": "typedoc --out docs/ src/ --module commonjs --target ES6 --disableOutputCheck --excludePrivate --externalPattern \"**/*.spec.ts\"", "style": "prettier -l \"src/**/*.ts\"", "style.fix": "prettier \"src/**/*.ts\" --write", - "fix-types": "node types-absolute-fixer.js", + "fix-types": "node types-absolute-fixer.js" }, "files": [ "src", From 0e14b2d2e3e0557137ffa66d17b93dab6e0eb766 Mon Sep 17 00:00:00 2001 From: amitm02 Date: Wed, 25 Jul 2018 09:47:09 +0300 Subject: [PATCH 7/9] fix lint issues --- src/file/paragraph/formatting/bidi.ts | 2 +- src/file/paragraph/paragraph.ts | 2 +- src/file/paragraph/run/formatting.ts | 2 +- src/file/paragraph/run/run.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/file/paragraph/formatting/bidi.ts b/src/file/paragraph/formatting/bidi.ts index 3c2515ec56..4a8bbdade9 100644 --- a/src/file/paragraph/formatting/bidi.ts +++ b/src/file/paragraph/formatting/bidi.ts @@ -4,4 +4,4 @@ export class Bidi extends XmlComponent { constructor() { super("w:bidi"); } -} \ No newline at end of file +} diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index 0d1e2379de..35faf62005 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -5,6 +5,7 @@ import { Num } from "file/numbering/num"; import { XmlComponent } from "file/xml-components"; import { Alignment } from "./formatting/alignment"; +import { Bidi } from "./formatting/bidi"; import { ThematicBreak } from "./formatting/border"; import { Indent } from "./formatting/indent"; import { KeepLines, KeepNext } from "./formatting/keep"; @@ -13,7 +14,6 @@ import { ISpacingProperties, Spacing } from "./formatting/spacing"; import { Style } from "./formatting/style"; import { CenterTabStop, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop"; import { NumberProperties } from "./formatting/unordered-list"; -import { Bidi} from "./formatting/bidi" import { Bookmark, Hyperlink } from "./links"; import { ParagraphProperties } from "./properties"; import { PictureRun, Run, TextRun } from "./run"; diff --git a/src/file/paragraph/run/formatting.ts b/src/file/paragraph/run/formatting.ts index eb6cc54c87..bf0520870c 100644 --- a/src/file/paragraph/run/formatting.ts +++ b/src/file/paragraph/run/formatting.ts @@ -133,4 +133,4 @@ export class RTL extends XmlComponent { }), ); } -} \ No newline at end of file +} diff --git a/src/file/paragraph/run/run.ts b/src/file/paragraph/run/run.ts index 3aeaa8a69e..3691272c2c 100644 --- a/src/file/paragraph/run/run.ts +++ b/src/file/paragraph/run/run.ts @@ -1,7 +1,7 @@ // http://officeopenxml.com/WPtext.php import { Break } from "./break"; import { Caps, SmallCaps } from "./caps"; -import { Bold, Color, DoubleStrike, Italics, Size, RTL, Strike } from "./formatting"; +import { Bold, Color, DoubleStrike, Italics, RTL, Size, Strike } from "./formatting"; import { Begin, End, Page, Separate } from "./page-number"; import { RunProperties } from "./properties"; import { RunFonts } from "./run-fonts"; From 41308fea1340244526d9e0a5540926a4df530cb5 Mon Sep 17 00:00:00 2001 From: amitm02 Date: Wed, 25 Jul 2018 12:51:02 +0300 Subject: [PATCH 8/9] prettier --- src/file/paragraph/run/run.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/file/paragraph/run/run.spec.ts b/src/file/paragraph/run/run.spec.ts index d865813d36..65b74f140a 100644 --- a/src/file/paragraph/run/run.spec.ts +++ b/src/file/paragraph/run/run.spec.ts @@ -144,7 +144,7 @@ describe("Run", () => { run.rtl(); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ - "w:r": [{ "w:rPr": [{ "w:rtl": [{ _attr: { "w:val": true } }]}]}], + "w:r": [{ "w:rPr": [{ "w:rtl": [{ _attr: { "w:val": true } }] }] }], }); }); }); From e136f4e987e3f800b384a9bddbc592c6e6ddc844 Mon Sep 17 00:00:00 2001 From: amitm02 Date: Wed, 25 Jul 2018 13:07:58 +0300 Subject: [PATCH 9/9] more alignments --- src/file/paragraph/formatting/alignment.ts | 2 +- src/file/paragraph/paragraph.ts | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/file/paragraph/formatting/alignment.ts b/src/file/paragraph/formatting/alignment.ts index fbf0fdcdae..b1fa0ca2af 100644 --- a/src/file/paragraph/formatting/alignment.ts +++ b/src/file/paragraph/formatting/alignment.ts @@ -1,7 +1,7 @@ // http://officeopenxml.com/WPalignment.php import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; -export type AlignmentOptions = "left" | "center" | "right" | "both"; +export type AlignmentOptions = "start" | "end" | "center" | "both" | "distribute" | "left" | "right"; export class AlignmentAttributes extends XmlAttributeComponent<{ val: AlignmentOptions }> { protected xmlKeys = { val: "w:val" }; diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index 35faf62005..3695b70bd5 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -110,6 +110,21 @@ export class Paragraph extends XmlComponent { return this; } + public start(): Paragraph { + this.properties.push(new Alignment("start")); + return this; + } + + public end(): Paragraph { + this.properties.push(new Alignment("end")); + return this; + } + + public distribute(): Paragraph { + this.properties.push(new Alignment("distribute")); + return this; + } + public justified(): Paragraph { this.properties.push(new Alignment("both")); return this;