Compare commits

...

57 Commits
2.0.0 ... 2.1.3

Author SHA1 Message Date
5ae02c3342 Merge pull request #43 from jacwright/default-run-styles
Making it easier to work with default styles
2017-09-16 17:48:37 +01:00
258adba94c Version bump 2017-09-16 17:48:15 +01:00
190208d5df Making it easier to work with default styles
Adds the likely common styles, font and size, to be defined in defaults.
2017-09-16 08:24:15 -06:00
32cda4dfb3 Merge pull request #42 from jacwright/patch-1-test
Fix tests
2017-09-15 16:09:18 +01:00
b2c3dd2f7b Fix tests 2017-09-15 09:05:28 -06:00
58eca3ff5b Merge pull request #41 from jacwright/patch-1
Fix page/thematic breaks
2017-09-15 15:57:22 +01:00
d5c04f9042 Pin typescript to 2.4.1 2017-09-15 15:56:21 +01:00
67ea7c95de Just pagebreak, update test 2017-09-15 08:37:57 -06:00
e57fd8fc57 Fix page/thematic breaks
These items are not paragraph properties, but part of the content of the paragraph.
2017-09-15 08:25:43 -06:00
411c0dadb5 Add table demo 2017-07-29 01:58:29 +01:00
ee81f3c502 Version bump 2017-07-29 01:26:34 +01:00
8263b93c36 Add third demo 2017-07-29 01:26:04 +01:00
be709d082c Export formatting from paragraph folder 2017-07-29 01:15:33 +01:00
70c4e89a65 Version bump 2017-07-08 21:37:02 +01:00
8f632d4ecd Made XmlableObject non ambient typings to fix typescript problem 2017-07-08 20:45:19 +01:00
6784dc1f3d Updated archiver types 2017-07-08 01:24:25 +01:00
fd63a30298 Updated definitions 2017-07-07 16:51:22 +01:00
b0a29e26c9 Version bump 2017-07-07 14:36:34 +01:00
8826fb010d Added types to package json 2017-07-07 14:34:03 +01:00
97101adb10 Enabled declarations in tsconfig to be true 2017-07-07 14:31:08 +01:00
2ec171d4a8 Used my updated typings for archiver 1.3 2017-05-09 18:03:31 +01:00
8876bb1fea updated readme about demos 2017-04-17 19:53:53 +01:00
96ca9d9c23 commented out the rm 2017-04-17 16:36:56 +01:00
74a65f02fa remove exit code 2017-04-17 16:07:28 +01:00
339c017940 edited rm function 2017-04-17 15:41:03 +01:00
969b52ae05 added nojekyll to gh-pages 2017-04-17 13:24:43 +01:00
eb8f0f4033 added debugging to deployment 2017-04-17 13:05:02 +01:00
d7229eb049 removed rimraf 2017-04-16 12:41:24 +01:00
644819ed81 added deployment keys and scripts 2017-04-16 12:22:50 +01:00
96fd61d3e4 using stable version of node 2017-04-16 02:25:44 +01:00
b96cfe7b19 git fetch added 2017-04-16 01:29:29 +01:00
d0e7c97a88 added commit message with merge with gh pages 2017-04-16 01:18:22 +01:00
0ede54cfdc added travis doc deployment solution 2017-04-16 01:12:42 +01:00
5be1163549 remove docs in gitignore 2017-04-16 01:07:11 +01:00
580f6eb633 fixed tests 2017-04-16 00:44:35 +01:00
321be35918 added docs in gitignore 2017-04-16 00:30:27 +01:00
45a18742d7 moved documentation to gh-pages branch 2017-04-16 00:22:29 +01:00
7e81da404a updated readme 2017-04-16 00:09:07 +01:00
6c2abb4abc added typedoc generated docs 2017-04-16 00:07:16 +01:00
e8b0dbf93b added docs ignore to npmignore file 2017-04-16 00:04:29 +01:00
e59c255d85 added type to pack param 2017-04-15 23:45:27 +01:00
17b28cb724 fixed more linting issues 2017-04-15 20:11:54 +01:00
410152441b fixed tslinting issues 2017-04-15 17:54:47 +01:00
dfff4b96bd updated tslint to 5.1.0 2017-04-15 17:47:29 +01:00
72cb75a486 added comma 2017-04-15 17:46:56 +01:00
53fe1dd988 added typedoc support for generating documentation 2017-04-15 17:46:11 +01:00
043219f005 Merge pull request #32 from felipeochoa/keep-lines
add keepLines and keepNext support for paragraph formatting
2017-04-15 17:41:11 +01:00
0453f28951 add keepLines and keepNext support for paragraph formatting
This commit adds it to the three places where paragraph formatting can
be applied right now (directly on the paragraph, paragraph styles, and
bullets/numbering styles). I'm separately adding an entry to the wiki
regarding what these methods do (widow/orphan control)
2017-04-14 21:13:11 +02:00
94716e081b Merge pull request #31 from felipeochoa/spacing-bugfix
Spacing bugfix
2017-04-14 17:30:54 +01:00
30f826fd3d made a mini app which you can select the demo you want from a list with an interactive prompt. 2017-04-14 15:48:12 +01:00
99b7a03b8a update demo2 to test space preservation 2017-04-14 11:09:08 +02:00
b1c8b2beb8 add xml:space="preserve" to text runs
In MS Word 2015 (and possibly others), leading and trailing spaces are
ignored in text runs. This means that calling TextRun with
leading/trailing space would result in a document that didn't include
those spaces. The fix here (per http://officeopenxml.com/WPtext.php)
is to include an extra attribute on the "w:t" element that forces word
to recognize those spaces.
2017-04-14 11:08:19 +02:00
a706455a7c Merge pull request #30 from felipeochoa/overrides
Add support for numbering level overrides
2017-04-12 18:34:07 +01:00
8c388a95c4 bump patch version 2017-04-12 16:01:26 +02:00
9a41d78ecb add an additional demo 2017-04-12 16:00:16 +02:00
6fc4ad782a add #overrideLevel method to concrete numberings 2017-04-12 16:00:16 +02:00
16b9057ac6 prepare Level to be extended for overrides 2017-04-12 15:57:26 +02:00
53 changed files with 618 additions and 92 deletions

View File

@ -38,3 +38,6 @@ build-tests
# vscode # vscode
.vscode .vscode
# docs
docs

View File

@ -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"

View File

@ -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
View 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
View 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
View 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
View 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
View 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

Binary file not shown.

View File

@ -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"
} }
} }

