update file/document and section-properties

This commit is contained in:
Tom Hunkapiller
2021-05-25 03:41:12 +03:00
parent e198f0752a
commit 63cea76eac
54 changed files with 861 additions and 659 deletions

View File

@ -3,6 +3,7 @@ import { expect } from "chai";
import { Formatter } from "export/formatter";
import { Body } from "./body";
import { sectionMarginDefaults } from "./section-properties";
describe("Body", () => {
let body: Body;
@ -32,13 +33,13 @@ describe("Body", () => {
{
"w:pgMar": {
_attr: {
"w:top": 1440,
"w:right": 1440,
"w:bottom": 1440,
"w:left": 1440,
"w:header": 708,
"w:footer": 708,
"w:gutter": 0,
"w:top": sectionMarginDefaults.TOP,
"w:right": sectionMarginDefaults.RIGHT,
"w:bottom": sectionMarginDefaults.BOTTOM,
"w:left": sectionMarginDefaults.LEFT,
"w:header": sectionMarginDefaults.HEADER,
"w:footer": sectionMarginDefaults.FOOTER,
"w:gutter": sectionMarginDefaults.GUTTER,
},
},
},
@ -47,7 +48,7 @@ describe("Body", () => {
_attr: {},
},
},
{ "w:cols": { _attr: { "w:space": 708, "w:sep": false, "w:num": 1 } } },
// { "w:cols": { _attr: { "w:space": 708, "w:sep": false, "w:num": 1 } } },
{ "w:docGrid": { _attr: { "w:linePitch": 360 } } },
],
},

View File

@ -1,13 +0,0 @@
import { XmlAttributeComponent } from "file/xml-components";
export class ColumnsAttributes extends XmlAttributeComponent<{
readonly space?: number;
readonly num?: number;
readonly separate?: boolean;
}> {
protected readonly xmlKeys = {
space: "w:space",
num: "w:num",
separate: "w:sep",
};
}

View File

@ -1,15 +0,0 @@
import { XmlComponent } from "file/xml-components";
import { ColumnsAttributes } from "./columns-attributes";
export class Columns extends XmlComponent {
constructor(space: number, num: number, separate: boolean) {
super("w:cols");
this.root.push(
new ColumnsAttributes({
space: space,
num: num,
separate: separate,
}),
);
}
}

View File

@ -1,11 +0,0 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IDocGridAttributesProperties {
readonly linePitch?: number;
}
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
protected readonly xmlKeys = {
linePitch: "w:linePitch",
};
}

View File

@ -1,13 +0,0 @@
import { XmlComponent } from "file/xml-components";
import { DocGridAttributes } from "./doc-grid-attributes";
export class DocumentGrid extends XmlComponent {
constructor(linePitch: number) {
super("w:docGrid");
this.root.push(
new DocGridAttributes({
linePitch: linePitch,
}),
);
}
}

View File

@ -1,17 +0,0 @@
import { XmlAttributeComponent } from "file/xml-components";
export enum FooterReferenceType {
DEFAULT = "default",
FIRST = "first",
EVEN = "even",
}
export class FooterReferenceAttributes extends XmlAttributeComponent<{
readonly type: string;
readonly id: string;
}> {
protected readonly xmlKeys = {
type: "w:type",
id: "r:id",
};
}

View File

@ -1,42 +0,0 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { FooterReference } from "./footer-reference";
import { FooterReferenceType } from "./footer-reference-attributes";
describe("footerReference", () => {
it("should create", () => {
const footer = new FooterReference({
footerType: FooterReferenceType.DEFAULT,
footerId: 1,
});
const tree = new Formatter().format(footer);
expect(tree).to.deep.equal({
"w:footerReference": {
_attr: {
"r:id": "rId1",
"w:type": "default",
},
},
});
});
it("should create without a footer type", () => {
const footer = new FooterReference({
footerId: 1,
});
const tree = new Formatter().format(footer);
expect(tree).to.deep.equal({
"w:footerReference": {
_attr: {
"r:id": "rId1",
"w:type": "default",
},
},
});
});
});

View File

@ -1,20 +0,0 @@
import { XmlComponent } from "file/xml-components";
import { FooterReferenceAttributes, FooterReferenceType } from "./footer-reference-attributes";
export interface IFooterOptions {
readonly footerType?: FooterReferenceType;
readonly footerId?: number;
}
export class FooterReference extends XmlComponent {
constructor(options: IFooterOptions) {
super("w:footerReference");
this.root.push(
new FooterReferenceAttributes({
type: options.footerType || FooterReferenceType.DEFAULT,
id: `rId${options.footerId}`,
}),
);
}
}

View File

@ -1,2 +0,0 @@
export * from "./footer-reference";
export * from "./footer-reference-attributes";

View File

@ -1,17 +0,0 @@
import { XmlAttributeComponent } from "file/xml-components";
export enum HeaderReferenceType {
DEFAULT = "default",
FIRST = "first",
EVEN = "even",
}
export class HeaderReferenceAttributes extends XmlAttributeComponent<{
readonly type: string;
readonly id: string;
}> {
protected readonly xmlKeys = {
type: "w:type",
id: "r:id",
};
}

View File

@ -1,42 +0,0 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { HeaderReference } from "./header-reference";
import { HeaderReferenceType } from "./header-reference-attributes";
describe("HeaderReference", () => {
it("should create", () => {
const footer = new HeaderReference({
headerType: HeaderReferenceType.DEFAULT,
headerId: 1,
});
const tree = new Formatter().format(footer);
expect(tree).to.deep.equal({
"w:headerReference": {
_attr: {
"r:id": "rId1",
"w:type": "default",
},
},
});
});
it("should create without a header type", () => {
const footer = new HeaderReference({
headerId: 1,
});
const tree = new Formatter().format(footer);
expect(tree).to.deep.equal({
"w:headerReference": {
_attr: {
"r:id": "rId1",
"w:type": "default",
},
},
});
});
});

View File

@ -1,19 +0,0 @@
import { XmlComponent } from "file/xml-components";
import { HeaderReferenceAttributes, HeaderReferenceType } from "./header-reference-attributes";
export interface IHeaderReferenceOptions {
readonly headerType?: HeaderReferenceType;
readonly headerId?: number;
}
export class HeaderReference extends XmlComponent {
constructor(options: IHeaderReferenceOptions) {
super("w:headerReference");
this.root.push(
new HeaderReferenceAttributes({
type: options.headerType || HeaderReferenceType.DEFAULT,
id: `rId${options.headerId}`,
}),
);
}
}

View File

@ -1,2 +0,0 @@
export * from "./header-reference";
export * from "./header-reference-attributes";

View File

@ -1,8 +1,2 @@
export * from "./section-properties";
export * from "./footer-reference";
export * from "./header-reference";
export * from "./page-size";
export * from "./page-number";
export * from "./page-border";
export * from "./line-number";
export * from "./type";
export * from "./properties";

View File

@ -1 +0,0 @@
export * from "./line-number";

View File

@ -1,31 +0,0 @@
// http://officeopenxml.com/WPsectionLineNumbering.php
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
export enum LineNumberRestartFormat {
CONTINUOUS = "continuous",
NEW_SECTION = "newSection",
NEW_PAGE = "newPage",
}
export interface ILineNumberAttributes {
readonly countBy?: number;
readonly start?: number;
readonly restart?: LineNumberRestartFormat;
readonly distance?: number;
}
export class LineNumberAttributes extends XmlAttributeComponent<ILineNumberAttributes> {
protected readonly xmlKeys = {
countBy: "w:countBy",
start: "w:start",
restart: "w:restart",
distance: "w:distance",
};
}
export class LineNumberType extends XmlComponent {
constructor(options: ILineNumberAttributes) {
super("w:lnNumType");
this.root.push(new LineNumberAttributes(options));
}
}

View File

@ -1 +0,0 @@
export * from "./page-borders";

View File

@ -1,23 +0,0 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IPageMarginAttributes {
readonly top?: number;
readonly right?: number;
readonly bottom?: number;
readonly left?: number;
readonly header?: number;
readonly footer?: number;
readonly gutter?: number;
}
export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> {
protected readonly xmlKeys = {
top: "w:top",
right: "w:right",
bottom: "w:bottom",
left: "w:left",
header: "w:header",
footer: "w:footer",
gutter: "w:gutter",
};
}

View File

@ -1,19 +0,0 @@
import { XmlComponent } from "file/xml-components";
import { PageMarginAttributes } from "./page-margin-attributes";
export class PageMargin extends XmlComponent {
constructor(top: number, right: number, bottom: number, left: number, header: number, footer: number, gutter: number) {
super("w:pgMar");
this.root.push(
new PageMarginAttributes({
top: top,
right: right,
bottom: bottom,
left: left,
header: header,
footer: footer,
gutter: gutter,
}),
);
}
}

View File

@ -1 +0,0 @@
export * from "./page-number";

View File

@ -1,47 +0,0 @@
// http://officeopenxml.com/WPSectionPgNumType.php
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
export enum PageNumberFormat {
CARDINAL_TEXT = "cardinalText",
DECIMAL = "decimal",
DECIMAL_ENCLOSED_CIRCLE = "decimalEnclosedCircle",
DECIMAL_ENCLOSED_FULL_STOP = "decimalEnclosedFullstop",
DECIMAL_ENCLOSED_PAREN = "decimalEnclosedParen",
DECIMAL_ZERO = "decimalZero",
LOWER_LETTER = "lowerLetter",
LOWER_ROMAN = "lowerRoman",
NONE = "none",
ORDINAL_TEXT = "ordinalText",
UPPER_LETTER = "upperLetter",
UPPER_ROMAN = "upperRoman",
DECIMAL_FULL_WIDTH = "decimalFullWidth",
}
export enum PageNumberSeparator {
COLON = "colon",
EM_DASH = "emDash",
EN_DASH = "endash",
HYPHEN = "hyphen",
PERIOD = "period",
}
export interface IPageNumberTypeAttributes {
readonly start?: number;
readonly formatType?: PageNumberFormat;
readonly separator?: PageNumberSeparator;
}
export class PageNumberTypeAttributes extends XmlAttributeComponent<IPageNumberTypeAttributes> {
protected readonly xmlKeys = {
start: "w:start",
formatType: "w:fmt",
separator: "w:chapSep",
};
}
export class PageNumberType extends XmlComponent {
constructor(options: IPageNumberTypeAttributes) {
super("w:pgNumType");
this.root.push(new PageNumberTypeAttributes(options));
}
}

View File

@ -1,2 +0,0 @@
export * from "./page-size";
export * from "./page-size-attributes";

View File

@ -1,20 +0,0 @@
import { XmlAttributeComponent } from "file/xml-components";
export enum PageOrientation {
PORTRAIT = "portrait",
LANDSCAPE = "landscape",
}
export interface IPageSizeAttributes {
readonly width?: number;
readonly height?: number;
readonly orientation?: PageOrientation;
}
export class PageSizeAttributes extends XmlAttributeComponent<IPageSizeAttributes> {
protected readonly xmlKeys = {
width: "w:w",
height: "w:h",
orientation: "w:orient",
};
}

View File

@ -1,18 +0,0 @@
import { XmlComponent } from "file/xml-components";
import { PageOrientation, PageSizeAttributes } from "./page-size-attributes";
export class PageSize extends XmlComponent {
constructor(width: number, height: number, orientation: PageOrientation) {
super("w:pgSz");
const flip = orientation === PageOrientation.LANDSCAPE;
this.root.push(
new PageSizeAttributes({
width: flip ? height : width,
height: flip ? width : height,
orientation: orientation,
}),
);
}
}

View File

@ -0,0 +1,41 @@
import { decimalNumber, twipsMeasureValue } from "file/values";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
// <xsd:complexType name="CT_Columns">
// <xsd:sequence minOccurs="0">
// <xsd:element name="col" type="CT_Column" maxOccurs="45"/>
// </xsd:sequence>
// <xsd:attribute name="equalWidth" type="s:ST_OnOff" use="optional"/>
// <xsd:attribute name="space" type="s:ST_TwipsMeasure" use="optional" default="720"/>
// <xsd:attribute name="num" type="ST_DecimalNumber" use="optional" default="1"/>
// <xsd:attribute name="sep" type="s:ST_OnOff" use="optional"/>
// </xsd:complexType>
export interface IColumnsAttributes {
readonly space?: number | string;
readonly count?: number;
readonly separate?: boolean;
readonly equalWidth?: boolean;
}
export class ColumnsAttributes extends XmlAttributeComponent<IColumnsAttributes> {
protected readonly xmlKeys = {
space: "w:space",
count: "w:num",
separate: "w:sep",
equalWidth: "w:equalWidth",
};
}
export class Columns extends XmlComponent {
constructor({ space, count, separate, equalWidth }: IColumnsAttributes) {
super("w:cols");
this.root.push(
new ColumnsAttributes({
space: space === undefined ? undefined : twipsMeasureValue(space),
count: count === undefined ? undefined : decimalNumber(count),
separate,
equalWidth,
}),
);
}
}

View File

@ -0,0 +1,38 @@
import { decimalNumber } from "file/values";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
// not implemented
// <xsd:simpleType name="ST_DocGrid">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="default"/>
// <xsd:enumeration value="lines"/>
// <xsd:enumeration value="linesAndChars"/>
// <xsd:enumeration value="snapToChars"/>
// </xsd:restriction>
// </xsd:simpleType>
// <xsd:complexType name="CT_DocGrid">
// <xsd:attribute name="type" type="ST_DocGrid"/>
// <xsd:attribute name="linePitch" type="ST_DecimalNumber"/>
// <xsd:attribute name="charSpace" type="ST_DecimalNumber"/>
// </xsd:complexType>
export interface IDocGridAttributesProperties {
readonly linePitch?: number;
}
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
protected readonly xmlKeys = {
linePitch: "w:linePitch",
};
}
export class DocumentGrid extends XmlComponent {
constructor(linePitch: number) {
super("w:docGrid");
this.root.push(
new DocGridAttributes({
linePitch: decimalNumber(linePitch),
}),
);
}
}

