Merge pull request #30 from felipeochoa/overrides
Add support for numbering level overrides
This commit is contained in:
70
demo/demo2.js
Normal file
70
demo/demo2.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
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');
|
||||||
|
doc.createParagraph('This is normal');
|
||||||
|
|
||||||
|
const exporter = new docx.LocalPacker(doc, styles, undefined, numbering);
|
||||||
|
exporter.pack('test.docx');
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "docx",
|
"name": "docx",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"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/demo.js",
|
||||||
|
"demo2": "npm run build && node ./demo/demo2.js"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"ts",
|
"ts",
|
||||||
|
@ -56,21 +56,29 @@ class LevelJc extends XmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Level extends XmlComponent {
|
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();
|
||||||
@ -198,3 +206,13 @@ export class Level extends XmlComponent {
|
|||||||
return this;
|
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"};
|
||||||
|
}
|
||||||
|
|
||||||
|
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}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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", () => {
|
||||||
@ -394,3 +395,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": []},
|
||||||
|
]},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Reference in New Issue
Block a user