Merge remote-tracking branch 'ric/master' into feature/check-boxes

This commit is contained in:
Dolan Miu
2023-06-24 20:50:35 +01:00
9 changed files with 423 additions and 3 deletions

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

View 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",
},
},
},
],
});
});
});
});

View File

@ -0,0 +1,44 @@
// <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 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));
}
}

View File

@ -0,0 +1,211 @@
import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { CheckBox } from ".";
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("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(undefined, {
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",
},
},
},
],
},
],
},
],
});
});
});
});

View 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(alias?: string, options?: ICheckboxSymbolOptions) {
super("w:sdt");
const properties = new StructuredDocumentTagProperties(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);
}
}

View File

@ -0,0 +1,3 @@
export * from "./checkbox-util";
export * from "./checkbox-symbol";
export * from "./checkbox";

View File

@ -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";

View File

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

View File

@ -2,8 +2,10 @@
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 (typeof alias === "string") {
this.root.push(new StringValueElement("w:alias", alias)); this.root.push(new StringValueElement("w:alias", alias));
} }
}
} }