View File

@ -0,0 +1,56 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./header-footer-reference";
describe("HeaderFooterReference", () => {
it("#constructor (footer)", () => {
const footer = new HeaderFooterReference(HeaderFooterType.FOOTER, {
type: HeaderFooterReferenceType.DEFAULT,
id: 1,
});
const tree = new Formatter().format(footer);
expect(tree).to.deep.equal({
"w:footerReference": {
_attr: {
"r:id": "rId1",
"w:type": "default",
},
},
});
});
it("#constructor (header)", () => {
const header = new HeaderFooterReference(HeaderFooterType.HEADER, {
type: HeaderFooterReferenceType.DEFAULT,
id: 1,
});
const tree = new Formatter().format(header);
expect(tree).to.deep.equal({
"w:headerReference": {
_attr: {
"r:id": "rId1",
"w:type": "default",
},
},
});
});
it("should create without a type", () => {
const footer = new HeaderFooterReference(HeaderFooterType.FOOTER, {
id: 1,
});
const tree = new Formatter().format(footer);
expect(tree).to.deep.equal({
"w:footerReference": {
_attr: {
"r:id": "rId1",
"w:type": "default",
},
},
});
});
});

View File

@ -0,0 +1,65 @@
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
// <xsd:simpleType name="ST_HdrFtr">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="even"/>
// <xsd:enumeration value="default"/>
// <xsd:enumeration value="first"/>
// </xsd:restriction>
// </xsd:simpleType>
export enum HeaderFooterReferenceType {
DEFAULT = "default",
FIRST = "first",
EVEN = "even",
}
// </xsd:complexType>
// <xsd:group name="EG_HdrFtrReferences">
// <xsd:choice>
// <xsd:element name="headerReference" type="CT_HdrFtrRef" minOccurs="0"/>
// <xsd:element name="footerReference" type="CT_HdrFtrRef" minOccurs="0"/>
// </xsd:choice>
// </xsd:group>
// <xsd:complexType name="CT_HdrFtrRef">
// <xsd:complexContent>
// <xsd:extension base="CT_Rel">
// <xsd:attribute name="type" type="ST_HdrFtr" use="required"/>
// </xsd:extension>
// </xsd:complexContent>
// <xsd:complexType name="CT_Rel">
// <xsd:attribute ref="r:id" use="required"/>
// </xsd:complexType>
export interface IHeaderFooterOptions {
readonly type?: HeaderFooterReferenceType;
readonly id?: number;
}
class FooterReferenceAttributes extends XmlAttributeComponent<{
readonly type: HeaderFooterReferenceType;
readonly id: string;
}> {
protected readonly xmlKeys = {
type: "w:type",
id: "r:id",
};
}
export enum HeaderFooterType {
HEADER = "w:headerReference",
FOOTER = "w:footerReference",
}
export class HeaderFooterReference extends XmlComponent {
constructor(type: HeaderFooterType, options: IHeaderFooterOptions) {
super(type);
this.root.push(
new FooterReferenceAttributes({
type: options.type || HeaderFooterReferenceType.DEFAULT,
id: `rId${options.id}`,
}),
);
}
}