View File

@ -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;

View File

@ -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";

View File

@ -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}));
} }

View File

@ -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";

View File

@ -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
View 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");
}
}

View File

@ -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,

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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");

View File

@ -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");

View File

@ -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");
} }

View File

@ -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}));
} }

View File

@ -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;

View File

@ -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;
} }

View File

@ -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];

View File

@ -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";

View File

@ -0,0 +1,3 @@
export interface IXmlableObject extends Object {
_attr?: { [key: string]: (string | number | boolean) };
}

View File

@ -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();
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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,
}); });

View File

@ -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 {}

View File

@ -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}));
}
} }

View File

@ -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();

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
} }
} }

View File

@ -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));

View File

@ -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);

View File

@ -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",

View File

@ -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 {

View File

@ -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"]},
], ],
}); });
}); });

View File

@ -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": []}]}],
});
});
});
}); });

View File

@ -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));
}); });
}); });
}); });

View 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",
]});
});
});
});

View File

@ -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"]},
]});
}); });
}); });
}); });

View File

@ -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"]},
]},
]}, ]},
], ],
}); });

View File

@ -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"]);
}); });

View File

@ -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": []},
]},
],
});
});
});
});

View File

@ -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", () => {

View File

@ -8,7 +8,8 @@
"outDir": "../build", "outDir": "../build",
"sourceRoot": "./", "sourceRoot": "./",
"rootDir": "./", "rootDir": "./",
"module": "commonjs" "module": "commonjs",
"declaration": true
}, },
"exclude": [ "exclude": [
"tests" "tests"