Merge pull request #12 from h4buli/feature/section-page-borders
feature: add support for section page borders
This commit is contained in:
@ -3,3 +3,4 @@ export * from "./footer-reference";
|
||||
export * from "./header-reference";
|
||||
export * from "./page-size";
|
||||
export * from "./page-number";
|
||||
export * from "./page-border";
|
||||
|
@ -0,0 +1 @@
|
||||
export * from "./page-borders";
|
@ -0,0 +1,91 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "../../../../../export/formatter";
|
||||
import { PageBorders, PageBorderDisplay, PageBorderZOrder } from "./page-borders";
|
||||
import { BorderStyle } from "../../../../styles";
|
||||
|
||||
describe("PageBorders", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create empty element when no options are passed", () => {
|
||||
const properties = new PageBorders();
|
||||
const tree = new Formatter().format(properties);
|
||||
|
||||
expect(tree).to.equal("");
|
||||
});
|
||||
|
||||
it("should create page borders with some configuration", () => {
|
||||
const properties = new PageBorders({
|
||||
pageBorders: {
|
||||
display: PageBorderDisplay.FIRST_PAGE,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:pgBorders"]);
|
||||
expect(tree["w:pgBorders"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:pgBorders"][0]).to.deep.equal({ _attr: { "w:display": "firstPage" } });
|
||||
});
|
||||
|
||||
it("should create page borders with full configuration", () => {
|
||||
const properties = new PageBorders({
|
||||
pageBorders: {
|
||||
display: PageBorderDisplay.FIRST_PAGE,
|
||||
zOrder: PageBorderZOrder.BACK,
|
||||
},
|
||||
pageBorderTop: {
|
||||
style: BorderStyle.DOUBLE_WAVE,
|
||||
size: 10,
|
||||
color: "001122",
|
||||
},
|
||||
pageBorderRight: {
|
||||
style: BorderStyle.DOUBLE,
|
||||
size: 20,
|
||||
color: "223344",
|
||||
},
|
||||
pageBorderBottom: {
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 30,
|
||||
color: "556677",
|
||||
},
|
||||
pageBorderLeft: {
|
||||
style: BorderStyle.DOTTED,
|
||||
size: 40,
|
||||
color: "889900",
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:pgBorders"]);
|
||||
expect(tree["w:pgBorders"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:pgBorders"][0]).to.deep.equal({ _attr: { "w:display": "firstPage", "w:zOrder": "back" } });
|
||||
expect(tree["w:pgBorders"][1]).to.deep.equal({
|
||||
"w:top": [
|
||||
{
|
||||
_attr: { "w:color": "001122", "w:size": 10, "w:val": "doubleWave" },
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(tree["w:pgBorders"][2]).to.deep.equal({
|
||||
"w:right": [
|
||||
{
|
||||
_attr: { "w:color": "223344", "w:size": 20, "w:val": "double" },
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(tree["w:pgBorders"][3]).to.deep.equal({
|
||||
"w:bottom": [
|
||||
{
|
||||
_attr: { "w:color": "556677", "w:size": 30, "w:val": "single" },
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(tree["w:pgBorders"][4]).to.deep.equal({
|
||||
"w:left": [
|
||||
{
|
||||
_attr: { "w:color": "889900", "w:size": 40, "w:val": "dotted" },
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,94 @@
|
||||
// http://officeopenxml.com/WPsectionBorders.php
|
||||
import { XmlComponent, XmlAttributeComponent, IXmlableObject } from "file/xml-components";
|
||||
import { BorderStyle } from "../../../../styles";
|
||||
|
||||
export enum PageBorderDisplay {
|
||||
ALL_PAGES = "allPages",
|
||||
FIRST_PAGE = "firstPage",
|
||||
NOT_FIRST_PAGE = "notFirstPage",
|
||||
}
|
||||
|
||||
export enum PageBorderOffsetFrom {
|
||||
PAGE = "page",
|
||||
TEXT = "text",
|
||||
}
|
||||
|
||||
export enum PageBorderZOrder {
|
||||
BACK = "back",
|
||||
FRONT = "front",
|
||||
}
|
||||
|
||||
export interface IPageBorderAttributes {
|
||||
display?: PageBorderDisplay;
|
||||
offsetFrom?: PageBorderOffsetFrom;
|
||||
zOrder?: PageBorderZOrder;
|
||||
}
|
||||
|
||||
export interface PageBorderConfiguration {
|
||||
style?: BorderStyle;
|
||||
size?: number;
|
||||
color?: string;
|
||||
space?: number;
|
||||
}
|
||||
|
||||
export type PageBordersOptions = {
|
||||
pageBorders?: IPageBorderAttributes;
|
||||
pageBorderTop?: PageBorderConfiguration;
|
||||
pageBorderRight?: PageBorderConfiguration;
|
||||
pageBorderBottom?: PageBorderConfiguration;
|
||||
pageBorderLeft?: PageBorderConfiguration;
|
||||
};
|
||||
|
||||
class PageBordeAttributes extends XmlAttributeComponent<PageBorderConfiguration> {
|
||||
protected xmlKeys = {
|
||||
style: "w:val",
|
||||
size: "w:size",
|
||||
color: "w:color",
|
||||
space: "w:space",
|
||||
};
|
||||
}
|
||||
|
||||
class PageBorder extends XmlComponent {
|
||||
constructor(key: string, options: PageBorderConfiguration) {
|
||||
super(key);
|
||||
|
||||
this.root.push(new PageBordeAttributes(options));
|
||||
}
|
||||
}
|
||||
|
||||
class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes> {
|
||||
protected xmlKeys = {
|
||||
display: "w:display",
|
||||
offsetFrom: "w:offsetFrom",
|
||||
zOrder: "w:zOrder",
|
||||
};
|
||||
}
|
||||
|
||||
export class PageBorders extends XmlComponent {
|
||||
constructor(options?: PageBordersOptions) {
|
||||
super("w:pgBorders");
|
||||
|
||||
if (!options) return;
|
||||
|
||||
let pageBordersAttributes = {};
|
||||
|
||||
if (options.pageBorders) {
|
||||
pageBordersAttributes = {
|
||||
display: options.pageBorders.display,
|
||||
offsetFrom: options.pageBorders.offsetFrom,
|
||||
zOrder: options.pageBorders.zOrder,
|
||||
};
|
||||
}
|
||||
|
||||
this.root.push(new PageBordersAttributes(pageBordersAttributes));
|
||||
|
||||
if (options.pageBorderTop) this.root.push(new PageBorder("w:top", options.pageBorderTop));
|
||||
if (options.pageBorderRight) this.root.push(new PageBorder("w:right", options.pageBorderRight));
|
||||
if (options.pageBorderBottom) this.root.push(new PageBorder("w:bottom", options.pageBorderBottom));
|
||||
if (options.pageBorderLeft) this.root.push(new PageBorder("w:left", options.pageBorderLeft));
|
||||
}
|
||||
|
||||
public prepForXml(): IXmlableObject {
|
||||
return this.root.length > 0 ? super.prepForXml() : "";
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "../../../../export/formatter";
|
||||
import { SectionProperties } from "./section-properties";
|
||||
import { FooterReferenceType, PageNumberFormat } from ".";
|
||||
import { FooterReferenceType, PageNumberFormat, PageBorderOffsetFrom } from ".";
|
||||
|
||||
describe("SectionProperties", () => {
|
||||
describe("#constructor()", () => {
|
||||
@ -155,5 +155,18 @@ describe("SectionProperties", () => {
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create section properties with page borders", () => {
|
||||
const properties = new SectionProperties({
|
||||
pageBorders: {
|
||||
offsetFrom: PageBorderOffsetFrom.PAGE,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"][7]).to.deep.equal({
|
||||
"w:pgBorders": [{ _attr: { "w:offsetFrom": "page" } }],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ import { PageMargin } from "./page-margin/page-margin";
|
||||
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
|
||||
import { PageSize } from "./page-size/page-size";
|
||||
import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes";
|
||||
import { FooterReferenceType, IPageNumberTypeAttributes, PageNumberType, PageNumberFormat } from ".";
|
||||
import { FooterReferenceType, IPageNumberTypeAttributes, PageNumberType, PageNumberFormat, PageBordersOptions, PageBorders } from ".";
|
||||
import { HeaderReferenceType } from "./header-reference/header-reference-attributes";
|
||||
|
||||
export type SectionPropertiesOptions = IPageSizeAttributes &
|
||||
@ -19,7 +19,8 @@ export type SectionPropertiesOptions = IPageSizeAttributes &
|
||||
IDocGridAttributesProperties &
|
||||
HeaderOptions &
|
||||
FooterOptions &
|
||||
IPageNumberTypeAttributes;
|
||||
IPageNumberTypeAttributes &
|
||||
PageBordersOptions;
|
||||
|
||||
export class SectionProperties extends XmlComponent {
|
||||
private options: SectionPropertiesOptions;
|
||||
@ -45,6 +46,11 @@ export class SectionProperties extends XmlComponent {
|
||||
footerId: 0,
|
||||
pageNumberStart: undefined,
|
||||
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
||||
pageBorders: undefined,
|
||||
pageBorderTop: undefined,
|
||||
pageBorderRight: undefined,
|
||||
pageBorderBottom: undefined,
|
||||
pageBorderLeft: undefined,
|
||||
};
|
||||
|
||||
const mergedOptions = {
|
||||
@ -81,6 +87,24 @@ export class SectionProperties extends XmlComponent {
|
||||
|
||||
this.root.push(new PageNumberType(mergedOptions.pageNumberStart, mergedOptions.pageNumberFormatType));
|
||||
|
||||
if (
|
||||
mergedOptions.pageBorders ||
|
||||
mergedOptions.pageBorderTop ||
|
||||
mergedOptions.pageBorderRight ||
|
||||
mergedOptions.pageBorderBottom ||
|
||||
mergedOptions.pageBorderLeft
|
||||
) {
|
||||
this.root.push(
|
||||
new PageBorders({
|
||||
pageBorders: mergedOptions.pageBorders,
|
||||
pageBorderTop: mergedOptions.pageBorderTop,
|
||||
pageBorderRight: mergedOptions.pageBorderRight,
|
||||
pageBorderBottom: mergedOptions.pageBorderBottom,
|
||||
pageBorderLeft: mergedOptions.pageBorderLeft,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
this.options = mergedOptions;
|
||||
}
|
||||
|
||||
|
29
src/file/styles/border/border-style.ts
Normal file
29
src/file/styles/border/border-style.ts
Normal file
@ -0,0 +1,29 @@
|
||||
export enum BorderStyle {
|
||||
SINGLE = "single",
|
||||
DASH_DOT_STROKED = "dashDotStroked",
|
||||
DASHED = "dashed",
|
||||
DASH_SMALL_GAP = "dashSmallGap",
|
||||
DOT_DASH = "dotDash",
|
||||
DOT_DOT_DASH = "dotDotDash",
|
||||
DOTTED = "dotted",
|
||||
DOUBLE = "double",
|
||||
DOUBLE_WAVE = "doubleWave",
|
||||
INSET = "inset",
|
||||
NIL = "nil",
|
||||
NONE = "none",
|
||||
OUTSET = "outset",
|
||||
THICK = "thick",
|
||||
THICK_THIN_LARGE_GAP = "thickThinLargeGap",
|
||||
THICK_THIN_MEDIUM_GAP = "thickThinMediumGap",
|
||||
THICK_THIN_SMALL_GAP = "thickThinSmallGap",
|
||||
THIN_THICK_LARGE_GAP = "thinThickLargeGap",
|
||||
THIN_THICK_MEDIUM_GAP = "thinThickMediumGap",
|
||||
THIN_THICK_SMALL_GAP = "thinThickSmallGap",
|
||||
THIN_THICK_THIN_LARGE_GAP = "thinThickThinLargeGap",
|
||||
THIN_THICK_THIN_MEDIUM_GAP = "thinThickThinMediumGap",
|
||||
THIN_THICK_THIN_SMALL_GAP = "thinThickThinSmallGap",
|
||||
THREE_D_EMBOSS = "threeDEmboss",
|
||||
THREE_D_ENGRAVE = "threeDEngrave",
|
||||
TRIPLE = "triple",
|
||||
WAVE = "wave",
|
||||
}
|
1
src/file/styles/border/index.ts
Normal file
1
src/file/styles/border/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./border-style";
|
@ -1,6 +1,7 @@
|
||||
import { XmlComponent, BaseXmlComponent } from "file/xml-components";
|
||||
import { DocumentDefaults } from "./defaults";
|
||||
import { ParagraphStyle } from "./style";
|
||||
export * from "./border";
|
||||
|
||||
export class Styles extends XmlComponent {
|
||||
constructor(_initialStyles?: BaseXmlComponent) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { TableCellBorders, BorderStyle, TableCellWidth, WidthType } from "./table-cell";
|
||||
import { TableCellBorders, TableCellWidth, WidthType } from "./table-cell";
|
||||
import { Formatter } from "../../export/formatter";
|
||||
import { BorderStyle } from "../styles";
|
||||
|
||||
describe("TableCellBorders", () => {
|
||||
describe("#prepForXml", () => {
|
||||
|
@ -1,34 +1,5 @@
|
||||
import { XmlComponent, XmlAttributeComponent, IXmlableObject } from "file/xml-components";
|
||||
|
||||
export enum BorderStyle {
|
||||
SINGLE = "single",
|
||||
DASH_DOT_STROKED = "dashDotStroked",
|
||||
DASHED = "dashed",
|
||||
DASH_SMALL_GAP = "dashSmallGap",
|
||||
DOT_DASH = "dotDash",
|
||||
DOT_DOT_DASH = "dotDotDash",
|
||||
DOTTED = "dotted",
|
||||
DOUBLE = "double",
|
||||
DOUBLE_WAVE = "doubleWave",
|
||||
INSET = "inset",
|
||||
NIL = "nil",
|
||||
NONE = "none",
|
||||
OUTSET = "outset",
|
||||
THICK = "thick",
|
||||
THICK_THIN_LARGE_GAP = "thickThinLargeGap",
|
||||
THICK_THIN_MEDIUM_GAP = "thickThinMediumGap",
|
||||
THICK_THIN_SMALL_GAP = "thickThinSmallGap",
|
||||
THIN_THICK_LARGE_GAP = "thinThickLargeGap",
|
||||
THIN_THICK_MEDIUM_GAP = "thinThickMediumGap",
|
||||
THIN_THICK_SMALL_GAP = "thinThickSmallGap",
|
||||
THIN_THICK_THIN_LARGE_GAP = "thinThickThinLargeGap",
|
||||
THIN_THICK_THIN_MEDIUM_GAP = "thinThickThinMediumGap",
|
||||
THIN_THICK_THIN_SMALL_GAP = "thinThickThinSmallGap",
|
||||
THREE_D_EMBOSS = "threeDEmboss",
|
||||
THREE_D_ENGRAVE = "threeDEngrave",
|
||||
TRIPLE = "triple",
|
||||
WAVE = "wave",
|
||||
}
|
||||
import { BorderStyle } from "../styles";
|
||||
|
||||
interface ICellBorder {
|
||||
style: BorderStyle;
|
||||
|
Reference in New Issue
Block a user