Compare commits

..

88 Commits
4.4.0 ... 4.4.1

Author SHA1 Message Date
e5bfa99b92 Add correct docx mime type 2018-12-10 19:22:23 +00:00
f640f17fa6 Merge pull request #193 from dolanmiu/4.4.0
Version bump
2018-11-08 12:05:31 +00:00
494a32d45d Merge pull request #195 from kunizial/patch-1
Update numbering.md
2018-11-08 12:05:17 +00:00
8040a455be Update numbering.md
Fixed Typo
2018-11-08 11:09:09 +01:00
401ef7336b Merge pull request #190 from dolanmiu/feat/more-tests
Introduce some functional programming techniques
2018-11-02 03:12:28 +00:00
18134519be Edit threshold 2018-11-02 03:00:07 +00:00
7980f14efb Introduce some functional programming techniques 2018-11-02 02:51:57 +00:00
40d6a41305 Merge pull request #189 from dolanmiu/feat/more-tests
More tests
2018-11-02 00:53:54 +00:00
9cfd835171 More tests 2018-11-02 00:42:49 +00:00
95a9f592eb Merge pull request #143 from amitm02/importDotx
use .dotx files as an initial template for a new (document) file
2018-11-01 02:31:33 +00:00
61411fd0f3 Add tests 2018-11-01 02:22:32 +00:00
a84eb16392 Merge branch 'master' into importDotx
# Conflicts:
#	src/import-dotx/import-dotx.ts
2018-10-31 22:09:36 +00:00
3355a6f472 Added back tests and method 2018-10-31 21:57:10 +00:00
071a8ea9f7 Merge pull request #187 from dolanmiu/feat/clean-imports
Feat/clean imports
2018-10-26 21:00:42 +01:00
ea3777d28b Better naming 2018-10-26 20:30:42 +01:00
3346b97ee7 Clean up 2018-10-26 20:23:26 +01:00
2b834a75a8 Add codecov badge 2018-10-26 20:22:33 +01:00
21df53d547 Clean up 2018-10-26 20:16:18 +01:00
9143c1c2c1 Add nyc support 2018-10-26 20:11:40 +01:00
83cab7563d Add nyc to travis 2018-10-26 02:20:10 +01:00
b05fbe7f6e Merge pull request #185 from dolanmiu/feat/clean-imports
Add codecov and add more tests to travis
2018-10-26 02:12:52 +01:00
e6a57738f4 Demo 25 does not exist 2018-10-26 02:07:25 +01:00
cc6e35165a Add codecov and add more tests to travis 2018-10-26 02:00:45 +01:00
7791ddf76e Merge pull request #184 from dolanmiu/feat/clean-imports
Clean imports
2018-10-26 01:16:23 +01:00
4742cf0f3f Clean imports 2018-10-26 01:04:07 +01:00
8858970491 Merge pull request #182 from dolanmiu/feat/table-clean-up
Tidied up table components
2018-10-24 14:33:10 +01:00
f7d18bfead Tidied up table components 2018-10-23 23:44:50 +01:00
0ce1b7fa15 Merge pull request #181 from dolanmiu/feat/float-table
Created float positioning for tables
2018-10-23 21:40:33 +01:00
4633592711 Improve API 2018-10-23 20:03:29 +01:00
54697ab6b1 Created float positioning for tables 2018-10-23 09:08:43 -02:00
1eed844b9a Merge pull request #179 from dolanmiu/feat/import-dotx
Feat/import dotx
2018-10-23 00:47:18 +01:00
dd89fe2463 Fix casing 2018-10-23 00:41:18 +01:00
9c66db97ff Use single media instead of multiple 2018-10-23 00:31:51 +01:00
fea6afdfe4 Remove npm dependency 2018-10-22 20:27:32 +01:00
6ec2e742ef Merge branch 'master' into importDotx 2018-10-22 20:25:34 +01:00
5532f91423 Merge branch 'importxmljs' into importDotx 2018-10-17 09:17:42 +03:00
c849d5f3e5 fix demp30 2018-10-17 09:16:55 +03:00
3f3fd05cb1 works 2018-10-17 09:15:32 +03:00
a5bedf9a5b Add break after cases in switch 2018-10-17 01:40:17 +01:00
9d9dd62f00 c 2018-10-16 11:28:25 +03:00
97f76fb62c Change to new header API 2018-10-05 01:33:17 +01:00
3508fd97ec Merge branch 'importDotx' of https://github.com/amitm02/docx into importDotx 2018-10-05 01:21:29 +01:00
90f6f68693 Changed protected to private 2018-10-05 00:20:43 +01:00
733775d3b9 Rename demo 2018-10-05 00:08:14 +01:00
f3aa6a9203 detect if page title is defined in tempalte 2018-10-02 17:52:55 +03:00
ffdcc7baca hande hyplerlink references in header or footers 2018-10-02 16:17:26 +03:00
a1e20f4c9a handle templates with no headers or foolters 2018-10-02 16:02:28 +03:00
048ae6a58c extract styles from dotx 2018-09-26 14:33:05 +03:00
fafa54e4c9 bug fix (demo29 corrupted) 2018-09-26 13:10:21 +03:00
60dbb32e9e Revert "Revert "Add back relationships""
This reverts commit 52b07fd9cb.
2018-09-26 12:03:52 +03:00
52b07fd9cb Revert "Add back relationships"
This reverts commit 6e0c12afb3.
2018-09-26 10:12:40 +03:00
8ec5bc05e0 Export file properties 2018-09-26 02:03:32 +01:00
6e0c12afb3 Add back relationships 2018-09-26 00:24:33 +01:00
466e880bfc Merge from master 2018-09-25 23:46:55 +01:00
0a8feca6ab Rename importDocx to import-dotx 2018-09-24 22:00:08 +01:00
f2b50478bf Fix tests and use proper types for disregarding XMLComponent 2018-09-20 00:41:57 +01:00
fc71ebdfef Refactor code 2018-09-19 23:07:37 +01:00
10114bb12d Remove TemplatedFile 2018-09-19 23:04:34 +01:00
e6d4741955 Merge branch 'master' of https://github.com/dolanmiu/docx into importDotx
# Conflicts:
#	src/file/file.ts
2018-09-19 01:53:52 +01:00
4d7387524c Rename demo 2018-09-19 01:30:25 +01:00
5fe4405d76 Add templated file 2018-09-19 00:37:11 +01:00
79dffc873a Organise imports 2018-09-18 00:51:35 +01:00
26ee12759c Using custom parseOptions 2018-09-17 23:54:19 +01:00
2e00634bc4 Fix tests but break demo 27 2018-09-17 22:06:38 +01:00
d63e6bf6b1 Revert back body test 2018-09-17 21:44:12 +01:00
a95366e54e Fix demo 27 2018-09-17 21:18:27 +01:00
1c376abeb6 Fix demo 8 2018-09-17 21:15:24 +01:00
353d888abd Simplify code using Spreading 2018-09-17 20:27:43 +01:00
b6bd532295 Use dedicated XmlComponent rather than polute pure one 2018-09-17 20:22:11 +01:00
c5b004166d Add back comp null check 2018-09-17 20:18:31 +01:00
2f43600daf Remove MyDocument 2018-09-17 20:09:31 +01:00
b39c7ce323 Fix naming 2018-09-17 20:06:51 +01:00
5b00279996 Remove space 2018-09-17 19:44:21 +01:00
d1d1e01aff lint fix 2018-09-17 11:29:01 +03:00
980bc597e2 test fixes 2018-09-17 11:24:56 +03:00
a05c5edd49 Revert back .vscode folder 2018-09-14 02:44:47 +01:00
985452f5f4 Use proper name 2018-09-14 02:39:52 +01:00
482674b3b3 Fix spelling error 2018-09-14 02:37:03 +01:00
fcbfed9068 Revert code 2018-09-14 02:33:36 +01:00
385ad92331 Fix linting errors 2018-09-07 21:48:59 +01:00
571f8b526b Fix demo 2018-09-06 09:18:52 +01:00
7688aa99f6 Fix linting errors 2018-09-06 09:09:36 +01:00
4994bca34c Fix some linting errors 2018-09-06 08:30:23 +01:00
1a3603dbfb fix demo 16 2018-09-05 10:02:42 +03:00
e382dbff84 update demp template 2018-09-04 17:32:16 +03:00
e08be3d7a4 update template 2018-09-04 17:31:30 +03:00
03c4190c2c works! 2018-09-04 17:16:31 +03:00
010fde6258 commit 2018-08-29 18:36:48 +03:00
209 changed files with 3201 additions and 1546 deletions

3
.gitignore vendored
View File

@ -60,3 +60,6 @@ My Document.docx
# Temporary folder # Temporary folder
tmp tmp
# nyc
.nyc_output

25
.nycrc Normal file
View File

@ -0,0 +1,25 @@
{
"check-coverage": true,
"lines": 87.54,
"functions": 83.61,
"branches": 72.57,
"statements": 87.32,
"include": [
"src/**/*.ts"
],
"exclude": [
"src/**/*.spec.ts"
],
"reporter": [
"lcov",
"text",
"json"
],
"extension": [
".ts"
],
"cache": true,
"all": true,
"instrument": false,
"sourceMap": true
}

View File

@ -3,9 +3,10 @@ node_js:
- 9 - 9
install: install:
- npm install - npm install
- npm install -g codecov
script: script:
- npm run lint - npm run lint
- npm test - npm run test.coverage
- npm run style - npm run style
- npm run build - npm run build
- npm run ts-node -- ./demo/demo1.ts - npm run ts-node -- ./demo/demo1.ts
@ -32,12 +33,23 @@ script:
- npm run ts-node -- ./demo/demo22.ts - npm run ts-node -- ./demo/demo22.ts
- npm run ts-node -- ./demo/demo23.ts - npm run ts-node -- ./demo/demo23.ts
- npm run ts-node -- ./demo/demo24.ts - npm run ts-node -- ./demo/demo24.ts
# - npm run ts-node -- ./demo/demo25.ts
- npm run ts-node -- ./demo/demo26.ts
- npm run ts-node -- ./demo/demo27.ts
- npm run ts-node -- ./demo/demo28.ts
- npm run ts-node -- ./demo/demo29.ts
- npm run ts-node -- ./demo/demo30.ts
- npm run ts-node -- ./demo/demo31.ts
- npm run ts-node -- ./demo/demo32.ts
- npm run ts-node -- ./demo/demo33.ts
- npm run ts-node -- ./demo/demo34.ts
after_failure: 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 "docx.js.org" > docs/.nojekyll - echo "docx.js.org" > docs/.nojekyll
- echo "docx.js.org" > docs/CNAME - echo "docx.js.org" > docs/CNAME
- codecov
deploy: deploy:
provider: pages provider: pages
skip-cleanup: true skip-cleanup: true

