Compare commits
70 Commits
Author | SHA1 | Date | |
---|---|---|---|
95f8e37006 | |||
87083cb264 | |||
1e8dc95c9c | |||
abfa242c28 | |||
56b5414152 | |||
8f46060be2 | |||
93b17ca2af | |||
66008115b8 | |||
55697a7c32 | |||
e9b259db6b | |||
55c51f7af1 | |||
4e7fd6a6dc | |||
6294ec448f | |||
668198b5d1 | |||
56b2ffe706 | |||
2ab06ffe36 | |||
0c51082bb9 | |||
9a9a2019f6 | |||
d94348f5ca | |||
4c10741862 | |||
222a25e4e2 | |||
5fd4490c4f | |||
e1cc65cb97 | |||
991f837bc1 | |||
87b3035465 | |||
4498305a6c | |||
cac7abba91 | |||
b9b55b2829 | |||
11365d5be5 | |||
47a5aff40c | |||
721fbbac67 | |||
bcca50fb40 | |||
229d2eb689 | |||
3ef80cc7b3 | |||
f1f11f36e4 | |||
28f187064e | |||
c391ca533a | |||
0ca92b80f9 | |||
84501b6038 | |||
dcd3e90b19 | |||
be7d84dfa0 | |||
b0d60109c9 | |||
b4659f9901 | |||
25f657b842 | |||
dfffb066f3 | |||
4f06d760a3 | |||
aea2531111 | |||
16707201b4 | |||
c7c9652095 | |||
05378f58ae | |||
d7549a1140 | |||
e3ee455186 | |||
210d9c58f2 | |||
db85c3dd2f | |||
414d0248f5 | |||
fa400bcf39 | |||
9e9ca526fe | |||
41c0fb5fc0 | |||
58e7dbf445 | |||
20e0213c7d | |||
b8f83fd6ad | |||
d1f75e3a42 | |||
337ff464cf | |||
cad4a5510b | |||
aa8438d8bd | |||
79363c2c2c | |||
f706d8e62d | |||
e7ee2a0fdf | |||
bd17df8e98 | |||
e237326319 |
@ -12,7 +12,6 @@
|
|||||||
[![Downloads per month][downloads-image]][downloads-url]
|
[![Downloads per month][downloads-image]][downloads-url]
|
||||||
[![GitHub Action Workflow Status][github-actions-workflow-image]][github-actions-workflow-url]
|
[![GitHub Action Workflow Status][github-actions-workflow-image]][github-actions-workflow-url]
|
||||||
[![Known Vulnerabilities][snky-image]][snky-url]
|
[![Known Vulnerabilities][snky-image]][snky-url]
|
||||||
[![Chat on Gitter][gitter-image]][gitter-url]
|
|
||||||
[![PRs Welcome][pr-image]][pr-url]
|
[![PRs Welcome][pr-image]][pr-url]
|
||||||
[![codecov][codecov-image]][codecov-url]
|
[![codecov][codecov-image]][codecov-url]
|
||||||
|
|
||||||
@ -107,8 +106,6 @@ Made with 💖
|
|||||||
[github-actions-workflow-url]: https://github.com/dolanmiu/docx/actions
|
[github-actions-workflow-url]: https://github.com/dolanmiu/docx/actions
|
||||||
[snky-image]: https://snyk.io/test/github/dolanmiu/docx/badge.svg
|
[snky-image]: https://snyk.io/test/github/dolanmiu/docx/badge.svg
|
||||||
[snky-url]: https://snyk.io/test/github/dolanmiu/docx
|
[snky-url]: https://snyk.io/test/github/dolanmiu/docx
|
||||||
[gitter-image]: https://badges.gitter.im/dolanmiu/docx.svg
|
|
||||||
[gitter-url]: https://gitter.im/docx-lib/Lobby
|
|
||||||
[pr-image]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
|
[pr-image]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
|
||||||
[pr-url]: http://makeapullrequest.com
|
[pr-url]: http://makeapullrequest.com
|
||||||
[codecov-image]: https://codecov.io/gh/dolanmiu/docx/branch/master/graph/badge.svg
|
[codecov-image]: https://codecov.io/gh/dolanmiu/docx/branch/master/graph/badge.svg
|
||||||
|
@ -43,6 +43,15 @@ const doc = new Document({
|
|||||||
color: "#FF0000",
|
color: "#FF0000",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
document: {
|
||||||
|
run: {
|
||||||
|
size: "11pt",
|
||||||
|
font: "Calibri",
|
||||||
|
},
|
||||||
|
paragraph: {
|
||||||
|
alignment: AlignmentType.RIGHT,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
paragraphStyles: [
|
paragraphStyles: [
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,18 @@ import * as fs from "fs";
|
|||||||
import { Document, ExternalHyperlink, Footer, FootnoteReferenceRun, ImageRun, Packer, Paragraph, TextRun } from "docx";
|
import { Document, ExternalHyperlink, Footer, FootnoteReferenceRun, ImageRun, Packer, Paragraph, TextRun } from "docx";
|
||||||
|
|
||||||
const doc = new Document({
|
const doc = new Document({
|
||||||
|
styles: {
|
||||||
|
default: {
|
||||||
|
hyperlink: {
|
||||||
|
run: {
|
||||||
|
color: "FF0000",
|
||||||
|
underline: {
|
||||||
|
color: "0000FF",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
footnotes: {
|
footnotes: {
|
||||||
1: {
|
1: {
|
||||||
children: [
|
children: [
|
||||||
|
44
demo/90-check-boxes.ts
Normal file
44
demo/90-check-boxes.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Simple example to add check boxes to a document
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Packer, Paragraph, TextRun, CheckBox } from "docx";
|
||||||
|
|
||||||
|
const doc = new Document({
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
properties: {},
|
||||||
|
children: [
|
||||||
|
new Paragraph({
|
||||||
|
children: [
|
||||||
|
new TextRun("Hello World"),
|
||||||
|
new TextRun({ break: 1 }),
|
||||||
|
new CheckBox(),
|
||||||
|
new TextRun({ break: 1 }),
|
||||||
|
new CheckBox({ checked: true }),
|
||||||
|
new TextRun({ break: 1 }),
|
||||||
|
new CheckBox({ checked: true, checkedState: { value: "2611" } }),
|
||||||
|
new TextRun({ break: 1 }),
|
||||||
|
new CheckBox({ checked: true, checkedState: { value: "2611", font: "MS Gothic" } }),
|
||||||
|
new TextRun({ break: 1 }),
|
||||||
|
new CheckBox({
|
||||||
|
checked: true,
|
||||||
|
checkedState: { value: "2611", font: "MS Gothic" },
|
||||||
|
uncheckedState: { value: "2610", font: "MS Gothic" },
|
||||||
|
}),
|
||||||
|
new TextRun({ break: 1 }),
|
||||||
|
new CheckBox({
|
||||||
|
checked: true,
|
||||||
|
checkedState: { value: "2611", font: "MS Gothic" },
|
||||||
|
uncheckedState: { value: "2610", font: "MS Gothic" },
|
||||||
|
}),
|
||||||
|
new TextRun({ text: "Are you ok?", break: 1 }),
|
||||||
|
new CheckBox({ checked: true, alias: "Are you ok?" }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
Packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<script src="../build/index.umd.cjs"></script>
|
<script src="../build/index.umd.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@ import inquirer from "inquirer";
|
|||||||
import { $ } from "execa";
|
import { $ } from "execa";
|
||||||
|
|
||||||
export type Answers = {
|
export type Answers = {
|
||||||
type: "list" | "number";
|
readonly type: "list" | "number";
|
||||||
demoNumber?: number;
|
readonly demoNumber?: number;
|
||||||
demoFile?: number;
|
readonly demoFile?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const dir = "./demo";
|
const dir = "./demo";
|
||||||
@ -15,8 +15,7 @@ const fileNames = fs.readdirSync(dir);
|
|||||||
|
|
||||||
const keys = fileNames.map((f) => path.parse(f).name);
|
const keys = fileNames.map((f) => path.parse(f).name);
|
||||||
const getFileNumber = (file: string): number => {
|
const getFileNumber = (file: string): number => {
|
||||||
const nameParts = file.split("-");
|
const [firstPart] = file.split("-");
|
||||||
const firstPart = nameParts[0];
|
|
||||||
|
|
||||||
return Number(firstPart);
|
return Number(firstPart);
|
||||||
};
|
};
|
||||||
@ -35,15 +34,15 @@ const answers = await inquirer.prompt<Answers>([
|
|||||||
name: "demoFile",
|
name: "demoFile",
|
||||||
message: "What demo do you wish to run?",
|
message: "What demo do you wish to run?",
|
||||||
choices: demoFiles,
|
choices: demoFiles,
|
||||||
filter: (input) => parseInt(input.split("-")[0]),
|
filter: (input) => parseInt(input.split("-")[0], 10),
|
||||||
when: (answers) => answers.type === "list",
|
when: (a) => a.type === "list",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "number",
|
type: "number",
|
||||||
name: "demoNumber",
|
name: "demoNumber",
|
||||||
message: "What demo do you wish to run? (Enter a number)",
|
message: "What demo do you wish to run? (Enter a number)",
|
||||||
default: 1,
|
default: 1,
|
||||||
when: (answers) => answers.type === "number",
|
when: (a) => a.type === "number",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -56,6 +55,7 @@ if (files.length === 0) {
|
|||||||
const filePath = path.join(dir, files[0]);
|
const filePath = path.join(dir, files[0]);
|
||||||
|
|
||||||
console.log(`Running demo ${demoNumber}: ${files[0]}`);
|
console.log(`Running demo ${demoNumber}: ${files[0]}`);
|
||||||
await $`ts-node --project demo/tsconfig.json ${filePath}`;
|
const { stdout } = await $`ts-node --project demo/tsconfig.json ${filePath}`;
|
||||||
|
console.log(stdout);
|
||||||
console.log("Successfully created document!");
|
console.log("Successfully created document!");
|
||||||
}
|
}
|
||||||
|
2274
package-lock.json
generated
2274
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "docx",
|
"name": "docx",
|
||||||
"version": "8.1.0",
|
"version": "8.2.1",
|
||||||
"description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.",
|
"description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "build/index.umd.cjs",
|
"main": "build/index.umd.js",
|
||||||
"module": "./build/index.js",
|
"module": "./build/index.js",
|
||||||
"types": "./build/index.d.ts",
|
"types": "./build/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"browser": {
|
"browser": {
|
||||||
"default": "./build/index.umd.cjs"
|
"default": "./build/index.umd.js"
|
||||||
},
|
},
|
||||||
"require": "./build/index.cjs",
|
"require": "./build/index.cjs",
|
||||||
"types": "./build/index.d.ts",
|
"types": "./build/index.d.ts",
|
||||||
@ -58,7 +58,6 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.3.1",
|
||||||
"fflate": "^0.8.0",
|
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"nanoid": "^4.0.2",
|
"nanoid": "^4.0.2",
|
||||||
"xml": "^1.0.1",
|
"xml": "^1.0.1",
|
||||||
@ -78,8 +77,8 @@
|
|||||||
"@types/xml": "^1.0.8",
|
"@types/xml": "^1.0.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.36.1",
|
"@typescript-eslint/eslint-plugin": "^5.36.1",
|
||||||
"@typescript-eslint/parser": "^5.36.1",
|
"@typescript-eslint/parser": "^5.36.1",
|
||||||
"@vitest/coverage-v8": "^0.32.0",
|
"@vitest/coverage-v8": "^0.33.0",
|
||||||
"@vitest/ui": "^0.32.0",
|
"@vitest/ui": "^0.33.0",
|
||||||
"cspell": "^6.2.2",
|
"cspell": "^6.2.2",
|
||||||
"docsify-cli": "^4.3.0",
|
"docsify-cli": "^4.3.0",
|
||||||
"eslint": "^8.23.0",
|
"eslint": "^8.23.0",
|
||||||
@ -98,13 +97,13 @@
|
|||||||
"ts-node": "^10.2.1",
|
"ts-node": "^10.2.1",
|
||||||
"tsconfig-paths": "^4.0.0",
|
"tsconfig-paths": "^4.0.0",
|
||||||
"typedoc": "^0.24.8",
|
"typedoc": "^0.24.8",
|
||||||
"typescript": "5.1.3",
|
"typescript": "5.1.6",
|
||||||
"unzipper": "^0.10.11",
|
"unzipper": "^0.10.11",
|
||||||
"vite": "^4.3.2",
|
"vite": "^4.3.2",
|
||||||
"vite-plugin-dts": "^2.3.0",
|
"vite-plugin-dts": "^3.3.1",
|
||||||
"vite-plugin-node-polyfills": "^0.9.0",
|
"vite-plugin-node-polyfills": "^0.9.0",
|
||||||
"vite-tsconfig-paths": "^4.2.0",
|
"vite-tsconfig-paths": "^4.2.0",
|
||||||
"vitest": "^0.32.0"
|
"vitest": "^0.33.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
29
src/file/checkbox/checkbox-symbol.ts
Normal file
29
src/file/checkbox/checkbox-symbol.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// This represents element type CT_SdtCheckboxSymbol element
|
||||||
|
// <xsd:complexType name="CT_SdtCheckboxSymbol">
|
||||||
|
// <xsd:attribute name="font" type="w:ST_String"/>
|
||||||
|
// <xsd:attribute name="val" type="w:ST_ShortHexNumber"/>
|
||||||
|
// </xsd:complexType>
|
||||||
|
|
||||||
|
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
||||||
|
import { shortHexNumber } from "@util/values";
|
||||||
|
|
||||||
|
class CheckboxSymbolAttributes extends XmlAttributeComponent<{
|
||||||
|
readonly val?: string | number | boolean;
|
||||||
|
readonly symbolfont?: string;
|
||||||
|
}> {
|
||||||
|
protected readonly xmlKeys = {
|
||||||
|
val: "w14:val",
|
||||||
|
symbolfont: "w14:font",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CheckBoxSymbolElement extends XmlComponent {
|
||||||
|
public constructor(name: string, val: string, font?: string) {
|
||||||
|
super(name);
|
||||||
|
if (font) {
|
||||||
|
this.root.push(new CheckboxSymbolAttributes({ val: shortHexNumber(val), symbolfont: font }));
|
||||||
|
} else {
|
||||||
|
this.root.push(new CheckboxSymbolAttributes({ val }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
src/file/checkbox/checkbox-util.spec.ts
Normal file
85
src/file/checkbox/checkbox-util.spec.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { Formatter } from "@export/formatter";
|
||||||
|
import { CheckBoxUtil } from ".";
|
||||||
|
|
||||||
|
describe("CheckBoxUtil", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("should create a CheckBoxUtil with proper root and default values", () => {
|
||||||
|
const checkBoxUtil = new CheckBoxUtil();
|
||||||
|
|
||||||
|
const tree = new Formatter().format(checkBoxUtil);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w14:checkbox": [
|
||||||
|
{
|
||||||
|
"w14:checked": {
|
||||||
|
_attr: {
|
||||||
|
"w14:val": "0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:checkedState": {
|
||||||
|
_attr: {
|
||||||
|
"w14:font": "MS Gothic",
|
||||||
|
"w14:val": "2612",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:uncheckedState": {
|
||||||
|
_attr: {
|
||||||
|
"w14:font": "MS Gothic",
|
||||||
|
"w14:val": "2610",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create a CheckBoxUtil with proper structure and custom values", () => {
|
||||||
|
const checkBoxUtil = new CheckBoxUtil({
|
||||||
|
checked: true,
|
||||||
|
checkedState: {
|
||||||
|
value: "2713",
|
||||||
|
font: "Segoe UI Symbol",
|
||||||
|
},
|
||||||
|
uncheckedState: {
|
||||||
|
value: "2705",
|
||||||
|
font: "Segoe UI Symbol",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(checkBoxUtil);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w14:checkbox": [
|
||||||
|
{
|
||||||
|
"w14:checked": {
|
||||||
|
_attr: {
|
||||||
|
"w14:val": "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:checkedState": {
|
||||||
|
_attr: {
|
||||||
|
"w14:font": "Segoe UI Symbol",
|
||||||
|
"w14:val": "2713",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:uncheckedState": {
|
||||||
|
_attr: {
|
||||||
|
"w14:font": "Segoe UI Symbol",
|
||||||
|
"w14:val": "2705",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
45
src/file/checkbox/checkbox-util.ts
Normal file
45
src/file/checkbox/checkbox-util.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// <xsd:complexType name="CT_SdtCheckbox">
|
||||||
|
// <xsd:sequence>
|
||||||
|
// <xsd:element name="checked" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
// <xsd:element name="checkedState" type="CT_SdtCheckboxSymbol" minOccurs="0"/>
|
||||||
|
// <xsd:element name="uncheckedState" type="CT_SdtCheckboxSymbol" minOccurs="0"/>
|
||||||
|
// </xsd:sequence>
|
||||||
|
// </xsd:complexType>
|
||||||
|
// <xsd:element name="checkbox" type="CT_SdtCheckbox"/>
|
||||||
|
|
||||||
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
import { CheckBoxSymbolElement } from "@file/checkbox/checkbox-symbol";
|
||||||
|
|
||||||
|
export interface ICheckboxSymbolProperties {
|
||||||
|
readonly value?: string;
|
||||||
|
readonly font?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICheckboxSymbolOptions {
|
||||||
|
readonly alias?: string;
|
||||||
|
readonly checked?: boolean;
|
||||||
|
readonly checkedState?: ICheckboxSymbolProperties;
|
||||||
|
readonly uncheckedState?: ICheckboxSymbolProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CheckBoxUtil extends XmlComponent {
|
||||||
|
private readonly DEFAULT_UNCHECKED_SYMBOL: string = "2610";
|
||||||
|
private readonly DEFAULT_CHECKED_SYMBOL: string = "2612";
|
||||||
|
private readonly DEFAULT_FONT: string = "MS Gothic";
|
||||||
|
public constructor(options?: ICheckboxSymbolOptions) {
|
||||||
|
super("w14:checkbox");
|
||||||
|
|
||||||
|
const value = options?.checked ? "1" : "0";
|
||||||
|
let symbol: string;
|
||||||
|
let font: string;
|
||||||
|
this.root.push(new CheckBoxSymbolElement("w14:checked", value));
|
||||||
|
|
||||||
|
symbol = options?.checkedState?.value ? options?.checkedState?.value : this.DEFAULT_CHECKED_SYMBOL;
|
||||||
|
font = options?.checkedState?.font ? options?.checkedState?.font : this.DEFAULT_FONT;
|
||||||
|
this.root.push(new CheckBoxSymbolElement("w14:checkedState", symbol, font));
|
||||||
|
|
||||||
|
symbol = options?.uncheckedState?.value ? options?.uncheckedState?.value : this.DEFAULT_UNCHECKED_SYMBOL;
|
||||||
|
font = options?.uncheckedState?.font ? options?.uncheckedState?.font : this.DEFAULT_FONT;
|
||||||
|
this.root.push(new CheckBoxSymbolElement("w14:uncheckedState", symbol, font));
|
||||||
|
}
|
||||||
|
}
|
213
src/file/checkbox/checkbox.spec.ts
Normal file
213
src/file/checkbox/checkbox.spec.ts
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
|
import { CheckBox } from "./checkbox";
|
||||||
|
|
||||||
|
describe("CheckBox", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("should create a CheckBox with proper root and default values (no alias, no custom state)", () => {
|
||||||
|
const checkBox = new CheckBox();
|
||||||
|
|
||||||
|
const tree = new Formatter().format(checkBox);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:sdt": [
|
||||||
|
{
|
||||||
|
"w:sdtPr": [
|
||||||
|
{
|
||||||
|
"w14:checkbox": [
|
||||||
|
{
|
||||||
|
"w14:checked": {
|
||||||
|
_attr: {
|
||||||
|
"w14:val": "0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:checkedState": {
|
||||||
|
_attr: {
|
||||||
|
"w14:font": "MS Gothic",
|
||||||
|
"w14:val": "2612",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:uncheckedState": {
|
||||||
|
_attr: {
|
||||||
|
"w14:font": "MS Gothic",
|
||||||
|
"w14:val": "2610",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:sdtContent": [
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:sym": {
|
||||||
|
_attr: {
|
||||||
|
"w:char": "2610",
|
||||||
|
"w:font": "MS Gothic",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
["2713", "Segoe UI Symbol", "2713", "Segoe UI Symbol"],
|
||||||
|
[undefined, undefined, "2612", "MS Gothic"],
|
||||||
|
])("should create a CheckBox with proper root and custom values", (inputChar, inputFont, actualChar, actualFont) => {
|
||||||
|
const checkBox = new CheckBox({
|
||||||
|
alias: "Custom Checkbox",
|
||||||
|
checked: true,
|
||||||
|
checkedState: {
|
||||||
|
value: inputChar,
|
||||||
|
font: inputFont,
|
||||||
|
},
|
||||||
|
uncheckedState: {
|
||||||
|
value: "2705",
|
||||||
|
font: "Segoe UI Symbol",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(checkBox);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:sdt": [
|
||||||
|
{
|
||||||
|
"w:sdtPr": [
|
||||||
|
{
|
||||||
|
"w:alias": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": "Custom Checkbox",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:checkbox": [
|
||||||
|
{
|
||||||
|
"w14:checked": {
|
||||||
|
_attr: {
|
||||||
|
"w14:val": "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:checkedState": {
|
||||||
|
_attr: {
|
||||||
|
"w14:font": actualFont,
|
||||||
|
"w14:val": actualChar,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:uncheckedState": {
|
||||||
|
_attr: {
|
||||||
|
"w14:font": "Segoe UI Symbol",
|
||||||
|
"w14:val": "2705",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:sdtContent": [
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:sym": {
|
||||||
|
_attr: {
|
||||||
|
"w:char": actualChar,
|
||||||
|
"w:font": actualFont,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create a CheckBox with proper root, custom state, and no alias", () => {
|
||||||
|
const checkBox = new CheckBox({
|
||||||
|
checked: false,
|
||||||
|
checkedState: {
|
||||||
|
value: "2713",
|
||||||
|
font: "Segoe UI Symbol",
|
||||||
|
},
|
||||||
|
uncheckedState: {
|
||||||
|
value: "2705",
|
||||||
|
font: "Segoe UI Symbol",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(checkBox);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:sdt": [
|
||||||
|
{
|
||||||
|
"w:sdtPr": [
|
||||||
|
{
|
||||||
|
"w14:checkbox": [
|
||||||
|
{
|
||||||
|
"w14:checked": {
|
||||||
|
_attr: {
|
||||||
|
"w14:val": "0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:checkedState": {
|
||||||
|
_attr: {
|
||||||
|
"w14:font": "Segoe UI Symbol",
|
||||||
|
"w14:val": "2713",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w14:uncheckedState": {
|
||||||
|
_attr: {
|
||||||
|
"w14:font": "Segoe UI Symbol",
|
||||||
|
"w14:val": "2705",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:sdtContent": [
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:sym": {
|
||||||
|
_attr: {
|
||||||
|
"w:char": "2705",
|
||||||
|
"w:font": "Segoe UI Symbol",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
43
src/file/checkbox/checkbox.ts
Normal file
43
src/file/checkbox/checkbox.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { SymbolRun } from "@file/paragraph/run/symbol-run";
|
||||||
|
import { StructuredDocumentTagProperties } from "@file/table-of-contents/sdt-properties";
|
||||||
|
import { StructuredDocumentTagContent } from "@file/table-of-contents/sdt-content";
|
||||||
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
import { CheckBoxUtil, ICheckboxSymbolOptions } from "./checkbox-util";
|
||||||
|
|
||||||
|
export class CheckBox extends XmlComponent {
|
||||||
|
// default values per Microsoft
|
||||||
|
private readonly DEFAULT_UNCHECKED_SYMBOL: string = "2610";
|
||||||
|
private readonly DEFAULT_CHECKED_SYMBOL: string = "2612";
|
||||||
|
private readonly DEFAULT_FONT: string = "MS Gothic";
|
||||||
|
public constructor(options?: ICheckboxSymbolOptions) {
|
||||||
|
super("w:sdt");
|
||||||
|
|
||||||
|
const properties = new StructuredDocumentTagProperties(options?.alias);
|
||||||
|
properties.addChildElement(new CheckBoxUtil(options));
|
||||||
|
this.root.push(properties);
|
||||||
|
|
||||||
|
const content = new StructuredDocumentTagContent();
|
||||||
|
const checkedFont: string | undefined = options?.checkedState?.font;
|
||||||
|
const checkedText: string | undefined = options?.checkedState?.value;
|
||||||
|
const uncheckedFont: string | undefined = options?.uncheckedState?.font;
|
||||||
|
const uncheckedText: string | undefined = options?.uncheckedState?.value;
|
||||||
|
let symbolFont: string;
|
||||||
|
let char: string;
|
||||||
|
|
||||||
|
if (options?.checked) {
|
||||||
|
symbolFont = checkedFont ? checkedFont : this.DEFAULT_FONT;
|
||||||
|
char = checkedText ? checkedText : this.DEFAULT_CHECKED_SYMBOL;
|
||||||
|
} else {
|
||||||
|
symbolFont = uncheckedFont ? uncheckedFont : this.DEFAULT_FONT;
|
||||||
|
char = uncheckedText ? uncheckedText : this.DEFAULT_UNCHECKED_SYMBOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialRenderedChar = new SymbolRun({
|
||||||
|
char: char,
|
||||||
|
symbolfont: symbolFont,
|
||||||
|
});
|
||||||
|
|
||||||
|
content.addChildElement(initialRenderedChar);
|
||||||
|
this.root.push(content);
|
||||||
|
}
|
||||||
|
}
|
3
src/file/checkbox/index.ts
Normal file
3
src/file/checkbox/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./checkbox-util";
|
||||||
|
export * from "./checkbox-symbol";
|
||||||
|
export * from "./checkbox";
|
@ -17,3 +17,4 @@ export * from "./track-revision";
|
|||||||
export * from "./shared";
|
export * from "./shared";
|
||||||
export * from "./border";
|
export * from "./border";
|
||||||
export * from "./vertical-align";
|
export * from "./vertical-align";
|
||||||
|
export * from "./checkbox";
|
||||||
|
@ -6,6 +6,7 @@ import { FileChild } from "@file/file-child";
|
|||||||
|
|
||||||
import { TargetModeType } from "../relationships/relationship/relationship";
|
import { TargetModeType } from "../relationships/relationship/relationship";
|
||||||
import { DeletedTextRun, InsertedTextRun } from "../track-revision";
|
import { DeletedTextRun, InsertedTextRun } from "../track-revision";
|
||||||
|
import { CheckBox } from "../checkbox";
|
||||||
import { ColumnBreak, PageBreak } from "./formatting/break";
|
import { ColumnBreak, PageBreak } from "./formatting/break";
|
||||||
import { Bookmark, ConcreteHyperlink, ExternalHyperlink, InternalHyperlink } from "./links";
|
import { Bookmark, ConcreteHyperlink, ExternalHyperlink, InternalHyperlink } from "./links";
|
||||||
import { Math } from "./math";
|
import { Math } from "./math";
|
||||||
@ -33,7 +34,8 @@ export type ParagraphChild =
|
|||||||
| Comment
|
| Comment
|
||||||
| CommentRangeStart
|
| CommentRangeStart
|
||||||
| CommentRangeEnd
|
| CommentRangeEnd
|
||||||
| CommentReference;
|
| CommentReference
|
||||||
|
| CheckBox;
|
||||||
|
|
||||||
export interface IParagraphOptions extends IParagraphPropertiesOptions {
|
export interface IParagraphOptions extends IParagraphPropertiesOptions {
|
||||||
readonly text?: string;
|
readonly text?: string;
|
||||||
|
@ -318,4 +318,45 @@ describe("Default Styles", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("HyperlinkStyle#constructor", () => {
|
||||||
|
const style = new defaultStyles.HyperlinkStyle({
|
||||||
|
run: {
|
||||||
|
color: "FF0000",
|
||||||
|
underline: {
|
||||||
|
color: "0000FF",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "Hyperlink" } },
|
||||||
|
{ "w:name": { _attr: { "w:val": "Hyperlink" } } },
|
||||||
|
{ "w:basedOn": { _attr: { "w:val": "DefaultParagraphFont" } } },
|
||||||
|
{
|
||||||
|
"w:uiPriority": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": 99,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{ "w:u": { _attr: { "w:color": "0000FF", "w:val": "single" } } },
|
||||||
|
{
|
||||||
|
"w:color": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": "FF0000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -8,10 +8,10 @@ import { IBaseParagraphStyleOptions, IParagraphStyleOptions, StyleForParagraph }
|
|||||||
export class HeadingStyle extends StyleForParagraph {
|
export class HeadingStyle extends StyleForParagraph {
|
||||||
public constructor(options: IParagraphStyleOptions) {
|
public constructor(options: IParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
basedOn: "Normal",
|
basedOn: "Normal",
|
||||||
next: "Normal",
|
next: "Normal",
|
||||||
quickFormat: true,
|
quickFormat: true,
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,9 +19,9 @@ export class HeadingStyle extends StyleForParagraph {
|
|||||||
export class TitleStyle extends HeadingStyle {
|
export class TitleStyle extends HeadingStyle {
|
||||||
public constructor(options: IBaseParagraphStyleOptions) {
|
public constructor(options: IBaseParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "Title",
|
id: "Title",
|
||||||
name: "Title",
|
name: "Title",
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -29,9 +29,9 @@ export class TitleStyle extends HeadingStyle {
|
|||||||
export class Heading1Style extends HeadingStyle {
|
export class Heading1Style extends HeadingStyle {
|
||||||
public constructor(options: IBaseParagraphStyleOptions) {
|
public constructor(options: IBaseParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "Heading1",
|
id: "Heading1",
|
||||||
name: "Heading 1",
|
name: "Heading 1",
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,9 +39,9 @@ export class Heading1Style extends HeadingStyle {
|
|||||||
export class Heading2Style extends HeadingStyle {
|
export class Heading2Style extends HeadingStyle {
|
||||||
public constructor(options: IBaseParagraphStyleOptions) {
|
public constructor(options: IBaseParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "Heading2",
|
id: "Heading2",
|
||||||
name: "Heading 2",
|
name: "Heading 2",
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,9 +49,9 @@ export class Heading2Style extends HeadingStyle {
|
|||||||
export class Heading3Style extends HeadingStyle {
|
export class Heading3Style extends HeadingStyle {
|
||||||
public constructor(options: IBaseParagraphStyleOptions) {
|
public constructor(options: IBaseParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "Heading3",
|
id: "Heading3",
|
||||||
name: "Heading 3",
|
name: "Heading 3",
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,9 +59,9 @@ export class Heading3Style extends HeadingStyle {
|
|||||||
export class Heading4Style extends HeadingStyle {
|
export class Heading4Style extends HeadingStyle {
|
||||||
public constructor(options: IBaseParagraphStyleOptions) {
|
public constructor(options: IBaseParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "Heading4",
|
id: "Heading4",
|
||||||
name: "Heading 4",
|
name: "Heading 4",
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,9 +69,9 @@ export class Heading4Style extends HeadingStyle {
|
|||||||
export class Heading5Style extends HeadingStyle {
|
export class Heading5Style extends HeadingStyle {
|
||||||
public constructor(options: IBaseParagraphStyleOptions) {
|
public constructor(options: IBaseParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "Heading5",
|
id: "Heading5",
|
||||||
name: "Heading 5",
|
name: "Heading 5",
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,9 +79,9 @@ export class Heading5Style extends HeadingStyle {
|
|||||||
export class Heading6Style extends HeadingStyle {
|
export class Heading6Style extends HeadingStyle {
|
||||||
public constructor(options: IBaseParagraphStyleOptions) {
|
public constructor(options: IBaseParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "Heading6",
|
id: "Heading6",
|
||||||
name: "Heading 6",
|
name: "Heading 6",
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,9 +89,9 @@ export class Heading6Style extends HeadingStyle {
|
|||||||
export class StrongStyle extends HeadingStyle {
|
export class StrongStyle extends HeadingStyle {
|
||||||
public constructor(options: IBaseParagraphStyleOptions) {
|
public constructor(options: IBaseParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "Strong",
|
id: "Strong",
|
||||||
name: "Strong",
|
name: "Strong",
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,11 +99,11 @@ export class StrongStyle extends HeadingStyle {
|
|||||||
export class ListParagraph extends StyleForParagraph {
|
export class ListParagraph extends StyleForParagraph {
|
||||||
public constructor(options: IBaseParagraphStyleOptions) {
|
public constructor(options: IBaseParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "ListParagraph",
|
id: "ListParagraph",
|
||||||
name: "List Paragraph",
|
name: "List Paragraph",
|
||||||
basedOn: "Normal",
|
basedOn: "Normal",
|
||||||
quickFormat: true,
|
quickFormat: true,
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,7 +111,6 @@ export class ListParagraph extends StyleForParagraph {
|
|||||||
export class FootnoteText extends StyleForParagraph {
|
export class FootnoteText extends StyleForParagraph {
|
||||||
public constructor(options: IBaseParagraphStyleOptions) {
|
public constructor(options: IBaseParagraphStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "FootnoteText",
|
id: "FootnoteText",
|
||||||
name: "footnote text",
|
name: "footnote text",
|
||||||
link: "FootnoteTextChar",
|
link: "FootnoteTextChar",
|
||||||
@ -129,6 +128,7 @@ export class FootnoteText extends StyleForParagraph {
|
|||||||
run: {
|
run: {
|
||||||
size: 20,
|
size: 20,
|
||||||
},
|
},
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,7 +136,6 @@ export class FootnoteText extends StyleForParagraph {
|
|||||||
export class FootnoteReferenceStyle extends StyleForCharacter {
|
export class FootnoteReferenceStyle extends StyleForCharacter {
|
||||||
public constructor(options: IBaseCharacterStyleOptions) {
|
public constructor(options: IBaseCharacterStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "FootnoteReference",
|
id: "FootnoteReference",
|
||||||
name: "footnote reference",
|
name: "footnote reference",
|
||||||
basedOn: "DefaultParagraphFont",
|
basedOn: "DefaultParagraphFont",
|
||||||
@ -144,6 +143,7 @@ export class FootnoteReferenceStyle extends StyleForCharacter {
|
|||||||
run: {
|
run: {
|
||||||
superScript: true,
|
superScript: true,
|
||||||
},
|
},
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +151,6 @@ export class FootnoteReferenceStyle extends StyleForCharacter {
|
|||||||
export class FootnoteTextChar extends StyleForCharacter {
|
export class FootnoteTextChar extends StyleForCharacter {
|
||||||
public constructor(options: IBaseCharacterStyleOptions) {
|
public constructor(options: IBaseCharacterStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "FootnoteTextChar",
|
id: "FootnoteTextChar",
|
||||||
name: "Footnote Text Char",
|
name: "Footnote Text Char",
|
||||||
basedOn: "DefaultParagraphFont",
|
basedOn: "DefaultParagraphFont",
|
||||||
@ -160,6 +159,7 @@ export class FootnoteTextChar extends StyleForCharacter {
|
|||||||
run: {
|
run: {
|
||||||
size: 20,
|
size: 20,
|
||||||
},
|
},
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,7 +167,6 @@ export class FootnoteTextChar extends StyleForCharacter {
|
|||||||
export class HyperlinkStyle extends StyleForCharacter {
|
export class HyperlinkStyle extends StyleForCharacter {
|
||||||
public constructor(options: IBaseCharacterStyleOptions) {
|
public constructor(options: IBaseCharacterStyleOptions) {
|
||||||
super({
|
super({
|
||||||
...options,
|
|
||||||
id: "Hyperlink",
|
id: "Hyperlink",
|
||||||
name: "Hyperlink",
|
name: "Hyperlink",
|
||||||
basedOn: "DefaultParagraphFont",
|
basedOn: "DefaultParagraphFont",
|
||||||
@ -177,6 +176,7 @@ export class HyperlinkStyle extends StyleForCharacter {
|
|||||||
type: UnderlineType.SINGLE,
|
type: UnderlineType.SINGLE,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,11 @@
|
|||||||
import { StringValueElement, XmlComponent } from "@file/xml-components";
|
import { StringValueElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
export class StructuredDocumentTagProperties extends XmlComponent {
|
export class StructuredDocumentTagProperties extends XmlComponent {
|
||||||
public constructor(alias: string) {
|
public constructor(alias?: string) {
|
||||||
super("w:sdtPr");
|
super("w:sdtPr");
|
||||||
|
|
||||||
|
if (alias) {
|
||||||
this.root.push(new StringValueElement("w:alias", alias));
|
this.root.push(new StringValueElement("w:alias", alias));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -47,5 +47,31 @@ describe("content-types-manager", () => {
|
|||||||
type: "element",
|
type: "element",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should not append duplicate content type", () => {
|
||||||
|
const element = {
|
||||||
|
type: "element",
|
||||||
|
name: "xml",
|
||||||
|
elements: [
|
||||||
|
{
|
||||||
|
type: "element",
|
||||||
|
name: "Types",
|
||||||
|
elements: [
|
||||||
|
{
|
||||||
|
type: "element",
|
||||||
|
name: "Default",
|
||||||
|
attributes: {
|
||||||
|
ContentType: "image/png",
|
||||||
|
Extension: "png",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
appendContentType(element, "image/png", "png");
|
||||||
|
|
||||||
|
expect(element.elements.length).toBe(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,6 +4,18 @@ import { getFirstLevelElements } from "./util";
|
|||||||
|
|
||||||
export const appendContentType = (element: Element, contentType: string, extension: string): void => {
|
export const appendContentType = (element: Element, contentType: string, extension: string): void => {
|
||||||
const relationshipElements = getFirstLevelElements(element, "Types");
|
const relationshipElements = getFirstLevelElements(element, "Types");
|
||||||
|
|
||||||
|
const exist = relationshipElements.some(
|
||||||
|
(el) =>
|
||||||
|
el.type === "element" &&
|
||||||
|
el.name === "Default" &&
|
||||||
|
el?.attributes?.ContentType === contentType &&
|
||||||
|
el?.attributes?.Extension === extension,
|
||||||
|
);
|
||||||
|
if (exist) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line functional/immutable-data
|
// eslint-disable-next-line functional/immutable-data
|
||||||
relationshipElements.push({
|
relationshipElements.push({
|
||||||
attributes: {
|
attributes: {
|
||||||
|
@ -53,7 +53,7 @@ export interface PatchDocumentOptions {
|
|||||||
|
|
||||||
const imageReplacer = new ImageReplacer();
|
const imageReplacer = new ImageReplacer();
|
||||||
|
|
||||||
export const patchDocument = async (data: InputDataType, options: PatchDocumentOptions): Promise<Buffer> => {
|
export const patchDocument = async (data: InputDataType, options: PatchDocumentOptions): Promise<Uint8Array> => {
|
||||||
const zipContent = await JSZip.loadAsync(data);
|
const zipContent = await JSZip.loadAsync(data);
|
||||||
const contexts = new Map<string, IContext>();
|
const contexts = new Map<string, IContext>();
|
||||||
const file = {
|
const file = {
|
||||||
@ -213,7 +213,7 @@ export const patchDocument = async (data: InputDataType, options: PatchDocumentO
|
|||||||
}
|
}
|
||||||
|
|
||||||
return zip.generateAsync({
|
return zip.generateAsync({
|
||||||
type: "nodebuffer",
|
type: "uint8array",
|
||||||
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
compression: "DEFLATE",
|
compression: "DEFLATE",
|
||||||
});
|
});
|
||||||
|
@ -10,6 +10,9 @@ export default defineConfig({
|
|||||||
dts(),
|
dts(),
|
||||||
nodePolyfills({
|
nodePolyfills({
|
||||||
exclude: ["fs"],
|
exclude: ["fs"],
|
||||||
|
globals: {
|
||||||
|
Buffer: false,
|
||||||
|
},
|
||||||
protocolImports: true,
|
protocolImports: true,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@ -26,7 +29,25 @@ export default defineConfig({
|
|||||||
lib: {
|
lib: {
|
||||||
entry: [resolve(__dirname, "src/index.ts")],
|
entry: [resolve(__dirname, "src/index.ts")],
|
||||||
name: "docx",
|
name: "docx",
|
||||||
fileName: "index",
|
fileName: (d) => {
|
||||||
|
if (d === "umd") {
|
||||||
|
return "index.umd.js";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d === "cjs") {
|
||||||
|
return "index.cjs";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d === "es") {
|
||||||
|
return "index.js";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d === "iife") {
|
||||||
|
return "index.iife.js";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown";
|
||||||
|
},
|
||||||
formats: ["iife", "es", "cjs", "umd"],
|
formats: ["iife", "es", "cjs", "umd"],
|
||||||
},
|
},
|
||||||
outDir: resolve(__dirname, "build"),
|
outDir: resolve(__dirname, "build"),
|
||||||
|
Reference in New Issue
Block a user