@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
|
@@ -57,6 +57,26 @@ class Table {
|
|
|
57
57
|
this.worksheet = worksheet;
|
|
58
58
|
if (table) {
|
|
59
59
|
this.table = table;
|
|
60
|
+
// When loading tables from xlsx, Excel stores table ranges and cell values in the worksheet,
|
|
61
|
+
// but may not embed row data into the table definition. Hydrate rows from the worksheet so
|
|
62
|
+
// table mutations (e.g. addRow) can correctly expand table ranges and serialize.
|
|
63
|
+
if (Array.isArray(table.rows) && table.rows.length === 0 && table.tableRef) {
|
|
64
|
+
const decoded = colCache.decode(table.tableRef);
|
|
65
|
+
if ("dimensions" in decoded) {
|
|
66
|
+
const startRow = decoded.top + (table.headerRow === false ? 0 : 1);
|
|
67
|
+
const endRow = decoded.bottom - (table.totalsRow === true ? 1 : 0);
|
|
68
|
+
if (endRow >= startRow) {
|
|
69
|
+
for (let r = startRow; r <= endRow; r++) {
|
|
70
|
+
const row = worksheet.getRow(r);
|
|
71
|
+
const values = [];
|
|
72
|
+
for (let c = decoded.left; c <= decoded.right; c++) {
|
|
73
|
+
values.push(row.getCell(c).value);
|
|
74
|
+
}
|
|
75
|
+
table.rows.push(values);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
60
80
|
// check things are ok first
|
|
61
81
|
this.validate();
|
|
62
82
|
this.store();
|
|
@@ -133,9 +153,10 @@ class Table {
|
|
|
133
153
|
const { row, col } = table.tl;
|
|
134
154
|
assert(row > 0, "Table must be on valid row");
|
|
135
155
|
assert(col > 0, "Table must be on valid col");
|
|
136
|
-
const { width,
|
|
137
|
-
// autoFilterRef is a range that
|
|
138
|
-
|
|
156
|
+
const { width, tableHeight } = this;
|
|
157
|
+
// autoFilterRef is a single-row range that targets the header row only.
|
|
158
|
+
// Excel uses this for filter buttons; including data rows can break filter rendering.
|
|
159
|
+
table.autoFilterRef = colCache.encode(row, col, row, col + width - 1);
|
|
139
160
|
// tableRef is a range that includes optional headers and totals
|
|
140
161
|
table.tableRef = colCache.encode(row, col, row + tableHeight - 1, col + width - 1);
|
|
141
162
|
table.columns.forEach((column, i) => {
|
|
@@ -304,8 +325,9 @@ class Table {
|
|
|
304
325
|
}
|
|
305
326
|
}
|
|
306
327
|
this.store();
|
|
328
|
+
this._cache = undefined;
|
|
307
329
|
}
|
|
308
|
-
addRow(values, rowNumber) {
|
|
330
|
+
addRow(values, rowNumber, options) {
|
|
309
331
|
// Add a row of data, either insert at rowNumber or append
|
|
310
332
|
this.cacheState();
|
|
311
333
|
if (rowNumber === undefined) {
|
|
@@ -314,11 +336,17 @@ class Table {
|
|
|
314
336
|
else {
|
|
315
337
|
this.table.rows.splice(rowNumber, 0, values);
|
|
316
338
|
}
|
|
339
|
+
if (options?.commit !== false) {
|
|
340
|
+
this.commit();
|
|
341
|
+
}
|
|
317
342
|
}
|
|
318
|
-
removeRows(rowIndex, count = 1) {
|
|
343
|
+
removeRows(rowIndex, count = 1, options) {
|
|
319
344
|
// Remove a rows of data
|
|
320
345
|
this.cacheState();
|
|
321
346
|
this.table.rows.splice(rowIndex, count);
|
|
347
|
+
if (options?.commit !== false) {
|
|
348
|
+
this.commit();
|
|
349
|
+
}
|
|
322
350
|
}
|
|
323
351
|
getColumn(colIndex) {
|
|
324
352
|
const column = this.table.columns[colIndex];
|
|
@@ -274,7 +274,11 @@ export interface CellSharedFormulaValue {
|
|
|
274
274
|
result?: number | string | boolean | Date | CellErrorValue;
|
|
275
275
|
date1904?: boolean;
|
|
276
276
|
}
|
|
277
|
-
export
|
|
277
|
+
export interface CellCheckboxValue {
|
|
278
|
+
/** Indicates this is a checkbox value */
|
|
279
|
+
checkbox: boolean;
|
|
280
|
+
}
|
|
281
|
+
export type CellValue = null | number | string | boolean | Date | undefined | CellErrorValue | CellRichTextValue | CellHyperlinkValue | CellFormulaValue | CellArrayFormulaValue | CellSharedFormulaValue | CellCheckboxValue;
|
|
278
282
|
export interface CommentMargins {
|
|
279
283
|
insetmode: "auto" | "custom";
|
|
280
284
|
inset: number[];
|
|
@@ -8,6 +8,7 @@ export declare const OOXML_PATHS: {
|
|
|
8
8
|
readonly xlSharedStrings: "xl/sharedStrings.xml";
|
|
9
9
|
readonly xlStyles: "xl/styles.xml";
|
|
10
10
|
readonly xlTheme1: "xl/theme/theme1.xml";
|
|
11
|
+
readonly xlFeaturePropertyBag: "xl/featurePropertyBag/featurePropertyBag.xml";
|
|
11
12
|
};
|
|
12
13
|
export declare function normalizeZipPath(path: string): string;
|
|
13
14
|
export declare function getWorksheetNoFromWorksheetPath(path: string): number | undefined;
|
|
@@ -50,6 +51,7 @@ export declare const OOXML_REL_TARGETS: {
|
|
|
50
51
|
readonly workbookStyles: "styles.xml";
|
|
51
52
|
readonly workbookSharedStrings: "sharedStrings.xml";
|
|
52
53
|
readonly workbookTheme1: "theme/theme1.xml";
|
|
54
|
+
readonly workbookFeaturePropertyBag: "featurePropertyBag/featurePropertyBag.xml";
|
|
53
55
|
};
|
|
54
56
|
export declare function pivotCacheDefinitionRelTargetFromWorkbook(n: number | string): string;
|
|
55
57
|
export declare function commentsRelTargetFromWorksheet(sheetId: number | string): string;
|
|
@@ -62,3 +64,5 @@ export declare function pivotTableRelTargetFromWorksheetName(pivotName: string):
|
|
|
62
64
|
export declare function tableRelTargetFromWorksheet(target: string): string;
|
|
63
65
|
export declare function tableRelTargetFromWorksheetName(name: string): string;
|
|
64
66
|
export declare function mediaRelTargetFromRels(filename: string): string;
|
|
67
|
+
export declare function ctrlPropPath(id: number | string): string;
|
|
68
|
+
export declare function ctrlPropRelTargetFromWorksheet(id: number | string): string;
|
|
@@ -7,7 +7,8 @@ export const OOXML_PATHS = {
|
|
|
7
7
|
xlWorkbookRels: "xl/_rels/workbook.xml.rels",
|
|
8
8
|
xlSharedStrings: "xl/sharedStrings.xml",
|
|
9
9
|
xlStyles: "xl/styles.xml",
|
|
10
|
-
xlTheme1: "xl/theme/theme1.xml"
|
|
10
|
+
xlTheme1: "xl/theme/theme1.xml",
|
|
11
|
+
xlFeaturePropertyBag: "xl/featurePropertyBag/featurePropertyBag.xml"
|
|
11
12
|
};
|
|
12
13
|
const worksheetXmlRegex = /^xl\/worksheets\/sheet(\d+)[.]xml$/;
|
|
13
14
|
const worksheetRelsXmlRegex = /^xl\/worksheets\/_rels\/sheet(\d+)[.]xml[.]rels$/;
|
|
@@ -162,7 +163,8 @@ export const OOXML_REL_TARGETS = {
|
|
|
162
163
|
// Targets inside xl/_rels/workbook.xml.rels (base: xl/)
|
|
163
164
|
workbookStyles: "styles.xml",
|
|
164
165
|
workbookSharedStrings: "sharedStrings.xml",
|
|
165
|
-
workbookTheme1: "theme/theme1.xml"
|
|
166
|
+
workbookTheme1: "theme/theme1.xml",
|
|
167
|
+
workbookFeaturePropertyBag: "featurePropertyBag/featurePropertyBag.xml"
|
|
166
168
|
};
|
|
167
169
|
export function pivotCacheDefinitionRelTargetFromWorkbook(n) {
|
|
168
170
|
// Target inside xl/_rels/workbook.xml.rels (base: xl/)
|
|
@@ -207,3 +209,11 @@ export function mediaRelTargetFromRels(filename) {
|
|
|
207
209
|
// Target from a rels file located under xl/*/_rels (base is one level deeper than xl/)
|
|
208
210
|
return `../media/${filename}`;
|
|
209
211
|
}
|
|
212
|
+
// Form Control (ctrlProps) path functions
|
|
213
|
+
export function ctrlPropPath(id) {
|
|
214
|
+
return `xl/ctrlProps/ctrlProp${id}.xml`;
|
|
215
|
+
}
|
|
216
|
+
export function ctrlPropRelTargetFromWorksheet(id) {
|
|
217
|
+
// Target inside xl/worksheets/_rels/sheetN.xml.rels (base: xl/worksheets/)
|
|
218
|
+
return `../ctrlProps/ctrlProp${id}.xml`;
|
|
219
|
+
}
|
|
@@ -5,6 +5,7 @@ import type { Cell, FormulaResult } from "@excel/cell";
|
|
|
5
5
|
import { Image, type ImageModel } from "@excel/image";
|
|
6
6
|
import { Table, type TableModel } from "@excel/table";
|
|
7
7
|
import { DataValidations } from "@excel/data-validations";
|
|
8
|
+
import { FormCheckbox, type FormCheckboxModel, type FormCheckboxOptions, type FormControlRange } from "@excel/form-control";
|
|
8
9
|
import { type PivotTable, type PivotTableModel } from "@excel/pivot-table";
|
|
9
10
|
import type { Workbook } from "@excel/workbook";
|
|
10
11
|
import type { AddImageRange, AutoFilter, CellValue, ColBreak, ConditionalFormattingOptions, DataValidation, RowBreak, RowValues, TableProperties, WorksheetProperties, WorksheetView } from "@excel/types";
|
|
@@ -104,6 +105,7 @@ interface WorksheetModel {
|
|
|
104
105
|
tables: TableModel[];
|
|
105
106
|
pivotTables: PivotTable[];
|
|
106
107
|
conditionalFormattings: ConditionalFormattingOptions[];
|
|
108
|
+
formControls: FormCheckboxModel[];
|
|
107
109
|
cols?: ColumnModel[];
|
|
108
110
|
rows?: RowModel[];
|
|
109
111
|
dimensions?: Range;
|
|
@@ -135,6 +137,7 @@ declare class Worksheet {
|
|
|
135
137
|
};
|
|
136
138
|
pivotTables: PivotTable[];
|
|
137
139
|
conditionalFormattings: ConditionalFormattingOptions[];
|
|
140
|
+
formControls: FormCheckbox[];
|
|
138
141
|
private _headerRowCount?;
|
|
139
142
|
constructor(options: WorksheetOptions);
|
|
140
143
|
get name(): string;
|
|
@@ -295,6 +298,35 @@ declare class Worksheet {
|
|
|
295
298
|
*/
|
|
296
299
|
addBackgroundImage(imageId: string | number): void;
|
|
297
300
|
getBackgroundImageId(): string | undefined;
|
|
301
|
+
/**
|
|
302
|
+
* Add a form control checkbox to the worksheet.
|
|
303
|
+
*
|
|
304
|
+
* Form control checkboxes are the legacy style that work in Office 2007+,
|
|
305
|
+
* WPS Office, LibreOffice, and other spreadsheet applications.
|
|
306
|
+
*
|
|
307
|
+
* Unlike modern in-cell checkboxes (which only work in Microsoft 365),
|
|
308
|
+
* form control checkboxes are floating controls positioned over cells.
|
|
309
|
+
*
|
|
310
|
+
* @param range - Cell reference (e.g., "B2") or range (e.g., "B2:D3") for positioning
|
|
311
|
+
* @param options - Checkbox options
|
|
312
|
+
* @returns The created FormCheckbox instance
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* // Simple checkbox at B2
|
|
316
|
+
* ws.addFormCheckbox("B2");
|
|
317
|
+
*
|
|
318
|
+
* // Checkbox with label and linked cell
|
|
319
|
+
* ws.addFormCheckbox("B2:D3", {
|
|
320
|
+
* text: "Accept terms",
|
|
321
|
+
* link: "A2",
|
|
322
|
+
* checked: false
|
|
323
|
+
* });
|
|
324
|
+
*/
|
|
325
|
+
addFormCheckbox(range: FormControlRange, options?: FormCheckboxOptions): FormCheckbox;
|
|
326
|
+
/**
|
|
327
|
+
* Get all form control checkboxes in the worksheet
|
|
328
|
+
*/
|
|
329
|
+
getFormCheckboxes(): FormCheckbox[];
|
|
298
330
|
/**
|
|
299
331
|
* Protect the worksheet with optional password and options
|
|
300
332
|
*/
|
|
@@ -6,6 +6,7 @@ import { Enums } from "./enums.js";
|
|
|
6
6
|
import { Image } from "./image.js";
|
|
7
7
|
import { Table } from "./table.js";
|
|
8
8
|
import { DataValidations } from "./data-validations.js";
|
|
9
|
+
import { FormCheckbox } from "./form-control.js";
|
|
9
10
|
import { Encryptor } from "./utils/encryptor.browser.js";
|
|
10
11
|
import { uint8ArrayToBase64 } from "../../utils/utils.browser.js";
|
|
11
12
|
import { makePivotTable } from "./pivot-table.js";
|
|
@@ -92,6 +93,8 @@ class Worksheet {
|
|
|
92
93
|
this.tables = {};
|
|
93
94
|
this.pivotTables = [];
|
|
94
95
|
this.conditionalFormattings = [];
|
|
96
|
+
// for form controls (legacy checkboxes, etc.)
|
|
97
|
+
this.formControls = [];
|
|
95
98
|
}
|
|
96
99
|
get name() {
|
|
97
100
|
return this._name;
|
|
@@ -745,6 +748,43 @@ class Worksheet {
|
|
|
745
748
|
return image && image.imageId;
|
|
746
749
|
}
|
|
747
750
|
// =========================================================================
|
|
751
|
+
// Form Controls (Legacy Checkboxes)
|
|
752
|
+
/**
|
|
753
|
+
* Add a form control checkbox to the worksheet.
|
|
754
|
+
*
|
|
755
|
+
* Form control checkboxes are the legacy style that work in Office 2007+,
|
|
756
|
+
* WPS Office, LibreOffice, and other spreadsheet applications.
|
|
757
|
+
*
|
|
758
|
+
* Unlike modern in-cell checkboxes (which only work in Microsoft 365),
|
|
759
|
+
* form control checkboxes are floating controls positioned over cells.
|
|
760
|
+
*
|
|
761
|
+
* @param range - Cell reference (e.g., "B2") or range (e.g., "B2:D3") for positioning
|
|
762
|
+
* @param options - Checkbox options
|
|
763
|
+
* @returns The created FormCheckbox instance
|
|
764
|
+
*
|
|
765
|
+
* @example
|
|
766
|
+
* // Simple checkbox at B2
|
|
767
|
+
* ws.addFormCheckbox("B2");
|
|
768
|
+
*
|
|
769
|
+
* // Checkbox with label and linked cell
|
|
770
|
+
* ws.addFormCheckbox("B2:D3", {
|
|
771
|
+
* text: "Accept terms",
|
|
772
|
+
* link: "A2",
|
|
773
|
+
* checked: false
|
|
774
|
+
* });
|
|
775
|
+
*/
|
|
776
|
+
addFormCheckbox(range, options) {
|
|
777
|
+
const checkbox = new FormCheckbox(this, range, options);
|
|
778
|
+
this.formControls.push(checkbox);
|
|
779
|
+
return checkbox;
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Get all form control checkboxes in the worksheet
|
|
783
|
+
*/
|
|
784
|
+
getFormCheckboxes() {
|
|
785
|
+
return this.formControls;
|
|
786
|
+
}
|
|
787
|
+
// =========================================================================
|
|
748
788
|
// Worksheet Protection
|
|
749
789
|
/**
|
|
750
790
|
* Protect the worksheet with optional password and options
|
|
@@ -853,7 +893,8 @@ class Worksheet {
|
|
|
853
893
|
sheetProtection: this.sheetProtection,
|
|
854
894
|
tables: Object.values(this.tables).map(table => table.model),
|
|
855
895
|
pivotTables: this.pivotTables,
|
|
856
|
-
conditionalFormattings: this.conditionalFormattings
|
|
896
|
+
conditionalFormattings: this.conditionalFormattings,
|
|
897
|
+
formControls: this.formControls.map(fc => fc.model)
|
|
857
898
|
};
|
|
858
899
|
// =================================================
|
|
859
900
|
// columns
|
|
@@ -919,6 +960,8 @@ class Worksheet {
|
|
|
919
960
|
}, {});
|
|
920
961
|
this.pivotTables = value.pivotTables;
|
|
921
962
|
this.conditionalFormattings = value.conditionalFormattings;
|
|
963
|
+
// Form controls are currently write-only (not parsed from XLSX)
|
|
964
|
+
this.formControls = [];
|
|
922
965
|
}
|
|
923
966
|
}
|
|
924
967
|
export { Worksheet };
|
|
@@ -14,6 +14,8 @@ const RelType = {
|
|
|
14
14
|
Table: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table",
|
|
15
15
|
PivotCacheDefinition: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition",
|
|
16
16
|
PivotCacheRecords: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheRecords",
|
|
17
|
-
PivotTable: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
|
|
17
|
+
PivotTable: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable",
|
|
18
|
+
FeaturePropertyBag: "http://schemas.microsoft.com/office/2022/11/relationships/FeaturePropertyBag",
|
|
19
|
+
CtrlProp: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp"
|
|
18
20
|
};
|
|
19
21
|
export { RelType };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { XmlStream } from "../../../utils/xml-stream.js";
|
|
2
2
|
import { BaseXform } from "../base-xform.js";
|
|
3
|
-
import { OOXML_PATHS, commentsPathFromName, drawingPath, pivotCacheDefinitionPath, pivotCacheRecordsPath, pivotTablePath, tablePath, toContentTypesPartName, worksheetPath } from "../../../utils/ooxml-paths.js";
|
|
3
|
+
import { OOXML_PATHS, commentsPathFromName, ctrlPropPath, drawingPath, pivotCacheDefinitionPath, pivotCacheRecordsPath, pivotTablePath, tablePath, toContentTypesPartName, worksheetPath } from "../../../utils/ooxml-paths.js";
|
|
4
4
|
// used for rendering the [Content_Types].xml file
|
|
5
5
|
// not used for parsing
|
|
6
6
|
class ContentTypesXform extends BaseXform {
|
|
@@ -63,6 +63,13 @@ class ContentTypesXform extends BaseXform {
|
|
|
63
63
|
PartName: toContentTypesPartName(OOXML_PATHS.xlStyles),
|
|
64
64
|
ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"
|
|
65
65
|
});
|
|
66
|
+
// Add FeaturePropertyBag if checkboxes are used
|
|
67
|
+
if (model.hasCheckboxes) {
|
|
68
|
+
xmlStream.leafNode("Override", {
|
|
69
|
+
PartName: toContentTypesPartName(OOXML_PATHS.xlFeaturePropertyBag),
|
|
70
|
+
ContentType: "application/vnd.ms-excel.featurepropertybag+xml"
|
|
71
|
+
});
|
|
72
|
+
}
|
|
66
73
|
const hasSharedStrings = model.sharedStrings && model.sharedStrings.count;
|
|
67
74
|
if (hasSharedStrings) {
|
|
68
75
|
xmlStream.leafNode("Override", {
|
|
@@ -98,6 +105,22 @@ class ContentTypesXform extends BaseXform {
|
|
|
98
105
|
});
|
|
99
106
|
});
|
|
100
107
|
}
|
|
108
|
+
// Add form control (ctrlProps) content types
|
|
109
|
+
if (model.formControlRefs) {
|
|
110
|
+
// Ensure vml extension is declared (may already be declared for comments)
|
|
111
|
+
if (!model.commentRefs) {
|
|
112
|
+
xmlStream.leafNode("Default", {
|
|
113
|
+
Extension: "vml",
|
|
114
|
+
ContentType: "application/vnd.openxmlformats-officedocument.vmlDrawing"
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
for (const ctrlPropId of model.formControlRefs) {
|
|
118
|
+
xmlStream.leafNode("Override", {
|
|
119
|
+
PartName: toContentTypesPartName(ctrlPropPath(ctrlPropId)),
|
|
120
|
+
ContentType: "application/vnd.ms-excel.controlproperties+xml"
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
101
124
|
xmlStream.leafNode("Override", {
|
|
102
125
|
PartName: toContentTypesPartName(OOXML_PATHS.docPropsCore),
|
|
103
126
|
ContentType: "application/vnd.openxmlformats-package.core-properties+xml"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { BaseXform } from "../base-xform.js";
|
|
2
|
+
// FeaturePropertyBag is used to enable checkbox functionality
|
|
3
|
+
// This is a static XML file that MS Excel requires for checkboxes to work
|
|
4
|
+
class FeaturePropertyBagXform extends BaseXform {
|
|
5
|
+
render(xmlStream) {
|
|
6
|
+
xmlStream.openXml({ version: "1.0", encoding: "UTF-8", standalone: "yes" });
|
|
7
|
+
xmlStream.openNode("FeaturePropertyBags", {
|
|
8
|
+
xmlns: "http://schemas.microsoft.com/office/spreadsheetml/2022/featurepropertybag"
|
|
9
|
+
});
|
|
10
|
+
// Checkbox feature
|
|
11
|
+
xmlStream.leafNode("bag", { type: "Checkbox" });
|
|
12
|
+
// XFControls bag
|
|
13
|
+
xmlStream.openNode("bag", { type: "XFControls" });
|
|
14
|
+
xmlStream.leafNode("bagId", { k: "CellControl" }, "0");
|
|
15
|
+
xmlStream.closeNode();
|
|
16
|
+
// XFComplement bag
|
|
17
|
+
xmlStream.openNode("bag", { type: "XFComplement" });
|
|
18
|
+
xmlStream.leafNode("bagId", { k: "XFControls" }, "1");
|
|
19
|
+
xmlStream.closeNode();
|
|
20
|
+
// XFComplements bag
|
|
21
|
+
xmlStream.openNode("bag", { type: "XFComplements", extRef: "XFComplementsMapperExtRef" });
|
|
22
|
+
xmlStream.openNode("a", { k: "MappedFeaturePropertyBags" });
|
|
23
|
+
xmlStream.leafNode("bagId", {}, "2");
|
|
24
|
+
xmlStream.closeNode();
|
|
25
|
+
xmlStream.closeNode();
|
|
26
|
+
xmlStream.closeNode();
|
|
27
|
+
}
|
|
28
|
+
parseOpen() {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
parseText() { }
|
|
32
|
+
parseClose() {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export { FeaturePropertyBagXform };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BaseXform } from "@excel/xlsx/xform/base-xform";
|
|
2
|
+
import type { FormCheckboxModel } from "@excel/form-control";
|
|
3
|
+
/**
|
|
4
|
+
* Control Properties Xform - Generates ctrlProp*.xml for form controls
|
|
5
|
+
*
|
|
6
|
+
* Each form control (checkbox, button, etc.) has an associated ctrlProp file
|
|
7
|
+
* that stores its properties like objectType, checked state, and linked cell.
|
|
8
|
+
*/
|
|
9
|
+
declare class CtrlPropXform extends BaseXform {
|
|
10
|
+
model: FormCheckboxModel;
|
|
11
|
+
get tag(): string;
|
|
12
|
+
render(xmlStream: any, model?: FormCheckboxModel): void;
|
|
13
|
+
/**
|
|
14
|
+
* Generate XML string directly (convenience method)
|
|
15
|
+
* Uses render() internally to ensure consistency
|
|
16
|
+
*/
|
|
17
|
+
toXml(model: FormCheckboxModel): string;
|
|
18
|
+
parseOpen(): boolean;
|
|
19
|
+
parseText(): void;
|
|
20
|
+
parseClose(): boolean;
|
|
21
|
+
}
|
|
22
|
+
export { CtrlPropXform };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { XmlStream } from "../../../utils/xml-stream.js";
|
|
2
|
+
import { BaseXform } from "../base-xform.js";
|
|
3
|
+
/**
|
|
4
|
+
* Control Properties Xform - Generates ctrlProp*.xml for form controls
|
|
5
|
+
*
|
|
6
|
+
* Each form control (checkbox, button, etc.) has an associated ctrlProp file
|
|
7
|
+
* that stores its properties like objectType, checked state, and linked cell.
|
|
8
|
+
*/
|
|
9
|
+
class CtrlPropXform extends BaseXform {
|
|
10
|
+
get tag() {
|
|
11
|
+
return "formControlPr";
|
|
12
|
+
}
|
|
13
|
+
render(xmlStream, model) {
|
|
14
|
+
const renderModel = model || this.model;
|
|
15
|
+
const attrs = {
|
|
16
|
+
xmlns: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
|
|
17
|
+
objectType: "CheckBox",
|
|
18
|
+
checked: renderModel.checked,
|
|
19
|
+
lockText: "1"
|
|
20
|
+
};
|
|
21
|
+
// Add linked cell reference
|
|
22
|
+
if (renderModel.link) {
|
|
23
|
+
attrs.fmlaLink = renderModel.link;
|
|
24
|
+
}
|
|
25
|
+
// Add noThreeD for flat appearance
|
|
26
|
+
if (renderModel.noThreeD) {
|
|
27
|
+
attrs.noThreeD = "1";
|
|
28
|
+
}
|
|
29
|
+
xmlStream.openXml({ version: "1.0", encoding: "UTF-8", standalone: "yes" });
|
|
30
|
+
xmlStream.leafNode(this.tag, attrs);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Generate XML string directly (convenience method)
|
|
34
|
+
* Uses render() internally to ensure consistency
|
|
35
|
+
*/
|
|
36
|
+
toXml(model) {
|
|
37
|
+
const xmlStream = new XmlStream();
|
|
38
|
+
this.render(xmlStream, model);
|
|
39
|
+
return xmlStream.xml;
|
|
40
|
+
}
|
|
41
|
+
// Parsing not implemented - form controls are write-only for now
|
|
42
|
+
parseOpen() {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
parseText() {
|
|
46
|
+
// Not implemented
|
|
47
|
+
}
|
|
48
|
+
parseClose() {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export { CtrlPropXform };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BaseXform } from "@excel/xlsx/xform/base-xform";
|
|
2
|
+
import { type FormCheckboxModel } from "@excel/form-control";
|
|
3
|
+
/**
|
|
4
|
+
* Unified VML Drawing Xform - Combines Notes (comments) and Form Controls
|
|
5
|
+
*
|
|
6
|
+
* Excel uses a single VML file per worksheet that can contain:
|
|
7
|
+
* - Comment/note shapes (shapetype 202)
|
|
8
|
+
* - Form control shapes (checkbox shapetype 201, etc.)
|
|
9
|
+
*
|
|
10
|
+
* This unified xform renders both into a single VML file.
|
|
11
|
+
*/
|
|
12
|
+
interface VmlDrawingModel {
|
|
13
|
+
/** Comment/note shapes */
|
|
14
|
+
comments?: any[];
|
|
15
|
+
/** Form control checkboxes */
|
|
16
|
+
formControls?: FormCheckboxModel[];
|
|
17
|
+
}
|
|
18
|
+
declare class VmlDrawingXform extends BaseXform {
|
|
19
|
+
map: {
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
};
|
|
22
|
+
parser: any;
|
|
23
|
+
model: VmlDrawingModel;
|
|
24
|
+
constructor();
|
|
25
|
+
get tag(): string;
|
|
26
|
+
/**
|
|
27
|
+
* Render VML drawing containing both notes and form controls
|
|
28
|
+
*/
|
|
29
|
+
render(xmlStream: any, model?: VmlDrawingModel): void;
|
|
30
|
+
/**
|
|
31
|
+
* Render a checkbox form control shape
|
|
32
|
+
*/
|
|
33
|
+
private _renderCheckboxShape;
|
|
34
|
+
parseOpen(node: any): boolean;
|
|
35
|
+
parseText(text: string): void;
|
|
36
|
+
parseClose(name: string): boolean;
|
|
37
|
+
static DRAWING_ATTRIBUTES: {
|
|
38
|
+
"xmlns:v": string;
|
|
39
|
+
"xmlns:o": string;
|
|
40
|
+
"xmlns:x": string;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export { VmlDrawingXform };
|
|
44
|
+
export type { VmlDrawingModel };
|