View File

@ -0,0 +1,11 @@
export * from "./columns";
export * from "./doc-grid";
// export * from "./header-reference";
export * from "./page-size";
export * from "./page-number";
export * from "./page-borders";
export * from "./page-margin";
export * from "./page-borders";
export * from "./line-number";
export * from "./section-type";
export * from "./header-footer-reference";

View File

@ -0,0 +1,53 @@
// http://officeopenxml.com/WPsectionLineNumbering.php
import { decimalNumber, twipsMeasureValue } from "file/values";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
// <xsd:simpleType name="ST_LineNumberRestart">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="newPage"/>
// <xsd:enumeration value="newSection"/>
// <xsd:enumeration value="continuous"/>
// </xsd:restriction>
// </xsd:simpleType>
export enum LineNumberRestartFormat {
NEW_PAGE = "newPage",
NEW_SECTION = "newSection",
CONTINUOUS = "continuous",
}
// <xsd:complexType name="CT_LineNumber">
// <xsd:attribute name="countBy" type="ST_DecimalNumber" use="optional"/>
// <xsd:attribute name="start" type="ST_DecimalNumber" use="optional" default="1"/>
// <xsd:attribute name="distance" type="s:ST_TwipsMeasure" use="optional"/>
// <xsd:attribute name="restart" type="ST_LineNumberRestart" use="optional" default="newPage"/>
// </xsd:complexType>
export interface ILineNumberAttributes {
readonly countBy?: number;
readonly start?: number;
readonly restart?: LineNumberRestartFormat;
readonly distance?: number | string;
}
export class LineNumberAttributes extends XmlAttributeComponent<ILineNumberAttributes> {
protected readonly xmlKeys = {
countBy: "w:countBy",
start: "w:start",
restart: "w:restart",
distance: "w:distance",
};
}
export class LineNumberType extends XmlComponent {
constructor({ countBy, start, restart, distance }: ILineNumberAttributes) {
super("w:lnNumType");
this.root.push(
new LineNumberAttributes({
countBy: countBy === undefined ? undefined : decimalNumber(countBy),
start: start === undefined ? undefined : decimalNumber(start),
restart,
distance: distance === undefined ? undefined : twipsMeasureValue(distance),
}),
);
}
}

View File

