Merge branch 'master' into feat/base64-image
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "stable"
|
- 9
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
script:
|
script:
|
||||||
@ -24,7 +24,8 @@ after_failure:
|
|||||||
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
|
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
|
||||||
after_success:
|
after_success:
|
||||||
- npm run typedoc
|
- npm run typedoc
|
||||||
- echo "janchi.co.uk" > docs/.nojekyll
|
- echo "docx.js.org" > docs/.nojekyll
|
||||||
|
- echo "docx.js.org" > docs/CNAME
|
||||||
deploy:
|
deploy:
|
||||||
provider: pages
|
provider: pages
|
||||||
skip-cleanup: true
|
skip-cleanup: true
|
||||||
|
20
demo/demo19.js
Normal file
20
demo/demo19.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const docx = require("../build");
|
||||||
|
|
||||||
|
var doc = new docx.Document();
|
||||||
|
|
||||||
|
var paragraph = new docx.Paragraph("Hello World");
|
||||||
|
var institutionText = new docx.TextRun("Foo").bold();
|
||||||
|
var dateText = new docx.TextRun("Bar").tab().bold();
|
||||||
|
paragraph.addRun(institutionText);
|
||||||
|
paragraph.addRun(dateText);
|
||||||
|
|
||||||
|
doc.addParagraph(paragraph);
|
||||||
|
|
||||||
|
var exporter = new docx.BufferPacker(doc);
|
||||||
|
exporter.pack("My Document").then((buffer) => {
|
||||||
|
// At this point, you can do anything with the buffer, including casting it to a string etc.
|
||||||
|
console.log(buffer);
|
||||||
|
fs.writeFileSync('My Document.docx', buffer);
|
||||||
|
console.log("Document created successfully at project root!");
|
||||||
|
});
|
17
demo/demo20.js
Normal file
17
demo/demo20.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const docx = require("../build");
|
||||||
|
|
||||||
|
var doc = new docx.Document();
|
||||||
|
|
||||||
|
const table = doc.createTable(4, 4);
|
||||||
|
table
|
||||||
|
.getCell(2, 2)
|
||||||
|
.addContent(new docx.Paragraph("Hello"))
|
||||||
|
.cellProperties.borders.addTopBorder(docx.BorderStyle.DASH_DOT_STROKED, 3, "red")
|
||||||
|
.addBottomBorder(docx.BorderStyle.DOUBLE, 3, "blue")
|
||||||
|
.addStartBorder(docx.BorderStyle.DOT_DOT_DASH, 3, "green")
|
||||||
|
.addEndBorder(docx.BorderStyle.DOT_DOT_DASH, 3, "#ff8000");
|
||||||
|
|
||||||
|
var exporter = new docx.LocalPacker(doc);
|
||||||
|
exporter.pack("My Document");
|
||||||
|
|
||||||
|
console.log("Document created successfully at project root!");
|
31
demo/demo21.js
Normal file
31
demo/demo21.js
Normal file
@ -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!");
|
14
demo/demo22.js
Normal file
14
demo/demo22.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const docx = require('../build');
|
||||||
|
|
||||||
|
var doc = new docx.Document();
|
||||||
|
|
||||||
|
var textRun = new docx.TextRun("שלום עולם").rtl();
|
||||||
|
var paragraph = new docx.Paragraph().bidi();
|
||||||
|
paragraph.addRun(textRun);
|
||||||
|
|
||||||
|
doc.addParagraph(paragraph);
|
||||||
|
|
||||||
|
var exporter = new docx.LocalPacker(doc);
|
||||||
|
exporter.pack('My Document');
|
||||||
|
|
||||||
|
console.log('Document created successfully at project root!');
|
@ -42,9 +42,10 @@
|
|||||||
"types": "./build/index.d.ts",
|
"types": "./build/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/archiver": "^2.1.0",
|
"@types/archiver": "^2.1.0",
|
||||||
|
"@types/bluebird": "3.5.20",
|
||||||
"@types/express": "^4.0.35",
|
"@types/express": "^4.0.35",
|
||||||
"@types/image-size": "0.0.29",
|
"@types/image-size": "0.0.29",
|
||||||
"@types/request-promise": "^4.1.41",
|
"@types/request-promise": "^4.1.42",
|
||||||
"archiver": "^2.1.1",
|
"archiver": "^2.1.1",
|
||||||
"fast-xml-parser": "^3.3.6",
|
"fast-xml-parser": "^3.3.6",
|
||||||
"image-size": "^0.6.2",
|
"image-size": "^0.6.2",
|
||||||
@ -75,8 +76,8 @@
|
|||||||
"shelljs": "^0.7.7",
|
"shelljs": "^0.7.7",
|
||||||
"sinon": "^5.0.7",
|
"sinon": "^5.0.7",
|
||||||
"tslint": "^5.1.0",
|
"tslint": "^5.1.0",
|
||||||
"typedoc": "^0.9.0",
|
"typedoc": "^0.11.1",
|
||||||
"typescript": "2.6.2",
|
"typescript": "2.9.2",
|
||||||
"webpack": "^3.10.0"
|
"webpack": "^3.10.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,3 +2,4 @@ export * from "./packer/local";
|
|||||||
export * from "./packer/express";
|
export * from "./packer/express";
|
||||||
export * from "./packer/packer";
|
export * from "./packer/packer";
|
||||||
export * from "./packer/stream";
|
export * from "./packer/stream";
|
||||||
|
export * from "./packer/buffer";
|
||||||
|
28
src/export/packer/buffer-stream.ts
Normal file
28
src/export/packer/buffer-stream.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Writable } from "stream";
|
||||||
|
|
||||||
|
export class BufferStream extends Writable {
|
||||||
|
private data: Buffer[];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.data = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
public _write(chunk: any, encoding: string, next: (err?: Error) => void): void {
|
||||||
|
this.data.push(Buffer.from(chunk));
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line:ban-types
|
||||||
|
public end(cb?: Function): void {
|
||||||
|
super.end(cb);
|
||||||
|
|
||||||
|
this.emit("close");
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Buffer(): Buffer {
|
||||||
|
return Buffer.concat(this.data);
|
||||||
|
}
|
||||||
|
}
|
44
src/export/packer/buffer.spec.ts
Normal file
44
src/export/packer/buffer.spec.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/* tslint:disable:typedef space-before-function-paren */
|
||||||
|
import { assert } from "chai";
|
||||||
|
import { stub } from "sinon";
|
||||||
|
|
||||||
|
import { BufferPacker } from "../../export/packer/buffer";
|
||||||
|
import { File, Paragraph } from "../../file";
|
||||||
|
|
||||||
|
describe("BufferPacker", () => {
|
||||||
|
let packer: BufferPacker;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const file = new File({
|
||||||
|
creator: "Dolan Miu",
|
||||||
|
revision: "1",
|
||||||
|
lastModifiedBy: "Dolan Miu",
|
||||||
|
});
|
||||||
|
const paragraph = new Paragraph("test text");
|
||||||
|
const heading = new Paragraph("Hello world").heading1();
|
||||||
|
file.addParagraph(new Paragraph("title").title());
|
||||||
|
file.addParagraph(heading);
|
||||||
|
file.addParagraph(new Paragraph("heading 2").heading2());
|
||||||
|
file.addParagraph(paragraph);
|
||||||
|
|
||||||
|
packer = new BufferPacker(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#pack()", () => {
|
||||||
|
it("should create a standard docx file", async function() {
|
||||||
|
this.timeout(99999999);
|
||||||
|
const buffer = await packer.pack();
|
||||||
|
assert.isDefined(buffer);
|
||||||
|
assert.isTrue(buffer.byteLength > 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle exception if it throws any", () => {
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
const compiler = stub((packer as any).packer, "compile");
|
||||||
|
compiler.throwsException();
|
||||||
|
return packer.pack().catch((error) => {
|
||||||
|
assert.isDefined(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
20
src/export/packer/buffer.ts
Normal file
20
src/export/packer/buffer.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { File } from "../../file";
|
||||||
|
import { BufferStream } from "./buffer-stream";
|
||||||
|
import { Compiler } from "./compiler";
|
||||||
|
import { IPacker } from "./packer";
|
||||||
|
|
||||||
|
export class BufferPacker implements IPacker {
|
||||||
|
private readonly packer: Compiler;
|
||||||
|
|
||||||
|
constructor(file: File) {
|
||||||
|
this.packer = new Compiler(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async pack(): Promise<Buffer> {
|
||||||
|
const stream = new BufferStream();
|
||||||
|
|
||||||
|
await this.packer.compile(stream);
|
||||||
|
|
||||||
|
return stream.Buffer;
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ export class Compiler {
|
|||||||
public async compile(output: Writable | express.Response): Promise<void> {
|
public async compile(output: Writable | express.Response): Promise<void> {
|
||||||
this.archive.pipe(output);
|
this.archive.pipe(output);
|
||||||
|
|
||||||
const xmlDocument = xml(this.formatter.format(this.file.Document), true);
|
const xmlDocument = xml(this.formatter.format(this.file.Document));
|
||||||
const xmlStyles = xml(this.formatter.format(this.file.Styles));
|
const xmlStyles = xml(this.formatter.format(this.file.Styles));
|
||||||
const xmlProperties = xml(this.formatter.format(this.file.CoreProperties), {
|
const xmlProperties = xml(this.formatter.format(this.file.CoreProperties), {
|
||||||
declaration: {
|
declaration: {
|
||||||
|
@ -10,7 +10,7 @@ import { FootNotes } from "./footnotes";
|
|||||||
import { HeaderWrapper } from "./header-wrapper";
|
import { HeaderWrapper } from "./header-wrapper";
|
||||||
import { Media } from "./media";
|
import { Media } from "./media";
|
||||||
import { Numbering } from "./numbering";
|
import { Numbering } from "./numbering";
|
||||||
import { Hyperlink, Paragraph, PictureRun } from "./paragraph";
|
import { Bookmark, Hyperlink, Paragraph, PictureRun } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
import { Styles } from "./styles";
|
import { Styles } from "./styles";
|
||||||
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
||||||
@ -157,6 +157,20 @@ export class File {
|
|||||||
return hyperlink;
|
return hyperlink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
public addSection(sectionPropertiesOptions: SectionPropertiesOptions): void {
|
||||||
this.document.Body.addSection(sectionPropertiesOptions);
|
this.document.Body.addSection(sectionPropertiesOptions);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ describe("Numbering", () => {
|
|||||||
]);
|
]);
|
||||||
// Once chai 4.0.0 lands and #644 is resolved, we can add the following to the test:
|
// Once chai 4.0.0 lands and #644 is resolved, we can add the following to the test:
|
||||||
// {"w:lvlText": [{"_attr": {"w:val": "•"}}]},
|
// {"w:lvlText": [{"_attr": {"w:val": "•"}}]},
|
||||||
// {"w:rPr": [{"w:rFonts": [{"_attr": {"w:ascii": "Symbol", "w:hAnsi": "Symbol", "w:hint": "default"}}]}]},
|
// {"w:rPr": [{"w:rFonts": [{"_attr": {"w:ascii": "Symbol", "w:cs": "Symbol", "w:eastAsia": "Symbol", "w:hAnsi": "Symbol", "w:hint": "default"}}]}]},
|
||||||
// {"w:pPr": [{"_attr": {}},
|
// {"w:pPr": [{"_attr": {}},
|
||||||
// {"w:ind": [{"_attr": {"w:left": 720, "w:hanging": 360}}]}]},
|
// {"w:ind": [{"_attr": {"w:left": 720, "w:hanging": 360}}]}]},
|
||||||
});
|
});
|
||||||
@ -297,7 +297,9 @@ describe("AbstractNumbering", () => {
|
|||||||
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").font("Times");
|
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").font("Times");
|
||||||
const tree = new Formatter().format(level);
|
const tree = new Formatter().format(level);
|
||||||
expect(tree["w:lvl"]).to.include({
|
expect(tree["w:lvl"]).to.include({
|
||||||
"w:rPr": [{ "w:rFonts": [{ _attr: { "w:ascii": "Times", "w:hAnsi": "Times" } }] }],
|
"w:rPr": [
|
||||||
|
{ "w:rFonts": [{ _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } }] },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// http://officeopenxml.com/WPalignment.php
|
// http://officeopenxml.com/WPalignment.php
|
||||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
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 }> {
|
export class AlignmentAttributes extends XmlAttributeComponent<{ val: AlignmentOptions }> {
|
||||||
protected xmlKeys = { val: "w:val" };
|
protected xmlKeys = { val: "w:val" };
|
||||||
|
7
src/file/paragraph/formatting/bidi.ts
Normal file
7
src/file/paragraph/formatting/bidi.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
|
export class Bidi extends XmlComponent {
|
||||||
|
constructor() {
|
||||||
|
super("w:bidi");
|
||||||
|
}
|
||||||
|
}
|
23
src/file/paragraph/links/bookmark-attributes.ts
Normal file
23
src/file/paragraph/links/bookmark-attributes.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
|
export interface IBookmarkStartAttributesProperties {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BookmarkStartAttributes extends XmlAttributeComponent<IBookmarkStartAttributesProperties> {
|
||||||
|
protected xmlKeys = {
|
||||||
|
id: "w:id",
|
||||||
|
name: "w:name",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBookmarkEndAttributesProperties {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BookmarkEndAttributes extends XmlAttributeComponent<IBookmarkEndAttributesProperties> {
|
||||||
|
protected xmlKeys = {
|
||||||
|
id: "w:id",
|
||||||
|
};
|
||||||
|
}
|
42
src/file/paragraph/links/bookmark.spec.ts
Normal file
42
src/file/paragraph/links/bookmark.spec.ts
Normal file
@ -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));
|
||||||
|
});
|
||||||
|
});
|
54
src/file/paragraph/links/bookmark.ts
Normal file
54
src/file/paragraph/links/bookmark.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// 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, this.linkId);
|
||||||
|
this.text = new TextRun(text);
|
||||||
|
this.end = new BookmarkEnd(this.linkId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BookmarkStart extends XmlComponent {
|
||||||
|
public linkId: number;
|
||||||
|
|
||||||
|
constructor(name: 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);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ import { XmlAttributeComponent } from "file/xml-components";
|
|||||||
|
|
||||||
export interface IHyperlinkAttributesProperties {
|
export interface IHyperlinkAttributesProperties {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
anchor?: string;
|
||||||
history: number;
|
history: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9,5 +10,6 @@ export class HyperlinkAttributes extends XmlAttributeComponent<IHyperlinkAttribu
|
|||||||
protected xmlKeys = {
|
protected xmlKeys = {
|
||||||
id: "r:id",
|
id: "r:id",
|
||||||
history: "w:history",
|
history: "w:history",
|
||||||
|
anchor: "w:anchor",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ describe("Hyperlink", () => {
|
|||||||
it("should create a hyperlink with right attributes", () => {
|
it("should create a hyperlink with right attributes", () => {
|
||||||
const newJson = Utility.jsonify(hyperlink);
|
const newJson = Utility.jsonify(hyperlink);
|
||||||
const attributes = {
|
const attributes = {
|
||||||
id: "rId1",
|
|
||||||
history: 1,
|
history: 1,
|
||||||
|
id: "rId1",
|
||||||
};
|
};
|
||||||
assert.equal(JSON.stringify(newJson.root[0].root), JSON.stringify(attributes));
|
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);
|
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));
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,19 +2,27 @@
|
|||||||
|
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { TextRun } from "../run";
|
import { TextRun } from "../run";
|
||||||
import { HyperlinkAttributes } from "./hyperlink-attributes";
|
import { HyperlinkAttributes, IHyperlinkAttributesProperties } from "./hyperlink-attributes";
|
||||||
|
|
||||||
export class Hyperlink extends XmlComponent {
|
export class Hyperlink extends XmlComponent {
|
||||||
public linkId: number;
|
public linkId: number;
|
||||||
|
|
||||||
constructor(text: string, relationshipsCount: number) {
|
constructor(text: string, relationshipsCount: number, anchor?: string) {
|
||||||
super("w:hyperlink");
|
super("w:hyperlink");
|
||||||
|
|
||||||
this.linkId = relationshipsCount + 1;
|
this.linkId = relationshipsCount + 1;
|
||||||
const attributes = new HyperlinkAttributes({
|
|
||||||
id: `rId${this.linkId}`,
|
const props: IHyperlinkAttributesProperties = {
|
||||||
history: 1,
|
history: 1,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (anchor) {
|
||||||
|
props.anchor = anchor;
|
||||||
|
} else {
|
||||||
|
props.id = `rId${this.linkId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attributes = new HyperlinkAttributes(props);
|
||||||
this.root.push(attributes);
|
this.root.push(attributes);
|
||||||
this.root.push(new TextRun(text).style("Hyperlink"));
|
this.root.push(new TextRun(text).style("Hyperlink"));
|
||||||
}
|
}
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export * from "./hyperlink";
|
export * from "./hyperlink";
|
||||||
|
export * from "./bookmark";
|
||||||
|
@ -338,4 +338,14 @@ describe("Paragraph", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#bidi", () => {
|
||||||
|
it("set paragraph right to left layout", () => {
|
||||||
|
paragraph.bidi();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [{ "w:pPr": [{ "w:bidi": [] }] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -5,6 +5,7 @@ import { Num } from "file/numbering/num";
|
|||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { Alignment } from "./formatting/alignment";
|
import { Alignment } from "./formatting/alignment";
|
||||||
|
import { Bidi } from "./formatting/bidi";
|
||||||
import { ThematicBreak } from "./formatting/border";
|
import { ThematicBreak } from "./formatting/border";
|
||||||
import { Indent } from "./formatting/indent";
|
import { Indent } from "./formatting/indent";
|
||||||
import { KeepLines, KeepNext } from "./formatting/keep";
|
import { KeepLines, KeepNext } from "./formatting/keep";
|
||||||
@ -13,7 +14,7 @@ import { ISpacingProperties, Spacing } from "./formatting/spacing";
|
|||||||
import { Style } from "./formatting/style";
|
import { Style } from "./formatting/style";
|
||||||
import { CenterTabStop, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop";
|
import { CenterTabStop, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop";
|
||||||
import { NumberProperties } from "./formatting/unordered-list";
|
import { NumberProperties } from "./formatting/unordered-list";
|
||||||
import { Hyperlink } from "./links";
|
import { Bookmark, Hyperlink } from "./links";
|
||||||
import { ParagraphProperties } from "./properties";
|
import { ParagraphProperties } from "./properties";
|
||||||
import { PictureRun, Run, TextRun } from "./run";
|
import { PictureRun, Run, TextRun } from "./run";
|
||||||
|
|
||||||
@ -39,6 +40,14 @@ export class Paragraph extends XmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addBookmark(bookmark: Bookmark): Paragraph {
|
||||||
|
// Bookmarks by spec have three components, a start, text, and end
|
||||||
|
this.root.push(bookmark.start);
|
||||||
|
this.root.push(bookmark.text);
|
||||||
|
this.root.push(bookmark.end);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public createTextRun(text: string): TextRun {
|
public createTextRun(text: string): TextRun {
|
||||||
const run = new TextRun(text);
|
const run = new TextRun(text);
|
||||||
this.addRun(run);
|
this.addRun(run);
|
||||||
@ -101,6 +110,21 @@ export class Paragraph extends XmlComponent {
|
|||||||
return this;
|
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 {
|
public justified(): Paragraph {
|
||||||
this.properties.push(new Alignment("both"));
|
this.properties.push(new Alignment("both"));
|
||||||
return this;
|
return this;
|
||||||
@ -192,4 +216,9 @@ export class Paragraph extends XmlComponent {
|
|||||||
this.root.splice(1, 0, run);
|
this.root.splice(1, 0, run);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bidi(): Paragraph {
|
||||||
|
this.properties.push(new Bidi());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,3 +123,25 @@ export class Size extends XmlComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SizeCs extends XmlComponent {
|
||||||
|
constructor(size: number) {
|
||||||
|
super("w:szCs");
|
||||||
|
this.root.push(
|
||||||
|
new Attributes({
|
||||||
|
val: size,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RTL extends XmlComponent {
|
||||||
|
constructor() {
|
||||||
|
super("w:rtl");
|
||||||
|
this.root.push(
|
||||||
|
new Attributes({
|
||||||
|
val: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,14 +8,16 @@ describe("RunFonts", () => {
|
|||||||
it("uses the font name for both ascii and hAnsi", () => {
|
it("uses the font name for both ascii and hAnsi", () => {
|
||||||
const tree = new Formatter().format(new RunFonts("Times"));
|
const tree = new Formatter().format(new RunFonts("Times"));
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:rFonts": [{ _attr: { "w:ascii": "Times", "w:hAnsi": "Times" } }],
|
"w:rFonts": [{ _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses hint if given", () => {
|
it("uses hint if given", () => {
|
||||||
const tree = new Formatter().format(new RunFonts("Times", "default"));
|
const tree = new Formatter().format(new RunFonts("Times", "default"));
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:rFonts": [{ _attr: { "w:ascii": "Times", "w:hAnsi": "Times", "w:hint": "default" } }],
|
"w:rFonts": [
|
||||||
|
{ _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times", "w:hint": "default" } },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,8 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
|||||||
|
|
||||||
interface IRunFontAttributesProperties {
|
interface IRunFontAttributesProperties {
|
||||||
ascii: string;
|
ascii: string;
|
||||||
|
cs: string;
|
||||||
|
eastAsia: string;
|
||||||
hAnsi: string;
|
hAnsi: string;
|
||||||
hint?: string;
|
hint?: string;
|
||||||
}
|
}
|
||||||
@ -9,6 +11,8 @@ interface IRunFontAttributesProperties {
|
|||||||
class RunFontAttributes extends XmlAttributeComponent<IRunFontAttributesProperties> {
|
class RunFontAttributes extends XmlAttributeComponent<IRunFontAttributesProperties> {
|
||||||
protected xmlKeys = {
|
protected xmlKeys = {
|
||||||
ascii: "w:ascii",
|
ascii: "w:ascii",
|
||||||
|
cs: "w:cs",
|
||||||
|
eastAsia: "w:eastAsia",
|
||||||
hAnsi: "w:hAnsi",
|
hAnsi: "w:hAnsi",
|
||||||
hint: "w:hint",
|
hint: "w:hint",
|
||||||
};
|
};
|
||||||
@ -20,6 +24,8 @@ export class RunFonts extends XmlComponent {
|
|||||||
this.root.push(
|
this.root.push(
|
||||||
new RunFontAttributes({
|
new RunFontAttributes({
|
||||||
ascii: ascii,
|
ascii: ascii,
|
||||||
|
cs: ascii,
|
||||||
|
eastAsia: ascii,
|
||||||
hAnsi: ascii,
|
hAnsi: ascii,
|
||||||
hint: hint,
|
hint: hint,
|
||||||
}),
|
}),
|
||||||
|
@ -108,7 +108,13 @@ describe("Run", () => {
|
|||||||
run.font("Times");
|
run.font("Times");
|
||||||
const tree = new Formatter().format(run);
|
const tree = new Formatter().format(run);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:r": [{ "w:rPr": [{ "w:rFonts": [{ _attr: { "w:ascii": "Times", "w:hAnsi": "Times" } }] }] }],
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{ "w:rFonts": [{ _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } }] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -128,7 +134,21 @@ describe("Run", () => {
|
|||||||
run.size(24);
|
run.size(24);
|
||||||
const tree = new Formatter().format(run);
|
const tree = new Formatter().format(run);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:r": [{ "w:rPr": [{ "w:sz": [{ _attr: { "w:val": 24 } }] }] }],
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:sz": [{ _attr: { "w:val": 24 } }] }, { "w:szCs": [{ _attr: { "w:val": 24 } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#rtl", () => {
|
||||||
|
it("should set the run to the RTL mode", () => {
|
||||||
|
run.rtl();
|
||||||
|
const tree = new Formatter().format(run);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:r": [{ "w:rPr": [{ "w:rtl": [{ _attr: { "w:val": true } }] }] }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// http://officeopenxml.com/WPtext.php
|
// http://officeopenxml.com/WPtext.php
|
||||||
import { Break } from "./break";
|
import { Break } from "./break";
|
||||||
import { Caps, SmallCaps } from "./caps";
|
import { Caps, SmallCaps } from "./caps";
|
||||||
import { Bold, Color, DoubleStrike, Italics, Size, Strike } from "./formatting";
|
import { Bold, Color, DoubleStrike, Italics, RTL, Size, SizeCs, Strike } from "./formatting";
|
||||||
import { Begin, End, Page, Separate } from "./page-number";
|
import { Begin, End, Page, Separate } from "./page-number";
|
||||||
import { RunProperties } from "./properties";
|
import { RunProperties } from "./properties";
|
||||||
import { RunFonts } from "./run-fonts";
|
import { RunFonts } from "./run-fonts";
|
||||||
@ -43,6 +43,12 @@ export class Run extends XmlComponent {
|
|||||||
|
|
||||||
public size(size: number): Run {
|
public size(size: number): Run {
|
||||||
this.properties.push(new Size(size));
|
this.properties.push(new Size(size));
|
||||||
|
this.properties.push(new SizeCs(size));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public rtl(): Run {
|
||||||
|
this.properties.push(new RTL());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +100,8 @@ export class Run extends XmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public font(fontName: string): Run {
|
public font(fontName: string, hint?: string | undefined): Run {
|
||||||
this.properties.push(new RunFonts(fontName));
|
this.properties.push(new RunFonts(fontName, hint));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { Size } from "../../paragraph/run/formatting";
|
import { Size, SizeCs } from "../../paragraph/run/formatting";
|
||||||
import { RunProperties } from "../../paragraph/run/properties";
|
import { RunProperties } from "../../paragraph/run/properties";
|
||||||
import { RunFonts } from "../../paragraph/run/run-fonts";
|
import { RunFonts } from "../../paragraph/run/run-fonts";
|
||||||
|
|
||||||
@ -14,6 +14,7 @@ export class RunPropertiesDefaults extends XmlComponent {
|
|||||||
|
|
||||||
public size(size: number): RunPropertiesDefaults {
|
public size(size: number): RunPropertiesDefaults {
|
||||||
this.properties.push(new Size(size));
|
this.properties.push(new Size(size));
|
||||||
|
this.properties.push(new SizeCs(size));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +74,7 @@ export class ParagraphStyle extends Style {
|
|||||||
|
|
||||||
public size(twips: number): ParagraphStyle {
|
public size(twips: number): ParagraphStyle {
|
||||||
this.addRunProperty(new formatting.Size(twips));
|
this.addRunProperty(new formatting.Size(twips));
|
||||||
|
this.addRunProperty(new formatting.SizeCs(twips));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +283,7 @@ export class CharacterStyle extends Style {
|
|||||||
|
|
||||||
public size(twips: number): CharacterStyle {
|
public size(twips: number): CharacterStyle {
|
||||||
this.addRunProperty(new formatting.Size(twips));
|
this.addRunProperty(new formatting.Size(twips));
|
||||||
|
this.addRunProperty(new formatting.SizeCs(twips));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ describe("ParagraphStyle", () => {
|
|||||||
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
{ "w:pPr": [] },
|
{ "w:pPr": [] },
|
||||||
{
|
{
|
||||||
"w:rPr": [{ "w:sz": [{ _attr: { "w:val": 24 } }] }],
|
"w:rPr": [{ "w:sz": [{ _attr: { "w:val": 24 } }] }, { "w:szCs": [{ _attr: { "w:val": 24 } }] }],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -459,7 +459,11 @@ describe("ParagraphStyle", () => {
|
|||||||
"w:style": [
|
"w:style": [
|
||||||
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
{ "w:pPr": [] },
|
{ "w:pPr": [] },
|
||||||
{ "w:rPr": [{ "w:rFonts": [{ _attr: { "w:ascii": "Times", "w:hAnsi": "Times" } }] }] },
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{ "w:rFonts": [{ _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } }] },
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user