@cj-tech-master/excelts 4.0.4 → 4.1.0-canary.20260110033117.75bcac1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.browser.d.ts +2 -0
- package/dist/browser/index.browser.js +1 -0
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/index.js +1 -0
- package/dist/browser/modules/excel/cell.js +39 -1
- package/dist/browser/modules/excel/enums.d.ts +2 -1
- package/dist/browser/modules/excel/enums.js +2 -1
- package/dist/browser/modules/excel/form-control.d.ts +157 -0
- package/dist/browser/modules/excel/form-control.js +267 -0
- package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +1 -0
- package/dist/browser/modules/excel/stream/workbook-writer.browser.js +19 -1
- package/dist/browser/modules/excel/table.d.ts +6 -2
- package/dist/browser/modules/excel/table.js +33 -5
- package/dist/browser/modules/excel/types.d.ts +5 -1
- package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +4 -0
- package/dist/browser/modules/excel/utils/ooxml-paths.js +12 -2
- package/dist/browser/modules/excel/worksheet.d.ts +32 -0
- package/dist/browser/modules/excel/worksheet.js +44 -1
- package/dist/browser/modules/excel/xlsx/rel-type.d.ts +2 -0
- package/dist/browser/modules/excel/xlsx/rel-type.js +3 -1
- package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +24 -1
- package/dist/browser/modules/excel/xlsx/xform/core/feature-property-bag-xform.d.ts +8 -0
- package/dist/browser/modules/excel/xlsx/xform/core/feature-property-bag-xform.js +36 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +22 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +52 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.d.ts +44 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +181 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.js +5 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +24 -1
- package/dist/browser/modules/excel/xlsx/xform/style/style-xform.d.ts +2 -0
- package/dist/browser/modules/excel/xlsx/xform/style/style-xform.js +11 -0
- package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.d.ts +2 -0
- package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.js +28 -4
- package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +3 -0
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +43 -5
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/modules/excel/cell.js +39 -1
- package/dist/cjs/modules/excel/enums.js +2 -1
- package/dist/cjs/modules/excel/form-control.js +270 -0
- package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +19 -1
- package/dist/cjs/modules/excel/table.js +33 -5
- package/dist/cjs/modules/excel/utils/ooxml-paths.js +14 -2
- package/dist/cjs/modules/excel/worksheet.js +44 -1
- package/dist/cjs/modules/excel/xlsx/rel-type.js +3 -1
- package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +23 -0
- package/dist/cjs/modules/excel/xlsx/xform/core/feature-property-bag-xform.js +39 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +55 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +184 -0
- package/dist/cjs/modules/excel/xlsx/xform/sheet/cell-xform.js +5 -0
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +23 -0
- package/dist/cjs/modules/excel/xlsx/xform/style/style-xform.js +11 -0
- package/dist/cjs/modules/excel/xlsx/xform/style/styles-xform.js +28 -4
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +42 -4
- package/dist/esm/index.browser.js +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/modules/excel/cell.js +39 -1
- package/dist/esm/modules/excel/enums.js +2 -1
- package/dist/esm/modules/excel/form-control.js +267 -0
- package/dist/esm/modules/excel/stream/workbook-writer.browser.js +19 -1
- package/dist/esm/modules/excel/table.js +33 -5
- package/dist/esm/modules/excel/utils/ooxml-paths.js +12 -2
- package/dist/esm/modules/excel/worksheet.js +44 -1
- package/dist/esm/modules/excel/xlsx/rel-type.js +3 -1
- package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +24 -1
- package/dist/esm/modules/excel/xlsx/xform/core/feature-property-bag-xform.js +36 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +52 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +181 -0
- package/dist/esm/modules/excel/xlsx/xform/sheet/cell-xform.js +5 -0
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +24 -1
- package/dist/esm/modules/excel/xlsx/xform/style/style-xform.js +11 -0
- package/dist/esm/modules/excel/xlsx/xform/style/styles-xform.js +28 -4
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +43 -5
- package/dist/iife/excelts.iife.js +629 -40
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +30 -30
- package/dist/types/index.browser.d.ts +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/modules/excel/enums.d.ts +2 -1
- package/dist/types/modules/excel/form-control.d.ts +157 -0
- package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +1 -0
- package/dist/types/modules/excel/table.d.ts +6 -2
- package/dist/types/modules/excel/types.d.ts +5 -1
- package/dist/types/modules/excel/utils/ooxml-paths.d.ts +4 -0
- package/dist/types/modules/excel/worksheet.d.ts +32 -0
- package/dist/types/modules/excel/xlsx/rel-type.d.ts +2 -0
- package/dist/types/modules/excel/xlsx/xform/core/feature-property-bag-xform.d.ts +8 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +22 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/vml-drawing-xform.d.ts +44 -0
- package/dist/types/modules/excel/xlsx/xform/style/style-xform.d.ts +2 -0
- package/dist/types/modules/excel/xlsx/xform/style/styles-xform.d.ts +2 -0
- package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +3 -0
- package/package.json +9 -9
|
@@ -12,9 +12,11 @@ export { Image } from "@excel/image";
|
|
|
12
12
|
export * from "@excel/anchor";
|
|
13
13
|
export { Table } from "@excel/table";
|
|
14
14
|
export { DataValidations } from "@excel/data-validations";
|
|
15
|
+
export { FormCheckbox } from "@excel/form-control";
|
|
15
16
|
export * from "@excel/enums";
|
|
16
17
|
export * from "@excel/types";
|
|
17
18
|
export type { PivotTable, PivotTableModel, PivotTableSource, CacheField, DataField, PivotTableSubtotal, ParsedCacheDefinition, ParsedCacheRecords } from "@excel/pivot-table";
|
|
19
|
+
export type { FormCheckboxModel, FormCheckboxOptions, FormControlRange, FormControlAnchor } from "@excel/form-control";
|
|
18
20
|
import { WorkbookWriter } from "@excel/stream/workbook-writer.browser";
|
|
19
21
|
import { WorkbookReader } from "@excel/stream/workbook-reader.browser";
|
|
20
22
|
import { WorksheetWriter } from "@excel/stream/worksheet-writer";
|
|
@@ -15,6 +15,7 @@ export { Image } from "./modules/excel/image.js";
|
|
|
15
15
|
export * from "./modules/excel/anchor.js";
|
|
16
16
|
export { Table } from "./modules/excel/table.js";
|
|
17
17
|
export { DataValidations } from "./modules/excel/data-validations.js";
|
|
18
|
+
export { FormCheckbox } from "./modules/excel/form-control.js";
|
|
18
19
|
// =============================================================================
|
|
19
20
|
// Enums
|
|
20
21
|
// =============================================================================
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export { Image } from "@excel/image";
|
|
|
8
8
|
export * from "@excel/anchor";
|
|
9
9
|
export { Table } from "@excel/table";
|
|
10
10
|
export { DataValidations } from "@excel/data-validations";
|
|
11
|
+
export { FormCheckbox } from "@excel/form-control";
|
|
11
12
|
export { WorkbookWriter } from "@excel/stream/workbook-writer";
|
|
12
13
|
export { WorkbookReader } from "@excel/stream/workbook-reader";
|
|
13
14
|
export { WorksheetWriter } from "@excel/stream/worksheet-writer";
|
|
@@ -15,6 +16,7 @@ export { WorksheetReader } from "@excel/stream/worksheet-reader";
|
|
|
15
16
|
export * from "@excel/enums";
|
|
16
17
|
export * from "@excel/types";
|
|
17
18
|
export type { PivotTable, PivotTableModel, PivotTableSource, CacheField, DataField, PivotTableSubtotal, ParsedCacheDefinition, ParsedCacheRecords } from "@excel/pivot-table";
|
|
19
|
+
export type { FormCheckboxModel, FormCheckboxOptions, FormControlRange, FormControlAnchor } from "@excel/form-control";
|
|
18
20
|
export type { WorkbookReaderOptions, ParseEvent, SharedStringEvent, WorksheetReadyEvent, HyperlinksEvent } from "@excel/stream/workbook-reader";
|
|
19
21
|
export type { WorksheetReaderOptions, WorksheetEvent, RowEvent, HyperlinkEvent, WorksheetHyperlink } from "@excel/stream/worksheet-reader";
|
|
20
22
|
export type { WorkbookWriterOptions, ZipOptions, ZlibOptions } from "@excel/stream/workbook-writer";
|
package/dist/browser/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export { Image } from "./modules/excel/image.js";
|
|
|
11
11
|
export * from "./modules/excel/anchor.js";
|
|
12
12
|
export { Table } from "./modules/excel/table.js";
|
|
13
13
|
export { DataValidations } from "./modules/excel/data-validations.js";
|
|
14
|
+
export { FormCheckbox } from "./modules/excel/form-control.js";
|
|
14
15
|
// =============================================================================
|
|
15
16
|
// Node.js Only: Streaming Classes
|
|
16
17
|
// These can also be accessed via Workbook.createStreamWriter/createStreamReader
|
|
@@ -809,6 +809,40 @@ class BooleanValue {
|
|
|
809
809
|
return this.model.value.toString();
|
|
810
810
|
}
|
|
811
811
|
}
|
|
812
|
+
class CheckboxValue {
|
|
813
|
+
constructor(cell, value) {
|
|
814
|
+
this.model = {
|
|
815
|
+
address: cell.address,
|
|
816
|
+
type: Cell.Types.Checkbox,
|
|
817
|
+
value: value.checkbox
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
get value() {
|
|
821
|
+
return { checkbox: this.model.value };
|
|
822
|
+
}
|
|
823
|
+
set value(value) {
|
|
824
|
+
this.model.value = value.checkbox;
|
|
825
|
+
}
|
|
826
|
+
get type() {
|
|
827
|
+
return Cell.Types.Checkbox;
|
|
828
|
+
}
|
|
829
|
+
get effectiveType() {
|
|
830
|
+
return Cell.Types.Boolean;
|
|
831
|
+
}
|
|
832
|
+
get address() {
|
|
833
|
+
return this.model.address;
|
|
834
|
+
}
|
|
835
|
+
set address(value) {
|
|
836
|
+
this.model.address = value;
|
|
837
|
+
}
|
|
838
|
+
toCsvString() {
|
|
839
|
+
return this.model.value ? 1 : 0;
|
|
840
|
+
}
|
|
841
|
+
release() { }
|
|
842
|
+
toString() {
|
|
843
|
+
return this.model.value.toString();
|
|
844
|
+
}
|
|
845
|
+
}
|
|
812
846
|
class ErrorValue {
|
|
813
847
|
constructor(cell, value) {
|
|
814
848
|
this.model = {
|
|
@@ -898,6 +932,9 @@ const Value = {
|
|
|
898
932
|
return Cell.Types.Date;
|
|
899
933
|
}
|
|
900
934
|
if (typeof value === "object") {
|
|
935
|
+
if ("checkbox" in value && typeof value.checkbox === "boolean") {
|
|
936
|
+
return Cell.Types.Checkbox;
|
|
937
|
+
}
|
|
901
938
|
if ("text" in value && value.text && "hyperlink" in value && value.hyperlink) {
|
|
902
939
|
return Cell.Types.Hyperlink;
|
|
903
940
|
}
|
|
@@ -930,7 +967,8 @@ const Value = {
|
|
|
930
967
|
{ t: Cell.Types.SharedString, f: SharedStringValue },
|
|
931
968
|
{ t: Cell.Types.RichText, f: RichTextValue },
|
|
932
969
|
{ t: Cell.Types.Boolean, f: BooleanValue },
|
|
933
|
-
{ t: Cell.Types.Error, f: ErrorValue }
|
|
970
|
+
{ t: Cell.Types.Error, f: ErrorValue },
|
|
971
|
+
{ t: Cell.Types.Checkbox, f: CheckboxValue }
|
|
934
972
|
].reduce((p, t) => {
|
|
935
973
|
p[t.t] = t.f;
|
|
936
974
|
return p;
|
|
@@ -11,7 +11,8 @@ export var ValueType;
|
|
|
11
11
|
ValueType[ValueType["RichText"] = 8] = "RichText";
|
|
12
12
|
ValueType[ValueType["Boolean"] = 9] = "Boolean";
|
|
13
13
|
ValueType[ValueType["Error"] = 10] = "Error";
|
|
14
|
-
ValueType[ValueType["JSON"] = 11] = "JSON";
|
|
14
|
+
ValueType[ValueType["JSON"] = 11] = "JSON";
|
|
15
|
+
ValueType[ValueType["Checkbox"] = 12] = "Checkbox";
|
|
15
16
|
})(ValueType || (ValueType = {}));
|
|
16
17
|
export var FormulaType;
|
|
17
18
|
(function (FormulaType) {
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type { Worksheet } from "@excel/worksheet";
|
|
2
|
+
/**
|
|
3
|
+
* Form Control Checkbox - Legacy checkbox control compatible with Office 2007+ and WPS/LibreOffice
|
|
4
|
+
*
|
|
5
|
+
* Unlike the modern In-Cell Checkbox (which only works in Microsoft 365),
|
|
6
|
+
* Form Control Checkboxes are floating controls that work in virtually all
|
|
7
|
+
* spreadsheet applications.
|
|
8
|
+
*/
|
|
9
|
+
/** EMU (English Metric Units) to pixels conversion factor at 96 DPI */
|
|
10
|
+
export declare const EMU_PER_PIXEL = 9525;
|
|
11
|
+
/** EMU to points conversion factor */
|
|
12
|
+
export declare const EMU_PER_POINT = 12700;
|
|
13
|
+
/** Anchor position for form control placement */
|
|
14
|
+
export interface FormControlAnchor {
|
|
15
|
+
/** Column index (0-based) */
|
|
16
|
+
col: number;
|
|
17
|
+
/** Column offset in EMUs (1 pixel ≈ 9525 EMUs at 96 DPI) */
|
|
18
|
+
colOff: number;
|
|
19
|
+
/** Row index (0-based) */
|
|
20
|
+
row: number;
|
|
21
|
+
/** Row offset in EMUs */
|
|
22
|
+
rowOff: number;
|
|
23
|
+
}
|
|
24
|
+
/** Checkbox state values */
|
|
25
|
+
export type CheckboxState = "Checked" | "Unchecked" | "Mixed";
|
|
26
|
+
/** Options for adding a form control checkbox */
|
|
27
|
+
export interface FormCheckboxOptions {
|
|
28
|
+
/** Cell reference where the checkbox value (TRUE/FALSE) will be stored */
|
|
29
|
+
link?: string;
|
|
30
|
+
/** Initial checked state */
|
|
31
|
+
checked?: boolean;
|
|
32
|
+
/** Label text displayed next to the checkbox */
|
|
33
|
+
text?: string;
|
|
34
|
+
/** Whether to use flat appearance (no 3D effect) */
|
|
35
|
+
noThreeD?: boolean;
|
|
36
|
+
/** Whether to print the checkbox */
|
|
37
|
+
print?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Internal model for form control checkbox */
|
|
40
|
+
export interface FormCheckboxModel {
|
|
41
|
+
/** Unique shape ID (e.g., 1025, 1026, ...) */
|
|
42
|
+
shapeId: number;
|
|
43
|
+
/** Control property ID (rId in relationships) */
|
|
44
|
+
ctrlPropId: number;
|
|
45
|
+
/** Top-left anchor */
|
|
46
|
+
tl: FormControlAnchor;
|
|
47
|
+
/** Bottom-right anchor */
|
|
48
|
+
br: FormControlAnchor;
|
|
49
|
+
/** Cell link (e.g., "$A$1") */
|
|
50
|
+
link?: string;
|
|
51
|
+
/** Checked state */
|
|
52
|
+
checked: CheckboxState;
|
|
53
|
+
/** Label text */
|
|
54
|
+
text: string;
|
|
55
|
+
/** Use flat appearance */
|
|
56
|
+
noThreeD: boolean;
|
|
57
|
+
/** Print control */
|
|
58
|
+
print: boolean;
|
|
59
|
+
}
|
|
60
|
+
/** Range input for form control - can be a cell reference or position object */
|
|
61
|
+
export type FormControlRange = string | {
|
|
62
|
+
/** Top-left position */
|
|
63
|
+
tl: {
|
|
64
|
+
col: number;
|
|
65
|
+
row: number;
|
|
66
|
+
colOff?: number;
|
|
67
|
+
rowOff?: number;
|
|
68
|
+
} | string;
|
|
69
|
+
/** Bottom-right position (optional, defaults to reasonable size) */
|
|
70
|
+
br?: {
|
|
71
|
+
col: number;
|
|
72
|
+
row: number;
|
|
73
|
+
colOff?: number;
|
|
74
|
+
rowOff?: number;
|
|
75
|
+
} | string;
|
|
76
|
+
} | {
|
|
77
|
+
/** Start column (0-based) */
|
|
78
|
+
startCol: number;
|
|
79
|
+
/** Start row (0-based) */
|
|
80
|
+
startRow: number;
|
|
81
|
+
/** End column (0-based) */
|
|
82
|
+
endCol: number;
|
|
83
|
+
/** End row (0-based) */
|
|
84
|
+
endRow: number;
|
|
85
|
+
/** Column offset from start in EMUs */
|
|
86
|
+
startColOff?: number;
|
|
87
|
+
/** Row offset from start in EMUs */
|
|
88
|
+
startRowOff?: number;
|
|
89
|
+
/** Column offset from end in EMUs */
|
|
90
|
+
endColOff?: number;
|
|
91
|
+
/** Row offset from end in EMUs */
|
|
92
|
+
endRowOff?: number;
|
|
93
|
+
};
|
|
94
|
+
declare class FormCheckbox {
|
|
95
|
+
worksheet: Worksheet;
|
|
96
|
+
model: FormCheckboxModel;
|
|
97
|
+
constructor(worksheet: Worksheet, range: FormControlRange, options?: FormCheckboxOptions);
|
|
98
|
+
/**
|
|
99
|
+
* Get the checked state
|
|
100
|
+
*/
|
|
101
|
+
get checked(): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Set the checked state
|
|
104
|
+
*/
|
|
105
|
+
set checked(value: boolean);
|
|
106
|
+
/**
|
|
107
|
+
* Get the linked cell address
|
|
108
|
+
*/
|
|
109
|
+
get link(): string | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Set the linked cell address
|
|
112
|
+
*/
|
|
113
|
+
set link(value: string | undefined);
|
|
114
|
+
/**
|
|
115
|
+
* Get the label text
|
|
116
|
+
*/
|
|
117
|
+
get text(): string;
|
|
118
|
+
/**
|
|
119
|
+
* Set the label text
|
|
120
|
+
*/
|
|
121
|
+
set text(value: string);
|
|
122
|
+
/**
|
|
123
|
+
* Convert cell reference to absolute format (e.g., "A1" -> "$A$1")
|
|
124
|
+
*/
|
|
125
|
+
private _toAbsoluteRef;
|
|
126
|
+
/**
|
|
127
|
+
* Parse range input into anchor positions
|
|
128
|
+
*/
|
|
129
|
+
private _parseRange;
|
|
130
|
+
/**
|
|
131
|
+
* Convert anchor to VML anchor string format
|
|
132
|
+
* Format: "fromCol, fromColOff, fromRow, fromRowOff, toCol, toColOff, toRow, toRowOff"
|
|
133
|
+
* VML uses pixels for offsets
|
|
134
|
+
*/
|
|
135
|
+
getVmlAnchor(): string;
|
|
136
|
+
/**
|
|
137
|
+
* Get VML style string for positioning
|
|
138
|
+
*/
|
|
139
|
+
getVmlStyle(): string;
|
|
140
|
+
/**
|
|
141
|
+
* Get the numeric checked value for VML (0, 1, or 2)
|
|
142
|
+
*/
|
|
143
|
+
getVmlCheckedValue(): number;
|
|
144
|
+
/**
|
|
145
|
+
* Convert anchor to VML anchor string format from model
|
|
146
|
+
*/
|
|
147
|
+
static getVmlAnchor(model: FormCheckboxModel): string;
|
|
148
|
+
/**
|
|
149
|
+
* Get VML style string for positioning from model
|
|
150
|
+
*/
|
|
151
|
+
static getVmlStyle(model: FormCheckboxModel): string;
|
|
152
|
+
/**
|
|
153
|
+
* Get the numeric checked value for VML from model (0, 1, or 2)
|
|
154
|
+
*/
|
|
155
|
+
static getVmlCheckedValue(model: FormCheckboxModel): number;
|
|
156
|
+
}
|
|
157
|
+
export { FormCheckbox };
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { colCache } from "./utils/col-cache.js";
|
|
2
|
+
/**
|
|
3
|
+
* Form Control Checkbox - Legacy checkbox control compatible with Office 2007+ and WPS/LibreOffice
|
|
4
|
+
*
|
|
5
|
+
* Unlike the modern In-Cell Checkbox (which only works in Microsoft 365),
|
|
6
|
+
* Form Control Checkboxes are floating controls that work in virtually all
|
|
7
|
+
* spreadsheet applications.
|
|
8
|
+
*/
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Constants (exported for use by xforms)
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/** EMU (English Metric Units) to pixels conversion factor at 96 DPI */
|
|
13
|
+
export const EMU_PER_PIXEL = 9525;
|
|
14
|
+
/** EMU to points conversion factor */
|
|
15
|
+
export const EMU_PER_POINT = 12700;
|
|
16
|
+
/** Default column offset in EMUs (~15 pixels) */
|
|
17
|
+
const DEFAULT_COL_OFF = 142875;
|
|
18
|
+
/** Default row offset in EMUs (~3 pixels) */
|
|
19
|
+
const DEFAULT_ROW_OFF = 28575;
|
|
20
|
+
/** Default end column offset in EMUs (~29 pixels) */
|
|
21
|
+
const DEFAULT_END_COL_OFF = 276225;
|
|
22
|
+
/** Default end row offset in EMUs (~20 pixels) */
|
|
23
|
+
const DEFAULT_END_ROW_OFF = 190500;
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// FormCheckbox Class
|
|
26
|
+
// ============================================================================
|
|
27
|
+
class FormCheckbox {
|
|
28
|
+
constructor(worksheet, range, options) {
|
|
29
|
+
this.worksheet = worksheet;
|
|
30
|
+
// Parse range to get anchors
|
|
31
|
+
const { tl, br } = this._parseRange(range);
|
|
32
|
+
// Generate shape ID (starting from 1025)
|
|
33
|
+
const existingCount = worksheet.formControls?.length || 0;
|
|
34
|
+
const shapeId = 1025 + existingCount;
|
|
35
|
+
// Parse link cell reference
|
|
36
|
+
let link;
|
|
37
|
+
if (options?.link) {
|
|
38
|
+
// Ensure absolute reference format
|
|
39
|
+
link = this._toAbsoluteRef(options.link);
|
|
40
|
+
}
|
|
41
|
+
// Note: ctrlPropId is set later in worksheet-xform.ts prepare() for global uniqueness
|
|
42
|
+
this.model = {
|
|
43
|
+
shapeId,
|
|
44
|
+
ctrlPropId: 0, // Placeholder, set during prepare()
|
|
45
|
+
tl,
|
|
46
|
+
br,
|
|
47
|
+
link,
|
|
48
|
+
checked: options?.checked ? "Checked" : "Unchecked",
|
|
49
|
+
text: options?.text ?? "",
|
|
50
|
+
noThreeD: options?.noThreeD ?? true,
|
|
51
|
+
print: options?.print ?? false
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get the checked state
|
|
56
|
+
*/
|
|
57
|
+
get checked() {
|
|
58
|
+
return this.model.checked === "Checked";
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Set the checked state
|
|
62
|
+
*/
|
|
63
|
+
set checked(value) {
|
|
64
|
+
this.model.checked = value ? "Checked" : "Unchecked";
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get the linked cell address
|
|
68
|
+
*/
|
|
69
|
+
get link() {
|
|
70
|
+
return this.model.link;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Set the linked cell address
|
|
74
|
+
*/
|
|
75
|
+
set link(value) {
|
|
76
|
+
this.model.link = value ? this._toAbsoluteRef(value) : undefined;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get the label text
|
|
80
|
+
*/
|
|
81
|
+
get text() {
|
|
82
|
+
return this.model.text;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Set the label text
|
|
86
|
+
*/
|
|
87
|
+
set text(value) {
|
|
88
|
+
this.model.text = value;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Convert cell reference to absolute format (e.g., "A1" -> "$A$1")
|
|
92
|
+
*/
|
|
93
|
+
_toAbsoluteRef(ref) {
|
|
94
|
+
// If already absolute, return as-is
|
|
95
|
+
if (ref.includes("$")) {
|
|
96
|
+
return ref;
|
|
97
|
+
}
|
|
98
|
+
// Parse and convert
|
|
99
|
+
const addr = colCache.decodeAddress(ref);
|
|
100
|
+
return `$${colCache.n2l(addr.col)}$${addr.row}`;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Parse range input into anchor positions
|
|
104
|
+
*/
|
|
105
|
+
_parseRange(range) {
|
|
106
|
+
let tl;
|
|
107
|
+
let br;
|
|
108
|
+
if (typeof range === "string") {
|
|
109
|
+
// Parse cell reference like "B2" or "B2:D3"
|
|
110
|
+
const decoded = colCache.decode(range);
|
|
111
|
+
if ("top" in decoded) {
|
|
112
|
+
// It's a range like "B2:D3"
|
|
113
|
+
tl = {
|
|
114
|
+
col: decoded.left - 1, // Convert to 0-based
|
|
115
|
+
colOff: DEFAULT_COL_OFF,
|
|
116
|
+
row: decoded.top - 1,
|
|
117
|
+
rowOff: DEFAULT_ROW_OFF
|
|
118
|
+
};
|
|
119
|
+
br = {
|
|
120
|
+
col: decoded.right - 1,
|
|
121
|
+
colOff: DEFAULT_END_COL_OFF,
|
|
122
|
+
row: decoded.bottom - 1,
|
|
123
|
+
rowOff: DEFAULT_END_ROW_OFF
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
// Single cell reference - create default size checkbox
|
|
128
|
+
tl = {
|
|
129
|
+
col: decoded.col - 1,
|
|
130
|
+
colOff: DEFAULT_COL_OFF,
|
|
131
|
+
row: decoded.row - 1,
|
|
132
|
+
rowOff: DEFAULT_ROW_OFF
|
|
133
|
+
};
|
|
134
|
+
// Default size: about 2 columns wide, 1 row tall
|
|
135
|
+
br = {
|
|
136
|
+
col: decoded.col + 1,
|
|
137
|
+
colOff: DEFAULT_END_COL_OFF,
|
|
138
|
+
row: decoded.row,
|
|
139
|
+
rowOff: DEFAULT_END_ROW_OFF
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else if ("startCol" in range) {
|
|
144
|
+
// startCol/startRow/endCol/endRow format (0-based)
|
|
145
|
+
tl = {
|
|
146
|
+
col: range.startCol,
|
|
147
|
+
colOff: range.startColOff ?? DEFAULT_COL_OFF,
|
|
148
|
+
row: range.startRow,
|
|
149
|
+
rowOff: range.startRowOff ?? DEFAULT_ROW_OFF
|
|
150
|
+
};
|
|
151
|
+
br = {
|
|
152
|
+
col: range.endCol,
|
|
153
|
+
colOff: range.endColOff ?? DEFAULT_END_COL_OFF,
|
|
154
|
+
row: range.endRow,
|
|
155
|
+
rowOff: range.endRowOff ?? DEFAULT_END_ROW_OFF
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
// Object format with tl/br
|
|
160
|
+
if (typeof range.tl === "string") {
|
|
161
|
+
const decoded = colCache.decodeAddress(range.tl);
|
|
162
|
+
tl = {
|
|
163
|
+
col: decoded.col - 1,
|
|
164
|
+
colOff: DEFAULT_COL_OFF,
|
|
165
|
+
row: decoded.row - 1,
|
|
166
|
+
rowOff: DEFAULT_ROW_OFF
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
tl = {
|
|
171
|
+
col: range.tl.col,
|
|
172
|
+
colOff: range.tl.colOff ?? DEFAULT_COL_OFF,
|
|
173
|
+
row: range.tl.row,
|
|
174
|
+
rowOff: range.tl.rowOff ?? DEFAULT_ROW_OFF
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (range.br) {
|
|
178
|
+
if (typeof range.br === "string") {
|
|
179
|
+
const decoded = colCache.decodeAddress(range.br);
|
|
180
|
+
br = {
|
|
181
|
+
col: decoded.col - 1,
|
|
182
|
+
colOff: DEFAULT_END_COL_OFF,
|
|
183
|
+
row: decoded.row - 1,
|
|
184
|
+
rowOff: DEFAULT_END_ROW_OFF
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
br = {
|
|
189
|
+
col: range.br.col,
|
|
190
|
+
colOff: range.br.colOff ?? DEFAULT_END_COL_OFF,
|
|
191
|
+
row: range.br.row,
|
|
192
|
+
rowOff: range.br.rowOff ?? DEFAULT_END_ROW_OFF
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// Default size
|
|
198
|
+
br = {
|
|
199
|
+
col: tl.col + 2,
|
|
200
|
+
colOff: DEFAULT_END_COL_OFF,
|
|
201
|
+
row: tl.row + 1,
|
|
202
|
+
rowOff: DEFAULT_END_ROW_OFF
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return { tl, br };
|
|
207
|
+
}
|
|
208
|
+
// =========================================================================
|
|
209
|
+
// Instance methods - delegate to static methods
|
|
210
|
+
// =========================================================================
|
|
211
|
+
/**
|
|
212
|
+
* Convert anchor to VML anchor string format
|
|
213
|
+
* Format: "fromCol, fromColOff, fromRow, fromRowOff, toCol, toColOff, toRow, toRowOff"
|
|
214
|
+
* VML uses pixels for offsets
|
|
215
|
+
*/
|
|
216
|
+
getVmlAnchor() {
|
|
217
|
+
return FormCheckbox.getVmlAnchor(this.model);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get VML style string for positioning
|
|
221
|
+
*/
|
|
222
|
+
getVmlStyle() {
|
|
223
|
+
return FormCheckbox.getVmlStyle(this.model);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Get the numeric checked value for VML (0, 1, or 2)
|
|
227
|
+
*/
|
|
228
|
+
getVmlCheckedValue() {
|
|
229
|
+
return FormCheckbox.getVmlCheckedValue(this.model);
|
|
230
|
+
}
|
|
231
|
+
// =========================================================================
|
|
232
|
+
// Static utility methods - can be used with FormCheckboxModel directly
|
|
233
|
+
// =========================================================================
|
|
234
|
+
/**
|
|
235
|
+
* Convert anchor to VML anchor string format from model
|
|
236
|
+
*/
|
|
237
|
+
static getVmlAnchor(model) {
|
|
238
|
+
const { tl, br } = model;
|
|
239
|
+
const tlColOff = Math.round(tl.colOff / EMU_PER_PIXEL);
|
|
240
|
+
const tlRowOff = Math.round(tl.rowOff / EMU_PER_PIXEL);
|
|
241
|
+
const brColOff = Math.round(br.colOff / EMU_PER_PIXEL);
|
|
242
|
+
const brRowOff = Math.round(br.rowOff / EMU_PER_PIXEL);
|
|
243
|
+
return `${tl.col}, ${tlColOff}, ${tl.row}, ${tlRowOff}, ${br.col}, ${brColOff}, ${br.row}, ${brRowOff}`;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Get VML style string for positioning from model
|
|
247
|
+
*/
|
|
248
|
+
static getVmlStyle(model) {
|
|
249
|
+
const marginLeft = Math.round(model.tl.colOff / EMU_PER_POINT);
|
|
250
|
+
const marginTop = Math.round(model.tl.rowOff / EMU_PER_POINT);
|
|
251
|
+
return `position:absolute;margin-left:${marginLeft}pt;margin-top:${marginTop}pt;width:96pt;height:18pt;z-index:1;visibility:visible`;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get the numeric checked value for VML from model (0, 1, or 2)
|
|
255
|
+
*/
|
|
256
|
+
static getVmlCheckedValue(model) {
|
|
257
|
+
switch (model.checked) {
|
|
258
|
+
case "Checked":
|
|
259
|
+
return 1;
|
|
260
|
+
case "Mixed":
|
|
261
|
+
return 2;
|
|
262
|
+
default:
|
|
263
|
+
return 0;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
export { FormCheckbox };
|
|
@@ -132,6 +132,7 @@ export declare abstract class WorkbookWriterBase<TWorksheetWriter extends Worksh
|
|
|
132
132
|
addApp(): Promise<void>;
|
|
133
133
|
addCore(): Promise<void>;
|
|
134
134
|
addSharedStrings(): Promise<void>;
|
|
135
|
+
addFeaturePropertyBag(): Promise<void>;
|
|
135
136
|
addWorkbookRels(): Promise<void>;
|
|
136
137
|
addWorkbook(): Promise<void>;
|
|
137
138
|
_finalize(): Promise<this>;
|
|
@@ -20,6 +20,7 @@ import { ContentTypesXform } from "../xlsx/xform/core/content-types-xform.js";
|
|
|
20
20
|
import { AppXform } from "../xlsx/xform/core/app-xform.js";
|
|
21
21
|
import { WorkbookXform } from "../xlsx/xform/book/workbook-xform.js";
|
|
22
22
|
import { SharedStringsXform } from "../xlsx/xform/strings/shared-strings-xform.js";
|
|
23
|
+
import { FeaturePropertyBagXform } from "../xlsx/xform/core/feature-property-bag-xform.js";
|
|
23
24
|
import { theme1Xml } from "../xlsx/xml/theme1.js";
|
|
24
25
|
import { Writeable, stringToUint8Array } from "../../stream/index.browser.js";
|
|
25
26
|
import { mediaPath, OOXML_PATHS, OOXML_REL_TARGETS, worksheetRelTarget } from "../utils/ooxml-paths.js";
|
|
@@ -134,6 +135,7 @@ export class WorkbookWriterBase {
|
|
|
134
135
|
this.addCore(),
|
|
135
136
|
this.addSharedStrings(),
|
|
136
137
|
this.addStyles(),
|
|
138
|
+
this.addFeaturePropertyBag(),
|
|
137
139
|
this.addWorkbookRels()
|
|
138
140
|
]);
|
|
139
141
|
await this.addWorkbook();
|
|
@@ -226,7 +228,8 @@ export class WorkbookWriterBase {
|
|
|
226
228
|
worksheets: this._worksheets.filter(Boolean),
|
|
227
229
|
sharedStrings: this.sharedStrings,
|
|
228
230
|
commentRefs: this.commentRefs,
|
|
229
|
-
media: this.media
|
|
231
|
+
media: this.media,
|
|
232
|
+
hasCheckboxes: this.styles.hasCheckboxes
|
|
230
233
|
};
|
|
231
234
|
const xform = new ContentTypesXform();
|
|
232
235
|
this._addFile(xform.toXml(model), OOXML_PATHS.contentTypes);
|
|
@@ -280,6 +283,13 @@ export class WorkbookWriterBase {
|
|
|
280
283
|
}
|
|
281
284
|
return Promise.resolve();
|
|
282
285
|
}
|
|
286
|
+
addFeaturePropertyBag() {
|
|
287
|
+
if (this.styles.hasCheckboxes) {
|
|
288
|
+
const xform = new FeaturePropertyBagXform();
|
|
289
|
+
this._addFile(xform.toXml({}), OOXML_PATHS.xlFeaturePropertyBag);
|
|
290
|
+
}
|
|
291
|
+
return Promise.resolve();
|
|
292
|
+
}
|
|
283
293
|
addWorkbookRels() {
|
|
284
294
|
let count = 1;
|
|
285
295
|
const relationships = [
|
|
@@ -293,6 +303,14 @@ export class WorkbookWriterBase {
|
|
|
293
303
|
Target: OOXML_REL_TARGETS.workbookSharedStrings
|
|
294
304
|
});
|
|
295
305
|
}
|
|
306
|
+
// Add FeaturePropertyBag relationship if checkboxes are used
|
|
307
|
+
if (this.styles.hasCheckboxes) {
|
|
308
|
+
relationships.push({
|
|
309
|
+
Id: `rId${count++}`,
|
|
310
|
+
Type: RelType.FeaturePropertyBag,
|
|
311
|
+
Target: OOXML_REL_TARGETS.workbookFeaturePropertyBag
|
|
312
|
+
});
|
|
313
|
+
}
|
|
296
314
|
this._worksheets.forEach(ws => {
|
|
297
315
|
if (ws) {
|
|
298
316
|
ws.rId = `rId${count++}`;
|
|
@@ -52,8 +52,12 @@ declare class Table {
|
|
|
52
52
|
set model(value: TableModel);
|
|
53
53
|
cacheState(): void;
|
|
54
54
|
commit(): void;
|
|
55
|
-
addRow(values: CellValue[], rowNumber?: number
|
|
56
|
-
|
|
55
|
+
addRow(values: CellValue[], rowNumber?: number, options?: {
|
|
56
|
+
commit?: boolean;
|
|
57
|
+
}): void;
|
|
58
|
+
removeRows(rowIndex: number, count?: number, options?: {
|
|
59
|
+
commit?: boolean;
|
|
60
|
+
}): void;
|
|
57
61
|
getColumn(colIndex: number): Column;
|
|
58
62
|
addColumn(column: TableColumnProperties, values: CellValue[], colIndex?: number): void;
|
|
59
63
|
removeColumns(colIndex: number, count?: number): void;
|