24
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,24 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "typescript",
"tsconfig": "tsconfig.json",
"option": "watch",
"problemMatcher": [
"$tsc-watch"
]
},
{
"type": "npm",
"script": "ts-node",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View File

@ -15,6 +15,7 @@
[![Known Vulnerabilities][snky-image]][snky-url] [![Known Vulnerabilities][snky-image]][snky-url]
[![Chat on Gitter][gitter-image]][gitter-url] [![Chat on Gitter][gitter-image]][gitter-url]
[![PRs Welcome][pr-image]][pr-url] [![PRs Welcome][pr-image]][pr-url]
[![codecov][codecov-image]][codecov-url]
<p align="center"> <p align="center">
<img src="https://i.imgur.com/H5FA1Qy.gif" alt="drawing" width="800"/> <img src="https://i.imgur.com/H5FA1Qy.gif" alt="drawing" width="800"/>
@ -81,3 +82,5 @@ Made with 💖
[gitter-url]: https://gitter.im/docx-lib/Lobby [gitter-url]: https://gitter.im/docx-lib/Lobby
[pr-image]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg [pr-image]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
[pr-url]: http://makeapullrequest.com [pr-url]: http://makeapullrequest.com
[codecov-image]: https://codecov.io/gh/dolanmiu/docx/branch/master/graph/badge.svg
[codecov-url]: https://codecov.io/gh/dolanmiu/docx

View File

@ -15,8 +15,12 @@ const footer = doc.createFooter();
footer.createParagraph("Footer on another page"); footer.createParagraph("Footer on another page");
doc.addSection({ doc.addSection({
headerId: header.Header.ReferenceId, headers: {
footerId: footer.Footer.ReferenceId, default: header,
},
footers: {
default: footer,
},
pageNumberStart: 1, pageNumberStart: 1,
pageNumberFormatType: PageNumberFormat.DECIMAL, pageNumberFormatType: PageNumberFormat.DECIMAL,
}); });
@ -24,8 +28,12 @@ doc.addSection({
doc.createParagraph("hello"); doc.createParagraph("hello");
doc.addSection({ doc.addSection({
headerId: header.Header.ReferenceId, headers: {
footerId: footer.Footer.ReferenceId, default: header,
},
footers: {
default: footer,
},
pageNumberStart: 1, pageNumberStart: 1,
pageNumberFormatType: PageNumberFormat.DECIMAL, pageNumberFormatType: PageNumberFormat.DECIMAL,
orientation: PageOrientation.LANDSCAPE, orientation: PageOrientation.LANDSCAPE,

View File

@ -8,11 +8,11 @@ const doc = new Document();
const paragraph = new Paragraph("Hello World"); const paragraph = new Paragraph("Hello World");
doc.addParagraph(paragraph); doc.addParagraph(paragraph);
const image = Media.addImage(doc, "./demo/images/image1.jpeg"); const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
const image2 = Media.addImage(doc, "./demo/images/dog.png"); const image2 = Media.addImage(doc, fs.readFileSync("./demo/images/dog.png"));
const image3 = Media.addImage(doc, "./demo/images/cat.jpg"); const image3 = Media.addImage(doc, fs.readFileSync("./demo/images/cat.jpg"));
const image4 = Media.addImage(doc, "./demo/images/parrots.bmp"); const image4 = Media.addImage(doc, fs.readFileSync("./demo/images/parrots.bmp"));
const image5 = Media.addImage(doc, "./demo/images/pizza.gif"); const image5 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
const imageBase64Data = `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`; const imageBase64Data = `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`;
const image6 = Media.addImage(doc, Buffer.from(imageBase64Data, "base64"), 100, 100); const image6 = Media.addImage(doc, Buffer.from(imageBase64Data, "base64"), 100, 100);

View File

@ -8,7 +8,7 @@ const doc = new Document();
const table = doc.createTable(4, 4); const table = doc.createTable(4, 4);
table.getCell(2, 2).addContent(new Paragraph("Hello")); table.getCell(2, 2).addContent(new Paragraph("Hello"));
const image = Media.addImage(doc, "./demo/images/image1.jpeg"); const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
table.getCell(1, 1).addContent(image.Paragraph); table.getCell(1, 1).addContent(image.Paragraph);
const packer = new Packer(); const packer = new Packer();

View File

@ -30,5 +30,4 @@ const packer = new Packer();
packer.toBuffer(doc).then((buffer) => { packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer); fs.writeFileSync("My Document.docx", buffer);
console.log("Document created successfully at project root!");
}); });

29
demo/demo30.ts Normal file
View File

@ -0,0 +1,29 @@
import * as fs from "fs";
import { Document, ImportDotx, Packer, Paragraph } from "../build";
const importDotx = new ImportDotx();
const filePath = "./demo/dotx/template.dotx";
fs.readFile(filePath, (err, data) => {
if (err) {
throw new Error(`Failed to read file ${filePath}.`);
}
importDotx.extract(data).then((templateDocument) => {
// This any needs fixing
const sectionProps = {
titlePage: templateDocument.titlePageIsDefined,
} as any;
const doc = new Document(undefined, sectionProps, {
template: templateDocument,
});
const paragraph = new Paragraph("Hello World");
doc.addParagraph(paragraph);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});
});
});

32
demo/demo34.ts Normal file
View File

@ -0,0 +1,32 @@
// Example of how you would create a table with float positions
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import {
Document,
Packer,
Paragraph,
RelativeHorizontalPosition,
RelativeVerticalPosition,
TableAnchorType,
WidthType,
} from "../build";
const doc = new Document();
const table = doc.createTable(2, 2).float({
horizontalAnchor: TableAnchorType.MARGIN,
verticalAnchor: TableAnchorType.MARGIN,
relativeHorizontalPosition: RelativeHorizontalPosition.RIGHT,
relativeVerticalPosition: RelativeVerticalPosition.BOTTOM,
});
table.setFixedWidthLayout();
table.setWidth(WidthType.DXA, 4535);
table.getCell(0, 0).addContent(new Paragraph("Hello"));
table.getRow(0).mergeCells(0, 1);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

BIN
demo/dotx/template.dotx Normal file

Binary file not shown.

View File

@ -1,5 +1,15 @@
# Contribution Guidelines # Contribution Guidelines
* Include documentation reference(s) at the top of each file:
```js
// http://officeopenxml.com/WPdocument.php
```
* Follow Prettier standards, and consider using the [Prettier VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) plugin.
* Follow the `TSLint` rules
## Always think about the user ## Always think about the user
The number one pillar for contribution is to **ALWAYS** think about how the user will use the library. The number one pillar for contribution is to **ALWAYS** think about how the user will use the library.
@ -25,17 +35,33 @@ demo updated // Getting better, but capitalize the first letter
Unesesary coment removed // Make sure to use correct spelling Unesesary coment removed // Make sure to use correct spelling
``` ```
## Writing Code ## No leaky components in API interface
* Include documentation reference(s) at the top of each file: This mainly applies to the API the end user will consume.
Try to make method parameters accept primatives, or `json` objects, so that child components are created **inside** the component, rather than being **injected** in.
This is so that:
1. Imports are much cleaner, no need for:
```js ```js
// http://officeopenxml.com/WPdocument.php import { ChildComponent } from "./my-feature/sub-component/deeper/.../my-deep.component";
``` ```
* Follow Prettier standards, and consider using the [Prettier VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) plugin. 2. This is what I consider "leakage". The code is aware of the underlying implementation of the component.
3. It means the end user does not need to import and create the child component to be injected.
* Follow the `TSLint` rules **Do not**
`TableFloatProperties` is a class. The outside world would have to construct the object, and inject it in
```js
public float(tableFloatProperties: TableFloatProperties): Table
```
**Do**
`ITableFloatOptions` is an interface for a JSON of primatives.
```js
public float(tableFloatOptions: ITableFloatOptions): Table
```
## Add vs Create ## Add vs Create
@ -64,7 +90,7 @@ Getters and Setters are done with a capital letter like so:
```js ```js
public get Level() { public get Level() {
...
} }
``` ```
@ -130,7 +156,7 @@ enum WeaponType = {
## Spell correctly, full and in American English ## Spell correctly, full and in American English
I am not sure where these habit in software development comes from, but I do not believe it is beneficial: I am not sure where these habits in software development come from, but I do not believe it is beneficial:
**Do not:** **Do not:**
```js ```js

View File

@ -75,7 +75,7 @@ abstractNum.createLevel(0, "upperRoman", "%1", "start").addParagraphProperty(new
abstractNum.createLevel(1, "decimal", "%2.", "start").addParagraphProperty(new Indent(1440, 980)); abstractNum.createLevel(1, "decimal", "%2.", "start").addParagraphProperty(new Indent(1440, 980));
abstractNum.createLevel(2, "lowerLetter", "%3)", "start").addParagraphProperty(new Indent(2160, 1700)); abstractNum.createLevel(2, "lowerLetter", "%3)", "start").addParagraphProperty(new Indent(2160, 1700));
const concrete = numbering.createConcreteNumbering(numberedAbstract); const concrete = numbering.createConcreteNumbering(abstractNum);
``` ```
You can then apply your concrete style to paragraphs using their You can then apply your concrete style to paragraphs using their

View File

@ -6,17 +6,17 @@
"scripts": { "scripts": {
"pretest": "rimraf ./build", "pretest": "rimraf ./build",
"test": "mocha-webpack \"src/**/*.ts\"", "test": "mocha-webpack \"src/**/*.ts\"",
"test-watch": "mocha-webpack \"src/**/*.ts\" --watch", "test.coverage": "nyc npm test",
"test.watch": "npm test -- --watch",
"prepublishOnly": "npm run build", "prepublishOnly": "npm run build",
"lint": "tslint --project .", "lint": "tslint --project .",
"build": "npm run webpack && npm run fix-types", "build": "npm run webpack && npm run fix-types",
"tsc": "rimraf ./build && tsc -p .", "tsc": "rimraf ./build && tsc -p .",
"webpack": "rimraf ./build && webpack", "webpack": "rimraf ./build && webpack",
"build.web": "webpack --config webpack.web.config.js",
"demo": "npm run build && npm run ts-node ./demo", "demo": "npm run build && npm run ts-node ./demo",
"typedoc": "typedoc src/index.ts", "typedoc": "typedoc src/index.ts",
"style": "prettier -l \"src/**/*.ts\"", "style": "prettier -l \"src/**/*.ts\"",
"style.fix": "prettier \"src/**/*.ts\" --write", "style.fix": "npm run style -- --write",
"fix-types": "node types-absolute-fixer.js", "fix-types": "node types-absolute-fixer.js",
"ts-node": "ts-node" "ts-node": "ts-node"
}, },
@ -48,11 +48,11 @@
"types": "./build/index.d.ts", "types": "./build/index.d.ts",
"dependencies": { "dependencies": {
"@types/image-size": "0.0.29", "@types/image-size": "0.0.29",
"@types/jszip": "^3.1.3", "@types/jszip": "^3.1.4",
"fast-xml-parser": "^3.3.6",
"image-size": "^0.6.2", "image-size": "^0.6.2",
"jszip": "^3.1.5", "jszip": "^3.1.5",
"xml": "^1.0.1" "xml": "^1.0.1",
"xml-js": "^1.6.8"
}, },
"author": "Dolan Miu", "author": "Dolan Miu",
"license": "MIT", "license": "MIT",
@ -67,9 +67,11 @@
"awesome-typescript-loader": "^3.4.1", "awesome-typescript-loader": "^3.4.1",
"chai": "^3.5.0", "chai": "^3.5.0",
"glob": "^7.1.2", "glob": "^7.1.2",
"istanbul-instrumenter-loader": "^3.0.1",
"jszip": "^3.1.5", "jszip": "^3.1.5",
"mocha": "^5.2.0", "mocha": "^5.2.0",
"mocha-webpack": "^1.0.1", "mocha-webpack": "^1.0.1",
"nyc": "^13.1.0",
"pre-commit": "^1.2.2", "pre-commit": "^1.2.2",
"prettier": "^1.12.1", "prettier": "^1.12.1",
"prompt": "^1.0.0", "prompt": "^1.0.0",
@ -79,6 +81,7 @@
"sinon": "^5.0.7", "sinon": "^5.0.7",
"ts-node": "^7.0.1", "ts-node": "^7.0.1",
"tslint": "^5.11.0", "tslint": "^5.11.0",
"tslint-immutable": "^4.9.0",
"typedoc": "^0.11.1", "typedoc": "^0.11.1",
"typescript": "2.9.2", "typescript": "2.9.2",
"webpack": "^3.10.0" "webpack": "^3.10.0"

View File

@ -2,6 +2,12 @@ import { BaseXmlComponent, IXmlableObject } from "file/xml-components";
export class Formatter { export class Formatter {
public format(input: BaseXmlComponent): IXmlableObject { public format(input: BaseXmlComponent): IXmlableObject {
return input.prepForXml(); const output = input.prepForXml();
if (output) {
return output;
} else {
throw Error("XMLComponent did not format correctly");
}
} }
} }

View File

@ -1,6 +1,8 @@
/* tslint:disable:typedef space-before-function-paren */ /* tslint:disable:typedef space-before-function-paren */
import { expect } from "chai"; import { expect } from "chai";
import { File } from "../../file";
import { File } from "file";
import { Compiler } from "./next-compiler"; import { Compiler } from "./next-compiler";
describe("Compiler", () => { describe("Compiler", () => {

View File

@ -5,25 +5,25 @@ import { File } from "file";
import { Formatter } from "../formatter"; import { Formatter } from "../formatter";
interface IXmlifyedFile { interface IXmlifyedFile {
data: string; readonly data: string;
path: string; readonly path: string;
} }
interface IXmlifyedFileMapping { interface IXmlifyedFileMapping {
Document: IXmlifyedFile; readonly Document: IXmlifyedFile;
Styles: IXmlifyedFile; readonly Styles: IXmlifyedFile;
Properties: IXmlifyedFile; readonly Properties: IXmlifyedFile;
Numbering: IXmlifyedFile; readonly Numbering: IXmlifyedFile;
Relationships: IXmlifyedFile; readonly Relationships: IXmlifyedFile;
FileRelationships: IXmlifyedFile; readonly FileRelationships: IXmlifyedFile;
Headers: IXmlifyedFile[]; readonly Headers: IXmlifyedFile[];
Footers: IXmlifyedFile[]; readonly Footers: IXmlifyedFile[];
HeaderRelationships: IXmlifyedFile[]; readonly HeaderRelationships: IXmlifyedFile[];
FooterRelationships: IXmlifyedFile[]; readonly FooterRelationships: IXmlifyedFile[];
ContentTypes: IXmlifyedFile; readonly ContentTypes: IXmlifyedFile;
AppProperties: IXmlifyedFile; readonly AppProperties: IXmlifyedFile;
FootNotes: IXmlifyedFile; readonly FootNotes: IXmlifyedFile;
Settings: IXmlifyedFile; readonly Settings: IXmlifyedFile;
} }
export class Compiler { export class Compiler {
@ -59,6 +59,18 @@ export class Compiler {
zip.file(`word/media/${data.fileName}`, mediaData); zip.file(`word/media/${data.fileName}`, mediaData);
} }
for (const header of file.Headers) {
for (const data of header.Media.Array) {
zip.file(`word/media/${data.fileName}`, data.stream);
}
}
for (const footer of file.Footers) {
for (const data of footer.Media.Array) {
zip.file(`word/media/${data.fileName}`, data.stream);
}
}
return zip; return zip;
} }
@ -128,4 +140,13 @@ export class Compiler {
}, },
}; };
} }
/* By default docx collapse empty tags. <a></a> -> <a/>. this function mimic it
so comparing (diff) original docx file and the library output is easier
Currently not used, so commenting out */
// private collapseEmptyTags(xmlData: string): string {
// const regEx = /<(([^ <>]+)[^<>]*)><\/\2>/g;
// const collapsed = xmlData.replace(regEx, "<$1/>");
// return collapsed;
// }
} }

View File