@ -74,8 +74,8 @@ describe("PageBorders", () => {
},
});
expect(tree["w:pgBorders"][2]).to.deep.equal({
"w:right": {
_attr: { "w:color": "223344", "w:sz": 20, "w:val": "double" },
"w:left": {
_attr: { "w:color": "889900", "w:sz": 40, "w:val": "dotted" },
},
});
expect(tree["w:pgBorders"][3]).to.deep.equal({
@ -84,8 +84,8 @@ describe("PageBorders", () => {
},
});
expect(tree["w:pgBorders"][4]).to.deep.equal({
"w:left": {
_attr: { "w:color": "889900", "w:sz": 40, "w:val": "dotted" },
"w:right": {
_attr: { "w:color": "223344", "w:sz": 20, "w:val": "double" },
},
});
});

View File

@ -2,17 +2,36 @@
import { BorderElement, IBorderOptions } from "file/border";
import { IgnoreIfEmptyXmlComponent, XmlAttributeComponent } from "file/xml-components";
// <xsd:simpleType name="ST_PageBorderDisplay">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="allPages"/>
// <xsd:enumeration value="firstPage"/>
// <xsd:enumeration value="notFirstPage"/>
// </xsd:restriction>
// </xsd:simpleType>
export enum PageBorderDisplay {
ALL_PAGES = "allPages",
FIRST_PAGE = "firstPage",
NOT_FIRST_PAGE = "notFirstPage",
}
// <xsd:simpleType name="ST_PageBorderOffset">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="page"/>
// <xsd:enumeration value="text"/>
// </xsd:restriction>
// </xsd:simpleType>
export enum PageBorderOffsetFrom {
PAGE = "page",
TEXT = "text",
}
// <xsd:simpleType name="ST_PageBorderZOrder">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="front"/>
// <xsd:enumeration value="back"/>
// </xsd:restriction>
// </xsd:simpleType>
export enum PageBorderZOrder {
BACK = "back",
FRONT = "front",
@ -40,6 +59,17 @@ class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes>
};
}
// <xsd:complexType name="CT_PageBorders">
// <xsd:sequence>
// <xsd:element name="top" type="CT_TopPageBorder" minOccurs="0"/>
// <xsd:element name="left" type="CT_PageBorder" minOccurs="0"/>
// <xsd:element name="bottom" type="CT_BottomPageBorder" minOccurs="0"/>
// <xsd:element name="right" type="CT_PageBorder" minOccurs="0"/>
// </xsd:sequence>
// <xsd:attribute name="zOrder" type="ST_PageBorderZOrder" use="optional" default="front"/>
// <xsd:attribute name="display" type="ST_PageBorderDisplay" use="optional"/>
// <xsd:attribute name="offsetFrom" type="ST_PageBorderOffset" use="optional" default="text"/>
// </xsd:complexType>
export class PageBorders extends IgnoreIfEmptyXmlComponent {
constructor(options?: IPageBordersOptions) {
super("w:pgBorders");
@ -63,14 +93,14 @@ export class PageBorders extends IgnoreIfEmptyXmlComponent {
if (options.pageBorderTop) {
this.root.push(new BorderElement("w:top", options.pageBorderTop));
}
if (options.pageBorderRight) {
this.root.push(new BorderElement("w:right", options.pageBorderRight));
if (options.pageBorderLeft) {
this.root.push(new BorderElement("w:left", options.pageBorderLeft));
}
if (options.pageBorderBottom) {
this.root.push(new BorderElement("w:bottom", options.pageBorderBottom));
}
if (options.pageBorderLeft) {
this.root.push(new BorderElement("w:left", options.pageBorderLeft));
if (options.pageBorderRight) {
this.root.push(new BorderElement("w:right", options.pageBorderRight));
}
}
}

View File

@ -0,0 +1,58 @@
import { signedTwipsMeasureValue, twipsMeasureValue } from "file/values";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
// <xsd:complexType name="CT_PageMar">
// <xsd:attribute name="top" type="ST_SignedTwipsMeasure" use="required"/>
// <xsd:attribute name="right" type="s:ST_TwipsMeasure" use="required"/>
// <xsd:attribute name="bottom" type="ST_SignedTwipsMeasure" use="required"/>
// <xsd:attribute name="left" type="s:ST_TwipsMeasure" use="required"/>
// <xsd:attribute name="header" type="s:ST_TwipsMeasure" use="required"/>
// <xsd:attribute name="footer" type="s:ST_TwipsMeasure" use="required"/>
// <xsd:attribute name="gutter" type="s:ST_TwipsMeasure" use="required"/>
// </xsd:complexType>
export interface IPageMarginAttributes {
readonly top?: number | string;
readonly right?: number | string;
readonly bottom?: number | string;
readonly left?: number | string;
readonly header?: number | string;
readonly footer?: number | string;
readonly gutter?: number | string;
}
export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> {
protected readonly xmlKeys = {
top: "w:top",
right: "w:right",
bottom: "w:bottom",
left: "w:left",
header: "w:header",
footer: "w:footer",
gutter: "w:gutter",
};
}
export class PageMargin extends XmlComponent {
constructor(
top: number | string,
right: number | string,
bottom: number | string,
left: number | string,
header: number | string,
footer: number | string,
gutter: number | string,
) {
super("w:pgMar");
this.root.push(
new PageMarginAttributes({
top: signedTwipsMeasureValue(top),
right: twipsMeasureValue(right),
bottom: signedTwipsMeasureValue(bottom),
left: twipsMeasureValue(left),
header: twipsMeasureValue(header),
footer: twipsMeasureValue(footer),
gutter: twipsMeasureValue(gutter),
}),
);
}
}

View File

@ -0,0 +1,54 @@
// http://officeopenxml.com/WPSectionPgNumType.php
import { NumberFormat } from "file/shared/number-format";
import { decimalNumber } from "file/values";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
// <xsd:simpleType name="ST_ChapterSep">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="hyphen"/>
// <xsd:enumeration value="period"/>
// <xsd:enumeration value="colon"/>
// <xsd:enumeration value="emDash"/>
// <xsd:enumeration value="enDash"/>
// </xsd:restriction>
// </xsd:simpleType>
export enum PageNumberSeparator {
HYPHEN = "hyphen",
PERIOD = "period",
COLON = "colon",
EM_DASH = "emDash",
EN_DASH = "endash",
}
export interface IPageNumberTypeAttributes {
readonly start?: number;
readonly formatType?: NumberFormat;
readonly separator?: PageNumberSeparator;
}
// <xsd:complexType name="CT_PageNumber">
// <xsd:attribute name="fmt" type="ST_NumberFormat" use="optional" default="decimal"/>
// <xsd:attribute name="start" type="ST_DecimalNumber" use="optional"/>
// <xsd:attribute name="chapStyle" type="ST_DecimalNumber" use="optional"/>
// <xsd:attribute name="chapSep" type="ST_ChapterSep" use="optional" default="hyphen"/>
// </xsd:complexType>
export class PageNumberTypeAttributes extends XmlAttributeComponent<IPageNumberTypeAttributes> {
protected readonly xmlKeys = {
start: "w:start",
formatType: "w:fmt",
separator: "w:chapSep",
};
}
export class PageNumberType extends XmlComponent {
constructor({ start, formatType, separator }: IPageNumberTypeAttributes) {
super("w:pgNumType");
this.root.push(
new PageNumberTypeAttributes({
start: start === undefined ? undefined : decimalNumber(start),
formatType,
separator,
}),
);
}
}

View File

@ -2,8 +2,7 @@ import { expect } from "chai";
import { Formatter } from "export/formatter";
import { PageSize } from "./page-size";
import { PageOrientation } from "./page-size-attributes";
import { PageOrientation, PageSize } from "./page-size";
describe("PageSize", () => {
describe("#constructor()", () => {

View File

@ -0,0 +1,52 @@
import { twipsMeasureValue } from "file/values";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
// <xsd:simpleType name="ST_PageOrientation">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="portrait"/>
// <xsd:enumeration value="landscape"/>
// </xsd:restriction>
// </xsd:simpleType>
export enum PageOrientation {
PORTRAIT = "portrait",
LANDSCAPE = "landscape",
}
// <xsd:complexType name="CT_PageSz">
// <xsd:attribute name="w" type="s:ST_TwipsMeasure"/>
// <xsd:attribute name="h" type="s:ST_TwipsMeasure"/>
// <xsd:attribute name="orient" type="ST_PageOrientation" use="optional"/>
// <xsd:attribute name="code" type="ST_DecimalNumber" use="optional"/>
// </xsd:complexType>
export interface IPageSizeAttributes {
readonly width?: number | string;
readonly height?: number | string;
readonly orientation?: PageOrientation;
}
export class PageSizeAttributes extends XmlAttributeComponent<IPageSizeAttributes> {
protected readonly xmlKeys = {
width: "w:w",
height: "w:h",
orientation: "w:orient",
};
}
export class PageSize extends XmlComponent {
constructor(width: number | string, height: number | string, orientation: PageOrientation) {
super("w:pgSz");
const flip = orientation === PageOrientation.LANDSCAPE;
const widthTwips = twipsMeasureValue(width);
const heightTwips = twipsMeasureValue(height);
this.root.push(
new PageSizeAttributes({
width: flip ? heightTwips : widthTwips,
height: flip ? widthTwips : heightTwips,
orientation: orientation,
}),
);
}
}

View File

@ -1,8 +1,7 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { Type } from "./section-type";
import { SectionType } from "./section-type-attributes";
import { SectionType, Type } from "./section-type";
describe("Type", () => {
it("should create with even page section type", () => {

View File

@ -0,0 +1,37 @@
// http://officeopenxml.com/WPsection.php
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
// <xsd:simpleType name="ST_SectionMark">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="nextPage"/>
// <xsd:enumeration value="nextColumn"/>
// <xsd:enumeration value="continuous"/>
// <xsd:enumeration value="evenPage"/>
// <xsd:enumeration value="oddPage"/>
// </xsd:restriction>
// </xsd:simpleType>
export enum SectionType {
NEXT_PAGE = "nextPage",
NEXT_COLUMN = "nextColumn",
CONTINUOUS = "continuous",
EVEN_PAGE = "evenPage",
ODD_PAGE = "oddPage",
}
// <xsd:complexType name="CT_SectType">
// <xsd:attribute name="val" type="ST_SectionMark"/>
// </xsd:complexType>
export class SectionTypeAttributes extends XmlAttributeComponent<{
readonly val: SectionType;
}> {
protected readonly xmlKeys = {
val: "w:val",
};
}
export class Type extends XmlComponent {
constructor(value: SectionType) {
super("w:type");
this.root.push(new SectionTypeAttributes({ val: value }));
}
}

View File

@ -5,13 +5,30 @@ import { Formatter } from "export/formatter";
import { FooterWrapper } from "file/footer-wrapper";
import { HeaderWrapper } from "file/header-wrapper";
import { Media } from "file/media";
import { NumberFormat } from "file/shared/number-format";
import { VerticalAlign } from "file/vertical-align";
import { LineNumberRestartFormat } from "./line-number";
import { PageBorderOffsetFrom } from "./page-border";
import { PageNumberFormat } from "./page-number";
import { SectionProperties } from "./section-properties";
import { SectionType } from "./type/section-type-attributes";
import { PageOrientation } from "./properties";
import { LineNumberRestartFormat } from "./properties/line-number";
import { PageBorderOffsetFrom } from "./properties/page-borders";
import { SectionType } from "./properties/section-type";
import { sectionMarginDefaults, sectionPageSizeDefaults, SectionProperties } from "./section-properties";
const DEFAULT_MARGINS = {
"w:bottom": sectionMarginDefaults.BOTTOM,
"w:footer": sectionMarginDefaults.FOOTER,
"w:top": sectionMarginDefaults.TOP,
"w:right": sectionMarginDefaults.RIGHT,
"w:left": sectionMarginDefaults.LEFT,
"w:header": sectionMarginDefaults.HEADER,
"w:gutter": sectionMarginDefaults.GUTTER,
};
const PAGE_SIZE_DEFAULTS = {
"w:h": sectionPageSizeDefaults.HEIGHT,
"w:orient": sectionPageSizeDefaults.ORIENTATION,
"w:w": sectionPageSizeDefaults.WIDTH,
};
describe("SectionProperties", () => {
describe("#constructor()", () => {
@ -21,26 +38,27 @@ describe("SectionProperties", () => {
const properties = new SectionProperties({
page: {
size: {
width: 11906,
height: 16838,
width: 1190,
height: 1680,
orientation: PageOrientation.PORTRAIT,
},
margin: {
top: convertInchesToTwip(1),
right: convertInchesToTwip(1),
bottom: convertInchesToTwip(1),
left: convertInchesToTwip(1),
header: 708,
footer: 708,
gutter: 0,
top: "2in",
right: "2in",
bottom: "2in",
left: "2in",
header: 808,
footer: 808,
gutter: 10,
},
pageNumbers: {
start: 10,
formatType: PageNumberFormat.CARDINAL_TEXT,
formatType: NumberFormat.CARDINAL_TEXT,
},
},
column: {
space: 708,
count: 1,
space: 208,
count: 2,
separate: true,
},
grid: {
@ -62,25 +80,25 @@ describe("SectionProperties", () => {
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:headerReference": { _attr: { "r:id": "rId100", "w:type": "default" } } });
expect(tree["w:sectPr"][1]).to.deep.equal({ "w:footerReference": { _attr: { "r:id": "rId200", "w:type": "even" } } });
expect(tree["w:sectPr"][2]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } } });
expect(tree["w:sectPr"][2]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 1680, "w:w": 1190, "w:orient": "portrait" } } });
expect(tree["w:sectPr"][3]).to.deep.equal({
"w:pgMar": {
_attr: {
"w:bottom": 1440,
"w:footer": 708,
"w:top": 1440,
"w:right": 1440,
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
"w:bottom": "2in",
"w:footer": 808,
"w:top": "2in",
"w:right": "2in",
"w:left": "2in",
"w:header": 808,
"w:gutter": 10,
},
},
});
expect(tree["w:sectPr"][4]).to.deep.equal({ "w:pgNumType": { _attr: { "w:fmt": "cardinalText", "w:start": 10 } } });
expect(tree["w:sectPr"][5]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:sep": true, "w:num": 1 } } });
expect(tree["w:sectPr"][5]).to.deep.equal({ "w:cols": { _attr: { "w:space": 208, "w:sep": true, "w:num": 2 } } });
expect(tree["w:sectPr"][6]).to.deep.equal({ "w:vAlign": { _attr: { "w:val": "top" } } });
expect(tree["w:sectPr"][7]).to.deep.equal({ "w:titlePg": { _attr: { "w:val": "1" } } });
expect(tree["w:sectPr"][7]).to.deep.equal({ "w:titlePg": {} });
expect(tree["w:sectPr"][8]).to.deep.equal({ "w:docGrid": { _attr: { "w:linePitch": 360 } } });
});
@ -89,22 +107,12 @@ describe("SectionProperties", () => {
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } } });
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: PAGE_SIZE_DEFAULTS } });
expect(tree["w:sectPr"][1]).to.deep.equal({
"w:pgMar": {
_attr: {
"w:bottom": 1440,
"w:footer": 708,
"w:top": 1440,
"w:right": 1440,
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
},
},
"w:pgMar": { _attr: DEFAULT_MARGINS },
});
expect(tree["w:sectPr"][3]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:sep": false, "w:num": 1 } } });
expect(tree["w:sectPr"][4]).to.deep.equal({ "w:docGrid": { _attr: { "w:linePitch": 360 } } });
// expect(tree["w:sectPr"][3]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:sep": false, "w:num": 1 } } });
expect(tree["w:sectPr"][3]).to.deep.equal({ "w:docGrid": { _attr: { "w:linePitch": 360 } } });
});
it("should create section properties with changed options", () => {
@ -118,17 +126,12 @@ describe("SectionProperties", () => {
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } } });
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: PAGE_SIZE_DEFAULTS } });
expect(tree["w:sectPr"][1]).to.deep.equal({
"w:pgMar": {
_attr: {
"w:bottom": 1440,
"w:footer": 708,
...DEFAULT_MARGINS,
"w:top": 0,
"w:right": 1440,
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
},
},
});
@ -145,17 +148,12 @@ describe("SectionProperties", () => {
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } } });
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: PAGE_SIZE_DEFAULTS } });
expect(tree["w:sectPr"][1]).to.deep.equal({
"w:pgMar": {
_attr: {
...DEFAULT_MARGINS,
"w:bottom": 0,
"w:footer": 708,
"w:top": 1440,
"w:right": 1440,
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
},
},
});
@ -167,24 +165,25 @@ describe("SectionProperties", () => {
size: {
width: 0,
height: 0,
orientation: PageOrientation.LANDSCAPE,
},
},
});
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 0, "w:w": 0, "w:orient": "portrait" } } });
expect(tree["w:sectPr"][0]).to.deep.equal({
"w:pgSz": {
_attr: {
"w:h": 0,
"w:orient": PageOrientation.LANDSCAPE,
"w:w": 0,
},
},
});
expect(tree["w:sectPr"][1]).to.deep.equal({
"w:pgMar": {
_attr: {
"w:bottom": 1440,
"w:footer": 708,
"w:top": 1440,
"w:right": 1440,
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
},
_attr: DEFAULT_MARGINS,
},
});
});
@ -211,7 +210,7 @@ describe("SectionProperties", () => {
const properties = new SectionProperties({
page: {
pageNumbers: {
formatType: PageNumberFormat.UPPER_ROMAN,
formatType: NumberFormat.UPPER_ROMAN,
},
},
});

View File

@ -1,29 +1,21 @@
// http://officeopenxml.com/WPsection.php
// tslint:disable: no-unnecessary-initializer
import { convertInchesToTwip } from "convenience-functions";
import { FooterWrapper } from "file/footer-wrapper";
import { HeaderWrapper } from "file/header-wrapper";
import { VerticalAlign, VerticalAlignElement } from "file/vertical-align";
import { XmlComponent } from "file/xml-components";
import { OnOffElement, XmlComponent } from "file/xml-components";
import { Columns } from "./columns/columns";
import { DocumentGrid } from "./doc-grid/doc-grid";
import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes";
import { FooterReferenceType } from "./footer-reference";
import { FooterReference } from "./footer-reference/footer-reference";
import { HeaderReferenceType } from "./header-reference";
import { HeaderReference } from "./header-reference/header-reference";
import { ILineNumberAttributes, LineNumberType } from "./line-number";
import { IPageBordersOptions, PageBorders } from "./page-border";
import { PageMargin } from "./page-margin/page-margin";
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
import { IPageNumberTypeAttributes, PageNumberType } from "./page-number";
import { PageSize } from "./page-size/page-size";
import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes";
import { TitlePage } from "./title-page/title-page";
import { Type } from "./type/section-type";
import { SectionType } from "./type/section-type-attributes";
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./properties/header-footer-reference";
import { Columns, IColumnsAttributes } from "./properties/columns";
import { DocumentGrid, IDocGridAttributesProperties } from "./properties/doc-grid";
import { ILineNumberAttributes, LineNumberType } from "./properties/line-number";
import { IPageBordersOptions, PageBorders } from "./properties/page-borders";
import { IPageMarginAttributes, PageMargin } from "./properties/page-margin";
import { IPageNumberTypeAttributes, PageNumberType } from "./properties/page-number";
import { IPageSizeAttributes, PageOrientation, PageSize } from "./properties/page-size";
import { SectionType, Type } from "./properties/section-type";
export interface IHeaderFooterGroup<T> {
readonly default?: T;
@ -44,11 +36,7 @@ export interface ISectionPropertiesOptions {
readonly lineNumbers?: ILineNumberAttributes;
readonly titlePage?: boolean;
readonly verticalAlign?: VerticalAlign;
readonly column?: {
readonly space?: number;
readonly count?: number;
readonly separate?: boolean;
};
readonly column?: IColumnsAttributes;
readonly type?: SectionType;
}
@ -84,18 +72,39 @@ export interface ISectionPropertiesOptions {
// <xsd:element name="printerSettings" type="CT_Rel" minOccurs="0"/>
// </xsd:sequence>
// </xsd:group>
export const sectionMarginDefaults = {
TOP: "1in",
RIGHT: "1in",
BOTTOM: "1in",
LEFT: "1in",
HEADER: 708,
FOOTER: 708,
GUTTER: 0,
};
export const sectionPageSizeDefaults = {
WIDTH: 11906,
HEIGHT: 16838,
ORIENTATION: PageOrientation.PORTRAIT,
};
export class SectionProperties extends XmlComponent {
constructor({
page: {
size: { width = 11906, height = 16838, orientation = PageOrientation.PORTRAIT } = {},
size: {
width = sectionPageSizeDefaults.WIDTH,
height = sectionPageSizeDefaults.HEIGHT,
orientation = sectionPageSizeDefaults.ORIENTATION,
} = {},
margin: {
top = convertInchesToTwip(1),
right = convertInchesToTwip(1),
bottom = convertInchesToTwip(1),
left = convertInchesToTwip(1),
header = 708,
footer = 708,
gutter = 0,
top = sectionMarginDefaults.TOP,
right = sectionMarginDefaults.RIGHT,
bottom = sectionMarginDefaults.BOTTOM,
left = sectionMarginDefaults.LEFT,
header = sectionMarginDefaults.HEADER,
footer = sectionMarginDefaults.FOOTER,
gutter = sectionMarginDefaults.GUTTER,
} = {},
pageNumbers = {},
borders,
@ -104,15 +113,15 @@ export class SectionProperties extends XmlComponent {
headerWrapperGroup = {},
footerWrapperGroup = {},
lineNumbers,
titlePage = false,
titlePage,
verticalAlign,
column: { space = 708, count = 1, separate = false } = {},
column,
type,
}: ISectionPropertiesOptions = {}) {
super("w:sectPr");
this.addHeaders(headerWrapperGroup);
this.addFooters(footerWrapperGroup);
this.addHeaderFooterGroup(HeaderFooterType.HEADER, headerWrapperGroup);
this.addHeaderFooterGroup(HeaderFooterType.FOOTER, footerWrapperGroup);
if (type) {
this.root.push(new Type(type));
@ -131,72 +140,48 @@ export class SectionProperties extends XmlComponent {
this.root.push(new PageNumberType(pageNumbers));
this.root.push(new Columns(space, count, separate));
if (column) {
this.root.push(new Columns(column));
}
if (verticalAlign) {
this.root.push(new VerticalAlignElement(verticalAlign));
}
if (titlePage) {
this.root.push(new TitlePage());
if (titlePage !== undefined) {
this.root.push(new OnOffElement("w:titlePg", titlePage));
}
this.root.push(new DocumentGrid(linePitch));
}
private addHeaders(headers: IHeaderFooterGroup<HeaderWrapper>): void {
if (headers.default) {
private addHeaderFooterGroup(
type: HeaderFooterType,
group: IHeaderFooterGroup<HeaderWrapper> | IHeaderFooterGroup<FooterWrapper>,
): void {
if (group.default) {
this.root.push(
new HeaderReference({
headerType: HeaderReferenceType.DEFAULT,
headerId: headers.default.View.ReferenceId,
new HeaderFooterReference(type, {
type: HeaderFooterReferenceType.DEFAULT,
id: group.default.View.ReferenceId,
}),
);
}
if (headers.first) {
if (group.first) {
this.root.push(
new HeaderReference({
headerType: HeaderReferenceType.FIRST,
headerId: headers.first.View.ReferenceId,
new HeaderFooterReference(type, {
type: HeaderFooterReferenceType.FIRST,
id: group.first.View.ReferenceId,
}),
);
}
if (headers.even) {
if (group.even) {
this.root.push(
new HeaderReference({
headerType: HeaderReferenceType.EVEN,
headerId: headers.even.View.ReferenceId,
}),
);
}
}
private addFooters(footers: IHeaderFooterGroup<FooterWrapper>): void {
if (footers.default) {
this.root.push(
new FooterReference({
footerType: FooterReferenceType.DEFAULT,
footerId: footers.default.View.ReferenceId,
}),
);
}
if (footers.first) {
this.root.push(
new FooterReference({
footerType: FooterReferenceType.FIRST,
footerId: footers.first.View.ReferenceId,
}),
);
}
if (footers.even) {
this.root.push(
new FooterReference({
footerType: FooterReferenceType.EVEN,
footerId: footers.even.View.ReferenceId,
new HeaderFooterReference(type, {
type: HeaderFooterReferenceType.EVEN,
id: group.even.View.ReferenceId,
}),
);
}

View File

@ -1,9 +0,0 @@
import { XmlAttributeComponent } from "file/xml-components";
export class TitlePageAttributes extends XmlAttributeComponent<{
readonly value: string;
}> {
protected readonly xmlKeys = {
value: "w:val",
};
}

View File

@ -1,17 +0,0 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { TitlePage } from "./title-page";
describe("PageSize", () => {
describe("#constructor()", () => {
it("should create title page property for different first page header", () => {
const properties = new TitlePage();
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:titlePg"]);
expect(tree["w:titlePg"]).to.deep.equal({ _attr: { "w:val": "1" } });
});
});
});

View File

@ -1,13 +0,0 @@
import { XmlComponent } from "file/xml-components";
import { TitlePageAttributes } from "./title-page-attributes";
export class TitlePage extends XmlComponent {
constructor() {
super("w:titlePg");
this.root.push(
new TitlePageAttributes({
value: "1",
}),
);
}
}

View File

@ -1,2 +0,0 @@
export * from "./section-type";
export * from "./section-type-attributes";

View File

@ -1,17 +0,0 @@
import { XmlAttributeComponent } from "file/xml-components";
export enum SectionType {
CONTINUOUS = "continuous",
EVEN_PAGE = "evenPage",
NEXT_COLUMN = "nextColumn",
NEXT_PAGE = "nextPage",
ODD_PAGE = "oddPage",
}
export class SectionTypeAttributes extends XmlAttributeComponent<{
readonly val: SectionType;
}> {
protected readonly xmlKeys = {
val: "w:val",
};
}

View File

@ -1,10 +0,0 @@
// http://officeopenxml.com/WPsection.php
import { XmlComponent } from "file/xml-components";
import { SectionType, SectionTypeAttributes } from "./section-type-attributes";
export class Type extends XmlComponent {
constructor(value: SectionType) {
super("w:type");
this.root.push(new SectionTypeAttributes({ val: value }));
}
}

View File

@ -34,8 +34,8 @@ describe("DocumentBackground", () => {
const documentBackground = new DocumentBackground({
color: "ffff00",
themeColor: "test",
themeShade: "test",
themeTint: "test",
themeShade: "0A",
themeTint: "0B",
});
const tree = new Formatter().format(documentBackground);
expect(tree).to.deep.equal({
@ -43,8 +43,8 @@ describe("DocumentBackground", () => {
_attr: {
"w:color": "ffff00",
"w:themeColor": "test",
"w:themeShade": "test",
"w:themeTint": "test",
"w:themeShade": "0A",
"w:themeTint": "0B",
},
},
});

View File

@ -1,7 +1,30 @@
// http://officeopenxml.com/WPdocument.php
// http://www.datypic.com/sc/ooxml/e-w_background-1.html
import { hexColorValue, uCharHexNumber } from "file/values";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
// <xsd:simpleType name="ST_ThemeColor">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="dark1"/>
// <xsd:enumeration value="light1"/>
// <xsd:enumeration value="dark2"/>
// <xsd:enumeration value="light2"/>
// <xsd:enumeration value="accent1"/>
// <xsd:enumeration value="accent2"/>
// <xsd:enumeration value="accent3"/>
// <xsd:enumeration value="accent4"/>
// <xsd:enumeration value="accent5"/>
// <xsd:enumeration value="accent6"/>
// <xsd:enumeration value="hyperlink"/>
// <xsd:enumeration value="followedHyperlink"/>
// <xsd:enumeration value="none"/>
// <xsd:enumeration value="background1"/>
// <xsd:enumeration value="text1"/>
// <xsd:enumeration value="background2"/>
// <xsd:enumeration value="text2"/>
// </xsd:restriction>
// </xsd:simpleType>
export class DocumentBackgroundAttributes extends XmlAttributeComponent<{
readonly color: string;
readonly themeColor?: string;
@ -23,16 +46,32 @@ export interface IDocumentBackgroundOptions {
readonly themeTint?: string;
}
// <xsd:complexType name="CT_Background">
// <xsd:sequence>
// <xsd:sequence maxOccurs="unbounded">
// <xsd:any processContents="lax" namespace="urn:schemas-microsoft-com:vml" minOccurs="0"
// maxOccurs="unbounded"/>
// <xsd:any processContents="lax" namespace="urn:schemas-microsoft-com:office:office"
// minOccurs="0" maxOccurs="unbounded"/>
// </xsd:sequence>
// <xsd:element name="drawing" type="CT_Drawing" minOccurs="0"/>
// </xsd:sequence>
// <xsd:attribute name="color" type="ST_HexColor" use="optional" default="auto"/>
// <xsd:attribute name="themeColor" type="ST_ThemeColor" use="optional"/>
// <xsd:attribute name="themeTint" type="ST_UcharHexNumber" use="optional"/>
// <xsd:attribute name="themeShade" type="ST_UcharHexNumber" use="optional"/>
// </xsd:complexType>
export class DocumentBackground extends XmlComponent {
constructor(options: IDocumentBackgroundOptions) {
super("w:background");
this.root.push(
new DocumentBackgroundAttributes({
color: options.color ? options.color : "FFFFFF",
color: hexColorValue(options.color ? options.color : "FFFFFF"),
themeColor: options.themeColor,
themeShade: options.themeShade,
themeTint: options.themeTint,
themeShade: options.themeShade === undefined ? undefined : uCharHexNumber(options.themeShade),
themeTint: options.themeTint === undefined ? undefined : uCharHexNumber(options.themeTint),
}),
);
}

View File

@ -1,11 +1,18 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { sectionMarginDefaults, sectionPageSizeDefaults } from "./document";
import { File } from "./file";
import { Footer, Header } from "./header";
import { Paragraph } from "./paragraph";
const PAGE_SIZE_DEFAULTS = {
"w:h": sectionPageSizeDefaults.HEIGHT,
"w:orient": sectionPageSizeDefaults.ORIENTATION,
"w:w": sectionPageSizeDefaults.WIDTH,
};
describe("File", () => {
describe("#constructor", () => {
it("should create with correct headers and footers", () => {
@ -114,23 +121,19 @@ describe("File", () => {
"w:sectPr": [
{
"w:pgSz": {
_attr: {
"w:h": 16838,
"w:orient": "portrait",
"w:w": 11906,
},
_attr: PAGE_SIZE_DEFAULTS,
},
},
{
"w:pgMar": {
_attr: {
"w:bottom": 1440,
"w:footer": 708,
"w:gutter": 0,
"w:header": 708,
"w:left": 1440,
"w:right": 1440,
"w:top": 1440,
"w:bottom": sectionMarginDefaults.BOTTOM,
"w:footer": sectionMarginDefaults.FOOTER,
"w:gutter": sectionMarginDefaults.GUTTER,
"w:header": sectionMarginDefaults.HEADER,
"w:left": sectionMarginDefaults.LEFT,
"w:right": sectionMarginDefaults.RIGHT,
"w:top": sectionMarginDefaults.TOP,
},
},
},
@ -139,15 +142,15 @@ describe("File", () => {
_attr: {},
},
},
{
"w:cols": {
_attr: {
"w:num": 1,
"w:sep": false,
"w:space": 708,
},
},
},
// {
// "w:cols": {
// _attr: {
// "w:num": 1,
// "w:sep": false,
// "w:space": 708,
// },
// },
// },
{
"w:docGrid": {
_attr: {

View File

@ -3,7 +3,7 @@ import { ContentTypes } from "./content-types/content-types";
import { CoreProperties, IPropertiesOptions } from "./core-properties";
import { CustomProperties } from "./custom-properties";
import { DocumentWrapper } from "./document-wrapper";
import { FooterReferenceType, HeaderReferenceType, ISectionPropertiesOptions } from "./document/body/section-properties";
import { HeaderFooterReferenceType, ISectionPropertiesOptions } from "./document/body/section-properties";
import { IFileProperties } from "./file-properties";
import { FooterWrapper, IDocumentFooter } from "./footer-wrapper";
import { FootnotesWrapper } from "./footnotes-wrapper";
@ -188,7 +188,7 @@ export class File {
return wrapper;
}
private addHeaderToDocument(header: HeaderWrapper, type: HeaderReferenceType = HeaderReferenceType.DEFAULT): void {
private addHeaderToDocument(header: HeaderWrapper, type: HeaderFooterReferenceType = HeaderFooterReferenceType.DEFAULT): void {
this.headers.push({ header, type });
this.documentWrapper.Relationships.createRelationship(
header.View.ReferenceId,
@ -198,7 +198,7 @@ export class File {
this.contentTypes.addHeader(this.headers.length);
}
private addFooterToDocument(footer: FooterWrapper, type: FooterReferenceType = FooterReferenceType.DEFAULT): void {
private addFooterToDocument(footer: FooterWrapper, type: HeaderFooterReferenceType = HeaderFooterReferenceType.DEFAULT): void {
this.footers.push({ footer, type });
this.documentWrapper.Relationships.createRelationship(
footer.View.ReferenceId,

View File

@ -1,6 +1,6 @@
import { XmlComponent } from "file/xml-components";
import { FooterReferenceType } from "./document";
import { HeaderFooterReferenceType } from "./document";
import { IViewWrapper } from "./document-wrapper";
import { Footer } from "./footer/footer";
import { Media } from "./media";
@ -10,7 +10,7 @@ import { Table } from "./table";
export interface IDocumentFooter {
readonly footer: FooterWrapper;
readonly type: FooterReferenceType;
readonly type: HeaderFooterReferenceType;
}
export class FooterWrapper implements IViewWrapper {

View File

@ -1,6 +1,6 @@
import { XmlComponent } from "file/xml-components";
import { HeaderReferenceType } from "./document";
import { HeaderFooterReferenceType } from "./document";
import { IViewWrapper } from "./document-wrapper";
import { Header } from "./header/header";
import { Media } from "./media";
@ -10,7 +10,7 @@ import { Table } from "./table";
export interface IDocumentHeader {
readonly header: HeaderWrapper;
readonly type: HeaderReferenceType;
readonly type: HeaderFooterReferenceType;
}
export class HeaderWrapper implements IViewWrapper {

View File

@ -0,0 +1,133 @@
// <xsd:simpleType name="ST_NumberFormat">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="decimal"/>
// <xsd:enumeration value="upperRoman"/>
// <xsd:enumeration value="lowerRoman"/>
// <xsd:enumeration value="upperLetter"/>
// <xsd:enumeration value="lowerLetter"/>
// <xsd:enumeration value="ordinal"/>
// <xsd:enumeration value="cardinalText"/>
// <xsd:enumeration value="ordinalText"/>
// <xsd:enumeration value="hex"/>
// <xsd:enumeration value="chicago"/>
// <xsd:enumeration value="ideographDigital"/>
// <xsd:enumeration value="japaneseCounting"/>
// <xsd:enumeration value="aiueo"/>
// <xsd:enumeration value="iroha"/>
// <xsd:enumeration value="decimalFullWidth"/>
// <xsd:enumeration value="decimalHalfWidth"/>
// <xsd:enumeration value="japaneseLegal"/>
// <xsd:enumeration value="japaneseDigitalTenThousand"/>
// <xsd:enumeration value="decimalEnclosedCircle"/>
// <xsd:enumeration value="decimalFullWidth2"/>
// <xsd:enumeration value="aiueoFullWidth"/>
// <xsd:enumeration value="irohaFullWidth"/>
// <xsd:enumeration value="decimalZero"/>
// <xsd:enumeration value="bullet"/>
// <xsd:enumeration value="ganada"/>
// <xsd:enumeration value="chosung"/>
// <xsd:enumeration value="decimalEnclosedFullstop"/>
// <xsd:enumeration value="decimalEnclosedParen"/>
// <xsd:enumeration value="decimalEnclosedCircleChinese"/>
// <xsd:enumeration value="ideographEnclosedCircle"/>
// <xsd:enumeration value="ideographTraditional"/>
// <xsd:enumeration value="ideographZodiac"/>
// <xsd:enumeration value="ideographZodiacTraditional"/>
// <xsd:enumeration value="taiwaneseCounting"/>
// <xsd:enumeration value="ideographLegalTraditional"/>
// <xsd:enumeration value="taiwaneseCountingThousand"/>
// <xsd:enumeration value="taiwaneseDigital"/>
// <xsd:enumeration value="chineseCounting"/>
// <xsd:enumeration value="chineseLegalSimplified"/>
// <xsd:enumeration value="chineseCountingThousand"/>
// <xsd:enumeration value="koreanDigital"/>
// <xsd:enumeration value="koreanCounting"/>
// <xsd:enumeration value="koreanLegal"/>
// <xsd:enumeration value="koreanDigital2"/>
// <xsd:enumeration value="vietnameseCounting"/>
// <xsd:enumeration value="russianLower"/>
// <xsd:enumeration value="russianUpper"/>
// <xsd:enumeration value="none"/>
// <xsd:enumeration value="numberInDash"/>
// <xsd:enumeration value="hebrew1"/>
// <xsd:enumeration value="hebrew2"/>
// <xsd:enumeration value="arabicAlpha"/>
// <xsd:enumeration value="arabicAbjad"/>
// <xsd:enumeration value="hindiVowels"/>
// <xsd:enumeration value="hindiConsonants"/>
// <xsd:enumeration value="hindiNumbers"/>
// <xsd:enumeration value="hindiCounting"/>
// <xsd:enumeration value="thaiLetters"/>
// <xsd:enumeration value="thaiNumbers"/>
// <xsd:enumeration value="thaiCounting"/>
// <xsd:enumeration value="bahtText"/>
// <xsd:enumeration value="dollarText"/>
// <xsd:enumeration value="custom"/>
// </xsd:restriction>
// </xsd:simpleType>
export enum NumberFormat {
DECIMAL = "decimal",
UPPER_ROMAN = "upperRoman",
LOWER_ROMAN = "lowerRoman",
UPPER_LETTER = "upperLetter",
LOWER_LETTER = "lowerLetter",
ORDINAL = "ordinal",
CARDINAL_TEXT = "cardinalText",
ORDINAL_TEXT = "ordinalText",
HEX = "hex",
CHICAGO = "chicago",
IDEOGRAPH_DIGITAL = "ideographDigital",
JAPANESE_COUNTING = "japaneseCounting",
AIUEO = "aiueo",
IROHA = "iroha",
DECIMAL_FULL_WIDTH = "decimalFullWidth",
DECIMAL_HALF_WIDTH = "decimalHalfWidth",
JAPANESE_LEGAL = "japaneseLegal",
JAPANESE_DIGITAL_TEN_THOUSAND = "japaneseDigitalTenThousand",
DECIMAL_ENCLOSED_CIRCLE = "decimalEnclosedCircle",
DECIMAL_FULL_WIDTH_2 = "decimalFullWidth2",
AIUEO_FULL_WIDTH = "aiueoFullWidth",
IROHA_FULL_WIDTH = "irohaFullWidth",
DECIMAL_ZERO = "decimalZero",
BULLET = "bullet",
GANADA = "ganada",
CHOSUNG = "chosung",
DECIMAL_ENCLOSED_FULL_STOP = "decimalEnclosedFullstop",
DECIMAL_ENCLOSED_PAREN = "decimalEnclosedParen",
DECIMAL_ENCLOSED_CIRCLE_CHINESE = "decimalEnclosedCircleChinese",
IDEOGRAPH_ENCLOSED_CIRCLE = "ideographEnclosedCircle",
IDEOGRAPH_TRADITIONAL = "ideographTraditional",
IDEOGRAPH_ZODIAC = "ideographZodiac",
IDEOGRAPH_ZODIAC_TRADITIONAL = "ideographZodiacTraditional",
TAIWANESE_COUNTING = "taiwaneseCounting",
IDEOGRAPH_LEGAL_TRADITIONAL = "ideographLegalTraditional",
TAIWANESE_COUNTING_THOUSAND = "taiwaneseCountingThousand",
TAIWANESE_DIGITAL = "taiwaneseDigital",
CHINESE_COUNTING = "chineseCounting",
CHINESE_LEGAL_SIMPLIFIED = "chineseLegalSimplified",
CHINESE_COUNTING_TEN_THOUSAND = "chineseCountingThousand",
KOREAN_DIGITAL = "koreanDigital",
KOREAN_COUNTING = "koreanCounting",
KOREAN_LEGAL = "koreanLegal",
KOREAN_DIGITAL_2 = "koreanDigital2",
VIETNAMESE_COUNTING = "vietnameseCounting",
RUSSIAN_LOWER = "russianLower",
RUSSIAN_UPPER = "russianUpper",
NONE = "none",
NUMBER_IN_DASH = "numberInDash",
HEBREW_1 = "hebrew1",
HEBREW_2 = "hebrew2",
ARABIC_ALPHA = "arabicAlpha",
ARABIC_ABJAD = "arabicAbjad",
HINDI_VOWELS = "hindiVowels",
HINDI_CONSONANTS = "hindiConsonants",
HINDI_NUMBERS = "hindiNumbers",
HINDI_COUNTING = "hindiCounting",
THAI_LETTERS = "thaiLetters",
THAI_NUMBERS = "thaiNumbers",
THAI_COUNTING = "thaiCounting",
BAHT_TEXT = "bahtText",
DOLLAR_TEXT = "dollarText",
// <xsd:enumeration value="custom"/>
}

View File

@ -1,8 +1,7 @@
import * as JSZip from "jszip";
import { Element as XMLElement, ElementCompact as XMLElementCompact, xml2js } from "xml-js";
import { FooterReferenceType } from "file/document/body/section-properties/footer-reference";
import { HeaderReferenceType } from "file/document/body/section-properties/header-reference";
import { HeaderFooterReferenceType } from "file/document/body/section-properties";
import { FooterWrapper, IDocumentFooter } from "file/footer-wrapper";
import { HeaderWrapper, IDocumentHeader } from "file/header-wrapper";
import { Media } from "file/media";
@ -17,8 +16,8 @@ const schemeToType = {
};
interface IDocumentRefs {
readonly headers: { readonly id: number; readonly type: HeaderReferenceType }[];
readonly footers: { readonly id: number; readonly type: FooterReferenceType }[];
readonly headers: { readonly id: number; readonly type: HeaderFooterReferenceType }[];
readonly footers: { readonly id: number; readonly type: HeaderFooterReferenceType }[];
}
enum RelationshipType {
@ -219,7 +218,7 @@ export class ImportDotx {
throw Error("header referecne element has no attributes");
}
return {
type: item._attributes["w:type"] as HeaderReferenceType,
type: item._attributes["w:type"] as HeaderFooterReferenceType,
id: this.parseRefId(item._attributes["r:id"] as string),
};
});
@ -239,7 +238,7 @@ export class ImportDotx {
throw Error("footer referecne element has no attributes");
}
return {
type: item._attributes["w:type"] as FooterReferenceType,
type: item._attributes["w:type"] as HeaderFooterReferenceType,
id: this.parseRefId(item._attributes["r:id"] as string),
};
});