@cj-tech-master/excelts 4.0.4 → 4.1.0-canary.20260110032830.e7d8c4e
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
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VmlDrawingXform = void 0;
|
|
4
|
+
const xml_stream_1 = require("../../../utils/xml-stream.js");
|
|
5
|
+
const base_xform_1 = require("../base-xform.js");
|
|
6
|
+
const vml_shape_xform_1 = require("../comment/vml-shape-xform.js");
|
|
7
|
+
const form_control_1 = require("../../../form-control.js");
|
|
8
|
+
class VmlDrawingXform extends base_xform_1.BaseXform {
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
this.map = {
|
|
12
|
+
"v:shape": new vml_shape_xform_1.VmlShapeXform()
|
|
13
|
+
};
|
|
14
|
+
this.model = { comments: [], formControls: [] };
|
|
15
|
+
}
|
|
16
|
+
get tag() {
|
|
17
|
+
return "xml";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Render VML drawing containing both notes and form controls
|
|
21
|
+
*/
|
|
22
|
+
render(xmlStream, model) {
|
|
23
|
+
const renderModel = model || this.model;
|
|
24
|
+
const hasComments = renderModel.comments && renderModel.comments.length > 0;
|
|
25
|
+
const hasFormControls = renderModel.formControls && renderModel.formControls.length > 0;
|
|
26
|
+
xmlStream.openXml(xml_stream_1.XmlStream.StdDocAttributes);
|
|
27
|
+
xmlStream.openNode(this.tag, VmlDrawingXform.DRAWING_ATTRIBUTES);
|
|
28
|
+
// Shape layout - shared by both notes and form controls
|
|
29
|
+
xmlStream.openNode("o:shapelayout", { "v:ext": "edit" });
|
|
30
|
+
xmlStream.leafNode("o:idmap", { "v:ext": "edit", data: 1 });
|
|
31
|
+
xmlStream.closeNode();
|
|
32
|
+
// Shapetype 202 for notes/comments
|
|
33
|
+
if (hasComments) {
|
|
34
|
+
xmlStream.openNode("v:shapetype", {
|
|
35
|
+
id: "_x0000_t202",
|
|
36
|
+
coordsize: "21600,21600",
|
|
37
|
+
"o:spt": 202,
|
|
38
|
+
path: "m,l,21600r21600,l21600,xe"
|
|
39
|
+
});
|
|
40
|
+
xmlStream.leafNode("v:stroke", { joinstyle: "miter" });
|
|
41
|
+
xmlStream.leafNode("v:path", { gradientshapeok: "t", "o:connecttype": "rect" });
|
|
42
|
+
xmlStream.closeNode();
|
|
43
|
+
}
|
|
44
|
+
// Shapetype 201 for form control checkboxes
|
|
45
|
+
if (hasFormControls) {
|
|
46
|
+
xmlStream.openNode("v:shapetype", {
|
|
47
|
+
id: "_x0000_t201",
|
|
48
|
+
coordsize: "21600,21600",
|
|
49
|
+
"o:spt": "201",
|
|
50
|
+
path: "m,l,21600r21600,l21600,xe"
|
|
51
|
+
});
|
|
52
|
+
xmlStream.leafNode("v:stroke", { joinstyle: "miter" });
|
|
53
|
+
xmlStream.leafNode("v:path", {
|
|
54
|
+
shadowok: "f",
|
|
55
|
+
"o:extrusionok": "f",
|
|
56
|
+
strokeok: "f",
|
|
57
|
+
fillok: "f",
|
|
58
|
+
"o:connecttype": "rect"
|
|
59
|
+
});
|
|
60
|
+
xmlStream.leafNode("o:lock", { "v:ext": "edit", shapetype: "t" });
|
|
61
|
+
xmlStream.closeNode();
|
|
62
|
+
}
|
|
63
|
+
// Render comment shapes
|
|
64
|
+
if (hasComments) {
|
|
65
|
+
const comments = renderModel.comments;
|
|
66
|
+
for (let i = 0; i < comments.length; i++) {
|
|
67
|
+
this.map["v:shape"].render(xmlStream, comments[i], i);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Render form control shapes
|
|
71
|
+
if (hasFormControls) {
|
|
72
|
+
for (const control of renderModel.formControls) {
|
|
73
|
+
this._renderCheckboxShape(xmlStream, control);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
xmlStream.closeNode();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Render a checkbox form control shape
|
|
80
|
+
*/
|
|
81
|
+
_renderCheckboxShape(xmlStream, control) {
|
|
82
|
+
const shapeAttrs = {
|
|
83
|
+
id: `_x0000_s${control.shapeId}`,
|
|
84
|
+
type: "#_x0000_t201",
|
|
85
|
+
style: form_control_1.FormCheckbox.getVmlStyle(control),
|
|
86
|
+
"o:insetmode": "auto",
|
|
87
|
+
fillcolor: "buttonFace [67]",
|
|
88
|
+
strokecolor: "windowText [64]",
|
|
89
|
+
"o:preferrelative": "t",
|
|
90
|
+
filled: "f",
|
|
91
|
+
stroked: "f"
|
|
92
|
+
};
|
|
93
|
+
xmlStream.openNode("v:shape", shapeAttrs);
|
|
94
|
+
// Fill element
|
|
95
|
+
xmlStream.leafNode("v:fill", { "o:detectmouseclick": "t" });
|
|
96
|
+
// Lock element
|
|
97
|
+
xmlStream.leafNode("o:lock", { "v:ext": "edit", text: "t" });
|
|
98
|
+
// Textbox for label
|
|
99
|
+
if (control.text) {
|
|
100
|
+
xmlStream.openNode("v:textbox", {
|
|
101
|
+
style: "mso-direction-alt:auto",
|
|
102
|
+
"o:singleclick": "t"
|
|
103
|
+
});
|
|
104
|
+
xmlStream.openNode("div", { style: "text-align:left" });
|
|
105
|
+
xmlStream.openNode("font", { face: "Tahoma", size: "160", color: "auto" });
|
|
106
|
+
xmlStream.writeText(control.text);
|
|
107
|
+
xmlStream.closeNode(); // font
|
|
108
|
+
xmlStream.closeNode(); // div
|
|
109
|
+
xmlStream.closeNode(); // v:textbox
|
|
110
|
+
}
|
|
111
|
+
// ClientData - the core of the checkbox control
|
|
112
|
+
xmlStream.openNode("x:ClientData", { ObjectType: "Checkbox" });
|
|
113
|
+
// Anchor position
|
|
114
|
+
xmlStream.openNode("x:Anchor");
|
|
115
|
+
xmlStream.writeText(form_control_1.FormCheckbox.getVmlAnchor(control));
|
|
116
|
+
xmlStream.closeNode();
|
|
117
|
+
// Print settings
|
|
118
|
+
xmlStream.leafNode("x:PrintObject", undefined, control.print ? "True" : "False");
|
|
119
|
+
xmlStream.leafNode("x:AutoFill", undefined, "False");
|
|
120
|
+
xmlStream.leafNode("x:AutoLine", undefined, "False");
|
|
121
|
+
xmlStream.leafNode("x:TextVAlign", undefined, "Center");
|
|
122
|
+
// Linked cell
|
|
123
|
+
if (control.link) {
|
|
124
|
+
xmlStream.leafNode("x:FmlaLink", undefined, control.link);
|
|
125
|
+
}
|
|
126
|
+
// 3D appearance
|
|
127
|
+
if (control.noThreeD) {
|
|
128
|
+
xmlStream.leafNode("x:NoThreeD");
|
|
129
|
+
}
|
|
130
|
+
// Checked state (0 = unchecked, 1 = checked, 2 = mixed)
|
|
131
|
+
xmlStream.leafNode("x:Checked", undefined, String(form_control_1.FormCheckbox.getVmlCheckedValue(control)));
|
|
132
|
+
xmlStream.closeNode(); // x:ClientData
|
|
133
|
+
xmlStream.closeNode(); // v:shape
|
|
134
|
+
}
|
|
135
|
+
// Parsing - delegate to VmlShapeXform for notes
|
|
136
|
+
parseOpen(node) {
|
|
137
|
+
if (this.parser) {
|
|
138
|
+
this.parser.parseOpen(node);
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
switch (node.name) {
|
|
142
|
+
case this.tag:
|
|
143
|
+
this.reset();
|
|
144
|
+
this.model = {
|
|
145
|
+
comments: [],
|
|
146
|
+
formControls: []
|
|
147
|
+
};
|
|
148
|
+
break;
|
|
149
|
+
default:
|
|
150
|
+
this.parser = this.map[node.name];
|
|
151
|
+
if (this.parser) {
|
|
152
|
+
this.parser.parseOpen(node);
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
parseText(text) {
|
|
159
|
+
if (this.parser) {
|
|
160
|
+
this.parser.parseText(text);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
parseClose(name) {
|
|
164
|
+
if (this.parser) {
|
|
165
|
+
if (!this.parser.parseClose(name)) {
|
|
166
|
+
this.model.comments.push(this.parser.model);
|
|
167
|
+
this.parser = undefined;
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
switch (name) {
|
|
172
|
+
case this.tag:
|
|
173
|
+
return false;
|
|
174
|
+
default:
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
exports.VmlDrawingXform = VmlDrawingXform;
|
|
180
|
+
VmlDrawingXform.DRAWING_ATTRIBUTES = {
|
|
181
|
+
"xmlns:v": "urn:schemas-microsoft-com:vml",
|
|
182
|
+
"xmlns:o": "urn:schemas-microsoft-com:office:office",
|
|
183
|
+
"xmlns:x": "urn:schemas-microsoft-com:office:excel"
|
|
184
|
+
};
|
|
@@ -192,6 +192,11 @@ class CellXform extends base_xform_1.BaseXform {
|
|
|
192
192
|
xmlStream.addAttribute("t", "b");
|
|
193
193
|
xmlStream.leafNode("v", null, model.value ? "1" : "0");
|
|
194
194
|
break;
|
|
195
|
+
case enums_1.Enums.ValueType.Checkbox:
|
|
196
|
+
// Checkboxes are stored as boolean values
|
|
197
|
+
xmlStream.addAttribute("t", "b");
|
|
198
|
+
xmlStream.leafNode("v", null, model.value ? "1" : "0");
|
|
199
|
+
break;
|
|
195
200
|
case enums_1.Enums.ValueType.Error:
|
|
196
201
|
xmlStream.addAttribute("t", "e");
|
|
197
202
|
xmlStream.leafNode("v", null, model.value.error);
|
|
@@ -278,6 +278,29 @@ class WorkSheetXform extends base_xform_1.BaseXform {
|
|
|
278
278
|
Target: (0, ooxml_paths_1.pivotTableRelTargetFromWorksheet)(pivotTable.tableNumber)
|
|
279
279
|
});
|
|
280
280
|
});
|
|
281
|
+
// prepare form controls (legacy checkboxes)
|
|
282
|
+
// Form controls share the VML file with comments, but need separate ctrlProp relationships
|
|
283
|
+
if (model.formControls && model.formControls.length > 0) {
|
|
284
|
+
// If no comments, we need to add the VML drawing relationship for form controls
|
|
285
|
+
if (model.comments.length === 0) {
|
|
286
|
+
rels.push({
|
|
287
|
+
Id: nextRid(rels),
|
|
288
|
+
Type: rel_type_1.RelType.VmlDrawing,
|
|
289
|
+
Target: (0, ooxml_paths_1.vmlDrawingRelTargetFromWorksheet)(model.id)
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
// Add ctrlProp relationships for each form control
|
|
293
|
+
for (const control of model.formControls) {
|
|
294
|
+
const globalCtrlPropId = options.formControlRefs.length + 1;
|
|
295
|
+
control.ctrlPropId = globalCtrlPropId;
|
|
296
|
+
rels.push({
|
|
297
|
+
Id: nextRid(rels),
|
|
298
|
+
Type: rel_type_1.RelType.CtrlProp,
|
|
299
|
+
Target: (0, ooxml_paths_1.ctrlPropRelTargetFromWorksheet)(globalCtrlPropId)
|
|
300
|
+
});
|
|
301
|
+
options.formControlRefs.push(globalCtrlPropId);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
281
304
|
// prepare ext items
|
|
282
305
|
this.map.extLst.prepare(model, options);
|
|
283
306
|
}
|
|
@@ -55,6 +55,17 @@ class StyleXform extends base_xform_1.BaseXform {
|
|
|
55
55
|
if (model.protection) {
|
|
56
56
|
this.map.protection.render(xmlStream, model.protection);
|
|
57
57
|
}
|
|
58
|
+
// Add checkbox extLst if needed
|
|
59
|
+
if (model.checkbox && model.xfComplementIndex !== undefined) {
|
|
60
|
+
xmlStream.openNode("extLst");
|
|
61
|
+
xmlStream.openNode("ext", {
|
|
62
|
+
"xmlns:xfpb": "http://schemas.microsoft.com/office/spreadsheetml/2022/featurepropertybag",
|
|
63
|
+
uri: "{C7286773-470A-42A8-94C5-96B5CB345126}"
|
|
64
|
+
});
|
|
65
|
+
xmlStream.leafNode("xfpb:xfComplement", { i: model.xfComplementIndex });
|
|
66
|
+
xmlStream.closeNode();
|
|
67
|
+
xmlStream.closeNode();
|
|
68
|
+
}
|
|
58
69
|
xmlStream.closeNode();
|
|
59
70
|
}
|
|
60
71
|
parseOpen(node) {
|
|
@@ -85,6 +85,7 @@ class StylesXform extends base_xform_1.BaseXform {
|
|
|
85
85
|
this._addFill({ type: "pattern", pattern: "none" });
|
|
86
86
|
this._addFill({ type: "pattern", pattern: "gray125" });
|
|
87
87
|
this.weakMap = new WeakMap();
|
|
88
|
+
this._hasCheckboxes = false;
|
|
88
89
|
}
|
|
89
90
|
render(xmlStream, model) {
|
|
90
91
|
const renderModel = model || this.model;
|
|
@@ -225,12 +226,15 @@ class StylesXform extends base_xform_1.BaseXform {
|
|
|
225
226
|
// default (zero) font
|
|
226
227
|
this._addFont({ size: 11, color: { theme: 1 }, name: "Calibri", family: 2, scheme: "minor" });
|
|
227
228
|
}
|
|
228
|
-
|
|
229
|
-
|
|
229
|
+
const type = cellType || enums_1.Enums.ValueType.Number;
|
|
230
|
+
// If we have seen this style object before, assume it has the same styleId.
|
|
231
|
+
// Do not cache by object identity for checkbox cells because the styleId must
|
|
232
|
+
// include checkbox-specific extLst, and the same style object may be reused
|
|
233
|
+
// for non-checkbox cells.
|
|
234
|
+
if (type !== enums_1.Enums.ValueType.Checkbox && this.weakMap && this.weakMap.has(model)) {
|
|
230
235
|
return this.weakMap.get(model);
|
|
231
236
|
}
|
|
232
237
|
const style = {};
|
|
233
|
-
const type = cellType || enums_1.Enums.ValueType.Number;
|
|
234
238
|
if (model.numFmt) {
|
|
235
239
|
style.numFmtId = this._addNumFmtStr(model.numFmt);
|
|
236
240
|
}
|
|
@@ -261,8 +265,17 @@ class StylesXform extends base_xform_1.BaseXform {
|
|
|
261
265
|
if (model.protection) {
|
|
262
266
|
style.protection = model.protection;
|
|
263
267
|
}
|
|
268
|
+
if (type === enums_1.Enums.ValueType.Checkbox) {
|
|
269
|
+
// Checkbox rendering relies on style extensions (extLst) and workbook-level parts.
|
|
270
|
+
// Force applyAlignment="1" (without emitting an <alignment/> node) by providing
|
|
271
|
+
// an empty alignment object when none is specified.
|
|
272
|
+
this._hasCheckboxes = true;
|
|
273
|
+
style.alignment = style.alignment || {};
|
|
274
|
+
style.checkbox = true;
|
|
275
|
+
style.xfComplementIndex = 0;
|
|
276
|
+
}
|
|
264
277
|
const styleId = this._addStyle(style);
|
|
265
|
-
if (this.weakMap) {
|
|
278
|
+
if (type !== enums_1.Enums.ValueType.Checkbox && this.weakMap) {
|
|
266
279
|
this.weakMap.set(model, styleId);
|
|
267
280
|
}
|
|
268
281
|
return styleId;
|
|
@@ -325,6 +338,10 @@ class StylesXform extends base_xform_1.BaseXform {
|
|
|
325
338
|
getDxfStyle(id) {
|
|
326
339
|
return this.model.dxfs[id];
|
|
327
340
|
}
|
|
341
|
+
// Check if workbook uses checkbox feature
|
|
342
|
+
get hasCheckboxes() {
|
|
343
|
+
return !!this._hasCheckboxes;
|
|
344
|
+
}
|
|
328
345
|
// =========================================================================
|
|
329
346
|
// Private Interface
|
|
330
347
|
_addStyle(style) {
|
|
@@ -461,12 +478,19 @@ class StylesXformMock extends StylesXform {
|
|
|
461
478
|
// the styleId is returned. Note: cellType is used when numFmt not defined
|
|
462
479
|
addStyleModel(model, cellType) {
|
|
463
480
|
switch (cellType) {
|
|
481
|
+
case enums_1.Enums.ValueType.Checkbox:
|
|
482
|
+
// Checkbox rendering relies on style extensions (extLst) and workbook-level parts.
|
|
483
|
+
// The mock style manager intentionally does not build those structures.
|
|
484
|
+
throw new Error("Checkbox cells require styles to be enabled (useStyles: true)");
|
|
464
485
|
case enums_1.Enums.ValueType.Date:
|
|
465
486
|
return this.dateStyleId;
|
|
466
487
|
default:
|
|
467
488
|
return 0;
|
|
468
489
|
}
|
|
469
490
|
}
|
|
491
|
+
get hasCheckboxes() {
|
|
492
|
+
return false;
|
|
493
|
+
}
|
|
470
494
|
get dateStyleId() {
|
|
471
495
|
if (!this._dateStyleId) {
|
|
472
496
|
const dateStyle = {
|
|
@@ -20,13 +20,15 @@ const content_types_xform_1 = require("./xform/core/content-types-xform.js");
|
|
|
20
20
|
const app_xform_1 = require("./xform/core/app-xform.js");
|
|
21
21
|
const workbook_xform_1 = require("./xform/book/workbook-xform.js");
|
|
22
22
|
const worksheet_xform_1 = require("./xform/sheet/worksheet-xform.js");
|
|
23
|
+
const feature_property_bag_xform_1 = require("./xform/core/feature-property-bag-xform.js");
|
|
23
24
|
const drawing_xform_1 = require("./xform/drawing/drawing-xform.js");
|
|
24
25
|
const table_xform_1 = require("./xform/table/table-xform.js");
|
|
25
26
|
const pivot_cache_records_xform_1 = require("./xform/pivot-table/pivot-cache-records-xform.js");
|
|
26
27
|
const pivot_cache_definition_xform_1 = require("./xform/pivot-table/pivot-cache-definition-xform.js");
|
|
27
28
|
const pivot_table_xform_1 = require("./xform/pivot-table/pivot-table-xform.js");
|
|
28
29
|
const comments_xform_1 = require("./xform/comment/comments-xform.js");
|
|
29
|
-
const
|
|
30
|
+
const vml_drawing_xform_1 = require("./xform/drawing/vml-drawing-xform.js");
|
|
31
|
+
const ctrl_prop_xform_1 = require("./xform/drawing/ctrl-prop-xform.js");
|
|
30
32
|
const theme1_1 = require("./xml/theme1.js");
|
|
31
33
|
const rel_type_1 = require("./rel-type.js");
|
|
32
34
|
const stream_buf_1 = require("../utils/stream-buf.js");
|
|
@@ -206,6 +208,7 @@ class XLSX {
|
|
|
206
208
|
this.addTables(zip, model);
|
|
207
209
|
this.addPivotTables(zip, model);
|
|
208
210
|
await Promise.all([this.addThemes(zip, model), this.addStyles(zip, model)]);
|
|
211
|
+
await this.addFeaturePropertyBag(zip, model);
|
|
209
212
|
await this.addMedia(zip, model);
|
|
210
213
|
await Promise.all([this.addApp(zip, model), this.addCore(zip, model)]);
|
|
211
214
|
await this.addWorkbook(zip, model);
|
|
@@ -703,7 +706,7 @@ class XLSX {
|
|
|
703
706
|
model.drawingRels[name] = relationships;
|
|
704
707
|
}
|
|
705
708
|
async _processVmlDrawingEntry(entry, model, name) {
|
|
706
|
-
const xform = new
|
|
709
|
+
const xform = new vml_drawing_xform_1.VmlDrawingXform();
|
|
707
710
|
const vmlDrawing = await xform.parseStream(entry);
|
|
708
711
|
model.vmlDrawings[(0, ooxml_paths_1.vmlDrawingRelTargetFromWorksheetName)(name)] = vmlDrawing;
|
|
709
712
|
}
|
|
@@ -974,6 +977,14 @@ class XLSX {
|
|
|
974
977
|
Target: ooxml_paths_1.OOXML_REL_TARGETS.workbookSharedStrings
|
|
975
978
|
});
|
|
976
979
|
}
|
|
980
|
+
// Add FeaturePropertyBag relationship if checkboxes are used
|
|
981
|
+
if (model.hasCheckboxes) {
|
|
982
|
+
relationships.push({
|
|
983
|
+
Id: `rId${count++}`,
|
|
984
|
+
Type: XLSX.RelType.FeaturePropertyBag,
|
|
985
|
+
Target: ooxml_paths_1.OOXML_REL_TARGETS.workbookFeaturePropertyBag
|
|
986
|
+
});
|
|
987
|
+
}
|
|
977
988
|
(model.pivotTables || []).forEach((pivotTable) => {
|
|
978
989
|
pivotTable.rId = `rId${count++}`;
|
|
979
990
|
relationships.push({
|
|
@@ -995,6 +1006,13 @@ class XLSX {
|
|
|
995
1006
|
const xml = xform.toXml(relationships);
|
|
996
1007
|
zip.append(xml, { name: ooxml_paths_1.OOXML_PATHS.xlWorkbookRels });
|
|
997
1008
|
}
|
|
1009
|
+
async addFeaturePropertyBag(zip, model) {
|
|
1010
|
+
if (!model.hasCheckboxes) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
const xform = new feature_property_bag_xform_1.FeaturePropertyBagXform();
|
|
1014
|
+
zip.append(xform.toXml({}), { name: ooxml_paths_1.OOXML_PATHS.xlFeaturePropertyBag });
|
|
1015
|
+
}
|
|
998
1016
|
async addSharedStrings(zip, model) {
|
|
999
1017
|
if (model.sharedStrings && model.sharedStrings.count) {
|
|
1000
1018
|
zip.append(model.sharedStrings.xml, { name: ooxml_paths_1.OOXML_PATHS.xlSharedStrings });
|
|
@@ -1014,7 +1032,8 @@ class XLSX {
|
|
|
1014
1032
|
const worksheetXform = new worksheet_xform_1.WorkSheetXform();
|
|
1015
1033
|
const relationshipsXform = new relationships_xform_1.RelationshipsXform();
|
|
1016
1034
|
const commentsXform = new comments_xform_1.CommentsXform();
|
|
1017
|
-
const
|
|
1035
|
+
const vmlDrawingXform = new vml_drawing_xform_1.VmlDrawingXform();
|
|
1036
|
+
const ctrlPropXform = new ctrl_prop_xform_1.CtrlPropXform();
|
|
1018
1037
|
model.worksheets.forEach((worksheet, index) => {
|
|
1019
1038
|
const fileIndex = worksheet.fileIndex || index + 1;
|
|
1020
1039
|
let xmlStream = new xml_stream_1.XmlStream();
|
|
@@ -1025,14 +1044,30 @@ class XLSX {
|
|
|
1025
1044
|
relationshipsXform.render(xmlStream, worksheet.rels);
|
|
1026
1045
|
zip.append(xmlStream.xml, { name: (0, ooxml_paths_1.worksheetRelsPath)(fileIndex) });
|
|
1027
1046
|
}
|
|
1047
|
+
// Generate comments XML (separate from VML)
|
|
1028
1048
|
if (worksheet.comments.length > 0) {
|
|
1029
1049
|
xmlStream = new xml_stream_1.XmlStream();
|
|
1030
1050
|
commentsXform.render(xmlStream, worksheet);
|
|
1031
1051
|
zip.append(xmlStream.xml, { name: (0, ooxml_paths_1.commentsPath)(fileIndex) });
|
|
1052
|
+
}
|
|
1053
|
+
// Generate unified VML drawing (contains both notes and form controls)
|
|
1054
|
+
const hasComments = worksheet.comments.length > 0;
|
|
1055
|
+
const hasFormControls = worksheet.formControls && worksheet.formControls.length > 0;
|
|
1056
|
+
if (hasComments || hasFormControls) {
|
|
1032
1057
|
xmlStream = new xml_stream_1.XmlStream();
|
|
1033
|
-
|
|
1058
|
+
vmlDrawingXform.render(xmlStream, {
|
|
1059
|
+
comments: hasComments ? worksheet.comments : [],
|
|
1060
|
+
formControls: hasFormControls ? worksheet.formControls : []
|
|
1061
|
+
});
|
|
1034
1062
|
zip.append(xmlStream.xml, { name: (0, ooxml_paths_1.vmlDrawingPath)(fileIndex) });
|
|
1035
1063
|
}
|
|
1064
|
+
// Generate ctrlProp files for form controls
|
|
1065
|
+
if (hasFormControls) {
|
|
1066
|
+
worksheet.formControls.forEach((control) => {
|
|
1067
|
+
const xml = ctrlPropXform.toXml(control);
|
|
1068
|
+
zip.append(xml, { name: (0, ooxml_paths_1.ctrlPropPath)(control.ctrlPropId) });
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1036
1071
|
});
|
|
1037
1072
|
}
|
|
1038
1073
|
addDrawings(zip, model) {
|
|
@@ -1138,6 +1173,7 @@ class XLSX {
|
|
|
1138
1173
|
};
|
|
1139
1174
|
worksheetOptions.drawings = model.drawings = [];
|
|
1140
1175
|
worksheetOptions.commentRefs = model.commentRefs = [];
|
|
1176
|
+
worksheetOptions.formControlRefs = model.formControlRefs = [];
|
|
1141
1177
|
let tableCount = 0;
|
|
1142
1178
|
model.tables = [];
|
|
1143
1179
|
model.worksheets.forEach((worksheet) => {
|
|
@@ -1149,6 +1185,8 @@ class XLSX {
|
|
|
1149
1185
|
});
|
|
1150
1186
|
worksheetXform.prepare(worksheet, worksheetOptions);
|
|
1151
1187
|
});
|
|
1188
|
+
// ContentTypesXform expects this flag
|
|
1189
|
+
model.hasCheckboxes = model.styles.hasCheckboxes;
|
|
1152
1190
|
}
|
|
1153
1191
|
}
|
|
1154
1192
|
exports.XLSX = XLSX;
|
|
@@ -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/esm/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) {
|