Skip to content

Documentation and Refactoring #3028

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 14, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo/71-page-borders-2.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Example demonstrating page borders with style, colors and size

import { BorderStyle, Document, Packer, PageBorderDisplay, PageBorderOffsetFrom, PageBorderZOrder, Paragraph, TextRun } from "docx";
import * as fs from "fs";
import { Document, Packer, TextRun, Paragraph, BorderStyle, PageBorderDisplay, PageBorderOffsetFrom, PageBorderZOrder } from "docx";

const doc = new Document({
sections: [
Expand Down
69 changes: 69 additions & 0 deletions src/file/border/border.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,32 +55,101 @@ class BordersAttributes extends XmlAttributeComponent<IBorderOptions> {
};
}

/**
* Table borders are defined with the <w:tblBorders> element. Child elements of this element specify the kinds of `border`:
*
* `bottom`, `end` (`right` in the previous version of the standard), `insideH`, `insideV`, `start` (`left` in the previous version of the standard), and `top`.
*
* Reference: http://officeopenxml.com/WPtableBorders.php
*
* ## XSD Schema
* ```xml
* <xsd:simpleType name="ST_Border">
* <xsd:restriction base="xsd:string">
* <xsd:enumeration value="single"/>
* <xsd:enumeration value="dashDotStroked"/>
* <xsd:enumeration value="dashed"/>
* <xsd:enumeration value="dashSmallGap"/>
* <xsd:enumeration value="dotDash"/>
* <xsd:enumeration value="dotDotDash"/>
* <xsd:enumeration value="dotted"/>
* <xsd:enumeration value="double"/>
* <xsd:enumeration value="doubleWave"/>
* <xsd:enumeration value="inset"/>
* <xsd:enumeration value="nil"/>
* <xsd:enumeration value="none"/>
* <xsd:enumeration value="outset"/>
* <xsd:enumeration value="thick"/>
* <xsd:enumeration value="thickThinLargeGap"/>
* <xsd:enumeration value="thickThinMediumGap"/>
* <xsd:enumeration value="thickThinSmallGap"/>
* <xsd:enumeration value="thinThickLargeGap"/>
* <xsd:enumeration value="thinThickMediumGap"/>
* <xsd:enumeration value="thinThickSmallGap"/>
* <xsd:enumeration value="thinThickThinLargeGap"/>
* <xsd:enumeration value="thinThickThinMediumGap"/>
* <xsd:enumeration value="thinThickThinSmallGap"/>
* <xsd:enumeration value="threeDEmboss"/>
* <xsd:enumeration value="threeDEngrave"/>
* <xsd:enumeration value="triple"/>
* <xsd:enumeration value="wave"/>
* </xsd:restriction>
* </xsd:simpleType>
* ```
*/
export const BorderStyle = {
/** a single line */
SINGLE: "single",
/** a line with a series of alternating thin and thick strokes */
DASH_DOT_STROKED: "dashDotStroked",
/** a dashed line */
DASHED: "dashed",
/** a dashed line with small gaps */
DASH_SMALL_GAP: "dashSmallGap",
/** a line with alternating dots and dashes */
DOT_DASH: "dotDash",
/** a line with a repeating dot - dot - dash sequence */
DOT_DOT_DASH: "dotDotDash",
/** a dotted line */
DOTTED: "dotted",
/** a double line */
DOUBLE: "double",
/** a double wavy line */
DOUBLE_WAVE: "doubleWave",
/** an inset set of lines */
INSET: "inset",
/** no border */
NIL: "nil",
/** no border */
NONE: "none",
/** an outset set of lines */
OUTSET: "outset",
/** a single line */
THICK: "thick",
/** a thick line contained within a thin line with a large-sized intermediate gap */
THICK_THIN_LARGE_GAP: "thickThinLargeGap",
/** a thick line contained within a thin line with a medium-sized intermediate gap */
THICK_THIN_MEDIUM_GAP: "thickThinMediumGap",
/** a thick line contained within a thin line with a small intermediate gap */
THICK_THIN_SMALL_GAP: "thickThinSmallGap",
/** a thin line contained within a thick line with a large-sized intermediate gap */
THIN_THICK_LARGE_GAP: "thinThickLargeGap",
/** a thick line contained within a thin line with a medium-sized intermediate gap */
THIN_THICK_MEDIUM_GAP: "thinThickMediumGap",
/** a thick line contained within a thin line with a small intermediate gap */
THIN_THICK_SMALL_GAP: "thinThickSmallGap",
/** a thin-thick-thin line with a large gap */
THIN_THICK_THIN_LARGE_GAP: "thinThickThinLargeGap",
/** a thin-thick-thin line with a medium gap */
THIN_THICK_THIN_MEDIUM_GAP: "thinThickThinMediumGap",
/** a thin-thick-thin line with a small gap */
THIN_THICK_THIN_SMALL_GAP: "thinThickThinSmallGap",
/** a three-staged gradient line, getting darker towards the paragraph */
THREE_D_EMBOSS: "threeDEmboss",
/** a three-staged gradient like, getting darker away from the paragraph */
THREE_D_ENGRAVE: "threeDEngrave",
/** a triple line */
TRIPLE: "triple",
/** a wavy line */
WAVE: "wave",
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@ import { describe, expect, it } from "vitest";

import { Formatter } from "@export/formatter";

import { DocumentGrid, DocumentGridType } from ".";
import { DocumentGridType, createDocumentGrid } from ".";

describe("DocumentGrid", () => {
describe("createDocumentGrid", () => {
describe("#constructor()", () => {
it("should create documentGrid with specified linePitch", () => {
const docGrid = new DocumentGrid(360);
const docGrid = createDocumentGrid({ linePitch: 360 });
const tree = new Formatter().format(docGrid);

expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 360 } });
});

it("should create documentGrid with specified linePitch and type", () => {
const docGrid = new DocumentGrid(360, undefined, DocumentGridType.LINES);
const docGrid = createDocumentGrid({ linePitch: 360, type: DocumentGridType.LINES });
const tree = new Formatter().format(docGrid);

expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 360, "w:type": "lines" } });
});

it("should create documentGrid with specified linePitch,charSpace and type", () => {
const docGrid = new DocumentGrid(346, -1541, DocumentGridType.LINES_AND_CHARS);
const docGrid = createDocumentGrid({ linePitch: 346, charSpace: -1541, type: DocumentGridType.LINES_AND_CHARS });
const tree = new Formatter().format(docGrid);

expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 346, "w:charSpace": -1541, "w:type": "linesAndChars" } });
Expand Down
138 changes: 99 additions & 39 deletions src/file/document/body/section-properties/properties/doc-grid.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,113 @@
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { decimalNumber } from "@util/values";

// 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>

/**
* Specifies the type of the current document grid, which defines the grid behavior.
*
* The grid can define a grid which snaps all East Asian characters to grid positions, but leaves Latin text with its default spacing; a grid which adds the specified character pitch to all characters on each row; or a grid which affects only the line pitch for the current section.
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_DocGrid_topic_ID0ELYP2.html
*
* ## XSD Schema
* ```xml
* <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>
* ```
*/
export const DocumentGridType = {
/**
* Specifies that no document grid shall be applied to the contents of the current section in the document.
*/
DEFAULT: "default",
/**
* Specifies that the parent section shall have additional line pitch added to each line within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain the specified number of lines per page.
*/
LINES: "lines",
/**
* Specifies that the parent section shall have both the additional line pitch and character pitch added to each line and character within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain a specific number of lines per page and characters per line.
*
* When this value is set, the input specified via the user interface may be allowed in exact number of line/character pitch units. */
LINES_AND_CHARS: "linesAndChars",
/**
* Specifies that the parent section shall have both the additional line pitch and character pitch added to each line and character within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain a specific number of lines per page and characters per line.
*
* When this value is set, the input specified via the user interface may be restricted to the number of lines per page and characters per line, with the consumer or producer translating this information based on the current font data to get the resulting line and character pitch values
*/
SNAP_TO_CHARS: "snapToChars",
} as const;

export type IDocGridAttributesProperties = {
/**
* Specifies the type of the current document grid, which defines the grid behavior.
*
* The grid can define a grid which snaps all East Asian characters to grid positions, but leaves Latin text with its default spacing; a grid which adds the specified character pitch to each character on each row; or a grid which affects only the line pitch for the current section.
*/
readonly type?: (typeof DocumentGridType)[keyof typeof DocumentGridType];
readonly linePitch?: number;
/**
* Specifies the number of lines to be allowed on the document grid for the current page assuming all lines have equal line pitch applied to them. This line pitch shall not be added to any line which appears within a table cell unless the <adjustLineHeightInTable> element (§2.15.3.1) is present in the document's compatibility settings.
*
* This attribute is specified in twentieths of a point, and defines the pitch for each line of text on this page such that the desired number of single spaced lines of text fits on the current page.
*
* ```xml
* <w:docGrid w:linePitch="684" …/>
* ```
*
* The `linePitch` attribute specifies that 34.2 points is to the amount of pitch allowed for each line on this page in order to maintain the specific document grid. ]
*
* Individual paragraphs can override the line pitch information specified for the document grid by either:
*
* Specifying an exact line spacing value using the `lineRule` attribute of value exact on the <spacing> element (§2.3.1.33).
*
* Specifying that the paragraph text shall not snap to the document grid via the <snapToGrid> element (§2.3.1.32).
*
* The possible values for this attribute are defined by the ST_DecimalNumber simple type (§2.18.16).
*/
readonly linePitch: number;
/**
* Specifies the number of characters to be allowed on the document grid for each line in this section.
*
* This attribute's value shall be specified by multiplying the difference between the desired character pitch and the character pitch for that character in the font size of the Normal font by 4096.
*
* This value shall then be used to add the character pitch for the specified point size to each character in the section [: This results in text in the Normal style having a specific number of characters per line. ]
*
* ```xml
* <w:docGrid w:charSize="40960" …/>
* ```
* The `charSpace` attribute specifies a value of 40960, which means that the delta between the character pitch of each character in the grid and the Normal font is 10 points, resulting in a character pitch of 11+10 = 21 points for all characters in this section. ]
*
* Individual runs of text can override the line pitch information specified for the document grid by specifying that the run text shall not snap to the document grid via the <snapToGrid> element (§2.3.2.32).
*
* The possible values for this attribute are defined by the `ST_DecimalNumber` simple type (§2.18.16).
*/
readonly charSpace?: number;
};

export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
protected readonly xmlKeys = {
type: "w:type",
linePitch: "w:linePitch",
charSpace: "w:charSpace",
};
}

export class DocumentGrid extends XmlComponent {
public constructor(linePitch: number, charSpace?: number, type?: (typeof DocumentGridType)[keyof typeof DocumentGridType]) {
super("w:docGrid");

this.root.push(
new DocGridAttributes({
type: type,
linePitch: decimalNumber(linePitch),
charSpace: charSpace ? decimalNumber(charSpace) : undefined,
}),
);
}
}
/**
* This element specifies the settings for the document grid, which enables precise layout of full-width East Asian language characters within a document by specifying the desired number of characters per line and lines per page for all East Asian text content in this section.
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_docGrid_topic_ID0EHU5S.html
*
* ```xml
* <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>
* ```
* @returns
*/
export const createDocumentGrid = ({ type, linePitch, charSpace }: IDocGridAttributesProperties): XmlComponent =>
new BuilderElement<IDocGridAttributesProperties>({
name: "w:docGrid",
attributes: {
type: { key: "w:type", value: type },
linePitch: { key: "w:linePitch", value: decimalNumber(linePitch) },
charSpace: { key: "w:charSpace", value: charSpace ? decimalNumber(charSpace) : undefined },
},
});
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
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>
/**
* This simple type specifies the possible types of headers and footers which may be specified for a given header or footer reference in a document. This value determines the page(s) on which the current header or footer shall be displayed.
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_HdrFtr_topic_ID0E2UW2.html
*
* ## XSD Schema
* ```xml
* <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 const HeaderFooterReferenceType = {
/** Specifies that this header or footer shall appear on every page in this section which is not overridden with a specific `even` or `first` page header/footer. In a section with all three types specified, this type shall be used on all odd numbered pages (counting from the `first` page in the section, not the section numbering). */
DEFAULT: "default",
/** Specifies that this header or footer shall appear on the first page in this section. The appearance of this header or footer is contingent on the setting of the `titlePg` element (§2.10.6). */
FIRST: "first",
/** Specifies that this header or footer shall appear on all even numbered pages in this section (counting from the first page in the section, not the section numbering). The appearance of this header or footer is contingent on the setting of the `evenAndOddHeaders` element (§2.10.1). */
EVEN: "even",
} as const;

// </xsd:complexType>
// <xsd:group name="EG_HdrFtrReferences">
// <xsd:choice>
// <xsd:element name="headerReference" type="CT_HdrFtrRef" minOccurs="0"/>
Expand Down
Loading
Loading