Compare commits

...

19 Commits
4.2.0 ... 4.4.0

Author SHA1 Message Date
f091cff7c9 Version bump 2018-11-07 01:06:59 +00:00
3f80b054fc Merge pull request #178 from dolanmiu/bugfix/correct-toc-instruction
changed comma by semicolon to work in Word 2016.
2018-10-22 03:37:54 +01:00
96d81873d8 forgot to fix the test 2018-10-21 19:56:31 -02:00
c429ae9920 changed comma by semicolon to work in Word 2016. 2018-10-21 19:37:37 -02:00
6b4e769f48 Merge branch 'master' of https://github.com/dolanmiu/docx 2018-10-21 05:16:32 +01:00
b67a9de0e9 Angular README example 2018-10-21 05:14:14 +01:00
ac9f65a068 Merge pull request #177 from dolanmiu/feat/guidelines
Contribution guidelines improve
2018-10-21 04:51:45 +01:00
7e8ebb2af2 Contribution guidelines improve 2018-10-21 04:50:57 +01:00
f53fe2f881 Merge pull request #175 from dolanmiu/feat/sequential-field
Created classes and methods needed to create Sequential Identifiers
2018-10-21 02:00:20 +01:00
6fdd88527a Merge pull request #176 from dolanmiu/bugfix/correct-toc-instruction
fixed TOC instruction that was missing quotes for some switches
2018-10-20 17:36:44 +01:00
b6f431e14d fixed TOC instruction that was missing quotes for some switches 2018-10-20 09:17:37 -03:00
23dee01f06 Created classes and methods needed to create Sequential Identifiers 2018-10-19 16:50:51 -03:00
a466578467 Version bump 2018-10-15 23:34:35 +01:00
3a9420fedf Merge pull request #149 from dolanmiu/feat/grid-span
Feat/grid span
2018-10-15 23:23:20 +01:00
8ac19a83b2 Rename demos 2018-10-15 22:21:40 +01:00
9f0b2f7074 Improve API 2018-10-15 21:54:33 +01:00
a9167b4809 Update demos 2018-09-13 01:54:37 +01:00
f1b176670c Add more table demos 2018-09-12 21:03:06 +01:00
11ce9a5206 Add horizontal span 2018-09-12 21:01:52 +01:00
15 changed files with 329 additions and 17 deletions

View File

@ -29,6 +29,10 @@ Here are examples of `docx` being used with basic `HTML/JS` in a browser environ
* https://codepen.io/anon/pen/dqoVgQ
* https://jsfiddle.net/3xhezb5w/2
Here is an example of `docx` working in `Angular`:
* https://stackblitz.com/edit/angular-afvxtz
## Node
Press `endpoint` on the `RunKit` website:

26
demo/demo31.ts Normal file
View File

@ -0,0 +1,26 @@
// Example of how you would create a table and add data to it
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph, VerticalAlign } from "../build";
const doc = new Document();
const table = doc.createTable(2, 2);
table
.getCell(1, 1)
.addContent(new Paragraph("This text should be in the middle of the cell"))
.CellProperties.setVerticalAlign(VerticalAlign.CENTER);
table
.getCell(1, 0)
.addContent(
new Paragraph(
"Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah",
).heading1(),
);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

35
demo/demo32.ts Normal file
View File

@ -0,0 +1,35 @@
// Example of how you would create a table and add data to it
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph } from "../build";
const doc = new Document();
let table = doc.createTable(2, 2);
table.getCell(0, 0).addContent(new Paragraph("Hello"));
table.getRow(0).mergeCells(0, 1);
doc.createParagraph("Another table").heading2();
table = doc.createTable(2, 3);
table.getCell(0, 0).addContent(new Paragraph("World"));
table.getRow(0).mergeCells(0, 2);
doc.createParagraph("Another table").heading2();
table = doc.createTable(2, 4);
table.getCell(0, 0).addContent(new Paragraph("Foo"));
table.getCell(1, 0).addContent(new Paragraph("Bar1"));
table.getCell(1, 1).addContent(new Paragraph("Bar2"));
table.getCell(1, 2).addContent(new Paragraph("Bar3"));
table.getCell(1, 3).addContent(new Paragraph("Bar4"));
table.getRow(0).mergeCells(0, 3);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

22
demo/demo33.ts Normal file
View File

