Change docx folder to more appropriate "file" folder
This commit is contained in:
17
src/file/styles/defaults/index.ts
Normal file
17
src/file/styles/defaults/index.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { XmlComponent } from "../../xml-components";
|
||||
import { ParagraphPropertiesDefaults } from "./paragraph-properties";
|
||||
import { RunPropertiesDefaults } from "./run-properties";
|
||||
|
||||
export class DocumentDefaults extends XmlComponent {
|
||||
|
||||
private runPropertiesDefaults: RunPropertiesDefaults;
|
||||
private paragraphPropertiesDefaults: ParagraphPropertiesDefaults;
|
||||
|
||||
constructor() {
|
||||
super("w:docDefaults");
|
||||
this.runPropertiesDefaults = new RunPropertiesDefaults();
|
||||
this.paragraphPropertiesDefaults = new ParagraphPropertiesDefaults();
|
||||
this.root.push(this.runPropertiesDefaults);
|
||||
this.root.push(this.paragraphPropertiesDefaults);
|
||||
}
|
||||
}
|
10
src/file/styles/defaults/paragraph-properties.ts
Normal file
10
src/file/styles/defaults/paragraph-properties.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { ParagraphProperties } from "../../paragraph/properties";
|
||||
import { XmlComponent } from "../../xml-components";
|
||||
|
||||
export class ParagraphPropertiesDefaults extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("w:pPrDefault");
|
||||
this.root.push(new ParagraphProperties());
|
||||
}
|
||||
}
|
24
src/file/styles/defaults/run-properties.ts
Normal file
24
src/file/styles/defaults/run-properties.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Size } from "../../paragraph/run/formatting";
|
||||
import { RunProperties } from "../../paragraph/run/properties";
|
||||
import { RunFonts } from "../../paragraph/run/run-fonts";
|
||||
import { XmlComponent } from "../../xml-components";
|
||||
|
||||
export class RunPropertiesDefaults extends XmlComponent {
|
||||
private properties: RunProperties;
|
||||
|
||||
constructor() {
|
||||
super("w:rPrDefault");
|
||||
this.properties = new RunProperties();
|
||||
this.root.push(this.properties);
|
||||
}
|
||||
|
||||
public size(size: number): RunPropertiesDefaults {
|
||||
this.properties.push(new Size(size));
|
||||
return this;
|
||||
}
|
||||
|
||||
public font(fontName: string): RunPropertiesDefaults {
|
||||
this.properties.push(new RunFonts(fontName));
|
||||
return this;
|
||||
}
|
||||
}
|
54
src/file/styles/factory.ts
Normal file
54
src/file/styles/factory.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { Color, Italics, Size } from "../paragraph/run/formatting";
|
||||
|
||||
import { Styles } from "./";
|
||||
// import { DocumentDefaults } from "./defaults";
|
||||
import {
|
||||
Heading1Style, Heading2Style, Heading3Style, Heading4Style, Heading5Style, Heading6Style,
|
||||
ListParagraph, TitleStyle,
|
||||
} from "./style";
|
||||
|
||||
export class DefaultStylesFactory {
|
||||
|
||||
public newInstance(): Styles {
|
||||
const styles = new Styles();
|
||||
styles.createDocumentDefaults();
|
||||
|
||||
const titleStyle = new TitleStyle();
|
||||
titleStyle.addRunProperty(new Size(56));
|
||||
styles.push(titleStyle);
|
||||
|
||||
const heading1Style = new Heading1Style();
|
||||
heading1Style.addRunProperty(new Color("2E74B5"));
|
||||
heading1Style.addRunProperty(new Size(32));
|
||||
styles.push(heading1Style);
|
||||
|
||||
const heading2Style = new Heading2Style();
|
||||
heading2Style.addRunProperty(new Color("2E74B5"));
|
||||
heading2Style.addRunProperty(new Size(26));
|
||||
styles.push(heading2Style);
|
||||
|
||||
const heading3Style = new Heading3Style();
|
||||
heading3Style.addRunProperty(new Color("1F4D78"));
|
||||
heading3Style.addRunProperty(new Size(24));
|
||||
styles.push(heading3Style);
|
||||
|
||||
const heading4Style = new Heading4Style();
|
||||
heading4Style.addRunProperty(new Color("2E74B5"));
|
||||
heading4Style.addRunProperty(new Italics());
|
||||
styles.push(heading4Style);
|
||||
|
||||
const heading5Style = new Heading5Style();
|
||||
heading5Style.addRunProperty(new Color("2E74B5"));
|
||||
styles.push(heading5Style);
|
||||
|
||||
const heading6Style = new Heading6Style();
|
||||
heading6Style.addRunProperty(new Color("1F4D78"));
|
||||
styles.push(heading6Style);
|
||||
|
||||
const listParagraph = new ListParagraph();
|
||||
// listParagraph.addParagraphProperty();
|
||||
styles.push(listParagraph);
|
||||
|
||||
return styles;
|
||||
}
|
||||
}
|
37
src/file/styles/index.ts
Normal file
37
src/file/styles/index.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { DocumentAttributes } from "../document/document-attributes";
|
||||
import { XmlComponent } from "../xml-components";
|
||||
import { DocumentDefaults } from "./defaults";
|
||||
import { ParagraphStyle } from "./style";
|
||||
|
||||
export class Styles extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("w:styles");
|
||||
this.root.push(new DocumentAttributes({
|
||||
mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
||||
r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
||||
w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||
w14: "http://schemas.microsoft.com/office/word/2010/wordml",
|
||||
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
|
||||
Ignorable: "w14 w15",
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
public push(style: XmlComponent): Styles {
|
||||
this.root.push(style);
|
||||
return this;
|
||||
}
|
||||
|
||||
public createDocumentDefaults(): DocumentDefaults {
|
||||
const defaults = new DocumentDefaults();
|
||||
this.push(defaults);
|
||||
return defaults;
|
||||
}
|
||||
|
||||
public createParagraphStyle(styleId: string, name?: string): ParagraphStyle {
|
||||
const para = new ParagraphStyle(styleId, name);
|
||||
this.push(para);
|
||||
return para;
|
||||
}
|
||||
}
|
27
src/file/styles/latent-styles/exceptions.ts
Normal file
27
src/file/styles/latent-styles/exceptions.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../../docx/xml-components";
|
||||
|
||||
export interface ILatentStyleExceptionAttributesProperties {
|
||||
name?: string;
|
||||
uiPriority?: string;
|
||||
qFormat?: string;
|
||||
semiHidden?: string;
|
||||
unhideWhenUsed?: string;
|
||||
}
|
||||
|
||||
export class LatentStyleExceptionAttributes extends XmlAttributeComponent<ILatentStyleExceptionAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
name: "w:name",
|
||||
uiPriority: "w:uiPriority",
|
||||
qFormat: "w:qFormat",
|
||||
semiHidden: "w:semiHidden",
|
||||
unhideWhenUsed: "w:unhideWhenUsed",
|
||||
};
|
||||
}
|
||||
|
||||
export class LatentStyleException extends XmlComponent {
|
||||
|
||||
constructor(attributes: ILatentStyleExceptionAttributesProperties) {
|
||||
super("w:lsdException");
|
||||
this.root.push(new LatentStyleExceptionAttributes(attributes));
|
||||
}
|
||||
}
|
13
src/file/styles/latent-styles/index.ts
Normal file
13
src/file/styles/latent-styles/index.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlComponent } from "../../docx/xml-components";
|
||||
import { LatentStyleException } from "./exceptions";
|
||||
|
||||
export class LatentStyles extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("w:latentStyles");
|
||||
}
|
||||
|
||||
public push(latentException: LatentStyleException): void {
|
||||
this.root.push(latentException);
|
||||
}
|
||||
}
|
149
src/file/styles/sample/index.ts
Normal file
149
src/file/styles/sample/index.ts
Normal file
@ -0,0 +1,149 @@
|
||||
/* tslint:disable */
|
||||
function createLsdException(name, uiPriority, qFormat?, semiHidden?, unhideWhenUsed?) {
|
||||
'use strict';
|
||||
|
||||
return [{
|
||||
_attr: {
|
||||
'w:name': name,
|
||||
'w:uiPriority': uiPriority,
|
||||
'w:qFormat': qFormat,
|
||||
'w:semiHidden': semiHidden,
|
||||
'w:unhideWhenUsed': unhideWhenUsed
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
export function DefaultStyle() {
|
||||
var style = {
|
||||
'w:styles': [{
|
||||
_attr: {
|
||||
'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',
|
||||
'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
|
||||
'xmlns:w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
|
||||
'xmlns:w14': 'http://schemas.microsoft.com/office/word/2010/wordml',
|
||||
'xmlns:w15': 'http://schemas.microsoft.com/office/word/2012/wordml',
|
||||
'mc:Ignorable': 'w14 w15'
|
||||
}
|
||||
}, {
|
||||
'w:docDefaults': [{
|
||||
'w:rPrDefault': [{
|
||||
'w:rPr': [{
|
||||
'w:rFonts': [{
|
||||
_attr: {
|
||||
'w:asciiTheme': "minorHAnsi",
|
||||
'w:eastAsiaTheme': "minorHAnsi",
|
||||
'w:hAnsiTheme': "minorHAnsi",
|
||||
'w:cstheme': "minorBidi"
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
'w:sz': [{
|
||||
_attr: {
|
||||
'w:val': "22"
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
'w:szCs': [{
|
||||
_attr: {
|
||||
'w:val': "22"
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
'w:lang': [{
|
||||
_attr: {
|
||||
'w:val': "en-GB",
|
||||
'w:eastAsia': "en-US",
|
||||
'w:bidi': "ar-SA"
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
'w:pPrDefault': [{
|
||||
'w:pPr': [{
|
||||
'w:spacing': [{
|
||||
_attr: {
|
||||
'w:after': "160",
|
||||
'w:line': "259",
|
||||
'w:lineRule': "auto"
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
'w:latentStyles': [{
|
||||
_attr: {
|
||||
'w:defLockedState': "0",
|
||||
'w:defUIPriority': "99",
|
||||
'w:defSemiHidden': "0",
|
||||
'w:defUnhideWhenUsed': "0",
|
||||
'w:defQFormat': "0",
|
||||
'w:count': "371"
|
||||
}
|
||||
}, {
|
||||
'w:lsdException': createLsdException('Normal', 0, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("heading 1", 9, 1, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("heading 2", 9, 1, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("heading 3", 9, 1, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("heading 4", 9, 1, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("heading 5", 9, 1, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("heading 6", 9, 1, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("heading 7", 9, 1, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("heading 8", 9, 1, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("heading 9", 9, 1, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("index 1", undefined, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("index 2", undefined, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("index 3", undefined, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("index 4", undefined, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("index 5", undefined, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("index 6", undefined, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("index 7", undefined, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("index 8", undefined, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("index 9", undefined, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("toc 1", 39, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("toc 2", 39, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("toc 3", 39, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("toc 4", 39, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("toc 5", 39, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("toc 6", 39, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("toc 7", 39, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("toc 8", 39, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("toc 9", 39, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("Normal Indent", undefined, undefined, 1, 1)
|
||||
}, {
|
||||
'w:lsdException': createLsdException("footnote text", undefined, undefined, 1, 1)
|
||||
}]
|
||||
}]
|
||||
};
|
||||
|
||||
return style;
|
||||
};
|
73
src/file/styles/style/components.ts
Normal file
73
src/file/styles/style/components.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../../xml-components";
|
||||
|
||||
interface IComponentAttributes {
|
||||
val: string;
|
||||
}
|
||||
|
||||
class ComponentAttributes extends XmlAttributeComponent<IComponentAttributes> {
|
||||
protected xmlKeys = {val: "w:val"};
|
||||
}
|
||||
|
||||
export class Name extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("w:name");
|
||||
this.root.push(new ComponentAttributes({val: value}));
|
||||
}
|
||||
}
|
||||
|
||||
export class BasedOn extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("w:basedOn");
|
||||
this.root.push(new ComponentAttributes({val: value}));
|
||||
}
|
||||
}
|
||||
|
||||
export class Next extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("w:next");
|
||||
this.root.push(new ComponentAttributes({val: value}));
|
||||
}
|
||||
}
|
||||
|
||||
export class Link extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("w:link");
|
||||
this.root.push(new ComponentAttributes({val: value}));
|
||||
}
|
||||
}
|
||||
|
||||
export class UiPriority extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("w:uiPriority");
|
||||
// TODO: this value should be a ST_DecimalNumber
|
||||
this.root.push(new ComponentAttributes({val: value}));
|
||||
}
|
||||
}
|
||||
|
||||
export class UnhideWhenUsed extends XmlComponent {
|
||||
|
||||
}
|
||||
|
||||
export class QuickFormat extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("w:qFormat");
|
||||
}
|
||||
}
|
||||
|
||||
export class TableProperties extends XmlComponent {
|
||||
|
||||
}
|
||||
|
||||
export class RsId extends XmlComponent {
|
||||
|
||||
}
|
||||
|
||||
export class SemiHidden extends XmlComponent {
|
||||
|
||||
}
|
262
src/file/styles/style/index.ts
Normal file
262
src/file/styles/style/index.ts
Normal file
@ -0,0 +1,262 @@
|
||||
import * as paragraph from "../../paragraph";
|
||||
import * as formatting from "../../paragraph/run/formatting";
|
||||
import { RunProperties } from "../../paragraph/run/properties";
|
||||
import { XmlAttributeComponent, XmlComponent } from "../../xml-components";
|
||||
|
||||
import { BasedOn, Name, Next, QuickFormat } from "./components";
|
||||
|
||||
export interface IStyleAttributes {
|
||||
type?: string;
|
||||
styleId?: string;
|
||||
default?: boolean;
|
||||
customStyle?: string;
|
||||
}
|
||||
|
||||
class StyleAttributes extends XmlAttributeComponent<IStyleAttributes> {
|
||||
protected xmlKeys = {
|
||||
type: "w:type",
|
||||
styleId: "w:styleId",
|
||||
default: "w:default",
|
||||
customStyle: "w:customStyle",
|
||||
};
|
||||
}
|
||||
|
||||
export class Style extends XmlComponent {
|
||||
|
||||
constructor(attributes: IStyleAttributes, name?: string) {
|
||||
super("w:style");
|
||||
this.root.push(new StyleAttributes(attributes));
|
||||
if (name) {
|
||||
this.root.push(new Name(name));
|
||||
}
|
||||
}
|
||||
|
||||
public push(styleSegment: XmlComponent): void {
|
||||
this.root.push(styleSegment);
|
||||
}
|
||||
}
|
||||
|
||||
export class ParagraphStyle extends Style {
|
||||
|
||||
private paragraphProperties: paragraph.ParagraphProperties;
|
||||
private runProperties: RunProperties;
|
||||
|
||||
constructor(styleId: string, name?: string) {
|
||||
super({type: "paragraph", styleId: styleId}, name);
|
||||
this.paragraphProperties = new paragraph.ParagraphProperties();
|
||||
this.runProperties = new RunProperties();
|
||||
this.root.push(this.paragraphProperties);
|
||||
this.root.push(this.runProperties);
|
||||
}
|
||||
|
||||
public addParagraphProperty(property: XmlComponent): void {
|
||||
this.paragraphProperties.push(property);
|
||||
}
|
||||
|
||||
public addRunProperty(property: XmlComponent): void {
|
||||
this.runProperties.push(property);
|
||||
}
|
||||
|
||||
public basedOn(parentId: string): ParagraphStyle {
|
||||
this.root.push(new BasedOn(parentId));
|
||||
return this;
|
||||
}
|
||||
|
||||
public quickFormat(): ParagraphStyle {
|
||||
this.root.push(new QuickFormat());
|
||||
return this;
|
||||
}
|
||||
|
||||
public next(nextId: string): ParagraphStyle {
|
||||
this.root.push(new Next(nextId));
|
||||
return this;
|
||||
}
|
||||
|
||||
// ---------- Run formatting ---------------------- //
|
||||
|
||||
public size(twips: number): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Size(twips));
|
||||
return this;
|
||||
}
|
||||
|
||||
public bold(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Bold());
|
||||
return this;
|
||||
}
|
||||
|
||||
public italics(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Italics());
|
||||
return this;
|
||||
}
|
||||
|
||||
public smallCaps(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.SmallCaps());
|
||||
return this;
|
||||
}
|
||||
|
||||
public allCaps(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Caps());
|
||||
return this;
|
||||
}
|
||||
|
||||
public strike(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Strike());
|
||||
return this;
|
||||
}
|
||||
|
||||
public doubleStrike(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.DoubleStrike());
|
||||
return this;
|
||||
}
|
||||
|
||||
public subScript(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.SubScript());
|
||||
return this;
|
||||
}
|
||||
|
||||
public superScript(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.SuperScript());
|
||||
return this;
|
||||
}
|
||||
|
||||
public underline(underlineType?: string, color?: string): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Underline(underlineType, color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public color(color: string): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Color(color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public font(fontName: string): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.RunFonts(fontName));
|
||||
return this;
|
||||
}
|
||||
|
||||
// --------------------- Paragraph formatting ------------------------ //
|
||||
|
||||
public center(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Alignment("center"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public left(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Alignment("left"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public right(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Alignment("right"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public justified(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Alignment("both"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public thematicBreak(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.ThematicBreak());
|
||||
return this;
|
||||
}
|
||||
|
||||
public maxRightTabStop(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.MaxRightTabStop());
|
||||
return this;
|
||||
}
|
||||
|
||||
public leftTabStop(position: number): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.LeftTabStop(position));
|
||||
return this;
|
||||
}
|
||||
|
||||
public indent(attrs: object): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Indent(attrs));
|
||||
return this;
|
||||
}
|
||||
|
||||
public spacing(params: paragraph.ISpacingProperties): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Spacing(params));
|
||||
return this;
|
||||
}
|
||||
|
||||
public keepNext(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.KeepNext());
|
||||
return this;
|
||||
}
|
||||
|
||||
public keepLines(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.KeepLines());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class HeadingStyle extends ParagraphStyle {
|
||||
|
||||
constructor(styleId: string, name: string) {
|
||||
super(styleId, name);
|
||||
this.basedOn("Normal");
|
||||
this.next("Normal");
|
||||
this.quickFormat();
|
||||
}
|
||||
}
|
||||
|
||||
export class TitleStyle extends HeadingStyle {
|
||||
|
||||
constructor() {
|
||||
super("Title", "Title");
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading1Style extends HeadingStyle {
|
||||
|
||||
constructor() {
|
||||
super("Heading1", "Heading 1");
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading2Style extends HeadingStyle {
|
||||
|
||||
constructor() {
|
||||
super("Heading2", "Heading 2");
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading3Style extends HeadingStyle {
|
||||
|
||||
constructor() {
|
||||
super("Heading3", "Heading 3");
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading4Style extends HeadingStyle {
|
||||
|
||||
constructor() {
|
||||
super("Heading4", "Heading 4");
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading5Style extends HeadingStyle {
|
||||
|
||||
constructor() {
|
||||
super("Heading5", "Heading 5");
|
||||
}
|
||||
}
|
||||
|
||||
export class Heading6Style extends HeadingStyle {
|
||||
|
||||
constructor() {
|
||||
super("Heading6", "Heading 6");
|
||||
}
|
||||
}
|
||||
|
||||
export class ListParagraph extends ParagraphStyle {
|
||||
|
||||
constructor() {
|
||||
super("ListParagraph");
|
||||
this.root.push(new Name("List Paragraph"));
|
||||
this.root.push(new BasedOn("Normal"));
|
||||
this.root.push(new QuickFormat());
|
||||
}
|
||||
}
|
568
src/file/styles/styles.spec.ts
Normal file
568
src/file/styles/styles.spec.ts
Normal file
@ -0,0 +1,568 @@
|
||||
import { assert, expect } from "chai";
|
||||
import { Formatter } from "../../export/formatter";
|
||||
import { Styles } from "./";
|
||||
import { ParagraphStyle, Style } from "./style";
|
||||
import * as components from "./style/components";
|
||||
|
||||
describe("Styles", () => {
|
||||
let styles: Styles;
|
||||
|
||||
beforeEach(() => {
|
||||
styles = new Styles();
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create styles with correct rootKey", () => {
|
||||
const newJson = JSON.parse(JSON.stringify(styles));
|
||||
assert.equal(newJson.rootKey, "w:styles");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#createParagraphStyle", () => {
|
||||
it("should create a new paragraph style and push it onto this collection", () => {
|
||||
styles.createParagraphStyle("pStyleId");
|
||||
const tree = new Formatter().format(styles)["w:styles"].filter((x) => !x._attr);
|
||||
expect(tree).to.deep.equal([{
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "pStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
}]);
|
||||
});
|
||||
|
||||
it("should set the paragraph name if given", () => {
|
||||
styles.createParagraphStyle("pStyleId", "Paragraph Style");
|
||||
const tree = new Formatter().format(styles)["w:styles"].filter((x) => !x._attr);
|
||||
expect(tree).to.deep.equal([{
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "pStyleId"}},
|
||||
{"w:name": [{_attr: {"w:val": "Paragraph Style"}}]},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
}]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Style", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should set the given properties", () => {
|
||||
const style = new Style({
|
||||
type: "paragraph",
|
||||
styleId: "myStyleId",
|
||||
default: true,
|
||||
});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId", "w:default": true}},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the name of the style, if given", () => {
|
||||
const style = new Style({
|
||||
type: "paragraph",
|
||||
styleId: "myStyleId",
|
||||
}, "Style Name");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:name": [{_attr: {"w:val": "Style Name"}}]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Style components", () => {
|
||||
it("Name#constructor", () => {
|
||||
const style = new components.Name("Style Name");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({"w:name": [{_attr: {"w:val": "Style Name"}}]});
|
||||
});
|
||||
|
||||
it("BasedOn#constructor", () => {
|
||||
const style = new components.BasedOn("otherId");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({"w:basedOn": [{_attr: {"w:val": "otherId"}}]});
|
||||
});
|
||||
|
||||
it("Next#constructor", () => {
|
||||
const style = new components.Next("otherId");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({"w:next": [{_attr: {"w:val": "otherId"}}]});
|
||||
});
|
||||
|
||||
it("Link#constructor", () => {
|
||||
const style = new components.Link("otherId");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({"w:link": [{_attr: {"w:val": "otherId"}}]});
|
||||
});
|
||||
|
||||
it("UiPriority#constructor", () => {
|
||||
const style = new components.UiPriority("123");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({"w:uiPriority": [{_attr: {"w:val": "123"}}]});
|
||||
});
|
||||
});
|
||||
|
||||
describe("ParagraphStyle", () => {
|
||||
describe("#constructor", () => {
|
||||
it("should set the style type to paragraph and use the given style id", () => {
|
||||
const style = new ParagraphStyle("myStyleId");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the name of the style, if given", () => {
|
||||
const style = new ParagraphStyle("myStyleId", "Style Name");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:name": [{_attr: {"w:val": "Style Name"}}]},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatting methods: style attributes", () => {
|
||||
it("#basedOn", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.basedOn("otherId");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": []},
|
||||
{"w:basedOn": [{_attr: {"w:val": "otherId"}}]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#quickFormat", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.quickFormat();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": []},
|
||||
{"w:qFormat": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#next", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.next("otherId");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": []},
|
||||
{"w:next": [{_attr: {"w:val": "otherId"}}]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatting methods: paragraph properties", () => {
|
||||
it("#indent", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.indent({ left: 720 });
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [
|
||||
{"w:ind": [{_attr: {"w:left": 720}}]},
|
||||
]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#spacing", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.spacing({before: 50, after: 150});
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [
|
||||
{"w:spacing": [{_attr: {"w:before": 50, "w:after": 150}}]},
|
||||
]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#center", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.center();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [
|
||||
{"w:jc": [{_attr: {"w:val": "center"}}]},
|
||||
]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#left", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.left();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [
|
||||
{"w:jc": [{_attr: {"w:val": "left"}}]},
|
||||
]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#right", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.right();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [
|
||||
{"w:jc": [{_attr: {"w:val": "right"}}]},
|
||||
]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#justified", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.justified();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [
|
||||
{"w:jc": [{_attr: {"w:val": "both"}}]},
|
||||
]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#thematicBreak", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.thematicBreak();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [
|
||||
{"w:pBdr": [{"w:bottom": [{_attr: {
|
||||
"w:color": "auto",
|
||||
"w:space": "1",
|
||||
"w:val": "single",
|
||||
"w:sz": "6",
|
||||
}}]}]},
|
||||
]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#leftTabStop", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.leftTabStop(1200);
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [
|
||||
{"w:tabs": [
|
||||
{"w:tab": [{_attr: {"w:val": "left", "w:pos": 1200}}]},
|
||||
]},
|
||||
]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#maxRightTabStop", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.maxRightTabStop();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [
|
||||
{"w:tabs": [
|
||||
{"w:tab": [{_attr: {"w:val": "right", "w:pos": 9026}}]},
|
||||
]},
|
||||
]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#keepLines", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.keepLines();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [{"w:keepLines": []}]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#keepNext", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.keepNext();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": [{"w:keepNext": []}]},
|
||||
{"w:rPr": []},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatting methods: run properties", () => {
|
||||
it("#size", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.size(24);
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:sz": [{_attr: {"w:val": 24}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#smallCaps", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.smallCaps();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:smallCaps": [{_attr: {"w:val": true}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#allCaps", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.allCaps();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:caps": [{_attr: {"w:val": true}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#strike", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.strike();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:strike": [{_attr: {"w:val": true}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#doubleStrike", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.doubleStrike();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:dstrike": [{_attr: {"w:val": true}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#subScript", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.subScript();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:vertAlign": [{_attr: {"w:val": "subscript"}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#superScript", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.superScript();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:vertAlign": [{_attr: {"w:val": "superscript"}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#font", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.font("Times");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [{"w:rFonts": [{_attr: {"w:ascii": "Times", "w:hAnsi": "Times"}}]}]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#bold", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.bold();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:b": [{_attr: {"w:val": true}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("#italics", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.italics();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:i": [{_attr: {"w:val": true}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
describe("#underline", () => {
|
||||
it("should set underline to 'single' if no arguments are given", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.underline();
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:u": [{_attr: {"w:val": "single"}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the style if given", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.underline("double");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:u": [{_attr: {"w:val": "double"}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the style and color if given", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.underline("double", "005599");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:u": [{_attr: {"w:val": "double", "w:color": "005599"}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("#color", () => {
|
||||
const style = new ParagraphStyle("myStyleId")
|
||||
.color("123456");
|
||||
const tree = new Formatter().format(style);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:style": [
|
||||
{_attr: {"w:type": "paragraph", "w:styleId": "myStyleId"}},
|
||||
{"w:pPr": []},
|
||||
{"w:rPr": [
|
||||
{"w:color": [{_attr: {"w:val": "123456"}}]},
|
||||
]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user