@ -2,7 +2,8 @@
import { assert } from "chai"; import { assert } from "chai";
import { stub } from "sinon"; import { stub } from "sinon";
import { File, Paragraph } from "../../file"; import { File, Paragraph } from "file";
import { Packer } from "./packer"; import { Packer } from "./packer";
describe("Packer", () => { describe("Packer", () => {

View File

@ -10,21 +10,30 @@ export class Packer {
public async toBuffer(file: File): Promise<Buffer> { public async toBuffer(file: File): Promise<Buffer> {
const zip = await this.compiler.compile(file); const zip = await this.compiler.compile(file);
const zipData = (await zip.generateAsync({ type: "nodebuffer" })) as Buffer; const zipData = (await zip.generateAsync({
type: "nodebuffer",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
})) as Buffer;
return zipData; return zipData;
} }
public async toBase64String(file: File): Promise<string> { public async toBase64String(file: File): Promise<string> {
const zip = await this.compiler.compile(file); const zip = await this.compiler.compile(file);
const zipData = (await zip.generateAsync({ type: "base64" })) as string; const zipData = (await zip.generateAsync({
type: "base64",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
})) as string;
return zipData; return zipData;
} }
public async toBlob(file: File): Promise<Blob> { public async toBlob(file: File): Promise<Blob> {
const zip = await this.compiler.compile(file); const zip = await this.compiler.compile(file);
const zipData = (await zip.generateAsync({ type: "blob" })) as Blob; const zipData = (await zip.generateAsync({
type: "blob",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
})) as Blob;
return zipData; return zipData;
} }

View File

@ -1,12 +1,12 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IAppPropertiesAttributes { export interface IAppPropertiesAttributes {
xmlns: string; readonly xmlns: string;
vt: string; readonly vt: string;
} }
export class AppPropertiesAttributes extends XmlAttributeComponent<IAppPropertiesAttributes> { export class AppPropertiesAttributes extends XmlAttributeComponent<IAppPropertiesAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
xmlns: "xmlns", xmlns: "xmlns",
vt: "xmlns:vt", vt: "xmlns:vt",
}; };

View File

@ -1,11 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IContentTypeAttributes { export interface IContentTypeAttributes {
xmlns?: string; readonly xmlns?: string;
} }
export class ContentTypeAttributes extends XmlAttributeComponent<IContentTypeAttributes> { export class ContentTypeAttributes extends XmlAttributeComponent<IContentTypeAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
xmlns: "xmlns", xmlns: "xmlns",
}; };
} }

View File

@ -1,7 +1,9 @@
// tslint:disable:no-string-literal // tslint:disable:no-string-literal
import { expect } from "chai"; import { expect } from "chai";
import { Formatter } from "../../export/formatter";
import { Formatter } from "export/formatter";
import { ContentTypes } from "./content-types"; import { ContentTypes } from "./content-types";
describe("ContentTypes", () => { describe("ContentTypes", () => {

View File

@ -1,12 +1,12 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IDefaultAttributes { export interface IDefaultAttributes {
contentType: string; readonly contentType: string;
extension?: string; readonly extension?: string;
} }
export class DefaultAttributes extends XmlAttributeComponent<IDefaultAttributes> { export class DefaultAttributes extends XmlAttributeComponent<IDefaultAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
contentType: "ContentType", contentType: "ContentType",
extension: "Extension", extension: "Extension",
}; };

View File

@ -1,12 +1,12 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IOverrideAttributes { export interface IOverrideAttributes {
contentType: string; readonly contentType: string;
partName?: string; readonly partName?: string;
} }
export class OverrideAttributes extends XmlAttributeComponent<IOverrideAttributes> { export class OverrideAttributes extends XmlAttributeComponent<IOverrideAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
contentType: "ContentType", contentType: "ContentType",
partName: "PartName", partName: "PartName",
}; };

View File

@ -1,6 +1,7 @@
import { expect } from "chai"; import { expect } from "chai";
import { Formatter } from "../../export/formatter"; import { Formatter } from "export/formatter";
import { CoreProperties } from "./properties"; import { CoreProperties } from "./properties";
describe("Properties", () => { describe("Properties", () => {

View File

@ -3,14 +3,14 @@ import { DocumentAttributes } from "../document/document-attributes";
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 IPropertiesOptions { export interface IPropertiesOptions {
title?: string; readonly title?: string;
subject?: string; readonly subject?: string;
creator?: string; readonly creator?: string;
keywords?: string; readonly keywords?: string;
description?: string; readonly description?: string;
lastModifiedBy?: string; readonly lastModifiedBy?: string;
revision?: string; readonly revision?: string;
externalStyles?: string; readonly externalStyles?: string;
} }
export class CoreProperties extends XmlComponent { export class CoreProperties extends XmlComponent {

View File

@ -1,6 +1,7 @@
import { expect } from "chai"; import { expect } from "chai";
import { Formatter } from "../../../export/formatter"; import { Formatter } from "export/formatter";
import { Body } from "./body"; import { Body } from "./body";
describe("Body", () => { describe("Body", () => {
@ -16,11 +17,11 @@ describe("Body", () => {
expect(formatted) expect(formatted)
.to.have.property("w:sectPr") .to.have.property("w:sectPr")
.and.to.be.an.instanceof(Array); .and.to.be.an.instanceof(Array);
expect(formatted["w:sectPr"]).to.have.length(7); expect(formatted["w:sectPr"]).to.have.length(5);
}); });
}); });
describe("addSection", () => { describe("#addSection", () => {
it("should add section with options", () => { it("should add section with options", () => {
body.addSection({ body.addSection({
width: 10000, width: 10000,
@ -38,5 +39,93 @@ describe("Body", () => {
const newSection = formatted[1]["w:sectPr"]; const newSection = formatted[1]["w:sectPr"];
expect(newSection[0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 10000, "w:w": 10000, "w:orient": "portrait" } }] }); expect(newSection[0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 10000, "w:w": 10000, "w:orient": "portrait" } }] });
}); });
it("should add section with default parameters", () => {
body.addSection({
width: 10000,
height: 10000,
});
const tree = new Formatter().format(body);
expect(tree).to.deep.equal({
"w:body": [
{
"w:p": [
{ "w:pPr": [] },
{
"w:pPr": [
{
"w:sectPr": [
{ "w:pgSz": [{ _attr: { "w:w": 11906, "w:h": 16838, "w:orient": "portrait" } }] },
{
"w:pgMar": [
{
_attr: {
"w:top": 1440,
"w:right": 1440,
"w:bottom": 1440,
"w:left": 1440,
"w:header": 708,
"w:footer": 708,
"w:gutter": 0,
"w:mirrorMargins": false,
},
},
],
},
{ "w:cols": [{ _attr: { "w:space": 708 } }] },
{ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] },
{ "w:pgNumType": [{ _attr: { "w:fmt": "decimal" } }] },
],
},
],
},
],
},
{
"w:sectPr": [
{ "w:pgSz": [{ _attr: { "w:w": 10000, "w:h": 10000, "w:orient": "portrait" } }] },
{
"w:pgMar": [
{
_attr: {
"w:top": 1440,
"w:right": 1440,
"w:bottom": 1440,
"w:left": 1440,
"w:header": 708,
"w:footer": 708,
"w:gutter": 0,
"w:mirrorMargins": false,
},
},
],
},
{ "w:cols": [{ _attr: { "w:space": 708 } }] },
{ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] },
{ "w:pgNumType": [{ _attr: { "w:fmt": "decimal" } }] },
],
},
],
});
});
});
describe("#getParagraphs", () => {
it("should get no paragraphs", () => {
const paragraphs = body.getParagraphs();
expect(paragraphs).to.be.an.instanceof(Array);
});
});
describe("#DefaultSection", () => {
it("should get section", () => {
const section = body.DefaultSection;
const tree = new Formatter().format(section);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
});
}); });
}); });

View File

@ -35,11 +35,9 @@ export class Body extends XmlComponent {
this.sections.push(new SectionProperties(params)); this.sections.push(new SectionProperties(params));
} }
} }
public prepForXml(): IXmlableObject { public prepForXml(): IXmlableObject | undefined {
if (this.sections.length === 1) { if (this.sections.length === 1) {
this.root.push(this.sections[0]); this.root.push(this.sections[0]);
} else if (this.sections.length > 1) {
throw new Error("Invalid usage of sections. At the end of the body element there must be ONE section.");
} }
return super.prepForXml(); return super.prepForXml();

View File

@ -1,11 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IColumnsAttributes { export interface IColumnsAttributes {
space?: number; readonly space?: number;
} }
export class ColumnsAttributes extends XmlAttributeComponent<IColumnsAttributes> { export class ColumnsAttributes extends XmlAttributeComponent<IColumnsAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
space: "w:space", space: "w:space",
}; };
} }

View File

@ -1,11 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IDocGridAttributesProperties { export interface IDocGridAttributesProperties {
linePitch?: number; readonly linePitch?: number;
} }
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> { export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
protected xmlKeys = { protected readonly xmlKeys = {
linePitch: "w:linePitch", linePitch: "w:linePitch",
}; };
} }

View File

@ -7,12 +7,12 @@ export enum FooterReferenceType {
} }
export interface IFooterReferenceAttributes { export interface IFooterReferenceAttributes {
type: string; readonly type: string;
id: string; readonly id: string;
} }
export class FooterReferenceAttributes extends XmlAttributeComponent<IFooterReferenceAttributes> { export class FooterReferenceAttributes extends XmlAttributeComponent<IFooterReferenceAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
type: "w:type", type: "w:type",
id: "r:id", id: "r:id",
}; };

View File

@ -2,8 +2,8 @@ import { XmlComponent } from "file/xml-components";
import { FooterReferenceAttributes, FooterReferenceType } from "./footer-reference-attributes"; import { FooterReferenceAttributes, FooterReferenceType } from "./footer-reference-attributes";
export interface IFooterOptions { export interface IFooterOptions {
footerType?: FooterReferenceType; readonly footerType?: FooterReferenceType;
footerId?: number; readonly footerId?: number;
} }
export class FooterReference extends XmlComponent { export class FooterReference extends XmlComponent {

View File

@ -7,12 +7,12 @@ export enum HeaderReferenceType {
} }
export interface IHeaderReferenceAttributes { export interface IHeaderReferenceAttributes {
type: string; readonly type: string;
id: string; readonly id: string;
} }
export class HeaderReferenceAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> { export class HeaderReferenceAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
type: "w:type", type: "w:type",
id: "r:id", id: "r:id",
}; };

View File

