Merge pull request #421 from dolanmiu/feat/declaritive-styles-and-tab-stop
Declaritive styles and multiple tab stops
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
// Generate a CV
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { AlignmentType, Document, HeadingLevel, Packer, Paragraph, TextRun } from "../build";
|
||||
import { AlignmentType, Document, HeadingLevel, Packer, Paragraph, TabStopPosition, TabStopType, TextRun } from "../build";
|
||||
|
||||
// tslint:disable:no-shadowed-variable
|
||||
|
||||
@ -226,9 +226,12 @@ class DocumentCreator {
|
||||
|
||||
public createInstitutionHeader(institutionName: string, dateText: string): Paragraph {
|
||||
return new Paragraph({
|
||||
tabStop: {
|
||||
maxRight: {},
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
position: TabStopPosition.MAX,
|
||||
},
|
||||
],
|
||||
children: [
|
||||
new TextRun({
|
||||
text: institutionName,
|
||||
|
@ -1,82 +1,153 @@
|
||||
// Setting styles with JavaScript configuration
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { AlignmentType, Document, Footer, HeadingLevel, Media, Packer, Paragraph, Table, TableCell, TableRow } from "../build";
|
||||
import {
|
||||
AlignmentType,
|
||||
Document,
|
||||
Footer,
|
||||
HeadingLevel,
|
||||
Media,
|
||||
Packer,
|
||||
Paragraph,
|
||||
Table,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TabStopPosition,
|
||||
UnderlineType,
|
||||
} from "../build";
|
||||
|
||||
const doc = new Document();
|
||||
|
||||
doc.Styles.createParagraphStyle("Heading1", "Heading 1")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.quickFormat()
|
||||
.font("Calibri")
|
||||
.size(52)
|
||||
.center()
|
||||
.bold()
|
||||
.color("000000")
|
||||
.spacing({ line: 340 })
|
||||
.underline("single", "000000");
|
||||
|
||||
doc.Styles.createParagraphStyle("Heading2", "Heading 2")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.font("Calibri")
|
||||
.quickFormat()
|
||||
.size(26)
|
||||
.bold()
|
||||
.spacing({ line: 340 });
|
||||
|
||||
doc.Styles.createParagraphStyle("Heading3", "Heading 3")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.font("Calibri")
|
||||
.quickFormat()
|
||||
.size(26)
|
||||
.bold()
|
||||
.spacing({ line: 276 });
|
||||
|
||||
doc.Styles.createParagraphStyle("Heading4", "Heading 4")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.justified()
|
||||
.font("Calibri")
|
||||
.size(26)
|
||||
.bold();
|
||||
|
||||
doc.Styles.createParagraphStyle("normalPara", "Normal Para")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.font("Calibri")
|
||||
.quickFormat()
|
||||
.leftTabStop(453.543307087)
|
||||
.maxRightTabStop()
|
||||
.size(26)
|
||||
.spacing({ line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 });
|
||||
|
||||
doc.Styles.createParagraphStyle("normalPara2", "Normal Para2")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.quickFormat()
|
||||
.font("Calibri")
|
||||
.size(26)
|
||||
.justified()
|
||||
.spacing({ line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 });
|
||||
|
||||
doc.Styles.createParagraphStyle("aside", "Aside")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.color("999999")
|
||||
.italics()
|
||||
.indent({ left: 720 })
|
||||
.spacing({ line: 276 });
|
||||
|
||||
doc.Styles.createParagraphStyle("wellSpaced", "Well Spaced")
|
||||
.basedOn("Normal")
|
||||
.spacing({ line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 });
|
||||
|
||||
doc.Styles.createParagraphStyle("ListParagraph", "List Paragraph")
|
||||
.quickFormat()
|
||||
.basedOn("Normal");
|
||||
const doc = new Document({
|
||||
styles: {
|
||||
paragraphStyles: [
|
||||
{
|
||||
id: "Heading1",
|
||||
name: "Heading 1",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
font: "Calibri",
|
||||
size: 52,
|
||||
bold: true,
|
||||
color: "000000",
|
||||
underline: {
|
||||
type: UnderlineType.SINGLE,
|
||||
color: "000000",
|
||||
},
|
||||
},
|
||||
paragraph: {
|
||||
alignment: AlignmentType.CENTER,
|
||||
spacing: { line: 340 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "Heading2",
|
||||
name: "Heading 2",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
font: "Calibri",
|
||||
size: 26,
|
||||
bold: true,
|
||||
},
|
||||
paragraph: {
|
||||
spacing: { line: 340 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "Heading3",
|
||||
name: "Heading 3",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
font: "Calibri",
|
||||
size: 26,
|
||||
bold: true,
|
||||
},
|
||||
paragraph: {
|
||||
spacing: { line: 276 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "Heading4",
|
||||
name: "Heading 4",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
font: "Calibri",
|
||||
size: 26,
|
||||
bold: true,
|
||||
},
|
||||
paragraph: {
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "normalPara",
|
||||
name: "Normal Para",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
font: "Calibri",
|
||||
size: 26,
|
||||
bold: true,
|
||||
},
|
||||
paragraph: {
|
||||
spacing: { line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 },
|
||||
rightTabStop: TabStopPosition.MAX,
|
||||
leftTabStop: 453.543307087,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "normalPara2",
|
||||
name: "Normal Para2",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
font: "Calibri",
|
||||
size: 26,
|
||||
},
|
||||
paragraph: {
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
spacing: { line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "aside",
|
||||
name: "Aside",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
run: {
|
||||
color: "999999",
|
||||
italics: true,
|
||||
},
|
||||
paragraph: {
|
||||
spacing: { line: 276 },
|
||||
indent: { left: 720 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "wellSpaced",
|
||||
name: "Well Spaced",
|
||||
basedOn: "Normal",
|
||||
paragraph: {
|
||||
spacing: { line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "ListParagraph",
|
||||
name: "List Paragraph",
|
||||
basedOn: "Normal",
|
||||
quickFormat: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const image = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Page numbers
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { AlignmentType, Document, Header, Packer, Paragraph, TextRun } from "../build";
|
||||
import { AlignmentType, Document, Header, Packer, PageBreak, Paragraph, TextRun } from "../build";
|
||||
|
||||
const doc = new Document();
|
||||
|
||||
@ -26,8 +26,8 @@ doc.addSection({
|
||||
},
|
||||
children: [
|
||||
new Paragraph({
|
||||
text: "First Page",
|
||||
}).pageBreak(),
|
||||
children: [new TextRun("First Page"), new PageBreak()],
|
||||
}),
|
||||
new Paragraph("Second Page"),
|
||||
],
|
||||
});
|
||||
|
@ -6,7 +6,7 @@ import { Document, Footer, Header, Packer, PageNumberFormat, PageOrientation, Pa
|
||||
const doc = new Document();
|
||||
|
||||
doc.addSection({
|
||||
children: [new Paragraph("Hello World").pageBreak()],
|
||||
children: [new Paragraph("Hello World")],
|
||||
});
|
||||
|
||||
doc.addSection({
|
||||
|
@ -1,48 +1,89 @@
|
||||
// Example on how to customise the look at feel using Styles
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Document, HeadingLevel, Packer, Paragraph, TextRun } from "../build";
|
||||
import { Document, HeadingLevel, Packer, Paragraph, TextRun, UnderlineType } from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
creator: "Clippy",
|
||||
title: "Sample Document",
|
||||
description: "A brief example of using docx",
|
||||
styles: {
|
||||
paragraphStyles: [
|
||||
{
|
||||
id: "Heading1",
|
||||
name: "Heading 1",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
size: 28,
|
||||
bold: true,
|
||||
italics: true,
|
||||
},
|
||||
paragraph: {
|
||||
spacing: {
|
||||
after: 120,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "Heading2",
|
||||
name: "Heading 2",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
size: 26,
|
||||
bold: true,
|
||||
underline: {
|
||||
type: UnderlineType.DOUBLE,
|
||||
color: "FF0000",
|
||||
},
|
||||
},
|
||||
paragraph: {
|
||||
spacing: {
|
||||
before: 240,
|
||||
after: 120,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "aside",
|
||||
name: "Aside",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
run: {
|
||||
color: "999999",
|
||||
italics: true,
|
||||
},
|
||||
paragraph: {
|
||||
indent: {
|
||||
left: 720,
|
||||
},
|
||||
spacing: {
|
||||
line: 276,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "wellSpaced",
|
||||
name: "Well Spaced",
|
||||
basedOn: "Normal",
|
||||
quickFormat: true,
|
||||
paragraph: {
|
||||
spacing: { line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "ListParagraph",
|
||||
name: "List Paragraph",
|
||||
basedOn: "Normal",
|
||||
quickFormat: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
doc.Styles.createParagraphStyle("Heading1", "Heading 1")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.quickFormat()
|
||||
.size(28)
|
||||
.bold()
|
||||
.italics()
|
||||
.spacing({ after: 120 });
|
||||
|
||||
doc.Styles.createParagraphStyle("Heading2", "Heading 2")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.quickFormat()
|
||||
.size(26)
|
||||
.bold()
|
||||
.underline("double", "FF0000")
|
||||
.spacing({ before: 240, after: 120 });
|
||||
|
||||
doc.Styles.createParagraphStyle("aside", "Aside")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.color("999999")
|
||||
.italics()
|
||||
.indent({ left: 720 })
|
||||
.spacing({ line: 276 });
|
||||
|
||||
doc.Styles.createParagraphStyle("wellSpaced", "Well Spaced")
|
||||
.basedOn("Normal")
|
||||
.spacing({ line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 });
|
||||
|
||||
doc.Styles.createParagraphStyle("ListParagraph", "List Paragraph")
|
||||
.quickFormat()
|
||||
.basedOn("Normal");
|
||||
|
||||
const numberedAbstract = doc.Numbering.createAbstractNumbering();
|
||||
numberedAbstract.createLevel(0, "lowerLetter", "%1)", "left");
|
||||
|
||||
@ -82,14 +123,16 @@ doc.addSection({
|
||||
level: 0,
|
||||
},
|
||||
}),
|
||||
new Paragraph({}).addRun(
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Some monospaced content",
|
||||
font: {
|
||||
name: "Monospace",
|
||||
},
|
||||
}),
|
||||
),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
text: "An aside, in light gray italics and indented",
|
||||
style: "aside",
|
||||
|
@ -1,7 +1,7 @@
|
||||
// This demo shows how to create bookmarks then link to them with internal hyperlinks
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Document, HeadingLevel, Packer, Paragraph } from "../build";
|
||||
import { Document, HeadingLevel, Packer, PageBreak, Paragraph } from "../build";
|
||||
|
||||
const LOREM_IPSUM =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mi velit, convallis convallis scelerisque nec, faucibus nec leo. Phasellus at posuere mauris, tempus dignissim velit. Integer et tortor dolor. Duis auctor efficitur mattis. Vivamus ut metus accumsan tellus auctor sollicitudin venenatis et nibh. Cras quis massa ac metus fringilla venenatis. Proin rutrum mauris purus, ut suscipit magna consectetur id. Integer consectetur sollicitudin ante, vitae faucibus neque efficitur in. Praesent ultricies nibh lectus. Mauris pharetra id odio eget iaculis. Duis dictum, risus id pellentesque rutrum, lorem quam malesuada massa, quis ullamcorper turpis urna a diam. Cras vulputate metus vel massa porta ullamcorper. Etiam porta condimentum nulla nec tristique. Sed nulla urna, pharetra non tortor sed, sollicitudin molestie diam. Maecenas enim leo, feugiat eget vehicula id, sollicitudin vitae ante.";
|
||||
@ -22,11 +22,16 @@ doc.addSection({
|
||||
children: [
|
||||
new Paragraph({
|
||||
heading: HeadingLevel.HEADING_1,
|
||||
}).addBookmark(bookmark),
|
||||
children: [bookmark],
|
||||
}),
|
||||
new Paragraph("\n"),
|
||||
new Paragraph(LOREM_IPSUM),
|
||||
new Paragraph({}).pageBreak(),
|
||||
new Paragraph({}).addHyperLink(hyperlink),
|
||||
new Paragraph({
|
||||
children: [new PageBreak()],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [hyperlink],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -1,28 +1,53 @@
|
||||
// Custom styles using JavaScript configuration
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Document, HeadingLevel, Packer, Paragraph } from "../build";
|
||||
import { Document, HeadingLevel, Packer, Paragraph, UnderlineType } from "../build";
|
||||
|
||||
const doc = new Document();
|
||||
|
||||
// The first argument is an ID you use to apply the style to paragraphs
|
||||
// The second argument is a human-friendly name to show in the UI
|
||||
doc.Styles.createParagraphStyle("myWonkyStyle", "My Wonky Style")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.color("990000")
|
||||
.italics()
|
||||
.indent({ left: 720 }) // 720 TWIP === 720 / 20 pt === .5 in
|
||||
.spacing({ line: 276 }); // 276 / 240 = 1.15x line spacing
|
||||
|
||||
doc.Styles.createParagraphStyle("Heading2", "Heading 2")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.quickFormat()
|
||||
.size(26) // 26 half-points === 13pt font
|
||||
.bold()
|
||||
.underline("double", "FF0000")
|
||||
.spacing({ before: 240, after: 120 }); // TWIP for both
|
||||
const doc = new Document({
|
||||
styles: {
|
||||
paragraphStyles: [
|
||||
{
|
||||
id: "myWonkyStyle",
|
||||
name: "My Wonky Style",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
run: {
|
||||
color: "990000",
|
||||
italics: true,
|
||||
},
|
||||
paragraph: {
|
||||
indent: {
|
||||
left: 720,
|
||||
},
|
||||
spacing: {
|
||||
line: 276,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "Heading2",
|
||||
name: "Heading 2",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
bold: true,
|
||||
size: 26,
|
||||
underline: {
|
||||
type: UnderlineType.DOUBLE,
|
||||
color: "FF0000",
|
||||
},
|
||||
},
|
||||
paragraph: {
|
||||
spacing: {
|
||||
before: 240,
|
||||
after: 120,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
doc.addSection({
|
||||
children: [
|
||||
|
@ -3,15 +3,23 @@
|
||||
import * as fs from "fs";
|
||||
import { File, HeadingLevel, Packer, Paragraph, StyleLevel, TableOfContents } from "../build";
|
||||
|
||||
const doc = new File();
|
||||
|
||||
// The first argument is an ID you use to apply the style to paragraphs
|
||||
// The second argument is a human-friendly name to show in the UI
|
||||
doc.Styles.createParagraphStyle("MySpectacularStyle", "My Spectacular Style")
|
||||
.basedOn("Heading1")
|
||||
.next("Heading1")
|
||||
.color("990000")
|
||||
.italics();
|
||||
const doc = new File({
|
||||
styles: {
|
||||
paragraphStyles: [
|
||||
{
|
||||
id: "MySpectacularStyle",
|
||||
name: "My Spectacular Style",
|
||||
basedOn: "Heading1",
|
||||
next: "Heading1",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
italics: true,
|
||||
color: "990000",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// WordprocessingML docs for TableOfContents can be found here:
|
||||
// http://officeopenxml.com/WPtableOfContents.php
|
||||
|
@ -1,28 +1,44 @@
|
||||
// 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";
|
||||
import { Document, Packer, Paragraph, SequentialIdentifier, TextRun } from "../build";
|
||||
|
||||
const doc = new Document();
|
||||
|
||||
doc.addSection({
|
||||
children: [
|
||||
new Paragraph("Hello World 1->")
|
||||
.addSequentialIdentifier("Caption")
|
||||
.addRun(new TextRun(" text after sequencial caption 2->"))
|
||||
.addSequentialIdentifier("Caption"),
|
||||
new Paragraph("Hello World 1->")
|
||||
.addSequentialIdentifier("Label")
|
||||
.addRun(new TextRun(" text after sequencial caption 2->"))
|
||||
.addSequentialIdentifier("Label"),
|
||||
new Paragraph("Hello World 1->")
|
||||
.addSequentialIdentifier("Another")
|
||||
.addRun(new TextRun(" text after sequencial caption 3->"))
|
||||
.addSequentialIdentifier("Label"),
|
||||
new Paragraph("Hello World 2->")
|
||||
.addSequentialIdentifier("Another")
|
||||
.addRun(new TextRun(" text after sequencial caption 4->"))
|
||||
.addSequentialIdentifier("Label"),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun("Hello World 1->"),
|
||||
new SequentialIdentifier("Caption"),
|
||||
new TextRun(" text after sequencial caption 2->"),
|
||||
new SequentialIdentifier("Caption"),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun("Hello World 1->"),
|
||||
new SequentialIdentifier("Label"),
|
||||
new TextRun(" text after sequencial caption 2->"),
|
||||
new SequentialIdentifier("Label"),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun("Hello World 1->"),
|
||||
new SequentialIdentifier("Another"),
|
||||
new TextRun(" text after sequencial caption 3->"),
|
||||
new SequentialIdentifier("Label"),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun("Hello World 2->"),
|
||||
new SequentialIdentifier("Another"),
|
||||
new TextRun(" text after sequencial caption 4->"),
|
||||
new SequentialIdentifier("Label"),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -4,12 +4,14 @@ import * as fs from "fs";
|
||||
import { Document, Packer, Paragraph } from "../build";
|
||||
|
||||
const doc = new Document();
|
||||
const paragraph = new Paragraph({});
|
||||
const link = doc.createHyperlink("http://www.example.com", "Hyperlink");
|
||||
|
||||
paragraph.addHyperLink(link);
|
||||
doc.addSection({
|
||||
children: [paragraph],
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [link],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
|
@ -1,18 +1,26 @@
|
||||
// Multiple sections with total number of pages in each section
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Document, Packer, PageNumberFormat, TextRun } from "../build";
|
||||
import { AlignmentType, Document, Packer, PageNumberFormat, TextRun, Header, Paragraph, Footer, PageBreak } from "../build";
|
||||
|
||||
const doc = new Document();
|
||||
|
||||
const header = new Header({
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun("Header on another page"),
|
||||
new TextRun("Page Number: ").pageNumber(),
|
||||
new TextRun(" to ").numberOfTotalPagesSection(),
|
||||
],
|
||||
alignment: AlignmentType.CENTER,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const header = doc.createHeader();
|
||||
header.createParagraph("Header on another page");
|
||||
const footer = doc.createFooter();
|
||||
footer.createParagraph("Foo Bar corp. ")
|
||||
.center()
|
||||
.addRun(new TextRun("Page Number: ").pageNumber())
|
||||
.addRun(new TextRun(" to ").numberOfTotalPagesSection());
|
||||
const footer = new Footer({
|
||||
children: [new Paragraph("Foo Bar corp. ")],
|
||||
});
|
||||
|
||||
doc.addSection({
|
||||
headers: {
|
||||
@ -21,13 +29,17 @@ doc.addSection({
|
||||
footers: {
|
||||
default: footer,
|
||||
},
|
||||
properties: {
|
||||
pageNumberStart: 1,
|
||||
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
||||
},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [new TextRun("Section 1"), new PageBreak(), new TextRun("Section 1"), new PageBreak()],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
doc.createParagraph("Section 1").pageBreak();
|
||||
doc.createParagraph("Section 1").pageBreak();
|
||||
|
||||
doc.addSection({
|
||||
headers: {
|
||||
default: header,
|
||||
@ -35,15 +47,17 @@ doc.addSection({
|
||||
footers: {
|
||||
default: footer,
|
||||
},
|
||||
properties: {
|
||||
pageNumberStart: 1,
|
||||
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
||||
},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [new TextRun("Section 2"), new PageBreak(), new TextRun("Section 2"), new PageBreak()],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
doc.createParagraph("Section 2").pageBreak();
|
||||
doc.createParagraph("Section 2").pageBreak();
|
||||
|
||||
const packer = new Packer();
|
||||
|
||||
packer.toBuffer(doc).then((buffer) => {
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
||||
|
@ -248,10 +248,15 @@ The above example will create a heading with a page break directly under it.
|
||||
|
||||
## Page Break
|
||||
|
||||
To move to a new page (insert a page break), simply add `.pageBreak()` on a paragraph:
|
||||
To move to a new page (insert a page break):
|
||||
|
||||
```ts
|
||||
const paragraph = new docx.Paragraph("Amazing Heading").pageBreak();
|
||||
const paragraph = new docx.Paragraph({
|
||||
children: [
|
||||
new TextRun("Amazing Heading"),
|
||||
new PageBreak(),
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
The above example will create a heading and start a new page immediately afterwards.
|
||||
|
@ -3,111 +3,146 @@
|
||||
## Example
|
||||
|
||||
```ts
|
||||
const para = new Paragraph("To whom it may concern:").heading2().center();
|
||||
const para = new Paragraph({
|
||||
text: "To whom it may concern:",
|
||||
heading: HeadingLevel.HEADING_2,
|
||||
alignment: AlignmentType.CENTER,
|
||||
});
|
||||
|
||||
const name = new TextRun("Name:")
|
||||
.bold()
|
||||
.font("Calibri")
|
||||
.allCaps();
|
||||
const name = new TextRun({
|
||||
text: "Name:",
|
||||
bold: true,
|
||||
font: "Calibri",
|
||||
allCaps: true,
|
||||
});
|
||||
```
|
||||
|
||||
## Available methods
|
||||
## Available Options
|
||||
|
||||
* For run formatting:
|
||||
* `.bold()`, `.italics()`, `.smallCaps()`, `.allCaps()`, `.strike()`, `.doubleStrike()`, `.subScript()`, `.superScript()`: Set the formatting property to true
|
||||
* `.underline(style="single", color=null)`: Set the underline style and color
|
||||
* `.color(color)`: Set the text color, using 6 hex characters for RRGGBB (no leading `#`)
|
||||
* `.size(halfPts)`: Set the font size, measured in half-points
|
||||
* `.font(name)`: Set the run's font
|
||||
* `.style(name)`: Apply a named run style
|
||||
* `.characterSpacing(value)`: Set the character spacing adjustment (in TWIPs)
|
||||
* For paragraph formatting:
|
||||
* `.heading1()`, `.heading2()`, `.heading3()`, `.heading4()`, `.heading5()`, `.title()`: apply the appropriate style to the paragraph
|
||||
* `.left()`, `.center()`, `.right()`, `.justified()`: set the paragraph's alignment
|
||||
* `.thematicBreak()`, `.pageBreak()`: Insert a thick rule or a page break beneath the paragraph
|
||||
* `.leftTabStop(position)`: Add a left tab stop (measured in TWIPs from the left)
|
||||
* `.maxRightTabStop()`: Add a right tab stop at the far right
|
||||
* `.bullet()`: Use the default bullet style
|
||||
* `.setNumbering(numbering, indentLevel)`: Use a custom numbering format for the paragraph
|
||||
* `.style(name)`: Apply a named paragraph style
|
||||
* `.indent(start, hanging=0)`: Set the paragraph's indent level (in TWIPs)
|
||||
* `.spacing({before=0, after=0, line=0})`: Set the line and before/after on the paragraph. Before/after is measured in TWIPs, line is measured in 240ths of a line
|
||||
### Run formatting
|
||||
|
||||
Paragraph styles have all the run formatting methods, except `style()`, and `.left()`, `.center()`, `.right()`, `.justified()`, `.thematicBreak()`, `.leftTabStop(position)`, `.maxRightTabStop()`, `.indent(start, hanging=0)`, and `.spacing({before=0, after=0, line=0})` methods.
|
||||
- `bold`, `italics`, `smallCaps`, `allCaps`, `strike`, `doubleStrike`, `subScript`, `superScript`: Set the formatting property to true
|
||||
- `underline(style="single", color=null)`: Set the underline style and color
|
||||
- `color(color)`: Set the text color, using 6 hex characters for RRGGBB (no leading `#`)
|
||||
- `size(halfPts)`: Set the font size, measured in half-points
|
||||
- `font(name)`: Set the run's font
|
||||
- `style(name)`: Apply a named run style
|
||||
- `characterSpacing(value)`: Set the character spacing adjustment (in TWIPs)
|
||||
|
||||
### Paragraph formatting
|
||||
|
||||
- `heading1`, `heading2`, `heading3`, `heading4`, `heading5`, `title`: apply the appropriate style to the paragraph
|
||||
- `left`, `center`, `right`, `justified`: set the paragraph's alignment
|
||||
- `thematicBreak`, `pageBreak`: Insert a thick rule or a page break beneath the paragraph
|
||||
- `leftTabStop(position)`: Add a left tab stop (measured in TWIPs from the left)
|
||||
- `maxRightTabStop`: Add a right tab stop at the far right
|
||||
- `bullet`: Use the default bullet style
|
||||
- `setNumbering(numbering, indentLevel)`: Use a custom numbering format for the paragraph
|
||||
- `style(name)`: Apply a named paragraph style
|
||||
- `indent(start, hanging=0)`: Set the paragraph's indent level (in TWIPs)
|
||||
- `spacing({before=0, after=0, line=0})`: Set the line and before/after on the paragraph. Before/after is measured in TWIPs, line is measured in 240ths of a line
|
||||
|
||||
Paragraph styles have all the run formatting methods, except `style()`, and `left()`, `center()`, `right()`, `justified()`, `thematicBreak()`, `leftTabStop(position)`, `maxRightTabStop()`, `indent(start, hanging=0)`, and `spacing({before=0, after=0, line=0})` methods.
|
||||
|
||||
## Detailed guide
|
||||
|
||||
There are 4 items in DOCX that can be styled:
|
||||
There are 4 items in `docx` that can be styled:
|
||||
|
||||
* Characters: Attributes that can change within a paragraph. e.g., bold, italics, etc.
|
||||
* Paragraphs: Attributes like indent, text alignment, line spacing, etc.
|
||||
* Tables: Border styles, table formats, etc.
|
||||
* List items: These are the numbers and bullets that are automatically inserted
|
||||
- Characters: Attributes that can change within a paragraph. e.g., bold, italics, etc.
|
||||
- Paragraphs: Attributes like indent, text alignment, line spacing, etc.
|
||||
- Tables: Border styles, table formats, etc.
|
||||
- List items: These are the numbers and bullets that are automatically inserted
|
||||
|
||||
There are a few different ways of styling this content in DOCX, which somewhat resemble the HTML/CSS approach. In order of greatest to lowest priority:
|
||||
There are a few different ways of styling this content in `docx`, which somewhat resemble the HTML/CSS approach. In order of greatest to lowest priority:
|
||||
|
||||
1. Direct formatting (AKA inline formatting)
|
||||
2. Centrally defined styles (similar to external CSS)
|
||||
1. Direct formatting (inline formatting)
|
||||
2. Declaritive Styles (similar to external CSS)
|
||||
3. Document defaults (similar to a `*` rule in CSS)
|
||||
|
||||
Unlike CSS, less specific rules don't _necessarily_ override parent rules. The rules are a bit wonky, but if you're interested, see the [advanced formatting section](#Advanced formatting).
|
||||
|
||||
### Direct formatting (AKA inline formatting)
|
||||
### Direct formatting (inline formatting)
|
||||
|
||||
This is the type of formatting that your uncle uses when he types out documents: _N ... a ... m ... e ... :_ Then he grabs the mouse, highlights _Name:_ and moves over to the **B** for bold. This manner of formatting results in markup that is similar to writing `<span style="bold: true">Name:</span>` if you were typing out HTML. DOCX (the format) allows you to specify this for any of the four types of items. `docx` (the library) only supports this type of formatting for paragraphs and characters, using a _fluent_ api. Thus you could do:
|
||||
This is the type of formatting that your uncle uses when he types out documents: _N ... a ... m ... e ... :_ Then he grabs the mouse, highlights _Name:_ and moves over to the **B** for bold. This manner of formatting results in markup that is similar to writing `<span style="bold: true">Name:</span>` if you were typing out HTML. `docx` (the format) allows you to specify this for any of the four types of items. `docx` (the library) only supports this type of formatting for paragraphs and characters, using a _fluent_ api. Thus you could do:
|
||||
|
||||
```ts
|
||||
const name = new TextRun("Name:")
|
||||
.bold()
|
||||
.font("Calibri")
|
||||
.allCaps();
|
||||
const name = new TextRun({
|
||||
text: "Name:",
|
||||
bold: true,
|
||||
font: "Calibri",
|
||||
allCaps: true,
|
||||
});
|
||||
```
|
||||
|
||||
Or for paragraph formatting:
|
||||
|
||||
```ts
|
||||
const para = new Paragraph("To whom it may concern:").heading2().center();
|
||||
const para = new Paragraph({
|
||||
text: "To whom it may concern:",
|
||||
heading: HeadingLevel.HEADING_2,
|
||||
alignment: AlignmentType.CENTER,
|
||||
});
|
||||
```
|
||||
|
||||
### Centrally defined styles (similar to external CSS)
|
||||
### Declaritive Styles (similar to external CSS)
|
||||
|
||||
DOCX files contain a styles section separate from the main content, much like how HTML includes CSS files. Unlike CSS, DOCX distinguishes between styles meant for tables (which show up in the table formatting toolbar), styles for lists (which show up under bullets and numbering), and styles for runs and paragraphs, which show up as dropdowns offering standard styles, like "Heading 1", "Caption", or any custom styles defined in that document. <!-- TODO: add pictures of the panes -->. `docx` allows you to define these styles using a fluent interface as well.
|
||||
`docx` files contain a styles section separate from the main content, much like how HTML includes CSS files. Unlike CSS, `docx` distinguishes between styles meant for tables (which show up in the table formatting toolbar), styles for lists (which show up under bullets and numbering), and styles for runs and paragraphs, which show up as dropdowns offering standard styles, like "Heading 1", "Caption", or any custom styles defined in that document. <!-- TODO: add pictures of the panes -->. `docx` allows you to define these styles using a fluent interface as well.
|
||||
|
||||
There are three parts to using custom styles with `docx`:
|
||||
|
||||
1. Create a container object for the style definitions:
|
||||
```ts
|
||||
const myStyles = new docx.Styles();
|
||||
```
|
||||
2. Define your custom styles, similar to the way you would format a paragraph or run
|
||||
To add styles, define your custom styles in the `document`:
|
||||
|
||||
```ts
|
||||
// The first argument is an ID you use to apply the style to paragraphs
|
||||
// The second argument is a human-friendly name to show in the UI
|
||||
myStyles
|
||||
.createParagraphStyle("myWonkyStyle", "My Wonky Style")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.color("999999")
|
||||
.italics()
|
||||
.indent(720) // 720 TWIP === 720 / 20 pt === .5 in
|
||||
.spacing({ line: 276 }); // 276 / 240 = 1.15x line spacing
|
||||
|
||||
myStyles
|
||||
.createParagraphStyle("Heading2", "Heading 2")
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.quickFormat()
|
||||
.size(26) // 26 half-points === 13pt font
|
||||
.bold()
|
||||
.underline("double", "FF0000")
|
||||
.spacing({ before: 240, after: 120 }); // TWIP for both
|
||||
```
|
||||
|
||||
3. When you generate your document, make sure to pass the `styles` container to the `Packer`:
|
||||
|
||||
```ts
|
||||
Packer.pack(myOutStream);
|
||||
const doc = new Document({
|
||||
creator: "Clippy",
|
||||
title: "Sample Document",
|
||||
description: "A brief example of using docx",
|
||||
styles: {
|
||||
paragraphStyles: [
|
||||
{
|
||||
id: "myWonkyStyle",
|
||||
name: "My Wonky Style",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
italics: true,
|
||||
color: "999999",
|
||||
},
|
||||
paragraph: {
|
||||
spacing: {
|
||||
line: 276,
|
||||
},
|
||||
indent: {
|
||||
left: 720,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "Heading2",
|
||||
name: "Heading 2",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
size: 26
|
||||
bold: true,
|
||||
color: "999999",
|
||||
{
|
||||
type: UnderlineType.DOUBLE,
|
||||
color: "FF0000",
|
||||
},
|
||||
},
|
||||
paragraph: {
|
||||
spacing: {
|
||||
before: 240,
|
||||
after: 120
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Note**: If you are using the `.headingX` or `.title` methods of paragraphs, you must make sure to define `HeadingX` or `Title` styles for these. Otherwise they'll show up unstyled :(. If you are using the `.bullet` or `.setNumbering` methods, you need to define a `ListParagraph` style or the numbers may not show up.
|
||||
@ -144,19 +179,29 @@ To determine the value of a styling property, you must first identify whether it
|
||||
|
||||
The following properties are treated in a special manner; they're called toggle properties:
|
||||
|
||||
* Bold
|
||||
* All caps
|
||||
* Small caps
|
||||
* Italics
|
||||
* Single strike-through
|
||||
* Hidden
|
||||
* Imprint
|
||||
* Emboss
|
||||
* Character outline
|
||||
* Character shadow
|
||||
- Bold
|
||||
- All caps
|
||||
- Small caps
|
||||
- Italics
|
||||
- Single strike-through
|
||||
- Hidden
|
||||
- Imprint
|
||||
- Emboss
|
||||
- Character outline
|
||||
- Character shadow
|
||||
|
||||
For these properties, the rules state the following conflict resolution in case the property is specified at multiple points for the same item:
|
||||
|
||||
* Direct formatting trumps all if specified (either true or false)
|
||||
* Otherwise, if the property is true in document defaults, the property is set to true
|
||||
* Otherwise, the property's value is an XOR of its effective table, paragraph, and character values. (So specifying bold `true` on a table style and a paragraph style would result in non-bold text if a paragraph inside the table had that style)
|
||||
- Direct formatting trumps all if specified (either true or false)
|
||||
- Otherwise, if the property is true in document defaults, the property is set to true
|
||||
- Otherwise, the property's value is an XOR of its effective table, paragraph, and character values. (So specifying bold `true` on a table style and a paragraph style would result in non-bold text if a paragraph inside the table had that style)
|
||||
|
||||
## Examples
|
||||
|
||||
### Declaritive styles
|
||||
|
||||
Importing Images from file system path
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/2-declaritive-styles.ts ':include')
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/2-declaritive-styles.ts_
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
> Tab stops are useful, if you are unclear of what they are, [here is a link explaining](https://en.wikipedia.org/wiki/Tab_stop). It enables side by side text which is nicely laid out without the need for tables, or constantly pressing space bar.
|
||||
|
||||
!> **Note**: At the moment, the unit of measurement for a tab stop is counter intuitive for a human. It is using OpenXMLs own measuring system. For example, 2268 roughly translates to 3cm. Therefore in the future, I may consider changing it to percentages or even cm.
|
||||
!> **Note**: The unit of measurement for a tab stop is in [DXA](https://stackoverflow.com/questions/14360183/default-wordml-unit-measurement-pixel-or-point-or-inches)
|
||||
|
||||

|
||||
|
||||
@ -11,44 +11,111 @@ Simply call the relevant methods on the paragraph listed below. Then just add a
|
||||
## Example
|
||||
|
||||
```ts
|
||||
const paragraph = new docx.Paragraph().maxRightTabStop();
|
||||
const leftText = new docx.TextRun("Hey everyone").bold();
|
||||
const rightText = new docx.TextRun("11th November 2015").tab();
|
||||
paragraph.addRun(leftText);
|
||||
paragraph.addRun(rightText);
|
||||
const paragraph = new Paragraph({
|
||||
children: [new TextRun("Hey everyone").bold(), new TextRun("11th November 1999").tab()],
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
position: TabStopPosition.MAX,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
The example above will create a left aligned text, and a right aligned text on the same line. The laymans approach to this problem would be to either use text boxes or tables. YUK!
|
||||
|
||||
The example above will create a left aligned text, and a right aligned text on the same line. The laymans approach to this problem would be to either use text boxes or tables. Not ideal!
|
||||
|
||||
```ts
|
||||
const paragraph = new docx.Paragraph();
|
||||
paragraph.maxRightTabStop();
|
||||
paragraph.leftTabStop(1000);
|
||||
const text = new docx.TextRun("Second tab stop here I come!").tab().tab();
|
||||
paragraph.addRun(text);
|
||||
const paragraph = new Paragraph({
|
||||
children: [new TextRun("Second tab stop here I come!").tab().tab()],
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
position: TabStopPosition.MAX,
|
||||
},
|
||||
{
|
||||
type: TabStopType.LEFT,
|
||||
position: 1000,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
The above shows the use of two tab stops, and how to select/use it.
|
||||
|
||||
## Left Tab Stop
|
||||
You can add multiple tab stops of the same `type` too.
|
||||
|
||||
```ts
|
||||
paragraph.leftTabStop(2268);
|
||||
const paragraph = new Paragraph({
|
||||
children: [new TextRun("Multiple tab stops!").tab().tab()],
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
position: TabStopPosition.MAX,
|
||||
},
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
position: 1000,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Left Tab Stop
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.LEFT,
|
||||
position: 2268,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
2268 is the distance from the left side.
|
||||
|
||||
## Center Tab Stop
|
||||
|
||||
```ts
|
||||
paragraph.centerTabStop(2268);
|
||||
const paragraph = new Paragraph({
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.CENTER,
|
||||
position: 2268,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
2268 is the distance from the left side.
|
||||
|
||||
2268 is the distance from the center.
|
||||
|
||||
## Right Tab Stop
|
||||
|
||||
```ts
|
||||
paragraph.rightTabStop(2268);
|
||||
const paragraph = new Paragraph({
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
position: 2268,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
2268 is the distance from the left side.
|
||||
|
||||
2268 is the distance fro0oum the left side.
|
||||
|
||||
## Max Right Tab Stop
|
||||
|
||||
```ts
|
||||
paragraph.maxRightTabStop();
|
||||
const paragraph = new Paragraph({
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
position: TabStopPosition.MAX,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
This will create a tab stop on the very edge of the right hand side. Handy for right aligning and left aligning text on the same line.
|
||||
|
@ -47,30 +47,6 @@ Here is the list of all options that you can use to generate your tables of cont
|
||||
|
||||
## Examples
|
||||
|
||||
```ts
|
||||
// Let's define the options for generate a TOC for heading 1-5 and MySpectacularStyle,
|
||||
// making the entries be hyperlinks for the paragraph
|
||||
const toc = new TableOfContents("Summary", {
|
||||
hyperlink: true,
|
||||
headingStyleRange: "1-5",
|
||||
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)],
|
||||
});
|
||||
|
||||
doc.addTableOfContents(toc);
|
||||
|
||||
doc.add(new Paragraph("Header #1").heading1().pageBreakBefore());
|
||||
doc.add(new Paragraph("I'm a little text, very nicely written.'"));
|
||||
|
||||
doc.add(new Paragraph("Header #2").heading1().pageBreakBefore());
|
||||
doc.add(new Paragraph("I'm another text very nicely written.'"));
|
||||
doc.add(new Paragraph("Header #2.1").heading2());
|
||||
doc.add(new Paragraph("I'm another text very nicely written.'"));
|
||||
|
||||
doc.add(new Paragraph("My Spectacular Style #1").style("MySpectacularStyle").pageBreakBefore());
|
||||
```
|
||||
|
||||
### Complete example
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/28-table-of-contents.ts ':include')
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/28-table-of-contents.ts_
|
||||
|
@ -28,15 +28,52 @@ describe("Formatter", () => {
|
||||
});
|
||||
|
||||
it("should format simple paragraph with bold text", () => {
|
||||
const paragraph = new Paragraph("");
|
||||
paragraph.addRun(
|
||||
const paragraph = new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "test",
|
||||
bold: true,
|
||||
}),
|
||||
);
|
||||
const newJson = formatter.format(paragraph);
|
||||
assert.isDefined(newJson["w:p"][1]["w:r"][0]["w:rPr"][0]["w:b"]._attr["w:val"]);
|
||||
],
|
||||
});
|
||||
|
||||
const tree = formatter.format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:r": [
|
||||
{
|
||||
"w:rPr": [
|
||||
{
|
||||
"w:b": {
|
||||
_attr: {
|
||||
"w:val": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:bCs": {
|
||||
_attr: {
|
||||
"w:val": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"w:t": [
|
||||
{
|
||||
_attr: {
|
||||
"xml:space": "preserve",
|
||||
},
|
||||
},
|
||||
"test",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should format attributes (rsidSect)", () => {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { DocumentAttributes } from "../document/document-attributes";
|
||||
import { IStylesOptions } from "../styles";
|
||||
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
||||
|
||||
export interface IPropertiesOptions {
|
||||
@ -11,6 +13,7 @@ export interface IPropertiesOptions {
|
||||
readonly lastModifiedBy?: string;
|
||||
readonly revision?: string;
|
||||
readonly externalStyles?: string;
|
||||
readonly styles?: IStylesOptions;
|
||||
}
|
||||
|
||||
export class CoreProperties extends XmlComponent {
|
||||
|
@ -46,8 +46,6 @@ export interface ISectionOptions {
|
||||
export class File {
|
||||
// tslint:disable-next-line:readonly-keyword
|
||||
private currentRelationshipId: number = 1;
|
||||
// tslint:disable-next-line:readonly-keyword
|
||||
private styles: Styles;
|
||||
|
||||
private readonly document: Document;
|
||||
private readonly headers: IDocumentHeader[] = [];
|
||||
@ -61,6 +59,7 @@ export class File {
|
||||
private readonly settings: Settings;
|
||||
private readonly contentTypes: ContentTypes;
|
||||
private readonly appProperties: AppProperties;
|
||||
private readonly styles: Styles;
|
||||
|
||||
constructor(
|
||||
options: IPropertiesOptions = {
|
||||
@ -97,9 +96,16 @@ export class File {
|
||||
} else if (options.externalStyles) {
|
||||
const stylesFactory = new ExternalStylesFactory();
|
||||
this.styles = stylesFactory.newInstance(options.externalStyles);
|
||||
} else if (options.styles) {
|
||||
const stylesFactory = new DefaultStylesFactory();
|
||||
const defaultStyles = stylesFactory.newInstance();
|
||||
this.styles = new Styles({
|
||||
...defaultStyles,
|
||||
...options.styles,
|
||||
});
|
||||
} else {
|
||||
const stylesFactory = new DefaultStylesFactory();
|
||||
this.styles = stylesFactory.newInstance();
|
||||
this.styles = new Styles(stylesFactory.newInstance());
|
||||
}
|
||||
|
||||
this.addDefaultRelationships();
|
||||
@ -277,10 +283,6 @@ export class File {
|
||||
return this.styles;
|
||||
}
|
||||
|
||||
public set Styles(styles: Styles) {
|
||||
this.styles = styles;
|
||||
}
|
||||
|
||||
public get CoreProperties(): CoreProperties {
|
||||
return this.coreProperties;
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ export class FootNotes extends XmlComponent {
|
||||
line: 240,
|
||||
lineRule: "auto",
|
||||
},
|
||||
}).addRun(new SeperatorRun()),
|
||||
children: [new SeperatorRun()],
|
||||
}),
|
||||
);
|
||||
this.root.push(begin);
|
||||
|
||||
@ -56,7 +57,8 @@ export class FootNotes extends XmlComponent {
|
||||
line: 240,
|
||||
lineRule: "auto",
|
||||
},
|
||||
}).addRun(new ContinuationSeperatorRun()),
|
||||
children: [new ContinuationSeperatorRun()],
|
||||
}),
|
||||
);
|
||||
this.root.push(spacing);
|
||||
}
|
||||
|
@ -7,14 +7,15 @@ import {
|
||||
ISpacingProperties,
|
||||
KeepLines,
|
||||
KeepNext,
|
||||
LeftTabStop,
|
||||
MaxRightTabStop,
|
||||
Spacing,
|
||||
TabStop,
|
||||
TabStopType,
|
||||
ThematicBreak,
|
||||
} from "../paragraph/formatting";
|
||||
import { ParagraphProperties } from "../paragraph/properties";
|
||||
import * as formatting from "../paragraph/run/formatting";
|
||||
import { RunProperties } from "../paragraph/run/properties";
|
||||
import { UnderlineType } from "../paragraph/run/underline";
|
||||
|
||||
interface ILevelAttributesProperties {
|
||||
readonly ilvl?: number;
|
||||
@ -184,7 +185,7 @@ export class LevelBase extends XmlComponent {
|
||||
return this;
|
||||
}
|
||||
|
||||
public underline(underlineType?: string, color?: string): Level {
|
||||
public underline(underlineType?: UnderlineType, color?: string): Level {
|
||||
this.addRunProperty(new formatting.Underline(underlineType, color));
|
||||
return this;
|
||||
}
|
||||
@ -235,13 +236,12 @@ export class LevelBase extends XmlComponent {
|
||||
return this;
|
||||
}
|
||||
|
||||
public maxRightTabStop(): Level {
|
||||
this.addParagraphProperty(new MaxRightTabStop());
|
||||
return this;
|
||||
public rightTabStop(position: number): Level {
|
||||
return this.addParagraphProperty(new TabStop(TabStopType.RIGHT, position));
|
||||
}
|
||||
|
||||
public leftTabStop(position: number): Level {
|
||||
this.addParagraphProperty(new LeftTabStop(position));
|
||||
this.addParagraphProperty(new TabStop(TabStopType.LEFT, position));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@ import { Num } from "./num";
|
||||
import { Numbering } from "./numbering";
|
||||
|
||||
import { EMPTY_OBJECT } from "file/xml-components";
|
||||
import { TabStopPosition } from "../paragraph";
|
||||
import { UnderlineType } from "../paragraph/run/underline";
|
||||
|
||||
describe("Numbering", () => {
|
||||
let numbering: Numbering;
|
||||
@ -202,7 +204,7 @@ describe("AbstractNumbering", () => {
|
||||
|
||||
it("#maxRightTabStop", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1);
|
||||
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").maxRightTabStop();
|
||||
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").rightTabStop(TabStopPosition.MAX);
|
||||
const tree = new Formatter().format(level);
|
||||
expect(tree["w:lvl"]).to.include({
|
||||
"w:pPr": [
|
||||
@ -355,7 +357,7 @@ describe("AbstractNumbering", () => {
|
||||
|
||||
it("should set the style if given", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1);
|
||||
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").underline("double");
|
||||
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").underline(UnderlineType.DOUBLE);
|
||||
const tree = new Formatter().format(level);
|
||||
expect(tree["w:lvl"]).to.include({
|
||||
"w:rPr": [{ "w:u": { _attr: { "w:val": "double" } } }],
|
||||
@ -364,7 +366,7 @@ describe("AbstractNumbering", () => {
|
||||
|
||||
it("should set the style and color if given", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1);
|
||||
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").underline("double", "005599");
|
||||
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").underline(UnderlineType.DOUBLE, "005599");
|
||||
const tree = new Formatter().format(level);
|
||||
expect(tree["w:lvl"]).to.include({
|
||||
"w:rPr": [{ "w:u": { _attr: { "w:val": "double", "w:color": "005599" } } }],
|
||||
|
@ -2,13 +2,13 @@ import { assert } from "chai";
|
||||
|
||||
import { Utility } from "tests/utility";
|
||||
|
||||
import { LeaderType, LeftTabStop, MaxRightTabStop, RightTabStop } from "./tab-stop";
|
||||
import { LeaderType, TabStop, TabStopType } from "./tab-stop";
|
||||
|
||||
describe("LeftTabStop", () => {
|
||||
let tabStop: LeftTabStop;
|
||||
let tabStop: TabStop;
|
||||
|
||||
beforeEach(() => {
|
||||
tabStop = new LeftTabStop(100);
|
||||
tabStop = new TabStop(TabStopType.LEFT, 100);
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
@ -29,10 +29,10 @@ describe("LeftTabStop", () => {
|
||||
});
|
||||
|
||||
describe("RightTabStop", () => {
|
||||
let tabStop: RightTabStop;
|
||||
let tabStop: TabStop;
|
||||
|
||||
beforeEach(() => {
|
||||
tabStop = new RightTabStop(100, LeaderType.DOT);
|
||||
tabStop = new TabStop(TabStopType.RIGHT, 100, LeaderType.DOT);
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
@ -52,28 +52,3 @@ describe("RightTabStop", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("MaxRightTabStop", () => {
|
||||
let tabStop: MaxRightTabStop;
|
||||
|
||||
beforeEach(() => {
|
||||
tabStop = new MaxRightTabStop();
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Tab Stop with correct attributes", () => {
|
||||
const newJson = Utility.jsonify(tabStop);
|
||||
|
||||
const attributes = {
|
||||
val: "right",
|
||||
pos: 9026,
|
||||
};
|
||||
assert.equal(JSON.stringify(newJson.root[0].root[0].root), JSON.stringify(attributes));
|
||||
});
|
||||
|
||||
it("should create a Tab Stop with w:tab", () => {
|
||||
const newJson = Utility.jsonify(tabStop);
|
||||
assert.equal(newJson.root[0].rootKey, "w:tab");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,13 +2,13 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
export class TabStop extends XmlComponent {
|
||||
constructor(tab: TabStopItem) {
|
||||
constructor(type: TabStopType, position: number, leader?: LeaderType) {
|
||||
super("w:tabs");
|
||||
this.root.push(tab);
|
||||
this.root.push(new TabStopItem(type, position, leader));
|
||||
}
|
||||
}
|
||||
|
||||
export enum TabValue {
|
||||
export enum TabStopType {
|
||||
LEFT = "left",
|
||||
RIGHT = "right",
|
||||
CENTER = "center",
|
||||
@ -28,8 +28,12 @@ export enum LeaderType {
|
||||
UNDERSCORE = "underscore",
|
||||
}
|
||||
|
||||
export enum TabStopPosition {
|
||||
MAX = 9026,
|
||||
}
|
||||
|
||||
export class TabAttributes extends XmlAttributeComponent<{
|
||||
readonly val: TabValue;
|
||||
readonly val: TabStopType;
|
||||
readonly pos: string | number;
|
||||
readonly leader?: LeaderType;
|
||||
}> {
|
||||
@ -37,7 +41,7 @@ export class TabAttributes extends XmlAttributeComponent<{
|
||||
}
|
||||
|
||||
export class TabStopItem extends XmlComponent {
|
||||
constructor(value: TabValue, position: string | number, leader?: LeaderType) {
|
||||
constructor(value: TabStopType, position: string | number, leader?: LeaderType) {
|
||||
super("w:tab");
|
||||
this.root.push(
|
||||
new TabAttributes({
|
||||
@ -48,27 +52,3 @@ export class TabStopItem extends XmlComponent {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class MaxRightTabStop extends TabStop {
|
||||
constructor(leader?: LeaderType) {
|
||||
super(new TabStopItem(TabValue.RIGHT, 9026, leader));
|
||||
}
|
||||
}
|
||||
|
||||
export class LeftTabStop extends TabStop {
|
||||
constructor(position: number, leader?: LeaderType) {
|
||||
super(new TabStopItem(TabValue.LEFT, position, leader));
|
||||
}
|
||||
}
|
||||
|
||||
export class RightTabStop extends TabStop {
|
||||
constructor(position: number, leader?: LeaderType) {
|
||||
super(new TabStopItem(TabValue.RIGHT, position, leader));
|
||||
}
|
||||
}
|
||||
|
||||
export class CenterTabStop extends TabStop {
|
||||
constructor(position: number, leader?: LeaderType) {
|
||||
super(new TabStopItem(TabValue.CENTER, position, leader));
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import { Formatter } from "export/formatter";
|
||||
import { EMPTY_OBJECT } from "file/xml-components";
|
||||
|
||||
import { Numbering } from "../numbering";
|
||||
import { AlignmentType, HeadingLevel, LeaderType } from "./formatting";
|
||||
import { AlignmentType, HeadingLevel, LeaderType, PageBreak, TabStopPosition, TabStopType } from "./formatting";
|
||||
import { Paragraph } from "./paragraph";
|
||||
|
||||
describe("Paragraph", () => {
|
||||
@ -254,11 +254,14 @@ describe("Paragraph", () => {
|
||||
});
|
||||
|
||||
describe("#maxRightTabStop()", () => {
|
||||
it("should add maxRightTabStop to JSON", () => {
|
||||
it("should add right tab stop to JSON", () => {
|
||||
const paragraph = new Paragraph({
|
||||
tabStop: {
|
||||
maxRight: {},
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
position: TabStopPosition.MAX,
|
||||
},
|
||||
],
|
||||
});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
@ -287,12 +290,13 @@ describe("Paragraph", () => {
|
||||
describe("#leftTabStop()", () => {
|
||||
it("should add leftTabStop to JSON", () => {
|
||||
const paragraph = new Paragraph({
|
||||
tabStop: {
|
||||
left: {
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.LEFT,
|
||||
position: 100,
|
||||
leader: LeaderType.HYPHEN,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
@ -322,12 +326,13 @@ describe("Paragraph", () => {
|
||||
describe("#rightTabStop()", () => {
|
||||
it("should add rightTabStop to JSON", () => {
|
||||
const paragraph = new Paragraph({
|
||||
tabStop: {
|
||||
right: {
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
position: 100,
|
||||
leader: LeaderType.DOT,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
@ -357,12 +362,13 @@ describe("Paragraph", () => {
|
||||
describe("#centerTabStop()", () => {
|
||||
it("should add centerTabStop to JSON", () => {
|
||||
const paragraph = new Paragraph({
|
||||
tabStop: {
|
||||
center: {
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.CENTER,
|
||||
position: 100,
|
||||
leader: LeaderType.MIDDLE_DOT,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
@ -492,8 +498,9 @@ describe("Paragraph", () => {
|
||||
|
||||
describe("#pageBreak()", () => {
|
||||
it("should add page break to JSON", () => {
|
||||
const paragraph = new Paragraph({});
|
||||
paragraph.pageBreak();
|
||||
const paragraph = new Paragraph({
|
||||
children: [new PageBreak()],
|
||||
});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
|
@ -11,17 +11,12 @@ import { KeepLines, KeepNext } from "./formatting/keep";
|
||||
import { PageBreak, PageBreakBefore } from "./formatting/page-break";
|
||||
import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spacing";
|
||||
import { HeadingLevel, Style } from "./formatting/style";
|
||||
import { CenterTabStop, LeaderType, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop";
|
||||
import { LeaderType, TabStop, TabStopPosition, TabStopType } from "./formatting/tab-stop";
|
||||
import { NumberProperties } from "./formatting/unordered-list";
|
||||
import { Bookmark, Hyperlink, OutlineLevel } from "./links";
|
||||
import { ParagraphProperties } from "./properties";
|
||||
import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run";
|
||||
|
||||
interface ITabStopOptions {
|
||||
readonly position: number;
|
||||
readonly leader?: LeaderType;
|
||||
}
|
||||
|
||||
export interface IParagraphOptions {
|
||||
readonly text?: string;
|
||||
readonly border?: IBorderOptions;
|
||||
@ -36,14 +31,11 @@ export interface IParagraphOptions {
|
||||
readonly indent?: IIndentAttributesProperties;
|
||||
readonly keepLines?: boolean;
|
||||
readonly keepNext?: boolean;
|
||||
readonly tabStop?: {
|
||||
readonly left?: ITabStopOptions;
|
||||
readonly right?: ITabStopOptions;
|
||||
readonly maxRight?: {
|
||||
readonly tabStops?: Array<{
|
||||
readonly position: number | TabStopPosition;
|
||||
readonly type: TabStopType;
|
||||
readonly leader?: LeaderType;
|
||||
};
|
||||
readonly center?: ITabStopOptions;
|
||||
};
|
||||
}>;
|
||||
readonly style?: string;
|
||||
readonly bullet?: {
|
||||
readonly level: number;
|
||||
@ -53,7 +45,7 @@ export interface IParagraphOptions {
|
||||
readonly level: number;
|
||||
readonly custom?: boolean;
|
||||
};
|
||||
readonly children?: Array<TextRun | PictureRun | Hyperlink | SymbolRun>;
|
||||
readonly children?: Array<TextRun | PictureRun | Hyperlink | SymbolRun | Bookmark | PageBreak | SequentialIdentifier>;
|
||||
}
|
||||
|
||||
export class Paragraph extends XmlComponent {
|
||||
@ -130,21 +122,9 @@ export class Paragraph extends XmlComponent {
|
||||
this.properties.push(new KeepNext());
|
||||
}
|
||||
|
||||
if (options.tabStop) {
|
||||
if (options.tabStop.left) {
|
||||
this.properties.push(new LeftTabStop(options.tabStop.left.position, options.tabStop.left.leader));
|
||||
}
|
||||
|
||||
if (options.tabStop.right) {
|
||||
this.properties.push(new RightTabStop(options.tabStop.right.position, options.tabStop.right.leader));
|
||||
}
|
||||
|
||||
if (options.tabStop.maxRight) {
|
||||
this.properties.push(new MaxRightTabStop(options.tabStop.maxRight.leader));
|
||||
}
|
||||
|
||||
if (options.tabStop.center) {
|
||||
this.properties.push(new CenterTabStop(options.tabStop.center.position, options.tabStop.center.leader));
|
||||
if (options.tabStops) {
|
||||
for (const tabStop of options.tabStops) {
|
||||
this.properties.push(new TabStop(tabStop.type, tabStop.position, tabStop.leader));
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,34 +146,18 @@ export class Paragraph extends XmlComponent {
|
||||
|
||||
if (options.children) {
|
||||
for (const child of options.children) {
|
||||
if (child instanceof Bookmark) {
|
||||
this.root.push(child.start);
|
||||
this.root.push(child.text);
|
||||
this.root.push(child.end);
|
||||
continue;
|
||||
}
|
||||
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public addRun(run: Run): Paragraph {
|
||||
this.root.push(run);
|
||||
return this;
|
||||
}
|
||||
|
||||
public addHyperLink(hyperlink: Hyperlink): Paragraph {
|
||||
this.root.push(hyperlink);
|
||||
return this;
|
||||
}
|
||||
|
||||
public addBookmark(bookmark: Bookmark): Paragraph {
|
||||
// Bookmarks by spec have three components, a start, text, and end
|
||||
this.root.push(bookmark.start);
|
||||
this.root.push(bookmark.text);
|
||||
this.root.push(bookmark.end);
|
||||
return this;
|
||||
}
|
||||
|
||||
public pageBreak(): Paragraph {
|
||||
this.root.push(new PageBreak());
|
||||
return this;
|
||||
}
|
||||
|
||||
public referenceFootnote(id: number): Paragraph {
|
||||
this.root.push(new FootnoteReferenceRun(id));
|
||||
return this;
|
||||
@ -203,9 +167,4 @@ 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;
|
||||
}
|
||||
}
|
||||
|
@ -4,3 +4,4 @@ export * from "./symbol-run";
|
||||
export * from "./picture-run";
|
||||
export * from "./run-fonts";
|
||||
export * from "./sequential-identifier";
|
||||
export * from "./underline";
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { ShadingType } from "file/table";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { FieldInstruction } from "file/table-of-contents/field-instruction";
|
||||
import { Break } from "./break";
|
||||
import { Caps, SmallCaps } from "./caps";
|
||||
import { Begin, End, Separate } from "./field";
|
||||
@ -56,6 +57,7 @@ export interface IRunOptions {
|
||||
readonly fill: string;
|
||||
readonly color: string;
|
||||
};
|
||||
readonly children?: Array<Begin | FieldInstruction | Separate | End>;
|
||||
}
|
||||
|
||||
export class Run extends XmlComponent {
|
||||
@ -134,6 +136,12 @@ export class Run extends XmlComponent {
|
||||
this.properties.push(new Shading(options.shading.type, options.shading.fill, options.shading.color));
|
||||
this.properties.push(new ShadowComplexScript(options.shading.type, options.shading.fill, options.shading.color));
|
||||
}
|
||||
|
||||
if (options.children) {
|
||||
for (const child of options.children) {
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public break(): Run {
|
||||
|
@ -27,7 +27,7 @@ describe("Underline", () => {
|
||||
});
|
||||
|
||||
it("should use the given style type and color", () => {
|
||||
const underline = new u.Underline("double", "FF00CC");
|
||||
const underline = new u.Underline(u.UnderlineType.DOUBLE, "FF00CC");
|
||||
const tree = new Formatter().format(underline);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:u": { _attr: { "w:val": "double", "w:color": "FF00CC" } },
|
||||
|
@ -33,7 +33,7 @@ export abstract class BaseUnderline extends XmlComponent {
|
||||
}
|
||||
|
||||
export class Underline extends BaseUnderline {
|
||||
constructor(underlineType: string = "single", color?: string) {
|
||||
constructor(underlineType: UnderlineType = UnderlineType.SINGLE, color?: string) {
|
||||
super(underlineType, color);
|
||||
}
|
||||
}
|
||||
|
@ -38,11 +38,13 @@ export class ExternalStylesFactory {
|
||||
throw new Error("can not find styles element");
|
||||
}
|
||||
|
||||
const importedStyle = new Styles(new ImportedRootElementAttributes(stylesXmlElement.attributes));
|
||||
const stylesElements = stylesXmlElement.elements || [];
|
||||
for (const childElm of stylesElements) {
|
||||
importedStyle.push(convertToXmlComponent(childElm) as ImportedXmlComponent);
|
||||
}
|
||||
|
||||
const importedStyle = new Styles({
|
||||
initialStyles: new ImportedRootElementAttributes(stylesXmlElement.attributes),
|
||||
importedStyles: stylesElements.map((childElm) => convertToXmlComponent(childElm) as ImportedXmlComponent),
|
||||
});
|
||||
|
||||
return importedStyle;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { DocumentAttributes } from "../document/document-attributes";
|
||||
import { Color, Italics, Size } from "../paragraph/run/formatting";
|
||||
import { Styles } from "./";
|
||||
import { IStylesOptions } from "./styles";
|
||||
|
||||
import { DocumentDefaults } from "./defaults";
|
||||
import {
|
||||
FootnoteReferenceStyle,
|
||||
FootnoteText,
|
||||
@ -18,7 +18,7 @@ import {
|
||||
} from "./style";
|
||||
|
||||
export class DefaultStylesFactory {
|
||||
public newInstance(): Styles {
|
||||
public newInstance(): IStylesOptions {
|
||||
const documentAttributes = new DocumentAttributes({
|
||||
mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
||||
r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
||||
@ -27,57 +27,55 @@ export class DefaultStylesFactory {
|
||||
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
|
||||
Ignorable: "w14 w15",
|
||||
});
|
||||
const styles = new Styles(documentAttributes);
|
||||
styles.createDocumentDefaults();
|
||||
|
||||
const titleStyle = new TitleStyle();
|
||||
titleStyle.addRunProperty(new Size(56));
|
||||
styles.push(titleStyle);
|
||||
|
||||
const heading1Style = new Heading1Style();
|
||||
heading1Style.addRunProperty(new Color("2E74B5"));
|
||||
heading1Style.addRunProperty(new Size(32));
|
||||
styles.push(heading1Style);
|
||||
|
||||
const heading2Style = new Heading2Style();
|
||||
heading2Style.addRunProperty(new Color("2E74B5"));
|
||||
heading2Style.addRunProperty(new Size(26));
|
||||
styles.push(heading2Style);
|
||||
|
||||
const heading3Style = new Heading3Style();
|
||||
heading3Style.addRunProperty(new Color("1F4D78"));
|
||||
heading3Style.addRunProperty(new Size(24));
|
||||
styles.push(heading3Style);
|
||||
|
||||
const heading4Style = new Heading4Style();
|
||||
heading4Style.addRunProperty(new Color("2E74B5"));
|
||||
heading4Style.addRunProperty(new Italics());
|
||||
styles.push(heading4Style);
|
||||
|
||||
const heading5Style = new Heading5Style();
|
||||
heading5Style.addRunProperty(new Color("2E74B5"));
|
||||
styles.push(heading5Style);
|
||||
|
||||
const heading6Style = new Heading6Style();
|
||||
heading6Style.addRunProperty(new Color("1F4D78"));
|
||||
styles.push(heading6Style);
|
||||
|
||||
const listParagraph = new ListParagraph();
|
||||
// listParagraph.addParagraphProperty();
|
||||
styles.push(listParagraph);
|
||||
|
||||
const hyperLinkStyle = new HyperlinkStyle();
|
||||
styles.push(hyperLinkStyle);
|
||||
|
||||
const footnoteReferenceStyle = new FootnoteReferenceStyle();
|
||||
styles.push(footnoteReferenceStyle);
|
||||
|
||||
const footnoteTextStyle = new FootnoteText();
|
||||
styles.push(footnoteTextStyle);
|
||||
|
||||
const footnoteTextCharStyle = new FootnoteTextChar();
|
||||
styles.push(footnoteTextCharStyle);
|
||||
|
||||
return styles;
|
||||
return {
|
||||
initialStyles: documentAttributes,
|
||||
importedStyles: [
|
||||
new DocumentDefaults(),
|
||||
new TitleStyle({
|
||||
run: {
|
||||
size: 56,
|
||||
},
|
||||
}),
|
||||
new Heading1Style({
|
||||
run: {
|
||||
color: "2E74B5",
|
||||
size: 32,
|
||||
},
|
||||
}),
|
||||
new Heading2Style({
|
||||
run: {
|
||||
color: "2E74B5",
|
||||
size: 26,
|
||||
},
|
||||
}),
|
||||
new Heading3Style({
|
||||
run: {
|
||||
color: "1F4D78",
|
||||
size: 24,
|
||||
},
|
||||
}),
|
||||
new Heading4Style({
|
||||
run: {
|
||||
color: "2E74B5",
|
||||
italics: true,
|
||||
},
|
||||
}),
|
||||
new Heading5Style({
|
||||
run: {
|
||||
color: "2E74B5",
|
||||
},
|
||||
}),
|
||||
new Heading6Style({
|
||||
run: {
|
||||
color: "1F4D78",
|
||||
},
|
||||
}),
|
||||
new ListParagraph({}),
|
||||
new HyperlinkStyle({}),
|
||||
new FootnoteReferenceStyle({}),
|
||||
new FootnoteText({}),
|
||||
new FootnoteTextChar({}),
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { UnderlineType } from "file/paragraph/run/underline";
|
||||
import { ShadingType } from "file/table";
|
||||
import { EMPTY_OBJECT } from "file/xml-components";
|
||||
|
||||
import { CharacterStyle } from "./character-style";
|
||||
|
||||
import { EMPTY_OBJECT } from "file/xml-components";
|
||||
|
||||
describe("CharacterStyle", () => {
|
||||
describe("#constructor", () => {
|
||||
it("should set the style type to character and use the given style id", () => {
|
||||
const style = new CharacterStyle("myStyleId");
|
||||
const style = new CharacterStyle({ id: "myStyleId" });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -17,7 +18,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -29,7 +30,10 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("should set the name of the style, if given", () => {
|
||||
const style = new CharacterStyle("myStyleId", "Style Name");
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
name: "Style Name",
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -38,7 +42,222 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add smallCaps", () => {
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
smallCaps: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||
{
|
||||
"w:rPr": [{ "w:smallCaps": { _attr: { "w:val": true } } }],
|
||||
},
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add allCaps", () => {
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
allCaps: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||
{
|
||||
"w:rPr": [{ "w:caps": { _attr: { "w:val": true } } }],
|
||||
},
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add strike", () => {
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
strike: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||
{
|
||||
"w:rPr": [{ "w:strike": { _attr: { "w:val": true } } }],
|
||||
},
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add double strike", () => {
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
doubleStrike: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||
{
|
||||
"w:rPr": [{ "w:dstrike": { _attr: { "w:val": true } } }],
|
||||
},
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add sub script", () => {
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
subScript: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||
{
|
||||
"w:rPr": [
|
||||
{
|
||||
"w:vertAlign": {
|
||||
_attr: {
|
||||
"w:val": "subscript",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add font", () => {
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
font: "test font",
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||
{
|
||||
"w:rPr": [
|
||||
{
|
||||
"w:rFonts": {
|
||||
_attr: {
|
||||
"w:ascii": "test font",
|
||||
"w:cs": "test font",
|
||||
"w:eastAsia": "test font",
|
||||
"w:hAnsi": "test font",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add character spacing", () => {
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
characterSpacing: 100,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||
{
|
||||
"w:rPr": [{ "w:spacing": { _attr: { "w:val": 100 } } }],
|
||||
},
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -52,7 +271,7 @@ describe("CharacterStyle", () => {
|
||||
|
||||
describe("formatting methods: style attributes", () => {
|
||||
it("#basedOn", () => {
|
||||
const style = new CharacterStyle("myStyleId").basedOn("otherId");
|
||||
const style = new CharacterStyle({ id: "myStyleId", basedOn: "otherId" });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -60,7 +279,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -75,7 +294,12 @@ describe("CharacterStyle", () => {
|
||||
|
||||
describe("formatting methods: run properties", () => {
|
||||
it("#size", () => {
|
||||
const style = new CharacterStyle("myStyleId").size(24);
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
size: 24,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -86,7 +310,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -99,7 +323,12 @@ describe("CharacterStyle", () => {
|
||||
|
||||
describe("#underline", () => {
|
||||
it("should set underline to 'single' if no arguments are given", () => {
|
||||
const style = new CharacterStyle("myStyleId").underline();
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
underline: {},
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -110,7 +339,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -122,7 +351,14 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("should set the style if given", () => {
|
||||
const style = new CharacterStyle("myStyleId").underline("double");
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
underline: {
|
||||
type: UnderlineType.DOUBLE,
|
||||
},
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -133,7 +369,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -145,7 +381,15 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("should set the style and color if given", () => {
|
||||
const style = new CharacterStyle("myStyleId").underline("double", "005599");
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
underline: {
|
||||
type: UnderlineType.DOUBLE,
|
||||
color: "005599",
|
||||
},
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -156,7 +400,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -169,7 +413,12 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("#superScript", () => {
|
||||
const style = new CharacterStyle("myStyleId").superScript();
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
superScript: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -188,7 +437,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -200,7 +449,12 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("#color", () => {
|
||||
const style = new CharacterStyle("myStyleId").color("123456");
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
color: "123456",
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -211,7 +465,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -223,7 +477,12 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("#bold", () => {
|
||||
const style = new CharacterStyle("myStyleId").bold();
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
bold: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -234,7 +493,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -246,7 +505,12 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("#italics", () => {
|
||||
const style = new CharacterStyle("myStyleId").italics();
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
italics: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -257,7 +521,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -269,7 +533,7 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("#link", () => {
|
||||
const style = new CharacterStyle("myStyleId").link("MyLink");
|
||||
const style = new CharacterStyle({ id: "myStyleId", link: "MyLink" });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -277,7 +541,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -290,7 +554,7 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("#semiHidden", () => {
|
||||
const style = new CharacterStyle("myStyleId").semiHidden();
|
||||
const style = new CharacterStyle({ id: "myStyleId", semiHidden: true });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -298,7 +562,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -309,7 +573,12 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("#highlight", () => {
|
||||
const style = new CharacterStyle("myStyleId").highlight("005599");
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
highlight: "005599",
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -320,7 +589,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -332,7 +601,16 @@ describe("CharacterStyle", () => {
|
||||
});
|
||||
|
||||
it("#shadow", () => {
|
||||
const style = new CharacterStyle("myStyleId").shadow("pct10", "00FFFF", "FF0000");
|
||||
const style = new CharacterStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
shadow: {
|
||||
type: ShadingType.PERCENT_10,
|
||||
fill: "00FFFF",
|
||||
color: "FF0000",
|
||||
},
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -343,7 +621,7 @@ describe("CharacterStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1,69 +1,128 @@
|
||||
import * as formatting from "file/paragraph/run/formatting";
|
||||
import { RunProperties } from "file/paragraph/run/properties";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { UnderlineType } from "file/paragraph/run/underline";
|
||||
|
||||
import { BasedOn, Link, SemiHidden, UiPriority, UnhideWhenUsed } from "./components";
|
||||
import { Style } from "./style";
|
||||
|
||||
export interface IBaseCharacterStyleOptions {
|
||||
readonly basedOn?: string;
|
||||
readonly link?: string;
|
||||
readonly semiHidden?: boolean;
|
||||
readonly run?: {
|
||||
readonly size?: number;
|
||||
readonly bold?: boolean;
|
||||
readonly italics?: boolean;
|
||||
readonly smallCaps?: boolean;
|
||||
readonly allCaps?: boolean;
|
||||
readonly strike?: boolean;
|
||||
readonly doubleStrike?: boolean;
|
||||
readonly subScript?: boolean;
|
||||
readonly superScript?: boolean;
|
||||
readonly underline?: {
|
||||
readonly type?: UnderlineType;
|
||||
readonly color?: string;
|
||||
};
|
||||
readonly color?: string;
|
||||
readonly font?: string;
|
||||
readonly characterSpacing?: number;
|
||||
readonly highlight?: string;
|
||||
readonly shadow?: {
|
||||
readonly type: string;
|
||||
readonly fill: string;
|
||||
readonly color: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface ICharacterStyleOptions extends IBaseCharacterStyleOptions {
|
||||
readonly id: string;
|
||||
readonly name?: string;
|
||||
}
|
||||
|
||||
export class CharacterStyle extends Style {
|
||||
private readonly runProperties: RunProperties;
|
||||
|
||||
constructor(styleId: string, name?: string) {
|
||||
super({ type: "character", styleId: styleId }, name);
|
||||
constructor(options: ICharacterStyleOptions) {
|
||||
super({ type: "character", styleId: options.id }, options.name);
|
||||
this.runProperties = new RunProperties();
|
||||
this.root.push(this.runProperties);
|
||||
this.root.push(new UiPriority("99"));
|
||||
this.root.push(new UiPriority(99));
|
||||
this.root.push(new UnhideWhenUsed());
|
||||
|
||||
if (options.basedOn) {
|
||||
this.root.push(new BasedOn(options.basedOn));
|
||||
}
|
||||
|
||||
public basedOn(parentId: string): CharacterStyle {
|
||||
this.root.push(new BasedOn(parentId));
|
||||
return this;
|
||||
if (options.link) {
|
||||
this.root.push(new Link(options.link));
|
||||
}
|
||||
|
||||
public addRunProperty(property: XmlComponent): CharacterStyle {
|
||||
this.runProperties.push(property);
|
||||
return this;
|
||||
}
|
||||
|
||||
public color(color: string): CharacterStyle {
|
||||
return this.addRunProperty(new formatting.Color(color));
|
||||
}
|
||||
|
||||
public bold(): CharacterStyle {
|
||||
return this.addRunProperty(new formatting.Bold());
|
||||
}
|
||||
|
||||
public italics(): CharacterStyle {
|
||||
return this.addRunProperty(new formatting.Italics());
|
||||
}
|
||||
|
||||
public underline(underlineType?: string, color?: string): CharacterStyle {
|
||||
return this.addRunProperty(new formatting.Underline(underlineType, color));
|
||||
}
|
||||
|
||||
public superScript(): CharacterStyle {
|
||||
return this.addRunProperty(new formatting.SuperScript());
|
||||
}
|
||||
|
||||
public size(twips: number): CharacterStyle {
|
||||
return this.addRunProperty(new formatting.Size(twips)).addRunProperty(new formatting.SizeComplexScript(twips));
|
||||
}
|
||||
|
||||
public link(link: string): CharacterStyle {
|
||||
this.root.push(new Link(link));
|
||||
return this;
|
||||
}
|
||||
|
||||
public semiHidden(): CharacterStyle {
|
||||
if (options.semiHidden) {
|
||||
this.root.push(new SemiHidden());
|
||||
return this;
|
||||
}
|
||||
|
||||
public highlight(color: string): CharacterStyle {
|
||||
return this.addRunProperty(new formatting.Highlight(color));
|
||||
if (options.run) {
|
||||
if (options.run.size) {
|
||||
this.runProperties.push(new formatting.Size(options.run.size));
|
||||
this.runProperties.push(new formatting.SizeComplexScript(options.run.size));
|
||||
}
|
||||
|
||||
public shadow(value: string, fill: string, color: string): CharacterStyle {
|
||||
return this.addRunProperty(new formatting.Shading(value, fill, color));
|
||||
if (options.run.bold) {
|
||||
this.runProperties.push(new formatting.Bold());
|
||||
}
|
||||
|
||||
if (options.run.italics) {
|
||||
this.runProperties.push(new formatting.Italics());
|
||||
}
|
||||
|
||||
if (options.run.smallCaps) {
|
||||
this.runProperties.push(new formatting.SmallCaps());
|
||||
}
|
||||
|
||||
if (options.run.allCaps) {
|
||||
this.runProperties.push(new formatting.Caps());
|
||||
}
|
||||
|
||||
if (options.run.strike) {
|
||||
this.runProperties.push(new formatting.Strike());
|
||||
}
|
||||
|
||||
if (options.run.doubleStrike) {
|
||||
this.runProperties.push(new formatting.DoubleStrike());
|
||||
}
|
||||
|
||||
if (options.run.subScript) {
|
||||
this.runProperties.push(new formatting.SubScript());
|
||||
}
|
||||
|
||||
if (options.run.superScript) {
|
||||
this.runProperties.push(new formatting.SuperScript());
|
||||
}
|
||||
|
||||
if (options.run.underline) {
|
||||
this.runProperties.push(new formatting.Underline(options.run.underline.type, options.run.underline.color));
|
||||
}
|
||||
|
||||
if (options.run.color) {
|
||||
this.runProperties.push(new formatting.Color(options.run.color));
|
||||
}
|
||||
|
||||
if (options.run.font) {
|
||||
this.runProperties.push(new formatting.RunFonts(options.run.font));
|
||||
}
|
||||
|
||||
if (options.run.characterSpacing) {
|
||||
this.runProperties.push(new formatting.CharacterSpacing(options.run.characterSpacing));
|
||||
}
|
||||
|
||||
if (options.run.highlight) {
|
||||
this.runProperties.push(new formatting.Highlight(options.run.highlight));
|
||||
}
|
||||
|
||||
if (options.run.shadow) {
|
||||
this.runProperties.push(new formatting.Shading(options.run.shadow.type, options.run.shadow.fill, options.run.shadow.color));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ describe("Style components", () => {
|
||||
});
|
||||
|
||||
it("UiPriority#constructor", () => {
|
||||
const style = new components.UiPriority("123");
|
||||
const style = new components.UiPriority(123);
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({ "w:uiPriority": { _attr: { "w:val": "123" } } });
|
||||
expect(tree).to.deep.equal({ "w:uiPriority": { _attr: { "w:val": 123 } } });
|
||||
});
|
||||
|
||||
it("UnhideWhenUsed#constructor", () => {
|
||||
|
@ -1,7 +1,8 @@
|
||||
// http://officeopenxml.com/WPstyleGenProps.php
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
interface IComponentAttributes {
|
||||
readonly val: string;
|
||||
readonly val: string | number;
|
||||
}
|
||||
|
||||
class ComponentAttributes extends XmlAttributeComponent<IComponentAttributes> {
|
||||
@ -37,7 +38,7 @@ export class Link extends XmlComponent {
|
||||
}
|
||||
|
||||
export class UiPriority extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
constructor(value: number) {
|
||||
super("w:uiPriority");
|
||||
// TODO: this value should be a ST_DecimalNumber
|
||||
this.root.push(new ComponentAttributes({ val: value }));
|
||||
|
@ -1,12 +1,15 @@
|
||||
import { expect } from "chai";
|
||||
import { Formatter } from "export/formatter";
|
||||
import * as defaultStyels from "./default-styles";
|
||||
import * as defaultStyles from "./default-styles";
|
||||
|
||||
import { EMPTY_OBJECT } from "file/xml-components";
|
||||
|
||||
describe("Default Styles", () => {
|
||||
it("HeadingStyle#constructor", () => {
|
||||
const style = new defaultStyels.HeadingStyle("Heading1", "Heading 1");
|
||||
const style = new defaultStyles.HeadingStyle({
|
||||
id: "Heading1",
|
||||
name: "Heading 1",
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -20,7 +23,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("TitleStyle#constructor", () => {
|
||||
const style = new defaultStyels.TitleStyle();
|
||||
const style = new defaultStyles.TitleStyle({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -34,7 +37,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("Heading1Style#constructor", () => {
|
||||
const style = new defaultStyels.Heading1Style();
|
||||
const style = new defaultStyles.Heading1Style({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -48,7 +51,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("Heading2Style#constructor", () => {
|
||||
const style = new defaultStyels.Heading2Style();
|
||||
const style = new defaultStyles.Heading2Style({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -62,7 +65,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("Heading3Style#constructor", () => {
|
||||
const style = new defaultStyels.Heading3Style();
|
||||
const style = new defaultStyles.Heading3Style({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -76,7 +79,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("Heading4Style#constructor", () => {
|
||||
const style = new defaultStyels.Heading4Style();
|
||||
const style = new defaultStyles.Heading4Style({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -90,7 +93,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("Heading5Style#constructor", () => {
|
||||
const style = new defaultStyels.Heading5Style();
|
||||
const style = new defaultStyles.Heading5Style({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -104,7 +107,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("Heading6Style#constructor", () => {
|
||||
const style = new defaultStyels.Heading6Style();
|
||||
const style = new defaultStyles.Heading6Style({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -118,7 +121,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("ListParagraph#constructor", () => {
|
||||
const style = new defaultStyels.ListParagraph();
|
||||
const style = new defaultStyles.ListParagraph({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -131,7 +134,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("FootnoteText#constructor", () => {
|
||||
const style = new defaultStyels.FootnoteText();
|
||||
const style = new defaultStyles.FootnoteText({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -171,14 +174,14 @@ describe("Default Styles", () => {
|
||||
{ "w:basedOn": { _attr: { "w:val": "Normal" } } },
|
||||
{ "w:link": { _attr: { "w:val": "FootnoteTextChar" } } },
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
},
|
||||
},
|
||||
"w:semiHidden": EMPTY_OBJECT,
|
||||
},
|
||||
{
|
||||
"w:semiHidden": EMPTY_OBJECT,
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||
@ -188,7 +191,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("FootnoteReferenceStyle#constructor", () => {
|
||||
const style = new defaultStyels.FootnoteReferenceStyle();
|
||||
const style = new defaultStyles.FootnoteReferenceStyle({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -208,7 +211,7 @@ describe("Default Styles", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -225,7 +228,7 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("FootnoteTextChar#constructor", () => {
|
||||
const style = new defaultStyels.FootnoteTextChar();
|
||||
const style = new defaultStyles.FootnoteTextChar({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -252,7 +255,7 @@ describe("Default Styles", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -269,19 +272,28 @@ describe("Default Styles", () => {
|
||||
});
|
||||
|
||||
it("HyperlinkStyle#constructor", () => {
|
||||
const style = new defaultStyels.HyperlinkStyle();
|
||||
const style = new defaultStyles.HyperlinkStyle({});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{ _attr: { "w:type": "character", "w:styleId": "Hyperlink" } },
|
||||
{ "w:name": { _attr: { "w:val": "Hyperlink" } } },
|
||||
{
|
||||
"w:rPr": [{ "w:color": { _attr: { "w:val": "0563C1" } } }, { "w:u": { _attr: { "w:val": "single" } } }],
|
||||
"w:rPr": [
|
||||
{ "w:u": { _attr: { "w:val": "single" } } },
|
||||
{
|
||||
"w:color": {
|
||||
_attr: {
|
||||
"w:val": "0563C1",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1,106 +1,170 @@
|
||||
import { CharacterStyle } from "./character-style";
|
||||
import { ParagraphStyle } from "./paragraph-style";
|
||||
import { UnderlineType } from "file/paragraph/run/underline";
|
||||
|
||||
import { CharacterStyle, IBaseCharacterStyleOptions } from "./character-style";
|
||||
import { IBaseParagraphStyleOptions, IParagraphStyleOptions, ParagraphStyle } from "./paragraph-style";
|
||||
|
||||
export class HeadingStyle extends ParagraphStyle {
|
||||
constructor(styleId: string, name: string) {
|
||||
super(styleId, name);
|
||||
this.basedOn("Normal");
|
||||
this.next("Normal");
|
||||
this.quickFormat();
|
||||
constructor(options: IParagraphStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class TitleStyle extends HeadingStyle {
|
||||
constructor() {
|
||||
super("Title", "Title");
|
||||
constructor(options: IBaseParagraphStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "Title",
|
||||
name: "Title",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading1Style extends HeadingStyle {
|
||||
constructor() {
|
||||
super("Heading1", "Heading 1");
|
||||
constructor(options: IBaseParagraphStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "Heading1",
|
||||
name: "Heading 1",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading2Style extends HeadingStyle {
|
||||
constructor() {
|
||||
super("Heading2", "Heading 2");
|
||||
constructor(options: IBaseParagraphStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "Heading2",
|
||||
name: "Heading 2",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading3Style extends HeadingStyle {
|
||||
constructor() {
|
||||
super("Heading3", "Heading 3");
|
||||
constructor(options: IBaseParagraphStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "Heading3",
|
||||
name: "Heading 3",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading4Style extends HeadingStyle {
|
||||
constructor() {
|
||||
super("Heading4", "Heading 4");
|
||||
constructor(options: IBaseParagraphStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "Heading4",
|
||||
name: "Heading 4",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading5Style extends HeadingStyle {
|
||||
constructor() {
|
||||
super("Heading5", "Heading 5");
|
||||
constructor(options: IBaseParagraphStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "Heading5",
|
||||
name: "Heading 5",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading6Style extends HeadingStyle {
|
||||
constructor() {
|
||||
super("Heading6", "Heading 6");
|
||||
constructor(options: IBaseParagraphStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "Heading6",
|
||||
name: "Heading 6",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ListParagraph extends ParagraphStyle {
|
||||
constructor() {
|
||||
super("ListParagraph", "List Paragraph");
|
||||
this.basedOn("Normal");
|
||||
this.quickFormat();
|
||||
constructor(options: IBaseParagraphStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "ListParagraph",
|
||||
name: "List Paragraph",
|
||||
basedOn: "Normal",
|
||||
quickFormat: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class FootnoteText extends ParagraphStyle {
|
||||
constructor() {
|
||||
super("FootnoteText", "footnote text");
|
||||
this.basedOn("Normal")
|
||||
.link("FootnoteTextChar")
|
||||
.uiPriority("99")
|
||||
.semiHidden()
|
||||
.unhideWhenUsed()
|
||||
.spacing({
|
||||
constructor(options: IBaseParagraphStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "FootnoteText",
|
||||
name: "footnote text",
|
||||
link: "FootnoteTextChar",
|
||||
basedOn: "Normal",
|
||||
uiPriority: 99,
|
||||
semiHidden: true,
|
||||
unhideWhenUsed: true,
|
||||
paragraph: {
|
||||
spacing: {
|
||||
after: 0,
|
||||
line: 240,
|
||||
lineRule: "auto",
|
||||
})
|
||||
.size(20);
|
||||
},
|
||||
},
|
||||
run: {
|
||||
size: 20,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class FootnoteReferenceStyle extends CharacterStyle {
|
||||
constructor() {
|
||||
super("FootnoteReference", "footnote reference");
|
||||
this.basedOn("DefaultParagraphFont")
|
||||
.semiHidden()
|
||||
.superScript();
|
||||
constructor(options: IBaseCharacterStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "FootnoteReference",
|
||||
name: "footnote reference",
|
||||
basedOn: "DefaultParagraphFont",
|
||||
semiHidden: true,
|
||||
run: {
|
||||
superScript: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class FootnoteTextChar extends CharacterStyle {
|
||||
constructor() {
|
||||
super("FootnoteTextChar", "Footnote Text Char");
|
||||
this.basedOn("DefaultParagraphFont")
|
||||
.link("FootnoteText")
|
||||
.semiHidden()
|
||||
.size(20);
|
||||
constructor(options: IBaseCharacterStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "FootnoteTextChar",
|
||||
name: "Footnote Text Char",
|
||||
basedOn: "DefaultParagraphFont",
|
||||
link: "FootnoteText",
|
||||
semiHidden: true,
|
||||
run: {
|
||||
size: 20,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class HyperlinkStyle extends CharacterStyle {
|
||||
constructor() {
|
||||
super("Hyperlink", "Hyperlink");
|
||||
this.basedOn("DefaultParagraphFont")
|
||||
.color("0563C1")
|
||||
.underline("single");
|
||||
constructor(options: IBaseCharacterStyleOptions) {
|
||||
super({
|
||||
...options,
|
||||
id: "Hyperlink",
|
||||
name: "Hyperlink",
|
||||
basedOn: "DefaultParagraphFont",
|
||||
run: {
|
||||
color: "0563C1",
|
||||
underline: {
|
||||
type: UnderlineType.SINGLE,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { AlignmentType, TabStopPosition } from "file/paragraph";
|
||||
import { UnderlineType } from "file/paragraph/run/underline";
|
||||
import { ShadingType } from "file/table";
|
||||
import { EMPTY_OBJECT } from "file/xml-components";
|
||||
|
||||
import { ParagraphStyle } from "./paragraph-style";
|
||||
|
||||
import { EMPTY_OBJECT } from "file/xml-components";
|
||||
|
||||
describe("ParagraphStyle", () => {
|
||||
describe("#constructor", () => {
|
||||
it("should set the style type to paragraph and use the given style id", () => {
|
||||
const style = new ParagraphStyle("myStyleId");
|
||||
const style = new ParagraphStyle({ id: "myStyleId" });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||
@ -17,7 +19,10 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("should set the name of the style, if given", () => {
|
||||
const style = new ParagraphStyle("myStyleId", "Style Name");
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
name: "Style Name",
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -30,7 +35,7 @@ describe("ParagraphStyle", () => {
|
||||
|
||||
describe("formatting methods: style attributes", () => {
|
||||
it("#basedOn", () => {
|
||||
const style = new ParagraphStyle("myStyleId").basedOn("otherId");
|
||||
const style = new ParagraphStyle({ id: "myStyleId", basedOn: "otherId" });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -41,7 +46,7 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#quickFormat", () => {
|
||||
const style = new ParagraphStyle("myStyleId").quickFormat();
|
||||
const style = new ParagraphStyle({ id: "myStyleId", quickFormat: true });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:qFormat": EMPTY_OBJECT }],
|
||||
@ -49,7 +54,7 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#next", () => {
|
||||
const style = new ParagraphStyle("myStyleId").next("otherId");
|
||||
const style = new ParagraphStyle({ id: "myStyleId", next: "otherId" });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -62,7 +67,12 @@ describe("ParagraphStyle", () => {
|
||||
|
||||
describe("formatting methods: paragraph properties", () => {
|
||||
it("#indent", () => {
|
||||
const style = new ParagraphStyle("myStyleId").indent({ left: 720 });
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
indent: { left: 720 },
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -75,7 +85,7 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#spacing", () => {
|
||||
const style = new ParagraphStyle("myStyleId").spacing({ before: 50, after: 150 });
|
||||
const style = new ParagraphStyle({ id: "myStyleId", paragraph: { spacing: { before: 50, after: 150 } } });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -88,7 +98,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#center", () => {
|
||||
const style = new ParagraphStyle("myStyleId").center();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
alignment: AlignmentType.CENTER,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -101,7 +116,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#character spacing", () => {
|
||||
const style = new ParagraphStyle("myStyleId").characterSpacing(24);
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
characterSpacing: 24,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -114,7 +134,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#left", () => {
|
||||
const style = new ParagraphStyle("myStyleId").left();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
alignment: AlignmentType.LEFT,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -127,7 +152,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#right", () => {
|
||||
const style = new ParagraphStyle("myStyleId").right();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
alignment: AlignmentType.RIGHT,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -140,7 +170,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#justified", () => {
|
||||
const style = new ParagraphStyle("myStyleId").justified();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -153,7 +188,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#thematicBreak", () => {
|
||||
const style = new ParagraphStyle("myStyleId").thematicBreak();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
thematicBreak: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -181,7 +221,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#leftTabStop", () => {
|
||||
const style = new ParagraphStyle("myStyleId").leftTabStop(1200);
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
leftTabStop: 1200,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -198,7 +243,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#maxRightTabStop", () => {
|
||||
const style = new ParagraphStyle("myStyleId").maxRightTabStop();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
rightTabStop: TabStopPosition.MAX,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -215,7 +265,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#keepLines", () => {
|
||||
const style = new ParagraphStyle("myStyleId").keepLines();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
keepLines: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [{ "w:keepLines": EMPTY_OBJECT }] }],
|
||||
@ -223,7 +278,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#keepNext", () => {
|
||||
const style = new ParagraphStyle("myStyleId").keepNext();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
keepNext: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [{ "w:keepNext": EMPTY_OBJECT }] }],
|
||||
@ -231,7 +291,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#outlineLevel", () => {
|
||||
const style = new ParagraphStyle("myStyleId").outlineLevel(1);
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
paragraph: {
|
||||
outlineLevel: 1,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -244,7 +309,12 @@ describe("ParagraphStyle", () => {
|
||||
|
||||
describe("formatting methods: run properties", () => {
|
||||
it("#size", () => {
|
||||
const style = new ParagraphStyle("myStyleId").size(24);
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
size: 24,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -257,7 +327,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#smallCaps", () => {
|
||||
const style = new ParagraphStyle("myStyleId").smallCaps();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
smallCaps: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -270,7 +345,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#allCaps", () => {
|
||||
const style = new ParagraphStyle("myStyleId").allCaps();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
allCaps: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -283,7 +363,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#strike", () => {
|
||||
const style = new ParagraphStyle("myStyleId").strike();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
strike: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -296,7 +381,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#doubleStrike", () => {
|
||||
const style = new ParagraphStyle("myStyleId").doubleStrike();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
doubleStrike: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -309,7 +399,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#subScript", () => {
|
||||
const style = new ParagraphStyle("myStyleId").subScript();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
subScript: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -322,7 +417,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#superScript", () => {
|
||||
const style = new ParagraphStyle("myStyleId").superScript();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
superScript: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -335,7 +435,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#font", () => {
|
||||
const style = new ParagraphStyle("myStyleId").font("Times");
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
font: "Times",
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -350,7 +455,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#bold", () => {
|
||||
const style = new ParagraphStyle("myStyleId").bold();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
bold: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -363,7 +473,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#italics", () => {
|
||||
const style = new ParagraphStyle("myStyleId").italics();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
italics: true,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -376,7 +491,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#highlight", () => {
|
||||
const style = new ParagraphStyle("myStyleId").highlight("005599");
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
highlight: "005599",
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -389,7 +509,16 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#shadow", () => {
|
||||
const style = new ParagraphStyle("myStyleId").shadow("pct10", "00FFFF", "FF0000");
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
shadow: {
|
||||
type: ShadingType.PERCENT_10,
|
||||
fill: "00FFFF",
|
||||
color: "FF0000",
|
||||
},
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -403,7 +532,12 @@ describe("ParagraphStyle", () => {
|
||||
|
||||
describe("#underline", () => {
|
||||
it("should set underline to 'single' if no arguments are given", () => {
|
||||
const style = new ParagraphStyle("myStyleId").underline();
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
underline: {},
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -416,7 +550,14 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("should set the style if given", () => {
|
||||
const style = new ParagraphStyle("myStyleId").underline("double");
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
underline: {
|
||||
type: UnderlineType.DOUBLE,
|
||||
},
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -429,7 +570,15 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("should set the style and color if given", () => {
|
||||
const style = new ParagraphStyle("myStyleId").underline("double", "005599");
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
underline: {
|
||||
type: UnderlineType.DOUBLE,
|
||||
color: "005599",
|
||||
},
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -443,7 +592,12 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#color", () => {
|
||||
const style = new ParagraphStyle("myStyleId").color("123456");
|
||||
const style = new ParagraphStyle({
|
||||
id: "myStyleId",
|
||||
run: {
|
||||
color: "123456",
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -456,7 +610,7 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#link", () => {
|
||||
const style = new ParagraphStyle("myStyleId").link("MyLink");
|
||||
const style = new ParagraphStyle({ id: "myStyleId", link: "MyLink" });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:link": { _attr: { "w:val": "MyLink" } } }],
|
||||
@ -464,7 +618,7 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#semiHidden", () => {
|
||||
const style = new ParagraphStyle("myStyleId").semiHidden();
|
||||
const style = new ParagraphStyle({ id: "myStyleId", semiHidden: true });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:semiHidden": EMPTY_OBJECT }],
|
||||
@ -472,7 +626,7 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#uiPriority", () => {
|
||||
const style = new ParagraphStyle("myStyleId").uiPriority("99");
|
||||
const style = new ParagraphStyle({ id: "myStyleId", uiPriority: 99 });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
@ -480,7 +634,7 @@ describe("ParagraphStyle", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -489,7 +643,7 @@ describe("ParagraphStyle", () => {
|
||||
});
|
||||
|
||||
it("#unhideWhenUsed", () => {
|
||||
const style = new ParagraphStyle("myStyleId").unhideWhenUsed();
|
||||
const style = new ParagraphStyle({ id: "myStyleId", unhideWhenUsed: true });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:unhideWhenUsed": EMPTY_OBJECT }],
|
||||
|
@ -5,188 +5,207 @@ import {
|
||||
ISpacingProperties,
|
||||
KeepLines,
|
||||
KeepNext,
|
||||
LeftTabStop,
|
||||
MaxRightTabStop,
|
||||
OutlineLevel,
|
||||
ParagraphProperties,
|
||||
Spacing,
|
||||
ThematicBreak,
|
||||
} from "file/paragraph";
|
||||
import { IIndentAttributesProperties, TabStop, TabStopType } from "file/paragraph/formatting";
|
||||
import * as formatting from "file/paragraph/run/formatting";
|
||||
import { RunProperties } from "file/paragraph/run/properties";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { UnderlineType } from "file/paragraph/run/underline";
|
||||
import { ShadingType } from "file/table";
|
||||
|
||||
import { BasedOn, Link, Next, QuickFormat, SemiHidden, UiPriority, UnhideWhenUsed } from "./components";
|
||||
import { Style } from "./style";
|
||||
|
||||
export interface IBaseParagraphStyleOptions {
|
||||
readonly basedOn?: string;
|
||||
readonly next?: string;
|
||||
readonly quickFormat?: boolean;
|
||||
readonly link?: string;
|
||||
readonly semiHidden?: boolean;
|
||||
readonly uiPriority?: number;
|
||||
readonly unhideWhenUsed?: boolean;
|
||||
readonly run?: {
|
||||
readonly size?: number;
|
||||
readonly bold?: boolean;
|
||||
readonly italics?: boolean;
|
||||
readonly smallCaps?: boolean;
|
||||
readonly allCaps?: boolean;
|
||||
readonly strike?: boolean;
|
||||
readonly doubleStrike?: boolean;
|
||||
readonly subScript?: boolean;
|
||||
readonly superScript?: boolean;
|
||||
readonly underline?: {
|
||||
readonly type?: UnderlineType;
|
||||
readonly color?: string;
|
||||
};
|
||||
readonly color?: string;
|
||||
readonly font?: string;
|
||||
readonly characterSpacing?: number;
|
||||
readonly highlight?: string;
|
||||
readonly shadow?: {
|
||||
readonly type: ShadingType;
|
||||
readonly fill: string;
|
||||
readonly color: string;
|
||||
};
|
||||
};
|
||||
readonly paragraph?: {
|
||||
readonly alignment?: AlignmentType;
|
||||
readonly thematicBreak?: boolean;
|
||||
readonly rightTabStop?: number;
|
||||
readonly leftTabStop?: number;
|
||||
readonly indent?: IIndentAttributesProperties;
|
||||
readonly spacing?: ISpacingProperties;
|
||||
readonly keepNext?: boolean;
|
||||
readonly keepLines?: boolean;
|
||||
readonly outlineLevel?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IParagraphStyleOptions extends IBaseParagraphStyleOptions {
|
||||
readonly id: string;
|
||||
readonly name?: string;
|
||||
}
|
||||
export class ParagraphStyle extends Style {
|
||||
private readonly paragraphProperties: ParagraphProperties;
|
||||
private readonly runProperties: RunProperties;
|
||||
|
||||
constructor(styleId: string, name?: string) {
|
||||
super({ type: "paragraph", styleId: styleId }, name);
|
||||
constructor(options: IParagraphStyleOptions) {
|
||||
super({ type: "paragraph", styleId: options.id }, options.name);
|
||||
this.paragraphProperties = new ParagraphProperties({});
|
||||
this.runProperties = new RunProperties();
|
||||
this.root.push(this.paragraphProperties);
|
||||
this.root.push(this.runProperties);
|
||||
|
||||
if (options.basedOn) {
|
||||
this.root.push(new BasedOn(options.basedOn));
|
||||
}
|
||||
|
||||
public addParagraphProperty(property: XmlComponent): ParagraphStyle {
|
||||
this.paragraphProperties.push(property);
|
||||
return this;
|
||||
if (options.next) {
|
||||
this.root.push(new Next(options.next));
|
||||
}
|
||||
|
||||
public outlineLevel(level: number): ParagraphStyle {
|
||||
this.paragraphProperties.push(new OutlineLevel(level));
|
||||
return this;
|
||||
}
|
||||
|
||||
public addRunProperty(property: XmlComponent): ParagraphStyle {
|
||||
this.runProperties.push(property);
|
||||
return this;
|
||||
}
|
||||
|
||||
public basedOn(parentId: string): ParagraphStyle {
|
||||
this.root.push(new BasedOn(parentId));
|
||||
return this;
|
||||
}
|
||||
|
||||
public quickFormat(): ParagraphStyle {
|
||||
if (options.quickFormat) {
|
||||
this.root.push(new QuickFormat());
|
||||
return this;
|
||||
}
|
||||
|
||||
public next(nextId: string): ParagraphStyle {
|
||||
this.root.push(new Next(nextId));
|
||||
return this;
|
||||
if (options.link) {
|
||||
this.root.push(new Link(options.link));
|
||||
}
|
||||
|
||||
// ---------- Run formatting ---------------------- //
|
||||
|
||||
public size(twips: number): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.Size(twips)).addRunProperty(new formatting.SizeComplexScript(twips));
|
||||
}
|
||||
|
||||
public bold(): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.Bold());
|
||||
}
|
||||
|
||||
public italics(): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.Italics());
|
||||
}
|
||||
|
||||
public smallCaps(): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.SmallCaps());
|
||||
}
|
||||
|
||||
public allCaps(): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.Caps());
|
||||
}
|
||||
|
||||
public strike(): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.Strike());
|
||||
}
|
||||
|
||||
public doubleStrike(): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.DoubleStrike());
|
||||
}
|
||||
|
||||
public subScript(): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.SubScript());
|
||||
}
|
||||
|
||||
public superScript(): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.SuperScript());
|
||||
}
|
||||
|
||||
public underline(underlineType?: string, color?: string): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.Underline(underlineType, color));
|
||||
}
|
||||
|
||||
public color(color: string): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.Color(color));
|
||||
}
|
||||
|
||||
public font(fontName: string): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.RunFonts(fontName));
|
||||
}
|
||||
|
||||
public characterSpacing(value: number): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.CharacterSpacing(value));
|
||||
}
|
||||
|
||||
public highlight(color: string): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.Highlight(color));
|
||||
}
|
||||
|
||||
public shadow(value: string, fill: string, color: string): ParagraphStyle {
|
||||
return this.addRunProperty(new formatting.Shading(value, fill, color));
|
||||
}
|
||||
|
||||
// --------------------- Paragraph formatting ------------------------ //
|
||||
|
||||
public center(): ParagraphStyle {
|
||||
return this.addParagraphProperty(new Alignment(AlignmentType.CENTER));
|
||||
}
|
||||
|
||||
public left(): ParagraphStyle {
|
||||
return this.addParagraphProperty(new Alignment(AlignmentType.LEFT));
|
||||
}
|
||||
|
||||
public right(): ParagraphStyle {
|
||||
return this.addParagraphProperty(new Alignment(AlignmentType.RIGHT));
|
||||
}
|
||||
|
||||
public justified(): ParagraphStyle {
|
||||
return this.addParagraphProperty(new Alignment(AlignmentType.BOTH));
|
||||
}
|
||||
|
||||
public thematicBreak(): ParagraphStyle {
|
||||
return this.addParagraphProperty(new ThematicBreak());
|
||||
}
|
||||
|
||||
public maxRightTabStop(): ParagraphStyle {
|
||||
return this.addParagraphProperty(new MaxRightTabStop());
|
||||
}
|
||||
|
||||
public leftTabStop(position: number): ParagraphStyle {
|
||||
return this.addParagraphProperty(new LeftTabStop(position));
|
||||
}
|
||||
|
||||
public indent(attrs: object): ParagraphStyle {
|
||||
return this.addParagraphProperty(new Indent(attrs));
|
||||
}
|
||||
|
||||
public spacing(params: ISpacingProperties): ParagraphStyle {
|
||||
return this.addParagraphProperty(new Spacing(params));
|
||||
}
|
||||
|
||||
public keepNext(): ParagraphStyle {
|
||||
return this.addParagraphProperty(new KeepNext());
|
||||
}
|
||||
|
||||
public keepLines(): ParagraphStyle {
|
||||
return this.addParagraphProperty(new KeepLines());
|
||||
}
|
||||
|
||||
/*-------------- Style Properties -----------------*/
|
||||
|
||||
public link(link: string): ParagraphStyle {
|
||||
this.root.push(new Link(link));
|
||||
return this;
|
||||
}
|
||||
|
||||
public semiHidden(): ParagraphStyle {
|
||||
if (options.semiHidden) {
|
||||
this.root.push(new SemiHidden());
|
||||
return this;
|
||||
}
|
||||
|
||||
public uiPriority(priority: string): ParagraphStyle {
|
||||
this.root.push(new UiPriority(priority));
|
||||
return this;
|
||||
if (options.uiPriority) {
|
||||
this.root.push(new UiPriority(options.uiPriority));
|
||||
}
|
||||
|
||||
public unhideWhenUsed(): ParagraphStyle {
|
||||
if (options.unhideWhenUsed) {
|
||||
this.root.push(new UnhideWhenUsed());
|
||||
return this;
|
||||
}
|
||||
|
||||
if (options.run) {
|
||||
if (options.run.size) {
|
||||
this.runProperties.push(new formatting.Size(options.run.size));
|
||||
this.runProperties.push(new formatting.SizeComplexScript(options.run.size));
|
||||
}
|
||||
|
||||
if (options.run.bold) {
|
||||
this.runProperties.push(new formatting.Bold());
|
||||
}
|
||||
|
||||
if (options.run.italics) {
|
||||
this.runProperties.push(new formatting.Italics());
|
||||
}
|
||||
|
||||
if (options.run.smallCaps) {
|
||||
this.runProperties.push(new formatting.SmallCaps());
|
||||
}
|
||||
|
||||
if (options.run.allCaps) {
|
||||
this.runProperties.push(new formatting.Caps());
|
||||
}
|
||||
|
||||
if (options.run.strike) {
|
||||
this.runProperties.push(new formatting.Strike());
|
||||
}
|
||||
|
||||
if (options.run.doubleStrike) {
|
||||
this.runProperties.push(new formatting.DoubleStrike());
|
||||
}
|
||||
|
||||
if (options.run.subScript) {
|
||||
this.runProperties.push(new formatting.SubScript());
|
||||
}
|
||||
|
||||
if (options.run.superScript) {
|
||||
this.runProperties.push(new formatting.SuperScript());
|
||||
}
|
||||
|
||||
if (options.run.underline) {
|
||||
this.runProperties.push(new formatting.Underline(options.run.underline.type, options.run.underline.color));
|
||||
}
|
||||
|
||||
if (options.run.color) {
|
||||
this.runProperties.push(new formatting.Color(options.run.color));
|
||||
}
|
||||
|
||||
if (options.run.font) {
|
||||
this.runProperties.push(new formatting.RunFonts(options.run.font));
|
||||
}
|
||||
|
||||
if (options.run.characterSpacing) {
|
||||
this.runProperties.push(new formatting.CharacterSpacing(options.run.characterSpacing));
|
||||
}
|
||||
|
||||
if (options.run.highlight) {
|
||||
this.runProperties.push(new formatting.Highlight(options.run.highlight));
|
||||
}
|
||||
|
||||
if (options.run.shadow) {
|
||||
this.runProperties.push(new formatting.Shading(options.run.shadow.type, options.run.shadow.fill, options.run.shadow.color));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.paragraph) {
|
||||
if (options.paragraph.alignment) {
|
||||
this.paragraphProperties.push(new Alignment(options.paragraph.alignment));
|
||||
}
|
||||
|
||||
if (options.paragraph.thematicBreak) {
|
||||
this.paragraphProperties.push(new ThematicBreak());
|
||||
}
|
||||
|
||||
if (options.paragraph.rightTabStop) {
|
||||
this.paragraphProperties.push(new TabStop(TabStopType.RIGHT, options.paragraph.rightTabStop));
|
||||
}
|
||||
|
||||
if (options.paragraph.leftTabStop) {
|
||||
this.paragraphProperties.push(new TabStop(TabStopType.LEFT, options.paragraph.leftTabStop));
|
||||
}
|
||||
|
||||
if (options.paragraph.indent) {
|
||||
this.paragraphProperties.push(new Indent(options.paragraph.indent));
|
||||
}
|
||||
|
||||
if (options.paragraph.spacing) {
|
||||
this.paragraphProperties.push(new Spacing(options.paragraph.spacing));
|
||||
}
|
||||
|
||||
if (options.paragraph.keepNext) {
|
||||
this.paragraphProperties.push(new KeepNext());
|
||||
}
|
||||
|
||||
if (options.paragraph.keepLines) {
|
||||
this.paragraphProperties.push(new KeepLines());
|
||||
}
|
||||
|
||||
if (options.paragraph.outlineLevel) {
|
||||
this.paragraphProperties.push(new OutlineLevel(options.paragraph.outlineLevel));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,4 @@ export class Style extends XmlComponent {
|
||||
this.root.push(new Name(name));
|
||||
}
|
||||
}
|
||||
|
||||
public push(styleSegment: XmlComponent): void {
|
||||
this.root.push(styleSegment);
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,20 @@
|
||||
import { assert, expect } from "chai";
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { CharacterStyle, ParagraphStyle } from "./style";
|
||||
import { EMPTY_OBJECT } from "file/xml-components";
|
||||
|
||||
import { Styles } from "./styles";
|
||||
|
||||
import { EMPTY_OBJECT } from "file/xml-components";
|
||||
|
||||
describe("Styles", () => {
|
||||
let styles: Styles;
|
||||
|
||||
beforeEach(() => {
|
||||
styles = new Styles();
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create styles with correct rootKey", () => {
|
||||
const newJson = JSON.parse(JSON.stringify(styles));
|
||||
assert.equal(newJson.rootKey, "w:styles");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#createParagraphStyle", () => {
|
||||
it("should create a new paragraph style and push it onto this collection", () => {
|
||||
const pStyle = styles.createParagraphStyle("pStyleId");
|
||||
expect(pStyle).to.instanceOf(ParagraphStyle);
|
||||
const styles = new Styles({
|
||||
paragraphStyles: [
|
||||
{
|
||||
id: "pStyleId",
|
||||
},
|
||||
],
|
||||
});
|
||||
const tree = new Formatter().format(styles)["w:styles"].filter((x) => !x._attr);
|
||||
expect(tree).to.deep.equal([
|
||||
{
|
||||
@ -35,8 +24,14 @@ describe("Styles", () => {
|
||||
});
|
||||
|
||||
it("should set the paragraph name if given", () => {
|
||||
const pStyle = styles.createParagraphStyle("pStyleId", "Paragraph Style");
|
||||
expect(pStyle).to.instanceOf(ParagraphStyle);
|
||||
const styles = new Styles({
|
||||
paragraphStyles: [
|
||||
{
|
||||
id: "pStyleId",
|
||||
name: "Paragraph Style",
|
||||
},
|
||||
],
|
||||
});
|
||||
const tree = new Formatter().format(styles)["w:styles"].filter((x) => !x._attr);
|
||||
expect(tree).to.deep.equal([
|
||||
{
|
||||
@ -51,8 +46,13 @@ describe("Styles", () => {
|
||||
|
||||
describe("#createCharacterStyle", () => {
|
||||
it("should create a new character style and push it onto this collection", () => {
|
||||
const cStyle = styles.createCharacterStyle("pStyleId");
|
||||
expect(cStyle).to.instanceOf(CharacterStyle);
|
||||
const styles = new Styles({
|
||||
characterStyles: [
|
||||
{
|
||||
id: "pStyleId",
|
||||
},
|
||||
],
|
||||
});
|
||||
const tree = new Formatter().format(styles)["w:styles"].filter((x) => !x._attr);
|
||||
expect(tree).to.deep.equal([
|
||||
{
|
||||
@ -61,7 +61,7 @@ describe("Styles", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -74,8 +74,14 @@ describe("Styles", () => {
|
||||
});
|
||||
|
||||
it("should set the character name if given", () => {
|
||||
const cStyle = styles.createCharacterStyle("pStyleId", "Character Style");
|
||||
expect(cStyle).to.instanceOf(CharacterStyle);
|
||||
const styles = new Styles({
|
||||
characterStyles: [
|
||||
{
|
||||
id: "pStyleId",
|
||||
name: "Character Style",
|
||||
},
|
||||
],
|
||||
});
|
||||
const tree = new Formatter().format(styles)["w:styles"].filter((x) => !x._attr);
|
||||
expect(tree).to.deep.equal([
|
||||
{
|
||||
@ -85,7 +91,7 @@ describe("Styles", () => {
|
||||
{
|
||||
"w:uiPriority": {
|
||||
_attr: {
|
||||
"w:val": "99",
|
||||
"w:val": 99,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1,36 +1,41 @@
|
||||
import { BaseXmlComponent, XmlComponent } from "file/xml-components";
|
||||
import { DocumentDefaults } from "./defaults";
|
||||
import { BaseXmlComponent, ImportedXmlComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
import { CharacterStyle, ParagraphStyle } from "./style";
|
||||
import { ICharacterStyleOptions } from "./style/character-style";
|
||||
import { IParagraphStyleOptions } from "./style/paragraph-style";
|
||||
export * from "./border";
|
||||
|
||||
export interface IStylesOptions {
|
||||
readonly initialStyles?: BaseXmlComponent;
|
||||
readonly paragraphStyles?: IParagraphStyleOptions[];
|
||||
readonly characterStyles?: ICharacterStyleOptions[];
|
||||
readonly importedStyles?: Array<XmlComponent | ParagraphStyle | CharacterStyle | ImportedXmlComponent>;
|
||||
}
|
||||
|
||||
export class Styles extends XmlComponent {
|
||||
constructor(initialStyles?: BaseXmlComponent) {
|
||||
constructor(options: IStylesOptions) {
|
||||
super("w:styles");
|
||||
if (initialStyles) {
|
||||
this.root.push(initialStyles);
|
||||
}
|
||||
|
||||
if (options.initialStyles) {
|
||||
this.root.push(options.initialStyles);
|
||||
}
|
||||
|
||||
public push(style: XmlComponent): Styles {
|
||||
if (options.importedStyles) {
|
||||
for (const style of options.importedStyles) {
|
||||
this.root.push(style);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public createDocumentDefaults(): DocumentDefaults {
|
||||
const defaults = new DocumentDefaults();
|
||||
this.push(defaults);
|
||||
return defaults;
|
||||
if (options.paragraphStyles) {
|
||||
for (const style of options.paragraphStyles) {
|
||||
this.root.push(new ParagraphStyle(style));
|
||||
}
|
||||
}
|
||||
|
||||
public createParagraphStyle(styleId: string, name?: string): ParagraphStyle {
|
||||
const paragraphStyle = new ParagraphStyle(styleId, name);
|
||||
this.push(paragraphStyle);
|
||||
return paragraphStyle;
|
||||
}
|
||||
|
||||
public createCharacterStyle(styleId: string, name?: string): CharacterStyle {
|
||||
const characterStyle = new CharacterStyle(styleId, name);
|
||||
this.push(characterStyle);
|
||||
return characterStyle;
|
||||
if (options.characterStyles) {
|
||||
for (const style of options.characterStyles) {
|
||||
this.root.push(new CharacterStyle(style));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,18 +16,24 @@ export class TableOfContents extends XmlComponent {
|
||||
|
||||
const content = new StructuredDocumentTagContent();
|
||||
|
||||
const beginParagraph = new Paragraph({});
|
||||
const beginRun = new Run({});
|
||||
beginRun.addChildElement(new Begin(true));
|
||||
beginRun.addChildElement(new FieldInstruction(properties));
|
||||
beginRun.addChildElement(new Separate());
|
||||
beginParagraph.addRun(beginRun);
|
||||
const beginParagraph = new Paragraph({
|
||||
children: [
|
||||
new Run({
|
||||
children: [new Begin(true), new FieldInstruction(properties), new Separate()],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
content.addChildElement(beginParagraph);
|
||||
|
||||
const endParagraph = new Paragraph({});
|
||||
const endRun = new Run({});
|
||||
endRun.addChildElement(new End());
|
||||
endParagraph.addRun(endRun);
|
||||
const endParagraph = new Paragraph({
|
||||
children: [
|
||||
new Run({
|
||||
children: [new End()],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
content.addChildElement(endParagraph);
|
||||
|
||||
this.root.push(content);
|
||||
|
Reference in New Issue
Block a user