@ -0,0 +1,22 @@
// Sequential Captions
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph, TextRun } from "../build";
const doc = new Document();
const paragraph = new Paragraph("Hello World 1->").addSequentialIdentifier("Caption").addRun(new TextRun(" text after sequencial caption 2->")).addSequentialIdentifier("Caption");
const paragraph2 = new Paragraph("Hello World 1->").addSequentialIdentifier("Label").addRun(new TextRun(" text after sequencial caption 2->")).addSequentialIdentifier("Label");
const paragraph3 = new Paragraph("Hello World 1->").addSequentialIdentifier("Another").addRun(new TextRun(" text after sequencial caption 3->")).addSequentialIdentifier("Label");
const paragraph4 = new Paragraph("Hello World 2->").addSequentialIdentifier("Another").addRun(new TextRun(" text after sequencial caption 4->")).addSequentialIdentifier("Label");
doc.addParagraph(paragraph);
doc.addParagraph(paragraph2);
doc.addParagraph(paragraph3);
doc.addParagraph(paragraph4);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,5 +1,30 @@
# Contribution Guidelines
## Always think about the user
The number one pillar for contribution is to **ALWAYS** think about how the user will use the library.
Put yourself in their position, and imagine how they would feel about your feature you wrote.
1. Is it easy to use?
2. Has it been documented well?
3. Is it intuative?
4. Is it consistent with the rest of the API?
5. Is it fun to use?
## Good Commit Names
Please write good commit messages when making a commit: https://chris.beams.io/posts/git-commit/
**Do not:**
```
c // What?
rtl // Adding acryonyms without explaining anything else is not helpful
works! // Glad its working, but the message is not helpful
demo updated // Getting better, but capitalize the first letter
Unesesary coment removed // Make sure to use correct spelling
```
## Writing Code
* Include documentation reference(s) at the top of each file:
@ -45,18 +70,98 @@ public get Level() {
There is no performance advantage by doing this. It means we don't need to prefix all private variables with the ugly `_`:
**Do not:**
**Do not:**
```js
private get _level: string;
```
**Do**
**Do**
```js
private get level: string;
```
## Interfaces over type alias
Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a class cannot implement it.
> "In general, use what you want ( type alias / interface ) just be consistent"
> "always use interface for public API's definition when authoring a library or 3rd party ambient type definitions"
>
> * https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c
`Interface` is generally preferred over `type`: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types
**Do not:**
```js
type RelationshipFileInfo = { id: number, target: string };
```
**Do:**
```js
interface IRelationshipFileInfo {
id: number;
target: string;
}
```
## String enums vs type
To take full advantage of TypeScript's typing system, its best to use `string enums`:
**Do not:**
```js
type WeaponType = "bow" | "sword" | "wand";
```
**Do:**
```js
enum WeaponType = {
BOW = "bow",
SWORD = "sword",
WAND = "wand",
}
```
## Spell correctly, full and in American English
I am not sure where these habit in software development comes from, but I do not believe it is beneficial:
**Do not:**
```js
readdy // misspelling
perm // abbreviation
conf // abbreviation
cnty // abbreviation
relationFile // abbreviation
colour // U.K. English
```
**Do:**
```js
ready
permission
config
country
relationshipFile
color
```
## Keep files small (within reason)
To minimize merge conflicts, reduce complexity, and improve readability, keep the files small.
## Name files and folders with `/foo-bar/kebab-case.ts`
To be consistent and in-line with the project, name files `like-this.ts`.
https://stackoverflow.com/questions/7273316/what-is-the-javascript-filename-naming-convention
## Testing
Please write a test of every file you make and suffix it with `.spec.ts`.
@ -78,3 +183,5 @@ describe("ClassName", () => {
});
});
```
Try not to use the `tests/utility.ts` file as this is being deprecated.

View File

@ -1,6 +1,6 @@
{
"name": "docx",
"version": "4.2.0",
"version": "4.4.0",
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
"main": "build/index.js",
"scripts": {

View File

@ -16,7 +16,7 @@ import { CenterTabStop, LeaderType, LeftTabStop, MaxRightTabStop, RightTabStop }
import { NumberProperties } from "./formatting/unordered-list";
import { Bookmark, Hyperlink } from "./links";
import { ParagraphProperties } from "./properties";
import { PictureRun, Run, TextRun } from "./run";
import { PictureRun, Run, SequentialIdentifier, TextRun } from "./run";
export class Paragraph extends XmlComponent {
private readonly properties: ParagraphProperties;
@ -245,4 +245,9 @@ export class Paragraph extends XmlComponent {
this.root.splice(1, 0, run);
return this;
}
public addSequentialIdentifier(identifier: string): Paragraph {
this.root.push(new SequentialIdentifier(identifier));
return this;
}
}

View File

@ -1,3 +1,4 @@
export * from "./run";
export * from "./text-run";
export * from "./picture-run";
export * from "./sequential-identifier";

View File

@ -0,0 +1,19 @@
// http://officeopenxml.com/WPfieldInstructions.php
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
enum SpaceType {
DEFAULT = "default",
PRESERVE = "preserve",
}
class TextAttributes extends XmlAttributeComponent<{ space: SpaceType }> {
protected xmlKeys = { space: "xml:space" };
}
export class SequentialIdentifierInstruction extends XmlComponent {
constructor(identifier: string) {
super("w:instrText");
this.root.push(new TextAttributes({ space: SpaceType.PRESERVE }));
this.root.push(`SEQ ${identifier}`);
}
}

View File

@ -0,0 +1,60 @@
import { expect } from "chai";
import { Formatter } from "../../../export/formatter";
import { SequentialIdentifier } from "./sequential-identifier";
describe("Sequential Identifier", () => {
describe("#constructor", () => {
it("should construct a SEQ without options", () => {
const seq = new SequentialIdentifier("Figure");
const tree = new Formatter().format(seq);
expect(tree).to.be.deep.equal(DEFAULT_SEQ);
});
});
});
const DEFAULT_SEQ = {
"w:r": [
{
"w:rPr": [],
},
{
"w:fldChar": [
{
_attr: {
"w:fldCharType": "begin",
"w:dirty": true,
},
},
],
},
{
"w:instrText": [
{
_attr: {
"xml:space": "preserve",
},
},
"SEQ Figure",
],
},
{
"w:fldChar": [
{
_attr: {
"w:fldCharType": "separate",
},
},
],
},
{
"w:fldChar": [
{
_attr: {
"w:fldCharType": "end",
},
},
],
},
],
};

View File

@ -0,0 +1,13 @@
import { Run } from "file/paragraph/run";
import { Begin, End, Separate } from "file/paragraph/run/field";
import { SequentialIdentifierInstruction } from "./sequential-identifier-instruction";
export class SequentialIdentifier extends Run {
constructor(identifier: string) {
super();
this.root.push(new Begin(true));
this.root.push(new SequentialIdentifierInstruction(identifier));
this.root.push(new Separate());
this.root.push(new End());
}
}

View File

@ -41,22 +41,22 @@ export class FieldInstruction extends XmlComponent {
instruction = `${instruction} \\h`;
}
if (this.properties.tcFieldLevelRange) {
instruction = `${instruction} \\l "${this.properties.tcFieldLevelRange}`;
instruction = `${instruction} \\l "${this.properties.tcFieldLevelRange}"`;
}
if (this.properties.pageNumbersEntryLevelsRange) {
instruction = `${instruction} \\n "${this.properties.pageNumbersEntryLevelsRange}`;
instruction = `${instruction} \\n "${this.properties.pageNumbersEntryLevelsRange}"`;
}
if (this.properties.headingStyleRange) {
instruction = `${instruction} \\o "${this.properties.headingStyleRange}`;
instruction = `${instruction} \\o "${this.properties.headingStyleRange}"`;
}
if (this.properties.entryAndPageNumberSeparator) {
instruction = `${instruction} \\p "${this.properties.entryAndPageNumberSeparator}`;
instruction = `${instruction} \\p "${this.properties.entryAndPageNumberSeparator}"`;
}
if (this.properties.seqFieldIdentifierForPrefix) {
instruction = `${instruction} \\s "${this.properties.seqFieldIdentifierForPrefix}`;
instruction = `${instruction} \\s "${this.properties.seqFieldIdentifierForPrefix}"`;
}
if (this.properties.stylesWithLevels && this.properties.stylesWithLevels.length) {
const styles = this.properties.stylesWithLevels.map((sl) => `${sl.styleName},${sl.level}`).join(",");
const styles = this.properties.stylesWithLevels.map((sl) => `${sl.styleName};${sl.level}`).join(";");
instruction = `${instruction} \\t "${styles}"`;
}
if (this.properties.useAppliedParagraphOutlineLevel) {

View File

@ -174,7 +174,7 @@ const COMPLETE_TOC = {
"xml:space": "preserve",
},
},
'TOC \\a "A" \\b "B" \\c "C" \\d "D" \\f "F" \\h \\l "L \\n "N \\o "O \\p "P \\s "S \\t "SL,1,SL,2" \\u \\w \\x \\z',
'TOC \\a "A" \\b "B" \\c "C" \\d "D" \\f "F" \\h \\l "L" \\n "N" \\o "O" \\p "P" \\s "S" \\t "SL;1;SL;2" \\u \\w \\x \\z',
],
},
{

View File

@ -1,3 +1,4 @@
// http://officeopenxml.com/WPtableGrid.php
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
export class TableGrid extends XmlComponent {

View File

@ -1,3 +1,4 @@
// http://officeopenxml.com/WPtableGrid.php
import {
GridSpan,
TableCellBorders,
@ -60,7 +61,13 @@ export class Table extends XmlComponent {
}
public getRow(ix: number): TableRow {
return this.rows[ix];
const row = this.rows[ix];
if (!row) {
throw Error("Index out of bounds when trying to get row on table");
}
return row;
}
public getCell(row: number, col: number): TableCell {
@ -93,17 +100,29 @@ export class TableRow extends XmlComponent {
}
public getCell(ix: number): TableCell {
return this.cells[ix];
const cell = this.cells[ix];
if (!cell) {
throw Error("Index out of bounds when trying to get cell on row");
}
return cell;
}
public addGridSpan(ix: number, cellSpan: number): TableCell {
const remainCell = this.cells[ix];
public addGridSpan(index: number, cellSpan: number): TableCell {
const remainCell = this.cells[index];
remainCell.CellProperties.addGridSpan(cellSpan);
this.cells.splice(ix + 1, cellSpan - 1);
this.root.splice(ix + 2, cellSpan - 1);
this.cells.splice(index + 1, cellSpan - 1);
this.root.splice(index + 2, cellSpan - 1);
return remainCell;
}
public mergeCells(startIndex: number, endIndex: number): TableCell {
const cellSpan = endIndex - startIndex + 1;
return this.addGridSpan(startIndex, cellSpan);
}
}
export class TableRowProperties extends XmlComponent {