@ -2,8 +2,8 @@ import { XmlComponent } from "file/xml-components";
import { HeaderReferenceAttributes, HeaderReferenceType } from "./header-reference-attributes"; import { HeaderReferenceAttributes, HeaderReferenceType } from "./header-reference-attributes";
export interface IHeaderOptions { export interface IHeaderOptions {
headerType?: HeaderReferenceType; readonly headerType?: HeaderReferenceType;
headerId?: number; readonly headerId?: number;
} }
export class HeaderReference extends XmlComponent { export class HeaderReference extends XmlComponent {

View File

@ -1,16 +1,15 @@
import { expect } from "chai"; import { expect } from "chai";
import { Formatter } from "../../../../../export/formatter"; import { Formatter } from "export/formatter";
import { BorderStyle } from "../../../../styles"; import { BorderStyle } from "file/styles";
import { PageBorderDisplay, PageBorders, PageBorderZOrder } from "./page-borders"; import { PageBorderDisplay, PageBorders, PageBorderZOrder } from "./page-borders";
describe("PageBorders", () => { describe("PageBorders", () => {
describe("#constructor()", () => { describe("#constructor()", () => {
it("should create empty element when no options are passed", () => { it("should create empty element when no options are passed", () => {
const properties = new PageBorders(); const properties = new PageBorders();
const tree = new Formatter().format(properties); expect(() => new Formatter().format(properties)).to.throw();
expect(tree).to.equal("");
}); });
it("should create page borders with some configuration", () => { it("should create page borders with some configuration", () => {

View File

@ -1,6 +1,6 @@
// http://officeopenxml.com/WPsectionBorders.php // http://officeopenxml.com/WPsectionBorders.php
import { BorderStyle } from "file/styles";
import { IXmlableObject, XmlAttributeComponent, XmlComponent } from "file/xml-components"; import { IXmlableObject, XmlAttributeComponent, XmlComponent } from "file/xml-components";
import { BorderStyle } from "../../../../styles";
export enum PageBorderDisplay { export enum PageBorderDisplay {
ALL_PAGES = "allPages", ALL_PAGES = "allPages",
@ -19,28 +19,28 @@ export enum PageBorderZOrder {
} }
export interface IPageBorderAttributes { export interface IPageBorderAttributes {
display?: PageBorderDisplay; readonly display?: PageBorderDisplay;
offsetFrom?: PageBorderOffsetFrom; readonly offsetFrom?: PageBorderOffsetFrom;
zOrder?: PageBorderZOrder; readonly zOrder?: PageBorderZOrder;
} }
export interface IPageBorderConfiguration { export interface IPageBorderConfiguration {
style?: BorderStyle; readonly style?: BorderStyle;
size?: number; readonly size?: number;
color?: string; readonly color?: string;
space?: number; readonly space?: number;
} }
export interface IPageBordersOptions { export interface IPageBordersOptions {
pageBorders?: IPageBorderAttributes; readonly pageBorders?: IPageBorderAttributes;
pageBorderTop?: IPageBorderConfiguration; readonly pageBorderTop?: IPageBorderConfiguration;
pageBorderRight?: IPageBorderConfiguration; readonly pageBorderRight?: IPageBorderConfiguration;
pageBorderBottom?: IPageBorderConfiguration; readonly pageBorderBottom?: IPageBorderConfiguration;
pageBorderLeft?: IPageBorderConfiguration; readonly pageBorderLeft?: IPageBorderConfiguration;
} }
class PageBordeAttributes extends XmlAttributeComponent<IPageBorderConfiguration> { class PageBordeAttributes extends XmlAttributeComponent<IPageBorderConfiguration> {
protected xmlKeys = { protected readonly xmlKeys = {
style: "w:val", style: "w:val",
size: "w:size", size: "w:size",
color: "w:color", color: "w:color",
@ -57,7 +57,7 @@ class PageBorder extends XmlComponent {
} }
class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes> { class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
display: "w:display", display: "w:display",
offsetFrom: "w:offsetFrom", offsetFrom: "w:offsetFrom",
zOrder: "w:zOrder", zOrder: "w:zOrder",
@ -98,7 +98,9 @@ export class PageBorders extends XmlComponent {
} }
} }
public prepForXml(): IXmlableObject { public prepForXml(): IXmlableObject | undefined {
return this.root.length > 0 ? super.prepForXml() : ""; if (this.root.length > 0) {
return super.prepForXml();
}
} }
} }

View File

@ -1,18 +1,18 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IPageMarginAttributes { export interface IPageMarginAttributes {
top?: number; readonly top?: number;
right?: number; readonly right?: number;
bottom?: number; readonly bottom?: number;
left?: number; readonly left?: number;
header?: number; readonly header?: number;
footer?: number; readonly footer?: number;
gutter?: number; readonly gutter?: number;
mirror?: boolean; readonly mirror?: boolean;
} }
export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> { export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
top: "w:top", top: "w:top",
right: "w:right", right: "w:right",
bottom: "w:bottom", bottom: "w:bottom",

View File

@ -17,12 +17,12 @@ export enum PageNumberFormat {
} }
export interface IPageNumberTypeAttributes { export interface IPageNumberTypeAttributes {
pageNumberStart?: number; readonly pageNumberStart?: number;
pageNumberFormatType?: PageNumberFormat; readonly pageNumberFormatType?: PageNumberFormat;
} }
export class PageNumberTypeAttributes extends XmlAttributeComponent<IPageNumberTypeAttributes> { export class PageNumberTypeAttributes extends XmlAttributeComponent<IPageNumberTypeAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
pageNumberStart: "w:start", pageNumberStart: "w:start",
pageNumberFormatType: "w:fmt", pageNumberFormatType: "w:fmt",
}; };

View File

@ -6,13 +6,13 @@ export enum PageOrientation {
} }
export interface IPageSizeAttributes { export interface IPageSizeAttributes {
width?: number; readonly width?: number;
height?: number; readonly height?: number;
orientation?: PageOrientation; readonly orientation?: PageOrientation;
} }
export class PageSizeAttributes extends XmlAttributeComponent<IPageSizeAttributes> { export class PageSizeAttributes extends XmlAttributeComponent<IPageSizeAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
width: "w:w", width: "w:w",
height: "w:h", height: "w:h",
orientation: "w:orient", orientation: "w:orient",

View File

@ -1,6 +1,7 @@
import { expect } from "chai"; import { expect } from "chai";
import { Formatter } from "../../../../../export/formatter"; import { Formatter } from "export/formatter";
import { PageSize } from "./page-size"; import { PageSize } from "./page-size";
import { PageOrientation } from "./page-size-attributes"; import { PageOrientation } from "./page-size-attributes";

View File

@ -1,12 +1,19 @@
import { expect } from "chai"; import { expect } from "chai";
import { Formatter } from "../../../../export/formatter"; import { Formatter } from "export/formatter";
import { FooterReferenceType, PageBorderOffsetFrom, PageNumberFormat } from "./"; import { FooterWrapper } from "file/footer-wrapper";
import { HeaderWrapper } from "file/header-wrapper";
import { Media } from "file/media";
import { PageBorderOffsetFrom } from "./page-border";
import { PageNumberFormat } from "./page-number";
import { SectionProperties } from "./section-properties"; import { SectionProperties } from "./section-properties";
describe("SectionProperties", () => { describe("SectionProperties", () => {
describe("#constructor()", () => { describe("#constructor()", () => {
it("should create section properties with options", () => { it("should create section properties with options", () => {
const media = new Media();
const properties = new SectionProperties({ const properties = new SectionProperties({
width: 11906, width: 11906,
height: 16838, height: 16838,
@ -20,9 +27,12 @@ describe("SectionProperties", () => {
mirror: false, mirror: false,
space: 708, space: 708,
linePitch: 360, linePitch: 360,
headerId: 100, headers: {
footerId: 200, default: new HeaderWrapper(media, 100),
footerType: FooterReferenceType.EVEN, },
footers: {
even: new FooterWrapper(media, 200),
},
pageNumberStart: 10, pageNumberStart: 10,
pageNumberFormatType: PageNumberFormat.CARDINAL_TEXT, pageNumberFormatType: PageNumberFormat.CARDINAL_TEXT,
}); });
@ -78,9 +88,7 @@ describe("SectionProperties", () => {
}); });
expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": [{ _attr: { "w:space": 708 } }] }); expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": [{ _attr: { "w:space": 708 } }] });
expect(tree["w:sectPr"][3]).to.deep.equal({ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] }); expect(tree["w:sectPr"][3]).to.deep.equal({ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] });
expect(tree["w:sectPr"][4]).to.deep.equal({ "w:headerReference": [{ _attr: { "r:id": "rId0", "w:type": "default" } }] }); expect(tree["w:sectPr"][4]).to.deep.equal({ "w:pgNumType": [{ _attr: { "w:fmt": "decimal" } }] });
expect(tree["w:sectPr"][5]).to.deep.equal({ "w:footerReference": [{ _attr: { "r:id": "rId0", "w:type": "default" } }] });
expect(tree["w:sectPr"][6]).to.deep.equal({ "w:pgNumType": [{ _attr: { "w:fmt": "decimal" } }] });
}); });
it("should create section properties with changed options", () => { it("should create section properties with changed options", () => {
@ -170,7 +178,8 @@ describe("SectionProperties", () => {
}); });
const tree = new Formatter().format(properties); const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]); expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
expect(tree["w:sectPr"][7]).to.deep.equal({ const pgBorders = tree["w:sectPr"].find((item) => item["w:pgBorders"] !== undefined);
expect(pgBorders).to.deep.equal({
"w:pgBorders": [{ _attr: { "w:offsetFrom": "page" } }], "w:pgBorders": [{ _attr: { "w:offsetFrom": "page" } }],
}); });
}); });

View File

@ -1,115 +1,172 @@
// http://officeopenxml.com/WPsection.php // http://officeopenxml.com/WPsection.php
import { FooterWrapper } from "file/footer-wrapper";
import { HeaderWrapper } from "file/header-wrapper";
import { XmlComponent } from "file/xml-components"; import { XmlComponent } from "file/xml-components";
import { FooterReferenceType, IPageBordersOptions, IPageNumberTypeAttributes, PageBorders, PageNumberFormat, PageNumberType } from "./";
import { Columns } from "./columns/columns"; import { Columns } from "./columns/columns";
import { IColumnsAttributes } from "./columns/columns-attributes"; import { IColumnsAttributes } from "./columns/columns-attributes";
import { DocumentGrid } from "./doc-grid/doc-grid"; import { DocumentGrid } from "./doc-grid/doc-grid";
import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes"; import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes";
import { FooterReference, IFooterOptions } from "./footer-reference/footer-reference"; import { FooterReferenceType } from "./footer-reference";
import { HeaderReference, IHeaderOptions } from "./header-reference/header-reference"; import { FooterReference } from "./footer-reference/footer-reference";
import { HeaderReferenceType } from "./header-reference/header-reference-attributes"; import { HeaderReferenceType } from "./header-reference";
import { HeaderReference } from "./header-reference/header-reference";
import { IPageBordersOptions, PageBorders } from "./page-border";
import { PageMargin } from "./page-margin/page-margin"; import { PageMargin } from "./page-margin/page-margin";
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes"; import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
import { IPageNumberTypeAttributes, PageNumberFormat, PageNumberType } from "./page-number";
import { PageSize } from "./page-size/page-size"; import { PageSize } from "./page-size/page-size";
import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes"; import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes";
import { TitlePage } from "./title-page/title-page";
export interface IHeaderFooterGroup<T> {
readonly default?: T;
readonly first?: T;
readonly even?: T;
}
interface IHeadersOptions {
readonly headers?: IHeaderFooterGroup<HeaderWrapper>;
}
interface IFootersOptions {
readonly footers?: IHeaderFooterGroup<FooterWrapper>;
}
interface ITitlePageOptions {
readonly titlePage?: boolean;
}
export type SectionPropertiesOptions = IPageSizeAttributes & export type SectionPropertiesOptions = IPageSizeAttributes &
IPageMarginAttributes & IPageMarginAttributes &
IColumnsAttributes & IColumnsAttributes &
IDocGridAttributesProperties & IDocGridAttributesProperties &
IHeaderOptions & IHeadersOptions &
IFooterOptions & IFootersOptions &
IPageNumberTypeAttributes & IPageNumberTypeAttributes &
IPageBordersOptions; IPageBordersOptions &
ITitlePageOptions;
export class SectionProperties extends XmlComponent { export class SectionProperties extends XmlComponent {
private readonly options: SectionPropertiesOptions; private readonly options: SectionPropertiesOptions;
constructor(options?: SectionPropertiesOptions) { constructor(options: SectionPropertiesOptions = {}) {
super("w:sectPr"); super("w:sectPr");
const defaultOptions = { const {
width: 11906, width = 11906,
height: 16838, height = 16838,
top: 1440, top = 1440,
right: 1440, right = 1440,
bottom: 1440, bottom = 1440,
left: 1440, left = 1440,
header: 708, header = 708,
footer: 708, footer = 708,
gutter: 0, gutter = 0,
mirror: false, mirror = false,
space: 708, space = 708,
linePitch: 360, linePitch = 360,
orientation: PageOrientation.PORTRAIT, orientation = PageOrientation.PORTRAIT,
headerType: HeaderReferenceType.DEFAULT, headers,
headerId: 0, footers,
footerType: FooterReferenceType.DEFAULT, pageNumberFormatType = PageNumberFormat.DECIMAL,
footerId: 0, pageNumberStart,
pageNumberStart: undefined, pageBorders,
pageNumberFormatType: PageNumberFormat.DECIMAL, pageBorderTop,
pageBorders: undefined, pageBorderRight,
pageBorderTop: undefined, pageBorderBottom,
pageBorderRight: undefined, pageBorderLeft,
pageBorderBottom: undefined, titlePage = false,
pageBorderLeft: undefined, } = options;
};
const mergedOptions = { this.options = options;
...defaultOptions, this.root.push(new PageSize(width, height, orientation));
...options, this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter, mirror));
}; this.root.push(new Columns(space));
this.root.push(new DocumentGrid(linePitch));
this.root.push(new PageSize(mergedOptions.width, mergedOptions.height, mergedOptions.orientation)); this.addHeaders(headers);
this.root.push( this.addFooters(footers);
new PageMargin(
mergedOptions.top,
mergedOptions.right,
mergedOptions.bottom,
mergedOptions.left,
mergedOptions.header,
mergedOptions.footer,
mergedOptions.gutter,
mergedOptions.mirror,
),
);
this.root.push(new Columns(mergedOptions.space));
this.root.push(new DocumentGrid(mergedOptions.linePitch));
this.root.push( this.root.push(new PageNumberType(pageNumberStart, pageNumberFormatType));
new HeaderReference({
headerType: mergedOptions.headerType,
headerId: mergedOptions.headerId,
}),
);
this.root.push(
new FooterReference({
footerType: mergedOptions.footerType,
footerId: mergedOptions.footerId,
}),
);
this.root.push(new PageNumberType(mergedOptions.pageNumberStart, mergedOptions.pageNumberFormatType)); if (pageBorders || pageBorderTop || pageBorderRight || pageBorderBottom || pageBorderLeft) {
if (
mergedOptions.pageBorders ||
mergedOptions.pageBorderTop ||
mergedOptions.pageBorderRight ||
mergedOptions.pageBorderBottom ||
mergedOptions.pageBorderLeft
) {
this.root.push( this.root.push(
new PageBorders({ new PageBorders({
pageBorders: mergedOptions.pageBorders, pageBorders: pageBorders,
pageBorderTop: mergedOptions.pageBorderTop, pageBorderTop: pageBorderTop,
pageBorderRight: mergedOptions.pageBorderRight, pageBorderRight: pageBorderRight,
pageBorderBottom: mergedOptions.pageBorderBottom, pageBorderBottom: pageBorderBottom,
pageBorderLeft: mergedOptions.pageBorderLeft, pageBorderLeft: pageBorderLeft,
}), }),
); );
} }
this.options = mergedOptions; if (titlePage) {
this.root.push(new TitlePage());
}
}
private addHeaders(headers?: IHeaderFooterGroup<HeaderWrapper>): void {
if (headers) {
if (headers.default) {
this.root.push(
new HeaderReference({
headerType: HeaderReferenceType.DEFAULT,
headerId: headers.default.Header.ReferenceId,
}),
);
}
if (headers.first) {
this.root.push(
new HeaderReference({
headerType: HeaderReferenceType.FIRST,
headerId: headers.first.Header.ReferenceId,
}),
);
}
if (headers.even) {
this.root.push(
new HeaderReference({
headerType: HeaderReferenceType.EVEN,
headerId: headers.even.Header.ReferenceId,
}),
);
}
}
}
private addFooters(footers?: IHeaderFooterGroup<FooterWrapper>): void {
if (footers) {
if (footers.default) {
this.root.push(
new FooterReference({
footerType: FooterReferenceType.DEFAULT,
footerId: footers.default.Footer.ReferenceId,
}),
);
}
if (footers.first) {
this.root.push(
new FooterReference({
footerType: FooterReferenceType.FIRST,
footerId: footers.first.Footer.ReferenceId,
}),
);
}
if (footers.even) {
this.root.push(
new FooterReference({
footerType: FooterReferenceType.EVEN,
footerId: footers.even.Footer.ReferenceId,
}),
);
}
}
} }
public get Options(): SectionPropertiesOptions { public get Options(): SectionPropertiesOptions {

View File

@ -1,11 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IHeaderReferenceAttributes { export interface IHeaderReferenceAttributes {
value: string; readonly value: string;
} }
export class TitlePageAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> { export class TitlePageAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
value: "w:val", value: "w:val",
}; };
} }

View File

@ -1,6 +1,7 @@
import { expect } from "chai"; import { expect } from "chai";
import { Formatter } from "../../../../../export/formatter"; import { Formatter } from "export/formatter";
import { TitlePage } from "./title-page"; import { TitlePage } from "./title-page";
describe("PageSize", () => { describe("PageSize", () => {

View File

@ -1,33 +1,33 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IDocumentAttributesProperties { export interface IDocumentAttributesProperties {
wpc?: string; readonly wpc?: string;
mc?: string; readonly mc?: string;
o?: string; readonly o?: string;
r?: string; readonly r?: string;
m?: string; readonly m?: string;
v?: string; readonly v?: string;
wp14?: string; readonly wp14?: string;
wp?: string; readonly wp?: string;
w10?: string; readonly w10?: string;
w?: string; readonly w?: string;
w14?: string; readonly w14?: string;
w15?: string; readonly w15?: string;
wpg?: string; readonly wpg?: string;
wpi?: string; readonly wpi?: string;
wne?: string; readonly wne?: string;
wps?: string; readonly wps?: string;
Ignorable?: string; readonly Ignorable?: string;
cp?: string; readonly cp?: string;
dc?: string; readonly dc?: string;
dcterms?: string; readonly dcterms?: string;
dcmitype?: string; readonly dcmitype?: string;
xsi?: string; readonly xsi?: string;
type?: string; readonly type?: string;
} }
export class DocumentAttributes extends XmlAttributeComponent<IDocumentAttributesProperties> { export class DocumentAttributes extends XmlAttributeComponent<IDocumentAttributesProperties> {
protected xmlKeys = { protected readonly xmlKeys = {
wpc: "xmlns:wpc", wpc: "xmlns:wpc",
mc: "xmlns:mc", mc: "xmlns:mc",
o: "xmlns:o", o: "xmlns:o",

View File

@ -1,6 +1,7 @@
import { assert, expect } from "chai"; import { assert, expect } from "chai";
import { Formatter } from "../../export/formatter"; import { Formatter } from "export/formatter";
import { Paragraph } from "../paragraph"; import { Paragraph } from "../paragraph";
import { Table } from "../table"; import { Table } from "../table";
import { Document } from "./document"; import { Document } from "./document";

View File

@ -2,16 +2,16 @@ import { XmlAttributeComponent } from "file/xml-components";
import { IDistance } from "../drawing"; import { IDistance } from "../drawing";
export interface IAnchorAttributes extends IDistance { export interface IAnchorAttributes extends IDistance {
allowOverlap?: "0" | "1"; readonly allowOverlap?: "0" | "1";
behindDoc?: "0" | "1"; readonly behindDoc?: "0" | "1";
layoutInCell?: "0" | "1"; readonly layoutInCell?: "0" | "1";
locked?: "0" | "1"; readonly locked?: "0" | "1";
relativeHeight?: number; readonly relativeHeight?: number;
simplePos?: "0" | "1"; readonly simplePos?: "0" | "1";
} }
export class AnchorAttributes extends XmlAttributeComponent<IAnchorAttributes> { export class AnchorAttributes extends XmlAttributeComponent<IAnchorAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
distT: "distT", distT: "distT",
distB: "distB", distB: "distB",
distL: "distL", distL: "distL",

View File

@ -1,8 +1,10 @@
import { assert } from "chai"; import { assert } from "chai";
import { Utility } from "../../../tests/utility"; import { Utility } from "tests/utility";
import { IDrawingOptions, TextWrapStyle } from ".././";
import { Anchor } from "./"; import { IDrawingOptions } from "../drawing";
import { TextWrapStyle } from "../text-wrap";
import { Anchor } from "./anchor";
function createDrawing(drawingOptions: IDrawingOptions): Anchor { function createDrawing(drawingOptions: IDrawingOptions): Anchor {
return new Anchor( return new Anchor(
@ -101,7 +103,7 @@ describe("Anchor", () => {
assert.equal(graphic.rootKey, "a:graphic"); assert.equal(graphic.rootKey, "a:graphic");
}); });
it("should create a Drawing with text wrapping", () => { it("should create a Drawing with square text wrapping", () => {
anchor = createDrawing({ anchor = createDrawing({
textWrapping: { textWrapping: {
textWrapStyle: TextWrapStyle.SQUARE, textWrapStyle: TextWrapStyle.SQUARE,
@ -114,5 +116,44 @@ describe("Anchor", () => {
const textWrap = newJson.root[6]; const textWrap = newJson.root[6];
assert.equal(textWrap.rootKey, "wp:wrapSquare"); assert.equal(textWrap.rootKey, "wp:wrapSquare");
}); });
it("should create a Drawing with no text wrapping", () => {
anchor = createDrawing({
textWrapping: {
textWrapStyle: TextWrapStyle.NONE,
},
});
const newJson = Utility.jsonify(anchor);
assert.equal(newJson.root.length, 10);
const textWrap = newJson.root[6];
assert.equal(textWrap.rootKey, "wp:wrapNone");
});
it("should create a Drawing with tight text wrapping", () => {
anchor = createDrawing({
textWrapping: {
textWrapStyle: TextWrapStyle.TIGHT,
},
});
const newJson = Utility.jsonify(anchor);
assert.equal(newJson.root.length, 10);
const textWrap = newJson.root[6];
assert.equal(textWrap.rootKey, "wp:wrapTight");
});
it("should create a Drawing with tight text wrapping", () => {
anchor = createDrawing({
textWrapping: {
textWrapStyle: TextWrapStyle.TOP_AND_BOTTOM,
},
});
const newJson = Utility.jsonify(anchor);
assert.equal(newJson.root.length, 10);
const textWrap = newJson.root[6];
assert.equal(textWrap.rootKey, "wp:wrapTopAndBottom");
});
}); });
}); });

View File

@ -1,13 +1,13 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IDocPropertiesAttributes { export interface IDocPropertiesAttributes {
id?: number; readonly id?: number;
name?: string; readonly name?: string;
descr?: string; readonly descr?: string;
} }
export class DocPropertiesAttributes extends XmlAttributeComponent<IDocPropertiesAttributes> { export class DocPropertiesAttributes extends XmlAttributeComponent<IDocPropertiesAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
id: "id", id: "id",
name: "name", name: "name",
descr: "descr", descr: "descr",

View File

@ -1,7 +1,8 @@
import { assert } from "chai"; import { assert } from "chai";
import { Utility } from "../../tests/utility"; import { Utility } from "tests/utility";
import { Drawing, IDrawingOptions, PlacementPosition } from "./";
import { Drawing, IDrawingOptions, PlacementPosition } from "./drawing";
const imageBase64Data = `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`; const imageBase64Data = `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`;

View File

@ -11,16 +11,16 @@ export enum PlacementPosition {
} }
export interface IDistance { export interface IDistance {
distT?: number; readonly distT?: number;
distB?: number; readonly distB?: number;
distL?: number; readonly distL?: number;
distR?: number; readonly distR?: number;
} }
export interface IDrawingOptions { export interface IDrawingOptions {
position?: PlacementPosition; readonly position?: PlacementPosition;
textWrapping?: ITextWrapping; readonly textWrapping?: ITextWrapping;
floating?: IFloating; readonly floating?: IFloating;
} }
const defaultDrawingOptions: IDrawingOptions = { const defaultDrawingOptions: IDrawingOptions = {

View File

@ -1,14 +1,14 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IEffectExtentAttributes { export interface IEffectExtentAttributes {
b?: number; readonly b?: number;
l?: number; readonly l?: number;
r?: number; readonly r?: number;
t?: number; readonly t?: number;
} }
export class EffectExtentAttributes extends XmlAttributeComponent<IEffectExtentAttributes> { export class EffectExtentAttributes extends XmlAttributeComponent<IEffectExtentAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
b: "b", b: "b",
l: "l", l: "l",
r: "r", r: "r",

View File

@ -1,12 +1,12 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IExtentAttributes { export interface IExtentAttributes {
cx?: number; readonly cx?: number;
cy?: number; readonly cy?: number;
} }
export class ExtentAttributes extends XmlAttributeComponent<IExtentAttributes> { export class ExtentAttributes extends XmlAttributeComponent<IExtentAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
cx: "cx", cx: "cx",
cy: "cy", cy: "cy",
}; };

View File

@ -1,4 +1,5 @@
import { XmlComponent } from "file/xml-components"; import { XmlComponent } from "file/xml-components";
import { ExtentAttributes } from "./extent-attributes"; import { ExtentAttributes } from "./extent-attributes";
export class Extent extends XmlComponent { export class Extent extends XmlComponent {

View File

@ -1,8 +1,9 @@
import { assert } from "chai"; import { assert } from "chai";
import { VerticalPositionAlign } from "."; import { Utility } from "tests/utility";
import { Utility } from "../../../tests/utility";
import { Align } from "./align"; import { Align } from "./align";
import { VerticalPositionAlign } from "./floating-position";
describe("Align", () => { describe("Align", () => {
describe("#constructor()", () => { describe("#constructor()", () => {

View File

@ -39,22 +39,22 @@ export enum VerticalPositionAlign {
} }
export interface IHorizontalPositionOptions { export interface IHorizontalPositionOptions {
relative: HorizontalPositionRelativeFrom; readonly relative: HorizontalPositionRelativeFrom;
align?: HorizontalPositionAlign; readonly align?: HorizontalPositionAlign;
offset?: number; readonly offset?: number;
} }
export interface IVerticalPositionOptions { export interface IVerticalPositionOptions {
relative: VerticalPositionRelativeFrom; readonly relative: VerticalPositionRelativeFrom;
align?: VerticalPositionAlign; readonly align?: VerticalPositionAlign;
offset?: number; readonly offset?: number;
} }
export interface IFloating { export interface IFloating {
horizontalPosition: IHorizontalPositionOptions; readonly horizontalPosition: IHorizontalPositionOptions;
verticalPosition: IVerticalPositionOptions; readonly verticalPosition: IVerticalPositionOptions;
allowOverlap?: boolean; readonly allowOverlap?: boolean;
lockAnchor?: boolean; readonly lockAnchor?: boolean;
behindDocument?: boolean; readonly behindDocument?: boolean;
layoutInCell?: boolean; readonly layoutInCell?: boolean;
} }

View File

@ -1,7 +1,8 @@
import { assert } from "chai"; import { assert } from "chai";
import { HorizontalPositionAlign, HorizontalPositionRelativeFrom } from "."; import { Utility } from "tests/utility";
import { Utility } from "../../../tests/utility";
import { HorizontalPositionAlign, HorizontalPositionRelativeFrom } from "./floating-position";
import { HorizontalPosition } from "./horizontal-position"; import { HorizontalPosition } from "./horizontal-position";
describe("HorizontalPosition", () => { describe("HorizontalPosition", () => {

View File

@ -5,11 +5,11 @@ import { HorizontalPositionRelativeFrom, IHorizontalPositionOptions } from "./fl
import { PositionOffset } from "./position-offset"; import { PositionOffset } from "./position-offset";
interface IHorizontalPositionAttributes { interface IHorizontalPositionAttributes {
relativeFrom: HorizontalPositionRelativeFrom; readonly relativeFrom: HorizontalPositionRelativeFrom;
} }
class HorizontalPositionAttributes extends XmlAttributeComponent<IHorizontalPositionAttributes> { class HorizontalPositionAttributes extends XmlAttributeComponent<IHorizontalPositionAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
relativeFrom: "relativeFrom", relativeFrom: "relativeFrom",
}; };
} }

View File

@ -1,6 +1,7 @@
import { assert } from "chai"; import { assert } from "chai";
import { Utility } from "../../../tests/utility"; import { Utility } from "tests/utility";
import { PositionOffset } from "./position-offset"; import { PositionOffset } from "./position-offset";
describe("PositionOffset", () => { describe("PositionOffset", () => {

View File

@ -1,6 +1,7 @@
import { assert } from "chai"; import { assert } from "chai";
import { Utility } from "../../../tests/utility"; import { Utility } from "tests/utility";
import { SimplePos } from "./simple-pos"; import { SimplePos } from "./simple-pos";
describe("SimplePos", () => { describe("SimplePos", () => {

View File

@ -2,12 +2,12 @@
import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
interface ISimplePosAttributes { interface ISimplePosAttributes {
x: number; readonly x: number;
y: number; readonly y: number;
} }
class SimplePosAttributes extends XmlAttributeComponent<ISimplePosAttributes> { class SimplePosAttributes extends XmlAttributeComponent<ISimplePosAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
x: "x", x: "x",
y: "y", y: "y",
}; };

View File

@ -1,7 +1,8 @@
import { assert } from "chai"; import { assert } from "chai";
import { VerticalPositionAlign, VerticalPositionRelativeFrom } from "."; import { Utility } from "tests/utility";
import { Utility } from "../../../tests/utility";
import { VerticalPositionAlign, VerticalPositionRelativeFrom } from "./floating-position";
import { VerticalPosition } from "./vertical-position"; import { VerticalPosition } from "./vertical-position";
describe("VerticalPosition", () => { describe("VerticalPosition", () => {

View File

@ -5,11 +5,11 @@ import { IVerticalPositionOptions, VerticalPositionRelativeFrom } from "./floati
import { PositionOffset } from "./position-offset"; import { PositionOffset } from "./position-offset";
interface IVerticalPositionAttributes { interface IVerticalPositionAttributes {
relativeFrom: VerticalPositionRelativeFrom; readonly relativeFrom: VerticalPositionRelativeFrom;
} }
class VerticalPositionAttributes extends XmlAttributeComponent<IVerticalPositionAttributes> { class VerticalPositionAttributes extends XmlAttributeComponent<IVerticalPositionAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
relativeFrom: "relativeFrom", relativeFrom: "relativeFrom",
}; };
} }

View File

@ -1,12 +1,12 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IGraphicFrameLockAttributes { export interface IGraphicFrameLockAttributes {
xmlns?: string; readonly xmlns?: string;
noChangeAspect?: number; readonly noChangeAspect?: number;
} }
export class GraphicFrameLockAttributes extends XmlAttributeComponent<IGraphicFrameLockAttributes> { export class GraphicFrameLockAttributes extends XmlAttributeComponent<IGraphicFrameLockAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
xmlns: "xmlns:a", xmlns: "xmlns:a",
noChangeAspect: "noChangeAspect", noChangeAspect: "noChangeAspect",
}; };

View File

@ -1,11 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IGraphicDataAttributes { export interface IGraphicDataAttributes {
uri?: string; readonly uri?: string;
} }
export class GraphicDataAttributes extends XmlAttributeComponent<IGraphicDataAttributes> { export class GraphicDataAttributes extends XmlAttributeComponent<IGraphicDataAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
uri: "uri", uri: "uri",
}; };
} }

View File

@ -1,12 +1,12 @@
import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
interface IBlipProperties { interface IBlipProperties {
embed: string; readonly embed: string;
cstate: string; readonly cstate: string;
} }
class BlipAttributes extends XmlAttributeComponent<IBlipProperties> { class BlipAttributes extends XmlAttributeComponent<IBlipProperties> {
protected xmlKeys = { protected readonly xmlKeys = {
embed: "r:embed", embed: "r:embed",
cstate: "cstate", cstate: "cstate",
}; };

View File

@ -1,12 +1,12 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IPicLocksAttributes { export interface IPicLocksAttributes {
noChangeAspect?: number; readonly noChangeAspect?: number;
noChangeArrowheads?: number; readonly noChangeArrowheads?: number;
} }
export class PicLocksAttributes extends XmlAttributeComponent<IPicLocksAttributes> { export class PicLocksAttributes extends XmlAttributeComponent<IPicLocksAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
noChangeAspect: "noChangeAspect", noChangeAspect: "noChangeAspect",
noChangeArrowheads: "noChangeArrowheads", noChangeArrowheads: "noChangeArrowheads",
}; };

View File

@ -1,13 +1,13 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface INonVisualPropertiesAttributes { export interface INonVisualPropertiesAttributes {
id?: number; readonly id?: number;
name?: string; readonly name?: string;
descr?: string; readonly descr?: string;
} }
export class NonVisualPropertiesAttributes extends XmlAttributeComponent<INonVisualPropertiesAttributes> { export class NonVisualPropertiesAttributes extends XmlAttributeComponent<INonVisualPropertiesAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
id: "id", id: "id",
name: "name", name: "name",
descr: "desc", descr: "desc",

View File

@ -1,11 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IPicAttributes { export interface IPicAttributes {
xmlns?: string; readonly xmlns?: string;
} }
export class PicAttributes extends XmlAttributeComponent<IPicAttributes> { export class PicAttributes extends XmlAttributeComponent<IPicAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
xmlns: "xmlns:pic", xmlns: "xmlns:pic",
}; };
} }

View File

@ -1,12 +1,12 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IExtentsAttributes { export interface IExtentsAttributes {
cx?: number; readonly cx?: number;
cy?: number; readonly cy?: number;
} }
export class ExtentsAttributes extends XmlAttributeComponent<IExtentsAttributes> { export class ExtentsAttributes extends XmlAttributeComponent<IExtentsAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
cx: "cx", cx: "cx",
cy: "cy", cy: "cy",
}; };

View File

@ -1,12 +1,12 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IOffsetAttributes { export interface IOffsetAttributes {
x?: number; readonly x?: number;
y?: number; readonly y?: number;
} }
export class OffsetAttributes extends XmlAttributeComponent<IOffsetAttributes> { export class OffsetAttributes extends XmlAttributeComponent<IOffsetAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
x: "x", x: "x",
y: "y", y: "y",
}; };

View File

@ -1,11 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IPresetGeometryAttributes { export interface IPresetGeometryAttributes {
prst?: string; readonly prst?: string;
} }
export class PresetGeometryAttributes extends XmlAttributeComponent<IPresetGeometryAttributes> { export class PresetGeometryAttributes extends XmlAttributeComponent<IPresetGeometryAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
prst: "prst", prst: "prst",
}; };
} }

View File

@ -1,11 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IShapePropertiesAttributes { export interface IShapePropertiesAttributes {
bwMode?: string; readonly bwMode?: string;
} }
export class ShapePropertiesAttributes extends XmlAttributeComponent<IShapePropertiesAttributes> { export class ShapePropertiesAttributes extends XmlAttributeComponent<IShapePropertiesAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
bwMode: "bwMode", bwMode: "bwMode",
}; };
} }

View File

@ -2,11 +2,11 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
import { GraphicData } from "./graphic-data"; import { GraphicData } from "./graphic-data";
interface IGraphicProperties { interface IGraphicProperties {
a: string; readonly a: string;
} }
class GraphicAttributes extends XmlAttributeComponent<IGraphicProperties> { class GraphicAttributes extends XmlAttributeComponent<IGraphicProperties> {
protected xmlKeys = { protected readonly xmlKeys = {
a: "xmlns:a", a: "xmlns:a",
}; };
} }

View File

@ -5,7 +5,7 @@ import { IDistance } from "../drawing";
export interface IInlineAttributes extends IDistance {} export interface IInlineAttributes extends IDistance {}
export class InlineAttributes extends XmlAttributeComponent<IInlineAttributes> { export class InlineAttributes extends XmlAttributeComponent<IInlineAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
distT: "distT", distT: "distT",
distB: "distB", distB: "distB",
distL: "distL", distL: "distL",

View File

@ -16,7 +16,7 @@ export enum WrapTextOption {
} }
export interface ITextWrapping { export interface ITextWrapping {
textWrapStyle: TextWrapStyle; readonly textWrapStyle: TextWrapStyle;
wrapTextOption?: WrapTextOption; readonly wrapTextOption?: WrapTextOption;
distanceFromText?: IDistance; readonly distanceFromText?: IDistance;
} }

View File

@ -4,11 +4,11 @@ import { ITextWrapping, WrapTextOption } from ".";
import { IDistance } from "../drawing"; import { IDistance } from "../drawing";
interface IWrapSquareAttributes extends IDistance { interface IWrapSquareAttributes extends IDistance {
wrapText?: WrapTextOption; readonly wrapText?: WrapTextOption;
} }
class WrapSquareAttributes extends XmlAttributeComponent<IWrapSquareAttributes> { class WrapSquareAttributes extends XmlAttributeComponent<IWrapSquareAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
distT: "distT", distT: "distT",
distB: "distB", distB: "distB",
distL: "distL", distL: "distL",

View File

@ -3,25 +3,25 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
import { IDistance } from "../drawing"; import { IDistance } from "../drawing";
interface IWrapTightAttributes { interface IWrapTightAttributes {
distT?: number; readonly distT?: number;
distB?: number; readonly distB?: number;
} }
class WrapTightAttributes extends XmlAttributeComponent<IWrapTightAttributes> { class WrapTightAttributes extends XmlAttributeComponent<IWrapTightAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
distT: "distT", distT: "distT",
distB: "distB", distB: "distB",
}; };
} }
export class WrapTight extends XmlComponent { export class WrapTight extends XmlComponent {
constructor(distanceFromText?: IDistance) { constructor(
super("wp:wrapTight"); distanceFromText: IDistance = {
distanceFromText = distanceFromText || {
distT: 0, distT: 0,
distB: 0, distB: 0,
}; },
) {
super("wp:wrapTight");
this.root.push( this.root.push(
new WrapTightAttributes({ new WrapTightAttributes({

View File

@ -3,25 +3,25 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
import { IDistance } from "../drawing"; import { IDistance } from "../drawing";
interface IWrapTopAndBottomAttributes { interface IWrapTopAndBottomAttributes {
distT?: number; readonly distT?: number;
distB?: number; readonly distB?: number;
} }
class WrapTopAndBottomAttributes extends XmlAttributeComponent<IWrapTopAndBottomAttributes> { class WrapTopAndBottomAttributes extends XmlAttributeComponent<IWrapTopAndBottomAttributes> {
protected xmlKeys = { protected readonly xmlKeys = {
distT: "distT", distT: "distT",
distB: "distB", distB: "distB",
}; };
} }
export class WrapTopAndBottom extends XmlComponent { export class WrapTopAndBottom extends XmlComponent {
constructor(distanceFromText?: IDistance) { constructor(
super("wp:wrapTopAndBottom"); distanceFromText: IDistance = {
distanceFromText = distanceFromText || {
distT: 0, distT: 0,
distB: 0, distB: 0,
}; },
) {
super("wp:wrapTopAndBottom");
this.root.push( this.root.push(
new WrapTopAndBottomAttributes({ new WrapTopAndBottomAttributes({

View File

@ -0,0 +1,11 @@
import { IDocumentTemplate } from "../import-dotx";
export interface IFileProperties {
readonly template?: IDocumentTemplate;
}
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432
/**
* @ignore
*/
export const WORKAROUND = "";

58
src/file/file.spec.ts Normal file
View File

@ -0,0 +1,58 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { File } from "./file";
describe("File", () => {
describe("#constructor", () => {
it("should create with correct headers", () => {
const doc = new File();
const header = doc.createHeader();
const footer = doc.createFooter();
doc.addSection({
headers: {
default: header,
},
footers: {
default: footer,
},
});
const tree = new Formatter().format(doc.Document.Body);
expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"][0]._attr["w:type"]).to.equal("default");
expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"][0]._attr["w:type"]).to.equal("default");
});
it("should create with correct headers", () => {
const doc = new File();
const header = doc.createHeader();
const footer = doc.createFooter();
doc.addSection({
headers: {
default: header,
first: header,
even: header,
},
footers: {
default: footer,
first: footer,
even: footer,
},
});
const tree = new Formatter().format(doc.Document.Body);
expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"][0]._attr["w:type"]).to.equal("default");
expect(tree["w:body"][1]["w:sectPr"][5]["w:headerReference"][0]._attr["w:type"]).to.equal("first");
expect(tree["w:body"][1]["w:sectPr"][6]["w:headerReference"][0]._attr["w:type"]).to.equal("even");
expect(tree["w:body"][1]["w:sectPr"][7]["w:footerReference"][0]._attr["w:type"]).to.equal("default");
expect(tree["w:body"][1]["w:sectPr"][8]["w:footerReference"][0]._attr["w:type"]).to.equal("first");
expect(tree["w:body"][1]["w:sectPr"][9]["w:footerReference"][0]._attr["w:type"]).to.equal("even");
});
});
});

View File

@ -2,10 +2,17 @@ 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";
import { Document } from "./document"; import { Document } from "./document";
import { FooterReferenceType, HeaderReference, HeaderReferenceType, SectionPropertiesOptions } from "./document/body/section-properties"; import {
import { FooterWrapper } from "./footer-wrapper"; FooterReferenceType,
HeaderReference,
HeaderReferenceType,
IHeaderFooterGroup,
SectionPropertiesOptions,
} from "./document/body/section-properties";
import { IFileProperties } from "./file-properties";
import { FooterWrapper, IDocumentFooter } from "./footer-wrapper";
import { FootNotes } from "./footnotes"; import { FootNotes } from "./footnotes";
import { HeaderWrapper } from "./header-wrapper"; import { HeaderWrapper, IDocumentHeader } from "./header-wrapper";
import { Image, Media } from "./media"; import { Image, Media } from "./media";
import { Numbering } from "./numbering"; import { Numbering } from "./numbering";
import { Bookmark, Hyperlink, Paragraph } from "./paragraph"; import { Bookmark, Hyperlink, Paragraph } from "./paragraph";
@ -18,33 +25,53 @@ import { Table } from "./table";
import { TableOfContents } from "./table-of-contents"; import { TableOfContents } from "./table-of-contents";
export class File { export class File {
// tslint:disable-next-line:readonly-keyword
private currentRelationshipId: number = 1;
private readonly document: Document; private readonly document: Document;
private styles: Styles; private readonly headers: IDocumentHeader[] = [];
private readonly footers: IDocumentFooter[] = [];
private readonly docRelationships: Relationships;
private readonly coreProperties: CoreProperties; private readonly coreProperties: CoreProperties;
private readonly numbering: Numbering; private readonly numbering: Numbering;
private readonly media: Media; private readonly media: Media;
private readonly docRelationships: Relationships;
private readonly fileRelationships: Relationships; private readonly fileRelationships: Relationships;
private readonly headerWrapper: HeaderWrapper[] = [];
private readonly footerWrapper: FooterWrapper[] = [];
private readonly footNotes: FootNotes; private readonly footNotes: FootNotes;
private readonly settings: Settings; private readonly settings: Settings;
private readonly contentTypes: ContentTypes; private readonly contentTypes: ContentTypes;
private readonly appProperties: AppProperties; private readonly appProperties: AppProperties;
// tslint:disable-next-line:readonly-keyword
private styles: Styles;
private currentRelationshipId: number = 1; constructor(
options: IPropertiesOptions = {
constructor(options?: IPropertiesOptions, sectionPropertiesOptions?: SectionPropertiesOptions) {
if (!options) {
options = {
creator: "Un-named", creator: "Un-named",
revision: "1", revision: "1",
lastModifiedBy: "Un-named", lastModifiedBy: "Un-named",
}; },
sectionPropertiesOptions: SectionPropertiesOptions = {},
fileProperties: IFileProperties = {},
) {
this.coreProperties = new CoreProperties(options);
this.numbering = new Numbering();
this.docRelationships = new Relationships();
this.media = new Media();
this.fileRelationships = new Relationships();
this.appProperties = new AppProperties();
this.footNotes = new FootNotes();
this.contentTypes = new ContentTypes();
if (fileProperties.template) {
this.currentRelationshipId = fileProperties.template.currentRelationshipId + 1;
} }
if (options.externalStyles) { // set up styles
if (fileProperties.template && options.externalStyles) {
throw Error("can not use both template and external styles");
}
if (fileProperties.template) {
this.styles = fileProperties.template.styles;
} else if (options.externalStyles) {
const stylesFactory = new ExternalStylesFactory(); const stylesFactory = new ExternalStylesFactory();
this.styles = stylesFactory.newInstance(options.externalStyles); this.styles = stylesFactory.newInstance(options.externalStyles);
} else { } else {
@ -52,62 +79,31 @@ export class File {
this.styles = stylesFactory.newInstance(); this.styles = stylesFactory.newInstance();
} }
this.coreProperties = new CoreProperties(options); this.addDefaultRelationships();
this.numbering = new Numbering();
this.docRelationships = new Relationships();
this.docRelationships.createRelationship(
this.currentRelationshipId++,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
"styles.xml",
);
this.docRelationships.createRelationship(
this.currentRelationshipId++,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering",
"numbering.xml",
);
this.contentTypes = new ContentTypes();
this.docRelationships.createRelationship( if (fileProperties.template && fileProperties.template.headers) {
this.currentRelationshipId++, for (const templateHeader of fileProperties.template.headers) {
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes", this.addHeaderToDocument(templateHeader.header, templateHeader.type);
"footnotes.xml",
);
this.media = new Media();
const header = this.createHeader();
const footer = this.createFooter();
this.fileRelationships = new Relationships();
this.fileRelationships.createRelationship(
1,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
"word/document.xml",
);
this.fileRelationships.createRelationship(
2,
"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
"docProps/core.xml",
);
this.fileRelationships.createRelationship(
3,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
"docProps/app.xml",
);
this.appProperties = new AppProperties();
this.footNotes = new FootNotes();
if (!sectionPropertiesOptions) {
sectionPropertiesOptions = {
footerType: FooterReferenceType.DEFAULT,
headerType: HeaderReferenceType.DEFAULT,
headerId: header.Header.ReferenceId,
footerId: footer.Footer.ReferenceId,
};
} else {
sectionPropertiesOptions.headerId = header.Header.ReferenceId;
sectionPropertiesOptions.footerId = footer.Footer.ReferenceId;
} }
this.document = new Document(sectionPropertiesOptions); } else {
this.createHeader();
}
if (fileProperties.template && fileProperties.template.footers) {
for (const templateFooter of fileProperties.template.footers) {
this.addFooterToDocument(templateFooter.footer, templateFooter.type);
}
} else {
this.createFooter();
}
const newSectionPropertiesOptions = {
...sectionPropertiesOptions,
headers: this.groupHeaders(this.headers, sectionPropertiesOptions.headers),
footers: this.groupFooters(this.footers, sectionPropertiesOptions.footers),
};
this.document = new Document(newSectionPropertiesOptions);
this.settings = new Settings(); this.settings = new Settings();
} }
@ -115,8 +111,9 @@ export class File {
this.document.addTableOfContents(toc); this.document.addTableOfContents(toc);
} }
public addParagraph(paragraph: Paragraph): void { public addParagraph(paragraph: Paragraph): File {
this.document.addParagraph(paragraph); this.document.addParagraph(paragraph);
return this;
} }
public createParagraph(text?: string): Paragraph { public createParagraph(text?: string): Paragraph {
@ -144,8 +141,8 @@ export class File {
} }
public createHyperlink(link: string, text?: string): Hyperlink { public createHyperlink(link: string, text?: string): Hyperlink {
text = text === undefined ? link : text; const newText = text === undefined ? link : text;
const hyperlink = new Hyperlink(text, this.docRelationships.RelationshipCount); const hyperlink = new Hyperlink(newText, this.docRelationships.RelationshipCount);
this.docRelationships.createRelationship( this.docRelationships.createRelationship(
hyperlink.linkId, hyperlink.linkId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
@ -156,16 +153,16 @@ export class File {
} }
public createInternalHyperLink(anchor: string, text?: string): Hyperlink { public createInternalHyperLink(anchor: string, text?: string): Hyperlink {
text = text === undefined ? anchor : text; const newText = text === undefined ? anchor : text;
const hyperlink = new Hyperlink(text, this.docRelationships.RelationshipCount, anchor); const hyperlink = new Hyperlink(newText, this.docRelationships.RelationshipCount, anchor);
// NOTE: unlike File#createHyperlink(), since the link is to an internal bookmark // NOTE: unlike File#createHyperlink(), since the link is to an internal bookmark
// we don't need to create a new relationship. // we don't need to create a new relationship.
return hyperlink; return hyperlink;
} }
public createBookmark(name: string, text?: string): Bookmark { public createBookmark(name: string, text?: string): Bookmark {
text = text === undefined ? name : text; const newText = text === undefined ? name : text;
const bookmark = new Bookmark(name, text, this.docRelationships.RelationshipCount); const bookmark = new Bookmark(name, newText, this.docRelationships.RelationshipCount);
return bookmark; return bookmark;
} }
@ -179,25 +176,13 @@ export class File {
public createHeader(): HeaderWrapper { public createHeader(): HeaderWrapper {
const header = new HeaderWrapper(this.media, this.currentRelationshipId++); const header = new HeaderWrapper(this.media, this.currentRelationshipId++);
this.headerWrapper.push(header); this.addHeaderToDocument(header);
this.docRelationships.createRelationship(
header.Header.ReferenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
`header${this.headerWrapper.length}.xml`,
);
this.contentTypes.addHeader(this.headerWrapper.length);
return header; return header;
} }
public createFooter(): FooterWrapper { public createFooter(): FooterWrapper {
const footer = new FooterWrapper(this.media, this.currentRelationshipId++); const footer = new FooterWrapper(this.media, this.currentRelationshipId++);
this.footerWrapper.push(footer); this.addFooterToDocument(footer);
this.docRelationships.createRelationship(
footer.Footer.ReferenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
`footer${this.footerWrapper.length}.xml`,
);
this.contentTypes.addFooter(this.footerWrapper.length);
return footer; return footer;
} }
@ -214,6 +199,152 @@ export class File {
return headerWrapper; return headerWrapper;
} }
public getFooterByReferenceNumber(refId: number): FooterWrapper {
const entry = this.footers.map((item) => item.footer).find((h) => h.Footer.ReferenceId === refId);
if (entry) {
return entry;
}
throw new Error(`There is no footer with given reference id ${refId}`);
}
public getHeaderByReferenceNumber(refId: number): HeaderWrapper {
const entry = this.headers.map((item) => item.header).find((h) => h.Header.ReferenceId === refId);
if (entry) {
return entry;
}
throw new Error(`There is no header with given reference id ${refId}`);
}
public verifyUpdateFields(): void {
if (this.document.getTablesOfContents().length) {
this.settings.addUpdateFields();
}
}
private addHeaderToDocument(header: HeaderWrapper, type: HeaderReferenceType = HeaderReferenceType.DEFAULT): void {
this.headers.push({ header, type });
this.docRelationships.createRelationship(
header.Header.ReferenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
`header${this.headers.length}.xml`,
);
this.contentTypes.addHeader(this.headers.length);
}
private addFooterToDocument(footer: FooterWrapper, type: FooterReferenceType = FooterReferenceType.DEFAULT): void {
this.footers.push({ footer, type });
this.docRelationships.createRelationship(
footer.Footer.ReferenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
`footer${this.footers.length}.xml`,
);
this.contentTypes.addFooter(this.footers.length);
}
private addDefaultRelationships(): void {
this.fileRelationships.createRelationship(
1,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
"word/document.xml",
);
this.fileRelationships.createRelationship(
2,
"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
"docProps/core.xml",
);
this.fileRelationships.createRelationship(
3,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
"docProps/app.xml",
);
this.docRelationships.createRelationship(
this.currentRelationshipId++,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
"styles.xml",
);
this.docRelationships.createRelationship(
this.currentRelationshipId++,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering",
"numbering.xml",
);
this.docRelationships.createRelationship(
this.currentRelationshipId++,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
"footnotes.xml",
);
}
private groupHeaders(headers: IDocumentHeader[], group: IHeaderFooterGroup<HeaderWrapper> = {}): IHeaderFooterGroup<HeaderWrapper> {
let newGroup = group;
for (const header of headers) {
switch (header.type) {
case HeaderReferenceType.DEFAULT:
newGroup = {
...newGroup,
default: header.header,
};
break;
case HeaderReferenceType.FIRST:
newGroup = {
...newGroup,
first: header.header,
};
break;
case HeaderReferenceType.EVEN:
newGroup = {
...newGroup,
even: header.header,
};
break;
default:
newGroup = {
...newGroup,
default: header.header,
};
break;
}
}
return newGroup;
}
private groupFooters(footers: IDocumentFooter[], group: IHeaderFooterGroup<FooterWrapper> = {}): IHeaderFooterGroup<FooterWrapper> {
let newGroup = group;
for (const footer of footers) {
switch (footer.type) {
case FooterReferenceType.DEFAULT:
newGroup = {
...newGroup,
default: footer.footer,
};
break;
case FooterReferenceType.FIRST:
newGroup = {
...newGroup,
first: footer.footer,
};
break;
case FooterReferenceType.EVEN:
newGroup = {
...newGroup,
even: footer.footer,
};
break;
default:
newGroup = {
...newGroup,
default: footer.footer,
};
break;
}
}
return newGroup;
}
public get Document(): Document { public get Document(): Document {
return this.document; return this.document;
} }
@ -247,35 +378,19 @@ export class File {
} }
public get Header(): HeaderWrapper { public get Header(): HeaderWrapper {
return this.headerWrapper[0]; return this.headers[0].header;
} }
public get Headers(): HeaderWrapper[] { public get Headers(): HeaderWrapper[] {
return this.headerWrapper; return this.headers.map((item) => item.header);
}
public HeaderByRefNumber(refId: number): HeaderWrapper {
const entry = this.headerWrapper.find((h) => h.Header.ReferenceId === refId);
if (entry) {
return entry;
}
throw new Error(`There is no header with given reference id ${refId}`);
} }
public get Footer(): FooterWrapper { public get Footer(): FooterWrapper {
return this.footerWrapper[0]; return this.footers[0].footer;
} }
public get Footers(): FooterWrapper[] { public get Footers(): FooterWrapper[] {
return this.footerWrapper; return this.footers.map((item) => item.footer);
}
public FooterByRefNumber(refId: number): FooterWrapper {
const entry = this.footerWrapper.find((h) => h.Footer.ReferenceId === refId);
if (entry) {
return entry;
}
throw new Error(`There is no footer with given reference id ${refId}`);
} }
public get ContentTypes(): ContentTypes { public get ContentTypes(): ContentTypes {
@ -293,10 +408,4 @@ export class File {
public get Settings(): Settings { public get Settings(): Settings {
return this.settings; return this.settings;
} }
public verifyUpdateFields(): void {
if (this.document.getTablesOfContents().length) {
this.settings.addUpdateFields();
}
}
} }

View File

@ -1,16 +1,23 @@
import { XmlComponent } from "file/xml-components"; import { XmlComponent } from "file/xml-components";
import { FooterReferenceType } from "./document";
import { Footer } from "./footer/footer"; import { Footer } from "./footer/footer";
import { Image, Media } from "./media"; import { Image, IMediaData, Media } from "./media";
import { ImageParagraph, Paragraph } from "./paragraph"; import { ImageParagraph, Paragraph } from "./paragraph";
import { Relationships } from "./relationships"; import { Relationships } from "./relationships";
import { Table } from "./table"; import { Table } from "./table";
export interface IDocumentFooter {
readonly footer: FooterWrapper;
readonly type: FooterReferenceType;
}
export class FooterWrapper { export class FooterWrapper {
private readonly footer: Footer; private readonly footer: Footer;
private readonly relationships: Relationships; private readonly relationships: Relationships;
constructor(private readonly media: Media, referenceId: number) { constructor(private readonly media: Media, referenceId: number, initContent?: XmlComponent) {
this.footer = new Footer(referenceId); this.footer = new Footer(referenceId, initContent);
this.relationships = new Relationships(); this.relationships = new Relationships();
} }
@ -32,17 +39,33 @@ export class FooterWrapper {
return this.footer.createTable(rows, cols); return this.footer.createTable(rows, cols);
} }
public addChildElement(childElement: XmlComponent | string): void { public addChildElement(childElement: XmlComponent): void {
this.footer.addChildElement(childElement); this.footer.addChildElement(childElement);
} }
public createImage(image: Buffer, width?: number, height?: number): void { public addImageRelationship(image: Buffer, refId: number, width?: number, height?: number): IMediaData {
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height); const mediaData = this.media.addMedia(image, refId, width, height);
this.relationships.createRelationship( this.relationships.createRelationship(
mediaData.referenceId, mediaData.referenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
`media/${mediaData.fileName}`, `media/${mediaData.fileName}`,
); );
return mediaData;
}
public addHyperlinkRelationship(target: string, refId: number, targetMode?: "External" | undefined): void {
this.relationships.createRelationship(
refId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
target,
targetMode,
);
}
public createImage(image: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): void {
// TODO
// tslint:disable-next-line:no-any
const mediaData = this.addImageRelationship(image as any, this.relationships.RelationshipCount, width, height);
this.addImage(new Image(new ImageParagraph(mediaData))); this.addImage(new Image(new ImageParagraph(mediaData)));
} }
@ -58,4 +81,8 @@ export class FooterWrapper {
public get Relationships(): Relationships { public get Relationships(): Relationships {
return this.relationships; return this.relationships;
} }
public get Media(): Media {
return this.media;
}
} }

View File

@ -1,32 +1,32 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IFooterAttributesProperties { export interface IFooterAttributesProperties {
wpc?: string; readonly wpc?: string;
mc?: string; readonly mc?: string;
o?: string; readonly o?: string;
r?: string; readonly r?: string;
m?: string; readonly m?: string;
v?: string; readonly v?: string;
wp14?: string; readonly wp14?: string;
wp?: string; readonly wp?: string;
w10?: string; readonly w10?: string;
w?: string; readonly w?: string;
w14?: string; readonly w14?: string;
w15?: string; readonly w15?: string;
wpg?: string; readonly wpg?: string;
wpi?: string; readonly wpi?: string;
wne?: string; readonly wne?: string;
wps?: string; readonly wps?: string;
cp?: string; readonly cp?: string;
dc?: string; readonly dc?: string;
dcterms?: string; readonly dcterms?: string;
dcmitype?: string; readonly dcmitype?: string;
xsi?: string; readonly xsi?: string;
type?: string; readonly type?: string;
} }
export class FooterAttributes extends XmlAttributeComponent<IFooterAttributesProperties> { export class FooterAttributes extends XmlAttributeComponent<IFooterAttributesProperties> {
protected xmlKeys = { protected readonly xmlKeys = {
wpc: "xmlns:wpc", wpc: "xmlns:wpc",
mc: "xmlns:mc", mc: "xmlns:mc",
o: "xmlns:o", o: "xmlns:o",

View File

@ -1,14 +1,14 @@
// http://officeopenxml.com/WPfooters.php // http://officeopenxml.com/WPfooters.php
import { XmlComponent } from "file/xml-components"; import { InitializableXmlComponent, XmlComponent } from "file/xml-components";
import { Paragraph } from "../paragraph"; import { Paragraph } from "../paragraph";
import { Table } from "../table"; import { Table } from "../table";
import { FooterAttributes } from "./footer-attributes"; import { FooterAttributes } from "./footer-attributes";
export class Footer extends XmlComponent { export class Footer extends InitializableXmlComponent {
private readonly refId: number; private readonly refId: number;
constructor(referenceNumber: number) { constructor(referenceNumber: number, initContent?: XmlComponent) {
super("w:ftr"); super("w:ftr", initContent);
this.refId = referenceNumber; this.refId = referenceNumber;
this.root.push( this.root.push(
new FooterAttributes({ new FooterAttributes({

View File

@ -1,12 +1,12 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IFootnoteAttributesProperties { export interface IFootnoteAttributesProperties {
type?: string; readonly type?: string;
id: number; readonly id: number;
} }
export class FootnoteAttributes extends XmlAttributeComponent<IFootnoteAttributesProperties> { export class FootnoteAttributes extends XmlAttributeComponent<IFootnoteAttributesProperties> {
protected xmlKeys = { protected readonly xmlKeys = {
type: "w:type", type: "w:type",
id: "w:id", id: "w:id",
}; };

View File

@ -1,5 +1,7 @@
import { expect } from "chai"; import { expect } from "chai";
import { Formatter } from "../../../export/formatter";
import { Formatter } from "export/formatter";
import { Footnote, FootnoteType } from "./footnote"; import { Footnote, FootnoteType } from "./footnote";
describe("Footnote", () => { describe("Footnote", () => {

View File

@ -1,5 +1,6 @@
import { Paragraph } from "file/paragraph";
import { XmlComponent } from "file/xml-components"; import { XmlComponent } from "file/xml-components";
import { Paragraph } from "../../paragraph";
import { FootnoteAttributes } from "./footnote-attributes"; import { FootnoteAttributes } from "./footnote-attributes";
import { FootnoteRefRun } from "./run/footnote-ref-run"; import { FootnoteRefRun } from "./run/footnote-ref-run";

View File

@ -3,11 +3,11 @@ import { Style } from "file/paragraph/run/style";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
export interface IFootNoteReferenceRunAttributesProperties { export interface IFootNoteReferenceRunAttributesProperties {
id: number; readonly id: number;
} }
export class FootNoteReferenceRunAttributes extends XmlAttributeComponent<IFootNoteReferenceRunAttributesProperties> { export class FootNoteReferenceRunAttributes extends XmlAttributeComponent<IFootNoteReferenceRunAttributesProperties> {
protected xmlKeys = { protected readonly xmlKeys = {
id: "w:id", id: "w:id",
}; };
} }

View File

@ -1,27 +1,27 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IFootnotesAttributesProperties { export interface IFootnotesAttributesProperties {
wpc?: string; readonly wpc?: string;
mc?: string; readonly mc?: string;
o?: string; readonly o?: string;
r?: string; readonly r?: string;
m?: string; readonly m?: string;
v?: string; readonly v?: string;
wp14?: string; readonly wp14?: string;
wp?: string; readonly wp?: string;
w10?: string; readonly w10?: string;
w?: string; readonly w?: string;
w14?: string; readonly w14?: string;
w15?: string; readonly w15?: string;
wpg?: string; readonly wpg?: string;
wpi?: string; readonly wpi?: string;
wne?: string; readonly wne?: string;
wps?: string; readonly wps?: string;
Ignorable?: string; readonly Ignorable?: string;
} }
export class FootnotesAttributes extends XmlAttributeComponent<IFootnotesAttributesProperties> { export class FootnotesAttributes extends XmlAttributeComponent<IFootnotesAttributesProperties> {
protected xmlKeys = { protected readonly xmlKeys = {
wpc: "xmlns:wpc", wpc: "xmlns:wpc",
mc: "xmlns:mc", mc: "xmlns:mc",
o: "xmlns:o", o: "xmlns:o",

View File

@ -6,12 +6,13 @@ import { SeperatorRun } from "./footnote/run/seperator-run";
import { FootnotesAttributes } from "./footnotes-attributes"; import { FootnotesAttributes } from "./footnotes-attributes";
export class FootNotes extends XmlComponent { export class FootNotes extends XmlComponent {
private counter: number; // tslint:disable-next-line:readonly-keyword
private currentId: number;
constructor() { constructor() {
super("w:footnotes"); super("w:footnotes");
this.counter = 1; this.currentId = 1;
this.root.push( this.root.push(
new FootnotesAttributes({ new FootnotesAttributes({
@ -61,10 +62,10 @@ export class FootNotes extends XmlComponent {
} }
public createFootNote(paragraph: Paragraph): void { public createFootNote(paragraph: Paragraph): void {
const footnote = new Footnote(this.counter); const footnote = new Footnote(this.currentId);
footnote.addParagraph(paragraph); footnote.addParagraph(paragraph);
this.root.push(footnote); this.root.push(footnote);
this.counter++; this.currentId++;
} }
} }

View File

@ -0,0 +1,29 @@
import { expect } from "chai";
import * as sinon from "sinon";
import { HeaderWrapper } from "./header-wrapper";
import { Media } from "./media";
import { Paragraph } from "./paragraph";
import { Table } from "./table";
describe("HeaderWrapper", () => {
describe("#addParagraph", () => {
it("should call the underlying header's addParagraph", () => {
const file = new HeaderWrapper(new Media(), 1);
const spy = sinon.spy(file.Header, "addParagraph");
file.addParagraph(new Paragraph());
expect(spy.called).to.equal(true);
});
});
describe("#addTable", () => {
it("should call the underlying header's addParagraph", () => {
const file = new HeaderWrapper(new Media(), 1);
const spy = sinon.spy(file.Header, "addTable");
file.addTable(new Table(1, 1));
expect(spy.called).to.equal(true);
});
});
});

View File

@ -1,16 +1,23 @@
import { XmlComponent } from "file/xml-components"; import { XmlComponent } from "file/xml-components";
import { HeaderReferenceType } from "./document";
import { Header } from "./header/header"; import { Header } from "./header/header";
import { Image, Media } from "./media"; import { Image, IMediaData, Media } from "./media";
import { ImageParagraph, Paragraph } from "./paragraph"; import { ImageParagraph, Paragraph } from "./paragraph";
import { Relationships } from "./relationships"; import { Relationships } from "./relationships";
import { Table } from "./table"; import { Table } from "./table";
export interface IDocumentHeader {
readonly header: HeaderWrapper;
readonly type: HeaderReferenceType;
}
export class HeaderWrapper { export class HeaderWrapper {
private readonly header: Header; private readonly header: Header;
private readonly relationships: Relationships; private readonly relationships: Relationships;
constructor(private readonly media: Media, referenceId: number) { constructor(private readonly media: Media, referenceId: number, initContent?: XmlComponent) {
this.header = new Header(referenceId); this.header = new Header(referenceId, initContent);
this.relationships = new Relationships(); this.relationships = new Relationships();
} }
@ -36,13 +43,29 @@ export class HeaderWrapper {
this.header.addChildElement(childElement); this.header.addChildElement(childElement);
} }
public createImage(image: Buffer, width?: number, height?: number): void { public addImageRelationship(image: Buffer, refId: number, width?: number, height?: number): IMediaData {
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height); const mediaData = this.media.addMedia(image, refId, width, height);
this.relationships.createRelationship( this.relationships.createRelationship(
mediaData.referenceId, mediaData.referenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
`media/${mediaData.fileName}`, `media/${mediaData.fileName}`,
); );
return mediaData;
}
public addHyperlinkRelationship(target: string, refId: number, targetMode?: "External" | undefined): void {
this.relationships.createRelationship(
refId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
target,
targetMode,
);
}
public createImage(image: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): void {
// TODO
// tslint:disable-next-line:no-any
const mediaData = this.addImageRelationship(image as any, this.relationships.RelationshipCount, width, height);
this.addImage(new Image(new ImageParagraph(mediaData))); this.addImage(new Image(new ImageParagraph(mediaData)));
} }
@ -58,4 +81,8 @@ export class HeaderWrapper {
public get Relationships(): Relationships { public get Relationships(): Relationships {
return this.relationships; return this.relationships;
} }
public get Media(): Media {
return this.media;
}
} }

View File

@ -1,32 +1,43 @@
import { XmlAttributeComponent } from "file/xml-components"; import { XmlAttributeComponent } from "file/xml-components";
export interface IHeaderAttributesProperties { export interface IHeaderAttributesProperties {
wpc?: string; readonly wpc?: string;
mc?: string; readonly mc?: string;
o?: string; readonly o?: string;
r?: string; readonly r?: string;
m?: string; readonly m?: string;
v?: string; readonly v?: string;
wp14?: string; readonly wp14?: string;
wp?: string; readonly wp?: string;
w10?: string; readonly w10?: string;
w?: string; readonly w?: string;
w14?: string; readonly w14?: string;
w15?: string; readonly w15?: string;
wpg?: string; readonly wpg?: string;
wpi?: string; readonly wpi?: string;
wne?: string; readonly wne?: string;
wps?: string; readonly wps?: string;
cp?: string; readonly cp?: string;
dc?: string; readonly dc?: string;
dcterms?: string; readonly dcterms?: string;
dcmitype?: string; readonly dcmitype?: string;
xsi?: string; readonly xsi?: string;
type?: string; readonly type?: string;
readonly cx?: string;
readonly cx1?: string;
readonly cx2?: string;
readonly cx3?: string;
readonly cx4?: string;
readonly cx5?: string;
readonly cx6?: string;
readonly cx7?: string;
readonly cx8?: string;
readonly w16cid: string;
readonly w16se: string;
} }
export class HeaderAttributes extends XmlAttributeComponent<IHeaderAttributesProperties> { export class HeaderAttributes extends XmlAttributeComponent<IHeaderAttributesProperties> {
protected xmlKeys = { protected readonly xmlKeys = {
wpc: "xmlns:wpc", wpc: "xmlns:wpc",
mc: "xmlns:mc", mc: "xmlns:mc",
o: "xmlns:o", o: "xmlns:o",
@ -49,5 +60,16 @@ export class HeaderAttributes extends XmlAttributeComponent<IHeaderAttributesPro
dcmitype: "xmlns:dcmitype", dcmitype: "xmlns:dcmitype",
xsi: "xmlns:xsi", xsi: "xmlns:xsi",
type: "xsi:type", type: "xsi:type",
cx: "xmlns:cx",
cx1: "xmlns:cx1",
cx2: "xmlns:cx2",
cx3: "xmlns:cx3",
cx4: "xmlns:cx4",
cx5: "xmlns:cx5",
cx6: "xmlns:cx6",
cx7: "xmlns:cx7",
cx8: "xmlns:cx8",
w16cid: "xmlns:w16cid",
w16se: "xmlns:w16se",
}; };
} }

View File

@ -1,16 +1,17 @@
// http://officeopenxml.com/WPheaders.php // http://officeopenxml.com/WPheaders.php
import { XmlComponent } from "file/xml-components"; import { InitializableXmlComponent, XmlComponent } from "file/xml-components";
import { Paragraph } from "../paragraph"; import { Paragraph } from "../paragraph";
import { Table } from "../table"; import { Table } from "../table";
import { HeaderAttributes } from "./header-attributes"; import { HeaderAttributes } from "./header-attributes";
export class Header extends XmlComponent { export class Header extends InitializableXmlComponent {
private readonly refId: number; private readonly refId: number;
constructor(referenceNumber: number) { constructor(referenceNumber: number, initContent?: XmlComponent) {
super("w:hdr"); super("w:hdr", initContent);
this.refId = referenceNumber; this.refId = referenceNumber;
this.root.push( this.root.push(
new HeaderAttributes({ new HeaderAttributes({
wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas", wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
@ -29,6 +30,17 @@ export class Header extends XmlComponent {
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk", wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
wne: "http://schemas.microsoft.com/office/word/2006/wordml", wne: "http://schemas.microsoft.com/office/word/2006/wordml",
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
cx: "http://schemas.microsoft.com/office/drawing/2014/chartex",
cx1: "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex",
cx2: "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex",
cx3: "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex",
cx4: "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex",
cx5: "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex",
cx6: "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex",
cx7: "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex",
cx8: "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex",
w16cid: "http://schemas.microsoft.com/office/word/2016/wordml/cid",
w16se: "http://schemas.microsoft.com/office/word/2015/wordml/symex",
}), }),
); );
} }

View File

@ -1,6 +1,7 @@
export * from "./paragraph"; export * from "./paragraph";
export * from "./table"; export * from "./table";
export * from "./file"; export * from "./file";
export * from "./file-properties";
export * from "./numbering"; export * from "./numbering";
export * from "./media"; export * from "./media";
export * from "./drawing"; export * from "./drawing";

View File

@ -1,20 +1,20 @@
export interface IMediaDataDimensions { export interface IMediaDataDimensions {
pixels: { readonly pixels: {
x: number; readonly x: number;
y: number; readonly y: number;
}; };
emus: { readonly emus: {
x: number; readonly x: number;
y: number; readonly y: number;
}; };
} }
export interface IMediaData { export interface IMediaData {
referenceId: number; readonly referenceId: number;
stream: Buffer | Uint8Array | ArrayBuffer; readonly stream: Buffer | Uint8Array | ArrayBuffer;
path?: string; readonly path?: string;
fileName: string; readonly fileName: string;
dimensions: IMediaDataDimensions; readonly dimensions: IMediaDataDimensions;
} }
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432 // Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432

View File

@ -0,0 +1,140 @@
// tslint:disable:object-literal-key-quotes
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { File } from "../file";
import { Media } from "./media";
describe("Media", () => {
describe("#addImage", () => {
it("should add image", () => {
const file = new File();
const image = Media.addImage(file, "");
let tree = new Formatter().format(image.Paragraph);
expect(tree["w:p"]).to.be.an.instanceof(Array);
tree = new Formatter().format(image.Run);
expect(tree["w:r"]).to.be.an.instanceof(Array);
});
it("should ensure the correct relationship id is used when adding image", () => {
const file = new File();
const image1 = Media.addImage(file, "test");
const tree = new Formatter().format(image1.Paragraph);
const inlineElements = tree["w:p"][1]["w:r"][1]["w:drawing"][0]["wp:inline"];
const graphicData = inlineElements.find((x) => x["a:graphic"]);
expect(graphicData["a:graphic"][1]["a:graphicData"][1]["pic:pic"][2]["pic:blipFill"][0]["a:blip"][0]).to.deep.equal({
_attr: {
"r:embed": `rId${file.DocumentRelationships.RelationshipCount}`,
cstate: "none",
},
});
const image2 = Media.addImage(file, "test");
const tree2 = new Formatter().format(image2.Paragraph);
const inlineElements2 = tree2["w:p"][1]["w:r"][1]["w:drawing"][0]["wp:inline"];
const graphicData2 = inlineElements2.find((x) => x["a:graphic"]);
expect(graphicData2["a:graphic"][1]["a:graphicData"][1]["pic:pic"][2]["pic:blipFill"][0]["a:blip"][0]).to.deep.equal({
_attr: {
"r:embed": `rId${file.DocumentRelationships.RelationshipCount}`,
cstate: "none",
},
});
});
});
describe("#addMedia", () => {
it("should add media", () => {
// tslint:disable-next-line:no-any
(Media as any).generateId = () => "test";
const image = new Media().addMedia("", 1);
expect(image.fileName).to.equal("test.png");
expect(image.referenceId).to.equal(1);
expect(image.dimensions).to.deep.equal({
pixels: {
x: 100,
y: 100,
},
emus: {
x: 952500,
y: 952500,
},
});
});
it("should return UInt8Array if atob is present", () => {
// tslint:disable-next-line
((process as any).atob as any) = () => "atob result";
// tslint:disable-next-line:no-any
(Media as any).generateId = () => "test";
const image = new Media().addMedia("", 1);
expect(image.stream).to.be.an.instanceof(Uint8Array);
});
});
describe("#getMedia", () => {
it("should get media", () => {
// tslint:disable-next-line:no-any
(Media as any).generateId = () => "test";
const media = new Media();
media.addMedia("", 1);
const image = media.getMedia("test.png");
expect(image.fileName).to.equal("test.png");
expect(image.referenceId).to.equal(1);
expect(image.dimensions).to.deep.equal({
pixels: {
x: 100,
y: 100,
},
emus: {
x: 952500,
y: 952500,
},
});
});
it("Get media", () => {
const media = new Media();
expect(() => media.getMedia("test.png")).to.throw();
});
});
describe("#Array", () => {
it("Get images as array", () => {
// tslint:disable-next-line:no-any
(Media as any).generateId = () => "test";
const media = new Media();
media.addMedia("", 1);
const array = media.Array;
expect(array).to.be.an.instanceof(Array);
expect(array.length).to.equal(1);
const image = array[0];
expect(image.fileName).to.equal("test.png");
expect(image.referenceId).to.equal(1);
expect(image.dimensions).to.deep.equal({
pixels: {
x: 100,
y: 100,
},
emus: {
x: 952500,
y: 952500,
},
});
});
});
});

View File

@ -5,6 +5,7 @@ import { IMediaData } from "./data";
import { Image } from "./image"; import { Image } from "./image";
interface IHackedFile { interface IHackedFile {
// tslint:disable-next-line:readonly-keyword
currentRelationshipId: number; currentRelationshipId: number;
} }
@ -78,17 +79,15 @@ export class Media {
private createMedia( private createMedia(
key: string, key: string,
relationshipsCount: number, relationshipsCount: number,
dimensions: { width: number; height: number }, dimensions: { readonly width: number; readonly height: number },
data: Buffer | string | Uint8Array | ArrayBuffer, data: Buffer | string | Uint8Array | ArrayBuffer,
filePath?: string, filePath?: string,
): IMediaData { ): IMediaData {
if (typeof data === "string") { const newData = typeof data === "string" ? this.convertDataURIToBinary(data) : data;
data = this.convertDataURIToBinary(data);
}
const imageData = { const imageData: IMediaData = {
referenceId: this.map.size + relationshipsCount + 1, referenceId: relationshipsCount,
stream: data, stream: newData,
path: filePath, path: filePath,
fileName: key, fileName: key,
dimensions: { dimensions: {

Some files were not shown because too many files have changed in this diff Show More