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

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