Compare commits
57 Commits
Author | SHA1 | Date | |
---|---|---|---|
5ae02c3342 | |||
258adba94c | |||
190208d5df | |||
32cda4dfb3 | |||
b2c3dd2f7b | |||
58eca3ff5b | |||
d5c04f9042 | |||
67ea7c95de | |||
e57fd8fc57 | |||
411c0dadb5 | |||
ee81f3c502 | |||
8263b93c36 | |||
be709d082c | |||
70c4e89a65 | |||
8f632d4ecd | |||
6784dc1f3d | |||
fd63a30298 | |||
b0a29e26c9 | |||
8826fb010d | |||
97101adb10 | |||
2ec171d4a8 | |||
8876bb1fea | |||
96ca9d9c23 | |||
74a65f02fa | |||
339c017940 | |||
969b52ae05 | |||
eb8f0f4033 | |||
d7229eb049 | |||
644819ed81 | |||
96fd61d3e4 | |||
b96cfe7b19 | |||
d0e7c97a88 | |||
0ede54cfdc | |||
5be1163549 | |||
580f6eb633 | |||
321be35918 | |||
45a18742d7 | |||
7e81da404a | |||
6c2abb4abc | |||
e8b0dbf93b | |||
e59c255d85 | |||
17b28cb724 | |||
410152441b | |||
dfff4b96bd | |||
72cb75a486 | |||
53fe1dd988 | |||
043219f005 | |||
0453f28951 | |||
94716e081b | |||
30f826fd3d | |||
99b7a03b8a | |||
b1c8b2beb8 | |||
a706455a7c | |||
8c388a95c4 | |||
9a41d78ecb | |||
6fc4ad782a | |||
16b9057ac6 |
@ -38,3 +38,6 @@ build-tests
|
|||||||
|
|
||||||
# vscode
|
# vscode
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
|
# docs
|
||||||
|
docs
|
@ -1,10 +1,15 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "6"
|
- "stable"
|
||||||
- "node"
|
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
script:
|
script:
|
||||||
- npm test
|
- npm test
|
||||||
after_failure:
|
after_failure:
|
||||||
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
|
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
|
||||||
|
after_success:
|
||||||
|
- bash ./deploy-docs.sh
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- ENCRYPTION_LABEL: "ad385fa3b525"
|
||||||
|
|
||||||
|
@ -26,12 +26,14 @@ $ npm install --save docx
|
|||||||
$ npm run demo
|
$ npm run demo
|
||||||
```
|
```
|
||||||
|
|
||||||
will run the demo app in the `demo` folder, which creates a file called "My Document.docx" in the root of the project
|
will run the demo selector app in the `demo` folder. It will prompt you to select a demo number, which will run a demo from that folder.
|
||||||
|
|
||||||
## Guide
|
## Guide
|
||||||
|
|
||||||
Please refer to [the Wiki](https://github.com/dolanmiu/docx/wiki) for details on how to use this library, examples and much more!
|
Please refer to [the Wiki](https://github.com/dolanmiu/docx/wiki) for details on how to use this library, examples and much more!
|
||||||
|
|
||||||
|
Full documentation can be found here: [http://dolanmiu.github.io/docx](http://dolanmiu.github.io/docx)
|
||||||
|
|
||||||
## Simple Usage
|
## Simple Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
74
demo/demo2.js
Normal file
74
demo/demo2.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
const docx = require('../build');
|
||||||
|
|
||||||
|
const styles = new docx.Styles();
|
||||||
|
styles.createParagraphStyle('Heading1', 'Heading 1')
|
||||||
|
.basedOn("Normal")
|
||||||
|
.next("Normal")
|
||||||
|
.quickFormat()
|
||||||
|
.size(28)
|
||||||
|
.bold()
|
||||||
|
.italics()
|
||||||
|
.spacing({after: 120});
|
||||||
|
|
||||||
|
styles.createParagraphStyle('Heading2', 'Heading 2')
|
||||||
|
.basedOn("Normal")
|
||||||
|
.next("Normal")
|
||||||
|
.quickFormat()
|
||||||
|
.size(26)
|
||||||
|
.bold()
|
||||||
|
.underline('double', 'FF0000')
|
||||||
|
.spacing({before: 240, after: 120});
|
||||||
|
|
||||||
|
styles.createParagraphStyle('aside', 'Aside')
|
||||||
|
.basedOn('Normal')
|
||||||
|
.next('Normal')
|
||||||
|
.color('999999')
|
||||||
|
.italics()
|
||||||
|
.indent(720)
|
||||||
|
.spacing({line: 276});
|
||||||
|
|
||||||
|
styles.createParagraphStyle('wellSpaced', 'Well Spaced')
|
||||||
|
.basedOn('Normal')
|
||||||
|
.spacing({line: 276, before: 20 * 72 * .1, after: 20 * 72 * .05});
|
||||||
|
|
||||||
|
styles.createParagraphStyle('ListParagraph', 'List Paragraph')
|
||||||
|
.quickFormat()
|
||||||
|
.basedOn('Normal');
|
||||||
|
|
||||||
|
|
||||||
|
const numbering = new docx.Numbering();
|
||||||
|
const numberedAbstract = numbering.createAbstractNumbering();
|
||||||
|
numberedAbstract.createLevel(0, "lowerLetter", "%1)", "left");
|
||||||
|
|
||||||
|
const doc = new docx.Document({
|
||||||
|
creator: 'Clippy',
|
||||||
|
title: 'Sample Document',
|
||||||
|
description: 'A brief example of using docx',
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.createParagraph('Test heading1, bold and italicized').heading1();
|
||||||
|
doc.createParagraph('Some simple content');
|
||||||
|
doc.createParagraph('Test heading2 with double red underline').heading2();
|
||||||
|
|
||||||
|
const letterNumbering = numbering.createConcreteNumbering(numberedAbstract);
|
||||||
|
const letterNumbering5 = numbering.createConcreteNumbering(numberedAbstract);
|
||||||
|
letterNumbering5.overrideLevel(0, 5);
|
||||||
|
|
||||||
|
doc.createParagraph('Option1').setNumbering(letterNumbering, 0);
|
||||||
|
doc.createParagraph('Option5 -- override 2 to 5').setNumbering(letterNumbering5, 0);
|
||||||
|
doc.createParagraph('Option3').setNumbering(letterNumbering, 0);
|
||||||
|
|
||||||
|
doc.createParagraph()
|
||||||
|
.createTextRun('Some monospaced content')
|
||||||
|
.font('Monospace');
|
||||||
|
|
||||||
|
doc.createParagraph('An aside, in light gray italics and indented').style('aside');
|
||||||
|
doc.createParagraph('This is normal, but well-spaced text').style('wellSpaced');
|
||||||
|
const para = doc.createParagraph();
|
||||||
|
para.createTextRun('This is a bold run,').bold();
|
||||||
|
para.createTextRun(' switching to normal ');
|
||||||
|
para.createTextRun('and then underlined ').underline();
|
||||||
|
para.createTextRun('and back to normal.');
|
||||||
|
|
||||||
|
const exporter = new docx.LocalPacker(doc, styles, undefined, numbering);
|
||||||
|
exporter.pack('test.docx');
|
35
demo/demo3.js
Normal file
35
demo/demo3.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const docx = require('../build');
|
||||||
|
|
||||||
|
var doc = new docx.Document();
|
||||||
|
|
||||||
|
const numbering = new docx.Numbering();
|
||||||
|
|
||||||
|
const abstractNum = numbering.createAbstractNumbering();
|
||||||
|
abstractNum.createLevel(0, "upperRoman", "%1", "start")
|
||||||
|
.addParagraphProperty(new docx.Indent(720, 260));
|
||||||
|
abstractNum.createLevel(1, "decimal", "%2.", "start")
|
||||||
|
.addParagraphProperty(new docx.Indent(1440, 980));
|
||||||
|
abstractNum.createLevel(2, "lowerLetter", "%3)", "start")
|
||||||
|
.addParagraphProperty(new docx.Indent(2160, 1700));
|
||||||
|
|
||||||
|
const concrete = numbering.createConcreteNumbering(abstractNum);
|
||||||
|
|
||||||
|
var topLevelP = new docx.Paragraph("Hey you");
|
||||||
|
var subP = new docx.Paragraph("What's up fam");
|
||||||
|
var secondSubP = new docx.Paragraph("Hello World 2");
|
||||||
|
var subSubP = new docx.Paragraph("Yeah boi");
|
||||||
|
|
||||||
|
topLevelP.setNumbering(concrete, 0);
|
||||||
|
subP.setNumbering(concrete, 1);
|
||||||
|
secondSubP.setNumbering(concrete, 1);
|
||||||
|
subSubP.setNumbering(concrete, 2);
|
||||||
|
|
||||||
|
doc.addParagraph(topLevelP);
|
||||||
|
doc.addParagraph(subP);
|
||||||
|
doc.addParagraph(secondSubP);
|
||||||
|
doc.addParagraph(subSubP);
|
||||||
|
|
||||||
|
var exporter = new docx.LocalPacker(doc);
|
||||||
|
exporter.pack('My Document');
|
||||||
|
|
||||||
|
console.log('Document created succesfully at project root!');
|
12
demo/demo4.js
Normal file
12
demo/demo4.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
const docx = require('../build');
|
||||||
|
|
||||||
|
var doc = new docx.Document();
|
||||||
|
|
||||||
|
const table = doc.createTable(4, 4);
|
||||||
|
table.getCell(2, 2).addContent(new docx.Paragraph('Hello'));
|
||||||
|
|
||||||
|
|
||||||
|
var exporter = new docx.LocalPacker(doc);
|
||||||
|
exporter.pack('My Document');
|
||||||
|
|
||||||
|
console.log('Document created succesfully at project root!');
|
29
demo/index.js
Normal file
29
demo/index.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
var prompt = require('prompt');
|
||||||
|
var shelljs = require('shelljs');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
console.log('What demo do you wish to run? (Enter a number)');
|
||||||
|
|
||||||
|
var schema = {
|
||||||
|
properties: {
|
||||||
|
number: {
|
||||||
|
pattern: /^[0-9]+$/,
|
||||||
|
message: 'Please enter a number.',
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
prompt.start();
|
||||||
|
|
||||||
|
prompt.get(schema, function (err, result) {
|
||||||
|
var demoNumber = result.number;
|
||||||
|
var filePath = `./demo/demo${demoNumber}.js`;
|
||||||
|
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
console.error(`demo${demoNumber} does not exist: ${filePath}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(`Running demo ${demoNumber}`);
|
||||||
|
shelljs.exec(`node ${filePath}`);
|
||||||
|
});
|
68
deploy-docs.sh
Normal file
68
deploy-docs.sh
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e # Exit with nonzero exit code if anything fails
|
||||||
|
|
||||||
|
SOURCE_BRANCH="master"
|
||||||
|
TARGET_BRANCH="gh-pages"
|
||||||
|
|
||||||
|
function doCompile {
|
||||||
|
npm run typedoc
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pull requests and commits to other branches shouldn't try to deploy, just build to verify
|
||||||
|
if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "$SOURCE_BRANCH" ]; then
|
||||||
|
echo "Skipping deploy; just doing a build."
|
||||||
|
doCompile
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save some useful information
|
||||||
|
REPO=`git config remote.origin.url`
|
||||||
|
SSH_REPO=${REPO/https:\/\/github.com\//git@github.com:}
|
||||||
|
SHA=`git rev-parse --verify HEAD`
|
||||||
|
|
||||||
|
# Clone the existing gh-pages for this repo into docs/
|
||||||
|
# Create a new empty branch if gh-pages doesn't exist yet (should only happen on first deply)
|
||||||
|
git clone $REPO docs
|
||||||
|
cd docs
|
||||||
|
git checkout $TARGET_BRANCH || git checkout --orphan $TARGET_BRANCH
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Clean out existing contents
|
||||||
|
# echo "Cleaning out existing contents."
|
||||||
|
# rm -rf docs/*
|
||||||
|
|
||||||
|
# Run our compile script
|
||||||
|
doCompile
|
||||||
|
|
||||||
|
# Now let's go have some fun with the cloned repo
|
||||||
|
cd docs
|
||||||
|
git config user.name "Travis CI"
|
||||||
|
git config user.email "dolan_miu@hotmail.com"
|
||||||
|
ls
|
||||||
|
|
||||||
|
# add .nojekyll file
|
||||||
|
touch .nojekyll
|
||||||
|
|
||||||
|
# If there are no changes to the compiled out (e.g. this is a README update) then just bail.
|
||||||
|
if [ -z `git diff --exit-code` ]; then
|
||||||
|
echo "No changes to the output on this push; exiting."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Commit the "changes", i.e. the new version.
|
||||||
|
# The delta will show diffs between new and old versions.
|
||||||
|
git add .
|
||||||
|
git commit -m "Deploy to GitHub Pages: ${SHA}"
|
||||||
|
|
||||||
|
# Get the deploy key by using Travis's stored variables to decrypt deploy-key.enc
|
||||||
|
ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key"
|
||||||
|
ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv"
|
||||||
|
ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR}
|
||||||
|
ENCRYPTED_IV=${!ENCRYPTED_IV_VAR}
|
||||||
|
openssl aes-256-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in deploy-key.enc -out deploy-key -d
|
||||||
|
chmod 600 deploy-key
|
||||||
|
eval `ssh-agent -s`
|
||||||
|
ssh-add deploy-key
|
||||||
|
|
||||||
|
# Now that we're all set up, we can push.
|
||||||
|
git push $SSH_REPO $TARGET_BRANCH
|
BIN
deploy-key.enc
Normal file
BIN
deploy-key.enc
Normal file
Binary file not shown.
15
package.json
15
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "docx",
|
"name": "docx",
|
||||||
"version": "2.0.0",
|
"version": "2.1.3",
|
||||||
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
|
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -9,7 +9,8 @@
|
|||||||
"prepublishOnly": "npm run build",
|
"prepublishOnly": "npm run build",
|
||||||
"lint": "tslint --project ./ts",
|
"lint": "tslint --project ./ts",
|
||||||
"build": "rimraf ./build && tsc -p ts",
|
"build": "rimraf ./build && tsc -p ts",
|
||||||
"demo": "npm run build && node ./demo/demo.js"
|
"demo": "npm run build && node ./demo",
|
||||||
|
"typedoc": "typedoc --out docs/ ts/ --module commonjs --target ES6 --disableOutputCheck"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"ts",
|
"ts",
|
||||||
@ -31,8 +32,9 @@
|
|||||||
"officegen",
|
"officegen",
|
||||||
"clippy"
|
"clippy"
|
||||||
],
|
],
|
||||||
|
"types": "./build/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/archiver": "^0.15.37",
|
"@types/archiver": "^1.3.4",
|
||||||
"@types/express": "^4.0.35",
|
"@types/express": "^4.0.35",
|
||||||
"archiver": "^1.3.0",
|
"archiver": "^1.3.0",
|
||||||
"xml": "^1.0.1"
|
"xml": "^1.0.1"
|
||||||
@ -48,8 +50,11 @@
|
|||||||
"@types/mocha": "^2.2.39",
|
"@types/mocha": "^2.2.39",
|
||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"mocha": "^3.2.0",
|
"mocha": "^3.2.0",
|
||||||
|
"prompt": "^1.0.0",
|
||||||
"rimraf": "^2.5.2",
|
"rimraf": "^2.5.2",
|
||||||
"tslint": "^4.5.1",
|
"shelljs": "^0.7.7",
|
||||||
"typescript": "^2.2.1"
|
"tslint": "^5.1.0",
|
||||||
|
"typedoc": "^0.5.10",
|
||||||
|
"typescript": "2.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { XmlAttributeComponent } from "../xml-components";
|
import { XmlAttributeComponent } from "../xml-components";
|
||||||
|
|
||||||
interface IDocumentAttributesProperties {
|
export interface IDocumentAttributesProperties {
|
||||||
wpc?: string;
|
wpc?: string;
|
||||||
mc?: string;
|
mc?: string;
|
||||||
o?: string;
|
o?: string;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export { Document } from "./document";
|
export { Document } from "./document";
|
||||||
export { Paragraph } from "./paragraph";
|
export * from "./paragraph";
|
||||||
export { Run } from "./run";
|
export { Run } from "./run";
|
||||||
export { TextRun } from "./run/text-run";
|
export { TextRun } from "./run/text-run";
|
||||||
export { PictureRun } from "./run/picture-run";
|
export { PictureRun } from "./run/picture-run";
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
||||||
|
|
||||||
type alignmentOptions = "left" | "center" | "right" | "both";
|
export type AlignmentOptions = "left" | "center" | "right" | "both";
|
||||||
|
|
||||||
class AlignmentAttributes extends XmlAttributeComponent<{val: alignmentOptions}> {
|
export class AlignmentAttributes extends XmlAttributeComponent<{val: AlignmentOptions}> {
|
||||||
protected xmlKeys = {val: "w:val"};
|
protected xmlKeys = {val: "w:val"};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Alignment extends XmlComponent {
|
export class Alignment extends XmlComponent {
|
||||||
|
|
||||||
constructor(type: alignmentOptions) {
|
constructor(type: AlignmentOptions) {
|
||||||
super("w:jc");
|
super("w:jc");
|
||||||
this.root.push(new AlignmentAttributes({val: type}));
|
this.root.push(new AlignmentAttributes({val: type}));
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
export { Alignment } from "./alignment";
|
export { Alignment } from "./alignment";
|
||||||
export { ThematicBreak } from "./border";
|
export { ThematicBreak } from "./border";
|
||||||
export { Indent } from "./indent";
|
export { Indent } from "./indent";
|
||||||
|
export { KeepLines, KeepNext } from "./keep";
|
||||||
export { PageBreak } from "./page-break";
|
export { PageBreak } from "./page-break";
|
||||||
export { ParagraphProperties } from "./properties";
|
export { ParagraphProperties } from "./properties";
|
||||||
export { ISpacingProperties, Spacing } from "./spacing";
|
export { ISpacingProperties, Spacing } from "./spacing";
|
||||||
|
@ -8,6 +8,7 @@ import { XmlComponent } from "../xml-components";
|
|||||||
import { Alignment } from "./alignment";
|
import { Alignment } from "./alignment";
|
||||||
import { ThematicBreak } from "./border";
|
import { ThematicBreak } from "./border";
|
||||||
import { Indent } from "./indent";
|
import { Indent } from "./indent";
|
||||||
|
import { KeepLines, KeepNext } from "./keep";
|
||||||
import { PageBreak } from "./page-break";
|
import { PageBreak } from "./page-break";
|
||||||
import { ParagraphProperties } from "./properties";
|
import { ParagraphProperties } from "./properties";
|
||||||
import { ISpacingProperties, Spacing } from "./spacing";
|
import { ISpacingProperties, Spacing } from "./spacing";
|
||||||
@ -15,6 +16,8 @@ import { Style } from "./style";
|
|||||||
import { LeftTabStop, MaxRightTabStop } from "./tab-stop";
|
import { LeftTabStop, MaxRightTabStop } from "./tab-stop";
|
||||||
import { NumberProperties } from "./unordered-list";
|
import { NumberProperties } from "./unordered-list";
|
||||||
|
|
||||||
|
export * from "./formatting";
|
||||||
|
|
||||||
export class Paragraph extends XmlComponent {
|
export class Paragraph extends XmlComponent {
|
||||||
private properties: ParagraphProperties;
|
private properties: ParagraphProperties;
|
||||||
|
|
||||||
@ -100,7 +103,7 @@ export class Paragraph extends XmlComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public pageBreak(): Paragraph {
|
public pageBreak(): Paragraph {
|
||||||
this.properties.push(new PageBreak());
|
this.root.push(new PageBreak());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,5 +142,15 @@ export class Paragraph extends XmlComponent {
|
|||||||
public spacing(params: ISpacingProperties): Paragraph {
|
public spacing(params: ISpacingProperties): Paragraph {
|
||||||
this.properties.push(new Spacing(params));
|
this.properties.push(new Spacing(params));
|
||||||
return this;
|
return this;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
public keepNext(): Paragraph {
|
||||||
|
this.properties.push(new KeepNext());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public keepLines(): Paragraph {
|
||||||
|
this.properties.push(new KeepLines());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
13
ts/docx/paragraph/keep.ts
Normal file
13
ts/docx/paragraph/keep.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { XmlComponent } from "../xml-components";
|
||||||
|
|
||||||
|
export class KeepLines extends XmlComponent {
|
||||||
|
constructor() {
|
||||||
|
super("w:keepLines");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KeepNext extends XmlComponent {
|
||||||
|
constructor() {
|
||||||
|
super("w:keepNext");
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
||||||
|
|
||||||
class TabStop extends XmlComponent {
|
export class TabStop extends XmlComponent {
|
||||||
|
|
||||||
constructor(tab: Tab) {
|
constructor(tab: Tab) {
|
||||||
super("w:tabs");
|
super("w:tabs");
|
||||||
@ -8,15 +8,15 @@ class TabStop extends XmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type tabOptions = "left" | "right";
|
export type TabOptions = "left" | "right";
|
||||||
|
|
||||||
class TabAttributes extends XmlAttributeComponent<{val: tabOptions, pos: string | number}> {
|
export class TabAttributes extends XmlAttributeComponent<{val: TabOptions, pos: string | number}> {
|
||||||
protected xmlKeys = {val: "w:val", pos: "w:pos"};
|
protected xmlKeys = {val: "w:val", pos: "w:pos"};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Tab extends XmlComponent {
|
export class Tab extends XmlComponent {
|
||||||
|
|
||||||
constructor(value: tabOptions, position: string | number) {
|
constructor(value: TabOptions, position: string | number) {
|
||||||
super("w:tab");
|
super("w:tab");
|
||||||
this.root.push(new TabAttributes({
|
this.root.push(new TabAttributes({
|
||||||
val: value,
|
val: value,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "../../../../../xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "../../../../../xml-components";
|
||||||
import { GraphicData } from "./graphic-data";
|
import { GraphicData } from "./graphic-data";
|
||||||
|
|
||||||
|
|
||||||
interface IGraphicProperties {
|
interface IGraphicProperties {
|
||||||
a: string;
|
a: string;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import { XmlComponent } from "../../xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "../../xml-components";
|
||||||
|
|
||||||
|
class TextAttributes extends XmlAttributeComponent<{space: "default" | "preserve"}> {
|
||||||
|
protected xmlKeys = {space: "xml:space"};
|
||||||
|
}
|
||||||
|
|
||||||
export class Text extends XmlComponent {
|
export class Text extends XmlComponent {
|
||||||
|
|
||||||
constructor(text: string) {
|
constructor(text: string) {
|
||||||
super("w:t");
|
super("w:t");
|
||||||
|
this.root.push(new TextAttributes({space: "preserve"}));
|
||||||
if (text) {
|
if (text) {
|
||||||
this.root.push(text);
|
this.root.push(text);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Attributes, XmlComponent } from "../xml-components";
|
import { Attributes, XmlComponent } from "../xml-components";
|
||||||
|
|
||||||
abstract class VerticalAlign extends XmlComponent {
|
export abstract class VerticalAlign extends XmlComponent {
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super("w:vertAlign");
|
super("w:vertAlign");
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Attributes, XmlComponent } from "../xml-components";
|
import { Attributes, XmlComponent } from "../xml-components";
|
||||||
|
|
||||||
abstract class BaseUnderline extends XmlComponent {
|
export abstract class BaseUnderline extends XmlComponent {
|
||||||
|
|
||||||
constructor(underlineType: string, color?: string) {
|
constructor(underlineType: string, color?: string) {
|
||||||
super("w:u");
|
super("w:u");
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Paragraph } from "../paragraph";
|
import { Paragraph } from "../paragraph";
|
||||||
import { XmlComponent } from "../xml-components";
|
import { XmlComponent } from "../xml-components";
|
||||||
|
import { IXmlableObject } from "../xml-components/xmlable-object";
|
||||||
import { TableGrid } from "./grid";
|
import { TableGrid } from "./grid";
|
||||||
import { TableProperties, widthTypes } from "./properties";
|
import { TableProperties, WidthTypes } from "./properties";
|
||||||
|
|
||||||
export class Table extends XmlComponent {
|
export class Table extends XmlComponent {
|
||||||
private properties: TableProperties;
|
private properties: TableProperties;
|
||||||
@ -51,7 +51,7 @@ export class Table extends XmlComponent {
|
|||||||
return this.getRow(row).getCell(col);
|
return this.getRow(row).getCell(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setWidth(type: widthTypes, width: number | string): Table {
|
public setWidth(type: WidthTypes, width: number | string): Table {
|
||||||
this.properties.setWidth(type, width);
|
this.properties.setWidth(type, width);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ export class Table extends XmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TableRow extends XmlComponent {
|
export class TableRow extends XmlComponent {
|
||||||
private properties: TableRowProperties;
|
private properties: TableRowProperties;
|
||||||
private cells: TableCell[];
|
private cells: TableCell[];
|
||||||
|
|
||||||
@ -79,13 +79,13 @@ class TableRow extends XmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TableRowProperties extends XmlComponent {
|
export class TableRowProperties extends XmlComponent {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("w:trPr");
|
super("w:trPr");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TableCell extends XmlComponent {
|
export class TableCell extends XmlComponent {
|
||||||
private properties: TableCellProperties;
|
private properties: TableCellProperties;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -99,7 +99,7 @@ class TableCell extends XmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public prepForXml(): object {
|
public prepForXml(): IXmlableObject {
|
||||||
// Cells must end with a paragraph
|
// Cells must end with a paragraph
|
||||||
const retval = super.prepForXml();
|
const retval = super.prepForXml();
|
||||||
const content = retval["w:tc"];
|
const content = retval["w:tc"];
|
||||||
@ -116,7 +116,7 @@ class TableCell extends XmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TableCellProperties extends XmlComponent {
|
export class TableCellProperties extends XmlComponent {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("w:tcPr");
|
super("w:tcPr");
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
||||||
|
|
||||||
export type widthTypes = "dxa" | "pct" | "nil" | "auto";
|
export type WidthTypes = "dxa" | "pct" | "nil" | "auto";
|
||||||
|
|
||||||
export class TableProperties extends XmlComponent {
|
export class TableProperties extends XmlComponent {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("w:tblPr");
|
super("w:tblPr");
|
||||||
}
|
}
|
||||||
|
|
||||||
public setWidth(type: widthTypes, w: number | string): TableProperties {
|
public setWidth(type: WidthTypes, w: number | string): TableProperties {
|
||||||
this.root.push(new PreferredTableWidth(type, w));
|
this.root.push(new PreferredTableWidth(type, w));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ export class TableProperties extends XmlComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ITableWidth {
|
interface ITableWidth {
|
||||||
type: widthTypes;
|
type: WidthTypes;
|
||||||
w: number | string;
|
w: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,20 +28,20 @@ class TableWidthAttributes extends XmlAttributeComponent<ITableWidth> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PreferredTableWidth extends XmlComponent {
|
class PreferredTableWidth extends XmlComponent {
|
||||||
constructor(type: widthTypes, w: number | string) {
|
constructor(type: WidthTypes, w: number | string) {
|
||||||
super("w:tblW");
|
super("w:tblW");
|
||||||
this.root.push(new TableWidthAttributes({type, w}));
|
this.root.push(new TableWidthAttributes({type, w}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type tableLayout = "autofit" | "fixed";
|
type TableLayoutOptions = "autofit" | "fixed";
|
||||||
|
|
||||||
class TableLayoutAttributes extends XmlAttributeComponent<{type: tableLayout}> {
|
class TableLayoutAttributes extends XmlAttributeComponent<{type: TableLayoutOptions}> {
|
||||||
protected xmlKeys = {type: "w:type"};
|
protected xmlKeys = {type: "w:type"};
|
||||||
}
|
}
|
||||||
|
|
||||||
class TableLayout extends XmlComponent {
|
class TableLayout extends XmlComponent {
|
||||||
constructor(type: tableLayout) {
|
constructor(type: TableLayoutOptions) {
|
||||||
super("w:tblLayout");
|
super("w:tblLayout");
|
||||||
this.root.push(new TableLayoutAttributes({type}));
|
this.root.push(new TableLayoutAttributes({type}));
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { XmlAttributeComponent } from "./default-attributes";
|
import { XmlAttributeComponent } from "./default-attributes";
|
||||||
|
|
||||||
interface IAttributesProperties {
|
export interface IAttributesProperties {
|
||||||
val?: string | number | boolean;
|
val?: string | number | boolean;
|
||||||
color?: string;
|
color?: string;
|
||||||
space?: string;
|
space?: string;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { IXmlableObject } from "./xmlable-object";
|
||||||
|
|
||||||
export abstract class BaseXmlComponent {
|
export abstract class BaseXmlComponent {
|
||||||
protected rootKey: string;
|
protected rootKey: string;
|
||||||
|
|
||||||
@ -5,5 +7,5 @@ export abstract class BaseXmlComponent {
|
|||||||
this.rootKey = rootKey;
|
this.rootKey = rootKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract prepForXml(): object;
|
public abstract prepForXml(): IXmlableObject;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { BaseXmlComponent } from "./base";
|
import { BaseXmlComponent } from "./base";
|
||||||
|
import { IXmlableObject } from "./xmlable-object";
|
||||||
|
|
||||||
type AttributeMap<T> = {[P in keyof T]: string};
|
export type AttributeMap<T> = {[P in keyof T]: string};
|
||||||
|
|
||||||
export abstract class XmlAttributeComponent<T> extends BaseXmlComponent {
|
export abstract class XmlAttributeComponent<T> extends BaseXmlComponent {
|
||||||
protected root: T;
|
protected root: T;
|
||||||
@ -11,7 +12,7 @@ export abstract class XmlAttributeComponent<T> extends BaseXmlComponent {
|
|||||||
this.root = properties;
|
this.root = properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
public prepForXml(): {_attr: {[key: string]: (string | number | boolean)}} {
|
public prepForXml(): IXmlableObject {
|
||||||
const attrs = {};
|
const attrs = {};
|
||||||
Object.keys(this.root).forEach((key) => {
|
Object.keys(this.root).forEach((key) => {
|
||||||
const value = this.root[key];
|
const value = this.root[key];
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { BaseXmlComponent } from "./base";
|
import { BaseXmlComponent } from "./base";
|
||||||
|
import { IXmlableObject } from "./xmlable-object";
|
||||||
export { BaseXmlComponent };
|
export { BaseXmlComponent };
|
||||||
|
|
||||||
export abstract class XmlComponent extends BaseXmlComponent {
|
export abstract class XmlComponent extends BaseXmlComponent {
|
||||||
@ -9,7 +10,7 @@ export abstract class XmlComponent extends BaseXmlComponent {
|
|||||||
this.root = new Array<BaseXmlComponent>();
|
this.root = new Array<BaseXmlComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public prepForXml(): object {
|
public prepForXml(): IXmlableObject {
|
||||||
const children = this.root.map((comp) => {
|
const children = this.root.map((comp) => {
|
||||||
if (comp instanceof BaseXmlComponent) {
|
if (comp instanceof BaseXmlComponent) {
|
||||||
return comp.prepForXml();
|
return comp.prepForXml();
|
||||||
@ -22,5 +23,5 @@ export abstract class XmlComponent extends BaseXmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export * from "./attributes"
|
export * from "./attributes";
|
||||||
export * from "./default-attributes";
|
export * from "./default-attributes";
|
||||||
|
3
ts/docx/xml-components/xmlable-object.ts
Normal file
3
ts/docx/xml-components/xmlable-object.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export interface IXmlableObject extends Object {
|
||||||
|
_attr?: { [key: string]: (string | number | boolean) };
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
import { BaseXmlComponent } from "../docx/xml-components";
|
import { BaseXmlComponent } from "../docx/xml-components";
|
||||||
|
import { IXmlableObject } from "../docx/xml-components/xmlable-object";
|
||||||
|
|
||||||
export class Formatter {
|
export class Formatter {
|
||||||
public format(input: BaseXmlComponent): any {
|
public format(input: BaseXmlComponent): IXmlableObject {
|
||||||
return input.prepForXml();
|
return input.prepForXml();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,6 @@ export class ExpressPacker extends Packer {
|
|||||||
|
|
||||||
public pack(name: string): void {
|
public pack(name: string): void {
|
||||||
this.res.attachment(`${name}.docx`);
|
this.res.attachment(`${name}.docx`);
|
||||||
super.pack(this.res);
|
super.compile(this.res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,6 @@ export class LocalPacker extends Packer {
|
|||||||
public pack(path: string): void {
|
public pack(path: string): void {
|
||||||
path = path.replace(/.docx$/, "");
|
path = path.replace(/.docx$/, "");
|
||||||
this.stream = fs.createWriteStream(`${path}.docx`);
|
this.stream = fs.createWriteStream(`${path}.docx`);
|
||||||
super.pack(this.stream);
|
super.compile(this.stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import * as archiver from "archiver";
|
import * as archiver from "archiver";
|
||||||
|
import * as express from "express";
|
||||||
|
import * as fs from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as xml from "xml";
|
import * as xml from "xml";
|
||||||
import { Document } from "../../docx";
|
import { Document } from "../../docx";
|
||||||
@ -12,7 +14,7 @@ import { Formatter } from "../formatter";
|
|||||||
const TEMPLATE_PATH = path.resolve(__dirname, "../../../template");
|
const TEMPLATE_PATH = path.resolve(__dirname, "../../../template");
|
||||||
|
|
||||||
export abstract class Packer {
|
export abstract class Packer {
|
||||||
protected archive: any;
|
protected archive: archiver.Archiver;
|
||||||
private formatter: Formatter;
|
private formatter: Formatter;
|
||||||
private style: Styles;
|
private style: Styles;
|
||||||
|
|
||||||
@ -42,15 +44,13 @@ export abstract class Packer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public pack(output: any): void {
|
protected compile(output: fs.WriteStream | express.Response): void {
|
||||||
this.archive.pipe(output);
|
this.archive.pipe(output);
|
||||||
this.archive.glob("**", {
|
this.archive.glob("**", {
|
||||||
expand: true,
|
|
||||||
cwd: TEMPLATE_PATH,
|
cwd: TEMPLATE_PATH,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.archive.glob("**/.rels", {
|
this.archive.glob("**/.rels", {
|
||||||
expand: true,
|
|
||||||
cwd: TEMPLATE_PATH,
|
cwd: TEMPLATE_PATH,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -56,21 +56,29 @@ class LevelJc extends XmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Level extends XmlComponent {
|
export class LevelBase extends XmlComponent {
|
||||||
private paragraphProperties: ParagraphProperties;
|
private paragraphProperties: ParagraphProperties;
|
||||||
private runProperties: RunProperties;
|
private runProperties: RunProperties;
|
||||||
|
|
||||||
constructor(level: number, numberFormat: string, levelText: string, lvlJc: string) {
|
constructor(level: number, start?: number, numberFormat?: string, levelText?: string, lvlJc?: string) {
|
||||||
super("w:lvl");
|
super("w:lvl");
|
||||||
this.root.push(new LevelAttributes({
|
this.root.push(new LevelAttributes({
|
||||||
ilvl: level,
|
ilvl: level,
|
||||||
tentative: 1,
|
tentative: 1,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.root.push(new Start(1));
|
if (start !== undefined) {
|
||||||
this.root.push(new NumberFormat(numberFormat));
|
this.root.push(new Start(start));
|
||||||
this.root.push(new LevelText(levelText));
|
}
|
||||||
this.root.push(new LevelJc(lvlJc));
|
if (numberFormat !== undefined) {
|
||||||
|
this.root.push(new NumberFormat(numberFormat));
|
||||||
|
}
|
||||||
|
if (levelText !== undefined) {
|
||||||
|
this.root.push(new LevelText(levelText));
|
||||||
|
}
|
||||||
|
if (lvlJc !== undefined) {
|
||||||
|
this.root.push(new LevelJc(lvlJc));
|
||||||
|
}
|
||||||
|
|
||||||
this.paragraphProperties = new ParagraphProperties();
|
this.paragraphProperties = new ParagraphProperties();
|
||||||
this.runProperties = new RunProperties();
|
this.runProperties = new RunProperties();
|
||||||
@ -196,5 +204,25 @@ export class Level extends XmlComponent {
|
|||||||
public spacing(params: paragraph.ISpacingProperties): Level {
|
public spacing(params: paragraph.ISpacingProperties): Level {
|
||||||
this.addParagraphProperty(new paragraph.Spacing(params));
|
this.addParagraphProperty(new paragraph.Spacing(params));
|
||||||
return this;
|
return this;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
public keepNext(): Level {
|
||||||
|
this.addParagraphProperty(new paragraph.KeepNext());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public keepLines(): Level {
|
||||||
|
this.addParagraphProperty(new paragraph.KeepLines());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Level extends LevelBase {
|
||||||
|
// This is the level that sits under abstractNum. We make a
|
||||||
|
// handful of properties required
|
||||||
|
constructor(level: number, numberFormat: string, levelText: string, lvlJc: string) {
|
||||||
|
super(level, 1, numberFormat, levelText, lvlJc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LevelForOverride extends LevelBase {}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Attributes, XmlAttributeComponent, XmlComponent } from "../docx/xml-components";
|
import { Attributes, XmlAttributeComponent, XmlComponent } from "../docx/xml-components";
|
||||||
|
import { LevelForOverride } from "./level";
|
||||||
|
|
||||||
class AbstractNumId extends XmlComponent {
|
class AbstractNumId extends XmlComponent {
|
||||||
|
|
||||||
@ -29,4 +30,51 @@ export class Num extends XmlComponent {
|
|||||||
this.root.push(new AbstractNumId(abstractNumId));
|
this.root.push(new AbstractNumId(abstractNumId));
|
||||||
this.id = numId;
|
this.id = numId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public overrideLevel(num: number, start?: number): LevelOverride {
|
||||||
|
const olvl = new LevelOverride(num, start);
|
||||||
|
this.root.push(olvl);
|
||||||
|
return olvl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LevelOverrideAttributes extends XmlAttributeComponent<{ilvl: number}> {
|
||||||
|
protected xmlKeys = {ilvl: "w:ilvl"};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LevelOverride extends XmlComponent {
|
||||||
|
private levelNum: number;
|
||||||
|
private lvl?: LevelForOverride;
|
||||||
|
|
||||||
|
constructor(levelNum: number, start?: number) {
|
||||||
|
super("w:lvlOverride");
|
||||||
|
this.root.push(new LevelOverrideAttributes({ilvl: levelNum}));
|
||||||
|
if (start !== undefined) {
|
||||||
|
this.root.push(new StartOverride(start));
|
||||||
|
}
|
||||||
|
this.levelNum = levelNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
get level(): LevelForOverride {
|
||||||
|
let lvl: LevelForOverride;
|
||||||
|
if (!this.lvl) {
|
||||||
|
lvl = new LevelForOverride(this.levelNum);
|
||||||
|
this.root.push(lvl);
|
||||||
|
this.lvl = lvl;
|
||||||
|
} else {
|
||||||
|
lvl = this.lvl;
|
||||||
|
}
|
||||||
|
return lvl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartOverrideAttributes extends XmlAttributeComponent<{val: number}> {
|
||||||
|
protected xmlKeys = {val: "w:val"};
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartOverride extends XmlComponent {
|
||||||
|
constructor(start: number) {
|
||||||
|
super("w:startOverride");
|
||||||
|
this.root.push(new StartOverrideAttributes({val: start}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ export class Revision extends XmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class DateComponent extends XmlComponent {
|
export abstract class DateComponent extends XmlComponent {
|
||||||
protected getCurrentDate(): string {
|
protected getCurrentDate(): string {
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
|
@ -2,7 +2,7 @@ import { DocumentAttributes } from "../docx/document/document-attributes";
|
|||||||
import { XmlComponent } from "../docx/xml-components";
|
import { XmlComponent } from "../docx/xml-components";
|
||||||
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
||||||
|
|
||||||
interface IPropertiesOptions {
|
export interface IPropertiesOptions {
|
||||||
title?: string;
|
title?: string;
|
||||||
subject?: string;
|
subject?: string;
|
||||||
creator?: string;
|
creator?: string;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { XmlAttributeComponent } from "../docx/xml-components";
|
import { XmlAttributeComponent } from "../docx/xml-components";
|
||||||
|
|
||||||
interface IRelationshipsAttributesProperties {
|
export interface IRelationshipsAttributesProperties {
|
||||||
xmlns: string;
|
xmlns: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,24 @@
|
|||||||
import { RunProperties } from "../../docx/run/properties";
|
import { RunProperties } from "../../docx/run/properties";
|
||||||
import { XmlComponent } from "../../docx/xml-components";
|
import { XmlComponent } from "../../docx/xml-components";
|
||||||
|
import { RunFonts } from "../../docx/run/run-fonts";
|
||||||
|
import { Size } from "../../docx/run/formatting";
|
||||||
|
|
||||||
export class RunPropertiesDefaults extends XmlComponent {
|
export class RunPropertiesDefaults extends XmlComponent {
|
||||||
|
private properties: RunProperties;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("w:rPrDefault");
|
super("w:rPrDefault");
|
||||||
this.root.push(new RunProperties());
|
this.properties = new RunProperties();
|
||||||
|
this.root.push(this.properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public size(size: number): RunPropertiesDefaults {
|
||||||
|
this.properties.push(new Size(size));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public font(fontName: string): RunPropertiesDefaults {
|
||||||
|
this.properties.push(new RunFonts(fontName));
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ export class DefaultStylesFactory {
|
|||||||
|
|
||||||
public newInstance(): Styles {
|
public newInstance(): Styles {
|
||||||
const styles = new Styles();
|
const styles = new Styles();
|
||||||
styles.push(new DocumentDefaults());
|
styles.createDocumentDefaults();
|
||||||
|
|
||||||
const titleStyle = new TitleStyle();
|
const titleStyle = new TitleStyle();
|
||||||
titleStyle.addRunProperty(new Size(56));
|
titleStyle.addRunProperty(new Size(56));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { DocumentAttributes } from "../docx/document/document-attributes";
|
import { DocumentAttributes } from "../docx/document/document-attributes";
|
||||||
import { XmlComponent } from "../docx/xml-components";
|
import { XmlComponent } from "../docx/xml-components";
|
||||||
import { ParagraphStyle } from "./style";
|
import { ParagraphStyle } from "./style";
|
||||||
|
import { DocumentDefaults } from "./defaults";
|
||||||
|
|
||||||
export class Styles extends XmlComponent {
|
export class Styles extends XmlComponent {
|
||||||
|
|
||||||
@ -14,11 +15,7 @@ export class Styles extends XmlComponent {
|
|||||||
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
|
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
|
||||||
Ignorable: "w14 w15",
|
Ignorable: "w14 w15",
|
||||||
}));
|
}));
|
||||||
// let latentStyles = new LatentStyles();
|
|
||||||
// latentStyles.push(new LatentStyleException(new LatentStyleExceptionAttributes({
|
|
||||||
// name: "Normal"
|
|
||||||
// })));
|
|
||||||
// this.root.push(latentStyles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public push(style: XmlComponent): Styles {
|
public push(style: XmlComponent): Styles {
|
||||||
@ -26,6 +23,12 @@ export class Styles extends XmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public createDocumentDefaults(): DocumentDefaults {
|
||||||
|
const defaults = new DocumentDefaults();
|
||||||
|
this.push(defaults);
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
|
|
||||||
public createParagraphStyle(styleId: string, name?: string): ParagraphStyle {
|
public createParagraphStyle(styleId: string, name?: string): ParagraphStyle {
|
||||||
const para = new ParagraphStyle(styleId, name);
|
const para = new ParagraphStyle(styleId, name);
|
||||||
this.push(para);
|
this.push(para);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "../../docx/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "../../docx/xml-components";
|
||||||
|
|
||||||
interface ILatentStyleExceptionAttributesProperties {
|
export interface ILatentStyleExceptionAttributesProperties {
|
||||||
name?: string;
|
name?: string;
|
||||||
uiPriority?: string;
|
uiPriority?: string;
|
||||||
qFormat?: string;
|
qFormat?: string;
|
||||||
@ -8,7 +8,7 @@ interface ILatentStyleExceptionAttributesProperties {
|
|||||||
unhideWhenUsed?: string;
|
unhideWhenUsed?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class LatentStyleExceptionAttributes extends XmlAttributeComponent<ILatentStyleExceptionAttributesProperties> {
|
export class LatentStyleExceptionAttributes extends XmlAttributeComponent<ILatentStyleExceptionAttributesProperties> {
|
||||||
protected xmlKeys = {
|
protected xmlKeys = {
|
||||||
name: "w:name",
|
name: "w:name",
|
||||||
uiPriority: "w:uiPriority",
|
uiPriority: "w:uiPriority",
|
||||||
|
@ -179,7 +179,17 @@ export class ParagraphStyle extends Style {
|
|||||||
public spacing(params: paragraph.ISpacingProperties): ParagraphStyle {
|
public spacing(params: paragraph.ISpacingProperties): ParagraphStyle {
|
||||||
this.addParagraphProperty(new paragraph.Spacing(params));
|
this.addParagraphProperty(new paragraph.Spacing(params));
|
||||||
return this;
|
return this;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
public keepNext(): ParagraphStyle {
|
||||||
|
this.addParagraphProperty(new paragraph.KeepNext());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public keepLines(): ParagraphStyle {
|
||||||
|
this.addParagraphProperty(new paragraph.KeepLines());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HeadingStyle extends ParagraphStyle {
|
export class HeadingStyle extends ParagraphStyle {
|
||||||
|
@ -41,7 +41,7 @@ describe("Document", () => {
|
|||||||
expect(body[0]).to.have.property("w:p").which.includes({
|
expect(body[0]).to.have.property("w:p").which.includes({
|
||||||
"w:r": [
|
"w:r": [
|
||||||
{"w:rPr": []},
|
{"w:rPr": []},
|
||||||
{"w:t": ["sample paragraph text"]},
|
{"w:t": [{_attr: {"xml:space": "preserve"}}, "sample paragraph text"]},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -39,7 +39,7 @@ describe("Paragraph", () => {
|
|||||||
expect(tree).to.be.an("array").which.includes({
|
expect(tree).to.be.an("array").which.includes({
|
||||||
"w:r": [
|
"w:r": [
|
||||||
{"w:rPr": []},
|
{"w:rPr": []},
|
||||||
{"w:t": ["this is a test run"]},
|
{"w:t": [{_attr: {"xml:space": "preserve"}}, "this is a test run"]},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -144,12 +144,12 @@ describe("Paragraph", () => {
|
|||||||
const tree = new Formatter().format(paragraph);
|
const tree = new Formatter().format(paragraph);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:p": [{
|
"w:p": [{
|
||||||
"w:pPr": [{
|
"w:pPr": [],
|
||||||
"w:r": [
|
},{
|
||||||
{"w:rPr": []},
|
"w:r": [
|
||||||
{"w:br": [{_attr: {"w:type": "page"}}]},
|
{"w:rPr": []},
|
||||||
],
|
{"w:br": [{_attr: {"w:type": "page"}}]},
|
||||||
}],
|
],
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -269,4 +269,24 @@ describe("Paragraph", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#keepLines", () => {
|
||||||
|
it("should set the paragraph keepLines sub-component", () => {
|
||||||
|
paragraph.keepLines();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [{"w:pPr": [{"w:keepLines": []}]}],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#keepNext", () => {
|
||||||
|
it("should set the paragraph keepNext sub-component", () => {
|
||||||
|
paragraph.keepNext();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [{"w:pPr": [{"w:keepNext": []}]}],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,7 @@ describe("Drawing", () => {
|
|||||||
it("should create a Drawing with correct root key", () => {
|
it("should create a Drawing with correct root key", () => {
|
||||||
const newJson = Utility.jsonify(currentBreak);
|
const newJson = Utility.jsonify(currentBreak);
|
||||||
assert.equal(newJson.rootKey, "w:drawing");
|
assert.equal(newJson.rootKey, "w:drawing");
|
||||||
console.log(JSON.stringify(newJson, null, 2));
|
// console.log(JSON.stringify(newJson, null, 2));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
22
ts/tests/docx/run/run-components/text.ts
Normal file
22
ts/tests/docx/run/run-components/text.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
import { Text } from "../../../../docx/run/run-components/text";
|
||||||
|
import { Formatter } from "../../../../export/formatter";
|
||||||
|
|
||||||
|
describe("Text", () => {
|
||||||
|
describe("#constructor", () => {
|
||||||
|
it("creates an empty text run if no text is given", () => {
|
||||||
|
const t = new Text("");
|
||||||
|
const f = new Formatter().format(t);
|
||||||
|
expect(f).to.deep.equal({"w:t": [{_attr: {"xml:space": "preserve"}}]});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adds the passed in text to the component", () => {
|
||||||
|
const t = new Text(" this is\n text");
|
||||||
|
const f = new Formatter().format(t);
|
||||||
|
expect(f).to.deep.equal({"w:t": [
|
||||||
|
{_attr: {"xml:space": "preserve"}},
|
||||||
|
" this is\n text",
|
||||||
|
]});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,6 +1,6 @@
|
|||||||
import { assert } from "chai";
|
import { expect } from "chai";
|
||||||
import { TextRun } from "../../../docx/run/text-run";
|
import { TextRun } from "../../../docx/run/text-run";
|
||||||
import { Utility } from "../../utility";
|
import { Formatter } from "../../../export/formatter";
|
||||||
|
|
||||||
describe("TextRun", () => {
|
describe("TextRun", () => {
|
||||||
let run: TextRun;
|
let run: TextRun;
|
||||||
@ -9,8 +9,11 @@ describe("TextRun", () => {
|
|||||||
|
|
||||||
it("should add text into run", () => {
|
it("should add text into run", () => {
|
||||||
run = new TextRun("test");
|
run = new TextRun("test");
|
||||||
const newJson = Utility.jsonify(run);
|
const f = new Formatter().format(run);
|
||||||
assert.equal(newJson.root[1].root, "test");
|
expect(f).to.deep.equal({"w:r": [
|
||||||
|
{"w:rPr": []},
|
||||||
|
{"w:t": [{_attr: {"xml:space": "preserve"}}, "test"]},
|
||||||
|
]});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* tslint:disable:no-unused-expression */
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { Paragraph } from "../../../docx/paragraph";
|
import { Paragraph } from "../../../docx/paragraph";
|
||||||
import { Table } from "../../../docx/table";
|
import { Table } from "../../../docx/table";
|
||||||
@ -36,7 +37,7 @@ describe("Table", () => {
|
|||||||
{"w:tcPr": []},
|
{"w:tcPr": []},
|
||||||
{"w:p": [
|
{"w:p": [
|
||||||
{"w:pPr": []},
|
{"w:pPr": []},
|
||||||
{"w:r": [{"w:rPr": []}, {"w:t": [c]}]},
|
{"w:r": [{"w:rPr": []}, {"w:t": [{_attr: {"xml:space": "preserve"}}, c]}]},
|
||||||
]},
|
]},
|
||||||
]});
|
]});
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
@ -65,7 +66,7 @@ describe("Table", () => {
|
|||||||
{"w:tcPr": []},
|
{"w:tcPr": []},
|
||||||
{"w:p": [
|
{"w:p": [
|
||||||
{"w:pPr": []},
|
{"w:pPr": []},
|
||||||
{"w:r": [{"w:rPr": []}, {"w:t": [c]}]},
|
{"w:r": [{"w:rPr": []}, {"w:t": [{_attr: {"xml:space": "preserve"}}, c]}]},
|
||||||
]},
|
]},
|
||||||
]});
|
]});
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
@ -153,7 +154,7 @@ describe("Table", () => {
|
|||||||
{"w:tcPr": []},
|
{"w:tcPr": []},
|
||||||
{"w:p": [
|
{"w:p": [
|
||||||
{"w:pPr": []},
|
{"w:pPr": []},
|
||||||
{"w:r": [{"w:rPr": []}, {"w:t": ["Hello"]}]},
|
{"w:r": [{"w:rPr": []}, {"w:t": [{_attr: {"xml:space": "preserve"}}, "Hello"]}]},
|
||||||
]},
|
]},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -175,7 +176,10 @@ describe("Table", () => {
|
|||||||
{"w:tcPr": []},
|
{"w:tcPr": []},
|
||||||
{"w:p": [
|
{"w:p": [
|
||||||
{"w:pPr": []},
|
{"w:pPr": []},
|
||||||
{"w:r": [{"w:rPr": []}, {"w:t": ["Test paragraph"]}]},
|
{"w:r": [
|
||||||
|
{"w:rPr": []},
|
||||||
|
{"w:t": [{_attr: {"xml:space": "preserve"}}, "Test paragraph"]},
|
||||||
|
]},
|
||||||
]},
|
]},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -40,6 +40,10 @@ describe("Formatter", () => {
|
|||||||
});
|
});
|
||||||
let newJson = formatter.format(attributes);
|
let newJson = formatter.format(attributes);
|
||||||
newJson = Utility.jsonify(newJson);
|
newJson = Utility.jsonify(newJson);
|
||||||
|
if (newJson._attr === undefined) {
|
||||||
|
assert.fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
assert.isDefined(newJson._attr["w:rsidSect"]);
|
assert.isDefined(newJson._attr["w:rsidSect"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -49,6 +53,10 @@ describe("Formatter", () => {
|
|||||||
});
|
});
|
||||||
let newJson = formatter.format(attributes);
|
let newJson = formatter.format(attributes);
|
||||||
newJson = Utility.jsonify(newJson);
|
newJson = Utility.jsonify(newJson);
|
||||||
|
if (newJson._attr === undefined) {
|
||||||
|
assert.fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
assert.isDefined(newJson._attr["w:val"]);
|
assert.isDefined(newJson._attr["w:val"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import { expect } from "chai";
|
|||||||
import { Formatter } from "../export/formatter";
|
import { Formatter } from "../export/formatter";
|
||||||
import { Numbering } from "../numbering";
|
import { Numbering } from "../numbering";
|
||||||
import { AbstractNumbering } from "../numbering/abstract-numbering";
|
import { AbstractNumbering } from "../numbering/abstract-numbering";
|
||||||
|
import { LevelForOverride } from "../numbering/level";
|
||||||
import { Num } from "../numbering/num";
|
import { Num } from "../numbering/num";
|
||||||
|
|
||||||
describe("Numbering", () => {
|
describe("Numbering", () => {
|
||||||
@ -221,6 +222,26 @@ describe("AbstractNumbering", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("#keepLines", () => {
|
||||||
|
const abstractNumbering = new AbstractNumbering(1);
|
||||||
|
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.")
|
||||||
|
.keepLines();
|
||||||
|
const tree = new Formatter().format(level);
|
||||||
|
expect(tree["w:lvl"]).to.include({
|
||||||
|
"w:pPr": [{"w:keepLines": []}],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#keepNext", () => {
|
||||||
|
const abstractNumbering = new AbstractNumbering(1);
|
||||||
|
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.")
|
||||||
|
.keepNext();
|
||||||
|
const tree = new Formatter().format(level);
|
||||||
|
expect(tree["w:lvl"]).to.include({
|
||||||
|
"w:pPr": [{"w:keepNext": []}],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("formatting methods: run properties", () => {
|
describe("formatting methods: run properties", () => {
|
||||||
@ -394,3 +415,50 @@ describe("AbstractNumbering", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("concrete numbering", () => {
|
||||||
|
describe("#overrideLevel", () => {
|
||||||
|
let numbering;
|
||||||
|
let abstractNumbering;
|
||||||
|
let concreteNumbering;
|
||||||
|
beforeEach(() => {
|
||||||
|
numbering = new Numbering();
|
||||||
|
abstractNumbering = numbering.createAbstractNumbering();
|
||||||
|
concreteNumbering = numbering.createConcreteNumbering(abstractNumbering);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets a new override level for the given level number", () => {
|
||||||
|
concreteNumbering.overrideLevel(3);
|
||||||
|
const tree = new Formatter().format(concreteNumbering);
|
||||||
|
expect(tree["w:num"]).to.include({"w:lvlOverride": [{_attr: {"w:ilvl": 3}}]});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets the startOverride element if start is given", () => {
|
||||||
|
concreteNumbering.overrideLevel(1, 9);
|
||||||
|
const tree = new Formatter().format(concreteNumbering);
|
||||||
|
expect(tree["w:num"]).to.include({
|
||||||
|
"w:lvlOverride": [
|
||||||
|
{_attr: {"w:ilvl": 1}},
|
||||||
|
{"w:startOverride": [{_attr: {"w:val": 9}}]},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets the lvl element if overrideLevel.level is accessed", () => {
|
||||||
|
const ol = concreteNumbering.overrideLevel(1);
|
||||||
|
expect(ol.level).to.be.instanceof(LevelForOverride);
|
||||||
|
const tree = new Formatter().format(concreteNumbering);
|
||||||
|
expect(tree["w:num"]).to.include({
|
||||||
|
"w:lvlOverride": [
|
||||||
|
{_attr: {"w:ilvl": 1}},
|
||||||
|
{"w:lvl": [
|
||||||
|
{_attr: {"w15:tentative": 1, "w:ilvl": 1}},
|
||||||
|
{"w:pPr": []},
|
||||||
|
{"w:rPr": []},
|
||||||
|
]},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -326,6 +326,32 @@ describe("ParagraphStyle", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("#keepLines", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId")
|
||||||
|
.keepLines();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||||
|
{"w:pPr": [{"w:keepLines": []}]},
|
||||||
|
{"w:rPr": []},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#keepNext", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId")
|
||||||
|
.keepNext();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||||
|
{"w:pPr": [{"w:keepNext": []}]},
|
||||||
|
{"w:rPr": []},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("formatting methods: run properties", () => {
|
describe("formatting methods: run properties", () => {
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
"outDir": "../build",
|
"outDir": "../build",
|
||||||
"sourceRoot": "./",
|
"sourceRoot": "./",
|
||||||
"rootDir": "./",
|
"rootDir": "./",
|
||||||
"module": "commonjs"
|
"module": "commonjs",
|
||||||
|
"declaration": true
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"tests"
|
"tests"
|
||||||
|
Reference in New Issue
Block a user