@node-projects/excelforge 2.0.0
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/README.md +566 -0
- package/dist/core/SharedStrings.d.ts +11 -0
- package/dist/core/SharedStrings.js +67 -0
- package/dist/core/SharedStrings.js.map +1 -0
- package/dist/core/Workbook.d.ts +42 -0
- package/dist/core/Workbook.js +459 -0
- package/dist/core/Workbook.js.map +1 -0
- package/dist/core/WorkbookReader.d.ts +43 -0
- package/dist/core/WorkbookReader.js +563 -0
- package/dist/core/WorkbookReader.js.map +1 -0
- package/dist/core/Worksheet.d.ts +78 -0
- package/dist/core/Worksheet.js +568 -0
- package/dist/core/Worksheet.js.map +1 -0
- package/dist/core/properties.d.ts +91 -0
- package/dist/core/properties.js +265 -0
- package/dist/core/properties.js.map +1 -0
- package/dist/core/types.d.ts +388 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/features/ChartBuilder.d.ts +2 -0
- package/dist/features/ChartBuilder.js +165 -0
- package/dist/features/ChartBuilder.js.map +1 -0
- package/dist/features/TableBuilder.d.ts +2 -0
- package/dist/features/TableBuilder.js +36 -0
- package/dist/features/TableBuilder.js.map +1 -0
- package/dist/index-min.js +259 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/styles/StyleRegistry.d.ts +19 -0
- package/dist/styles/StyleRegistry.js +215 -0
- package/dist/styles/StyleRegistry.js.map +1 -0
- package/dist/styles/builders.d.ts +91 -0
- package/dist/styles/builders.js +136 -0
- package/dist/styles/builders.js.map +1 -0
- package/dist/utils/helpers.d.ts +26 -0
- package/dist/utils/helpers.js +85 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/xmlParser.d.ts +17 -0
- package/dist/utils/xmlParser.js +179 -0
- package/dist/utils/xmlParser.js.map +1 -0
- package/dist/utils/zip.d.ts +11 -0
- package/dist/utils/zip.js +571 -0
- package/dist/utils/zip.js.map +1 -0
- package/dist/utils/zipReader.d.ts +6 -0
- package/dist/utils/zipReader.js +84 -0
- package/dist/utils/zipReader.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Cell, CellValue, CellStyle, Image, Chart, ConditionalFormat, Table, AutoFilter, FreezePane, SplitPane, SheetProtection, PageSetup, PageMargins, HeaderFooter, PrintOptions, SheetView, ColumnDef, RowDef, Sparkline, DataValidation, WorksheetOptions } from '../core/types.js';
|
|
2
|
+
import type { SharedStrings } from '../core/SharedStrings.js';
|
|
3
|
+
import type { StyleRegistry } from '../styles/StyleRegistry.js';
|
|
4
|
+
export declare class Worksheet {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
private cells;
|
|
7
|
+
private merges;
|
|
8
|
+
private images;
|
|
9
|
+
private charts;
|
|
10
|
+
private conditionalFormats;
|
|
11
|
+
private tables;
|
|
12
|
+
private sparklines;
|
|
13
|
+
private colDefs;
|
|
14
|
+
private rowDefs;
|
|
15
|
+
private dataValidations;
|
|
16
|
+
options: WorksheetOptions;
|
|
17
|
+
view?: SheetView;
|
|
18
|
+
freezePane?: FreezePane;
|
|
19
|
+
splitPane?: SplitPane;
|
|
20
|
+
protection?: SheetProtection;
|
|
21
|
+
pageSetup?: PageSetup;
|
|
22
|
+
pageMargins?: PageMargins;
|
|
23
|
+
headerFooter?: HeaderFooter;
|
|
24
|
+
printOptions?: PrintOptions;
|
|
25
|
+
autoFilter?: AutoFilter;
|
|
26
|
+
sheetIndex: number;
|
|
27
|
+
rId: string;
|
|
28
|
+
drawingRId: string;
|
|
29
|
+
legacyDrawingRId: string;
|
|
30
|
+
tableRIds: string[];
|
|
31
|
+
constructor(name: string, options?: WorksheetOptions);
|
|
32
|
+
private key;
|
|
33
|
+
getCell(row: number, col: number): Cell;
|
|
34
|
+
getCellByRef(ref: string): Cell;
|
|
35
|
+
setCell(row: number, col: number, cell: Cell): this;
|
|
36
|
+
setValue(row: number, col: number, value: CellValue): this;
|
|
37
|
+
setFormula(row: number, col: number, formula: string): this;
|
|
38
|
+
setStyle(row: number, col: number, style: CellStyle): this;
|
|
39
|
+
writeArray(startRow: number, startCol: number, data: CellValue[][]): this;
|
|
40
|
+
writeColumn(startRow: number, col: number, values: CellValue[]): this;
|
|
41
|
+
writeRow(row: number, startCol: number, values: CellValue[]): this;
|
|
42
|
+
setColumn(col: number, def: ColumnDef): this;
|
|
43
|
+
setColumnWidth(col: number, width: number): this;
|
|
44
|
+
setRow(row: number, def: RowDef): this;
|
|
45
|
+
setRowHeight(row: number, height: number): this;
|
|
46
|
+
merge(startRow: number, startCol: number, endRow: number, endCol: number): this;
|
|
47
|
+
mergeByRef(ref: string): this;
|
|
48
|
+
addImage(img: Image): this;
|
|
49
|
+
getImages(): readonly Image[];
|
|
50
|
+
getComments(): Array<{
|
|
51
|
+
row: number;
|
|
52
|
+
col: number;
|
|
53
|
+
comment: import('../core/types.js').Comment;
|
|
54
|
+
}>;
|
|
55
|
+
addChart(chart: Chart): this;
|
|
56
|
+
getCharts(): readonly Chart[];
|
|
57
|
+
addConditionalFormat(cf: ConditionalFormat): this;
|
|
58
|
+
addTable(table: Table): this;
|
|
59
|
+
getTables(): readonly Table[];
|
|
60
|
+
addSparkline(s: Sparkline): this;
|
|
61
|
+
addDataValidation(sqref: string, dv: DataValidation): this;
|
|
62
|
+
freeze(row?: number, col?: number): this;
|
|
63
|
+
toXml(styles: StyleRegistry, shared: SharedStrings): string;
|
|
64
|
+
private _sheetViewXml;
|
|
65
|
+
private _colsXml;
|
|
66
|
+
private _sheetDataXml;
|
|
67
|
+
private _cellXml;
|
|
68
|
+
private _mergesXml;
|
|
69
|
+
private _conditionalFormatXml;
|
|
70
|
+
private _dataValidationsXml;
|
|
71
|
+
private _protectionXml;
|
|
72
|
+
private _pageSetupXml;
|
|
73
|
+
private _pageMarginsXml;
|
|
74
|
+
private _headerFooterXml;
|
|
75
|
+
private _printOptionsXml;
|
|
76
|
+
private _sparklineXml;
|
|
77
|
+
toDrawingXml(imageRIds: string[], chartRIds: string[]): string;
|
|
78
|
+
}
|
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
import { colIndexToLetter, indicesToCellRef, cellRefToIndices, parseRange, escapeXml, dateToSerial, pxToEmu, } from '../utils/helpers.js';
|
|
2
|
+
const SUBTOTAL_FN = {
|
|
3
|
+
average: 101, count: 102, countNums: 103, max: 104, min: 105,
|
|
4
|
+
stdDev: 107, sum: 109, var: 110, vars: 111,
|
|
5
|
+
};
|
|
6
|
+
export class Worksheet {
|
|
7
|
+
constructor(name, options = {}) {
|
|
8
|
+
this.cells = new Map();
|
|
9
|
+
this.merges = [];
|
|
10
|
+
this.images = [];
|
|
11
|
+
this.charts = [];
|
|
12
|
+
this.conditionalFormats = [];
|
|
13
|
+
this.tables = [];
|
|
14
|
+
this.sparklines = [];
|
|
15
|
+
this.colDefs = new Map();
|
|
16
|
+
this.rowDefs = new Map();
|
|
17
|
+
this.dataValidations = new Map();
|
|
18
|
+
this.sheetIndex = 0;
|
|
19
|
+
this.rId = '';
|
|
20
|
+
this.drawingRId = '';
|
|
21
|
+
this.legacyDrawingRId = '';
|
|
22
|
+
this.tableRIds = [];
|
|
23
|
+
this.name = name;
|
|
24
|
+
this.options = { ...options, name };
|
|
25
|
+
}
|
|
26
|
+
key(row, col) { return `${row},${col}`; }
|
|
27
|
+
getCell(row, col) {
|
|
28
|
+
const k = this.key(row, col);
|
|
29
|
+
if (!this.cells.has(k))
|
|
30
|
+
this.cells.set(k, {});
|
|
31
|
+
return this.cells.get(k);
|
|
32
|
+
}
|
|
33
|
+
getCellByRef(ref) {
|
|
34
|
+
const { row, col } = cellRefToIndices(ref);
|
|
35
|
+
return this.getCell(row, col);
|
|
36
|
+
}
|
|
37
|
+
setCell(row, col, cell) {
|
|
38
|
+
this.cells.set(this.key(row, col), cell);
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
setValue(row, col, value) {
|
|
42
|
+
this.getCell(row, col).value = value;
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
setFormula(row, col, formula) {
|
|
46
|
+
this.getCell(row, col).formula = formula;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
setStyle(row, col, style) {
|
|
50
|
+
this.getCell(row, col).style = style;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
writeArray(startRow, startCol, data) {
|
|
54
|
+
for (let r = 0; r < data.length; r++) {
|
|
55
|
+
for (let c = 0; c < data[r].length; c++) {
|
|
56
|
+
this.setValue(startRow + r, startCol + c, data[r][c]);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
writeColumn(startRow, col, values) {
|
|
62
|
+
values.forEach((v, i) => this.setValue(startRow + i, col, v));
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
writeRow(row, startCol, values) {
|
|
66
|
+
values.forEach((v, i) => this.setValue(row, startCol + i, v));
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
setColumn(col, def) {
|
|
70
|
+
this.colDefs.set(col, def);
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
setColumnWidth(col, width) {
|
|
74
|
+
const d = this.colDefs.get(col) ?? {};
|
|
75
|
+
this.colDefs.set(col, { ...d, width, customWidth: true });
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
setRow(row, def) {
|
|
79
|
+
this.rowDefs.set(row, def);
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
setRowHeight(row, height) {
|
|
83
|
+
const d = this.rowDefs.get(row) ?? {};
|
|
84
|
+
this.rowDefs.set(row, { ...d, height });
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
merge(startRow, startCol, endRow, endCol) {
|
|
88
|
+
this.merges.push({ startRow, startCol, endRow, endCol });
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
mergeByRef(ref) {
|
|
92
|
+
const [s, e] = ref.split(':');
|
|
93
|
+
const sc = cellRefToIndices(s);
|
|
94
|
+
const ec = cellRefToIndices(e);
|
|
95
|
+
return this.merge(sc.row, sc.col, ec.row, ec.col);
|
|
96
|
+
}
|
|
97
|
+
addImage(img) {
|
|
98
|
+
this.images.push(img);
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
getImages() { return this.images; }
|
|
102
|
+
getComments() {
|
|
103
|
+
const out = [];
|
|
104
|
+
for (const [key, cell] of this.cells) {
|
|
105
|
+
if (cell.comment) {
|
|
106
|
+
const [r, c] = key.split(',').map(Number);
|
|
107
|
+
out.push({ row: r, col: c, comment: cell.comment });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
addChart(chart) {
|
|
113
|
+
this.charts.push(chart);
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
getCharts() { return this.charts; }
|
|
117
|
+
addConditionalFormat(cf) {
|
|
118
|
+
this.conditionalFormats.push(cf);
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
addTable(table) {
|
|
122
|
+
this.tables.push(table);
|
|
123
|
+
if (table.totalsRow && table.columns?.length) {
|
|
124
|
+
const { startRow, startCol, endRow } = parseRange(table.ref);
|
|
125
|
+
const dataStart = startRow + 1;
|
|
126
|
+
const dataEnd = endRow - 1;
|
|
127
|
+
table.columns.forEach((col, i) => {
|
|
128
|
+
const colIdx = startCol + i;
|
|
129
|
+
if (col.totalsRowLabel) {
|
|
130
|
+
this.setValue(endRow, colIdx, col.totalsRowLabel);
|
|
131
|
+
}
|
|
132
|
+
else if (col.totalsRowFunction && col.totalsRowFunction !== 'none') {
|
|
133
|
+
const fn = SUBTOTAL_FN[col.totalsRowFunction];
|
|
134
|
+
if (fn !== undefined) {
|
|
135
|
+
const letter = colIndexToLetter(colIdx);
|
|
136
|
+
this.setFormula(endRow, colIdx, `SUBTOTAL(${fn},${letter}${dataStart}:${letter}${dataEnd})`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return this;
|
|
142
|
+
}
|
|
143
|
+
getTables() { return this.tables; }
|
|
144
|
+
addSparkline(s) {
|
|
145
|
+
this.sparklines.push(s);
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
addDataValidation(sqref, dv) {
|
|
149
|
+
this.dataValidations.set(sqref, dv);
|
|
150
|
+
return this;
|
|
151
|
+
}
|
|
152
|
+
freeze(row, col) {
|
|
153
|
+
this.freezePane = { row, col };
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
toXml(styles, shared) {
|
|
157
|
+
const fitToPage = this.pageSetup?.fitToPage;
|
|
158
|
+
const tabColor = this.options?.tabColor;
|
|
159
|
+
const sheetPrXml = (fitToPage || tabColor)
|
|
160
|
+
? `<sheetPr>${tabColor ? `<tabColor rgb="${tabColor}"/>` : ''}${fitToPage ? '<pageSetPr fitToPage="1"/>' : ''}</sheetPr>`
|
|
161
|
+
: '';
|
|
162
|
+
const sheetViewXml = this._sheetViewXml();
|
|
163
|
+
const colsXml = this._colsXml(styles);
|
|
164
|
+
const sheetDataXml = this._sheetDataXml(styles, shared);
|
|
165
|
+
const mergesXml = this._mergesXml();
|
|
166
|
+
const cfXml = this._conditionalFormatXml(styles);
|
|
167
|
+
const dvXml = this._dataValidationsXml();
|
|
168
|
+
const autoFilterXml = this.autoFilter ? `<autoFilter ref="${this.autoFilter.ref}"/>` : '';
|
|
169
|
+
const tablePartsXml = this.tables.length
|
|
170
|
+
? `<tableParts count="${this.tables.length}">${this.tableRIds.map(rId => `<tablePart r:id="${rId}"/>`).join('')}</tableParts>`
|
|
171
|
+
: '';
|
|
172
|
+
const drawingXml = (this.images.length || this.charts.length) && this.drawingRId
|
|
173
|
+
? `<drawing r:id="${this.drawingRId}"/>`
|
|
174
|
+
: '';
|
|
175
|
+
const legacyDrawingXml = this.legacyDrawingRId
|
|
176
|
+
? `<legacyDrawing r:id="${this.legacyDrawingRId}"/>`
|
|
177
|
+
: '';
|
|
178
|
+
const sparklineXml = this._sparklineXml();
|
|
179
|
+
const protectionXml = this._protectionXml();
|
|
180
|
+
const pageSetupXml = this._pageSetupXml();
|
|
181
|
+
const pageMarginsXml = this._pageMarginsXml();
|
|
182
|
+
const headerFooterXml = this._headerFooterXml();
|
|
183
|
+
const printOptionsXml = this._printOptionsXml();
|
|
184
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
185
|
+
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
186
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
|
187
|
+
xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
|
|
188
|
+
xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision">
|
|
189
|
+
${sheetPrXml}
|
|
190
|
+
${sheetViewXml}
|
|
191
|
+
${colsXml}
|
|
192
|
+
${sheetDataXml}
|
|
193
|
+
${protectionXml}
|
|
194
|
+
${autoFilterXml}
|
|
195
|
+
${mergesXml}
|
|
196
|
+
${cfXml}
|
|
197
|
+
${dvXml}
|
|
198
|
+
${printOptionsXml}
|
|
199
|
+
${pageMarginsXml}
|
|
200
|
+
${pageSetupXml}
|
|
201
|
+
${headerFooterXml}
|
|
202
|
+
${drawingXml}
|
|
203
|
+
${legacyDrawingXml}
|
|
204
|
+
${sparklineXml}
|
|
205
|
+
${tablePartsXml}
|
|
206
|
+
</worksheet>`;
|
|
207
|
+
}
|
|
208
|
+
_sheetViewXml() {
|
|
209
|
+
const v = this.view ?? {};
|
|
210
|
+
const attrs = [
|
|
211
|
+
'workbookViewId="0"',
|
|
212
|
+
v.showGridLines === false ? 'showGridLines="0"' : '',
|
|
213
|
+
v.showRowColHeaders === false ? 'showRowColHeaders="0"' : '',
|
|
214
|
+
v.zoomScale !== undefined ? `zoomScale="${v.zoomScale}"` : '',
|
|
215
|
+
v.rightToLeft ? 'rightToLeft="1"' : '',
|
|
216
|
+
v.tabSelected ? 'tabSelected="1"' : '',
|
|
217
|
+
v.view ? `view="${v.view}"` : '',
|
|
218
|
+
].filter(Boolean);
|
|
219
|
+
let paneXml = '';
|
|
220
|
+
if (this.freezePane) {
|
|
221
|
+
const { row = 0, col = 0 } = this.freezePane;
|
|
222
|
+
const topLeft = row && col
|
|
223
|
+
? indicesToCellRef(row + 1, col + 1)
|
|
224
|
+
: row ? indicesToCellRef(row + 1, 1)
|
|
225
|
+
: indicesToCellRef(1, col + 1);
|
|
226
|
+
const activePane = row && col ? 'bottomRight' : row ? 'bottomLeft' : 'topRight';
|
|
227
|
+
paneXml = `<pane xSplit="${col}" ySplit="${row}" topLeftCell="${topLeft}" activePane="${activePane}" state="frozen"/>
|
|
228
|
+
<selection pane="${activePane}" activeCell="${topLeft}" sqref="${topLeft}"/>`;
|
|
229
|
+
}
|
|
230
|
+
return `<sheetViews><sheetView ${attrs.join(' ')}>${paneXml}</sheetView></sheetViews>`;
|
|
231
|
+
}
|
|
232
|
+
_colsXml(styles) {
|
|
233
|
+
if (!this.colDefs.size)
|
|
234
|
+
return '';
|
|
235
|
+
const sorted = [...this.colDefs.entries()].sort((a, b) => a[0] - b[0]);
|
|
236
|
+
const items = sorted.map(([idx, def]) => {
|
|
237
|
+
const styleIdx = def.style ? styles.register(def.style) : 0;
|
|
238
|
+
return `<col min="${idx}" max="${idx}"` +
|
|
239
|
+
(def.width ? ` width="${def.width}" customWidth="1"` : '') +
|
|
240
|
+
(def.hidden ? ` hidden="1"` : '') +
|
|
241
|
+
(def.bestFit ? ` bestFit="1"` : '') +
|
|
242
|
+
(def.outlineLevel ? ` outlineLevel="${def.outlineLevel}"` : '') +
|
|
243
|
+
(def.collapsed ? ` collapsed="1"` : '') +
|
|
244
|
+
(styleIdx ? ` style="${styleIdx}"` : '') +
|
|
245
|
+
'/>';
|
|
246
|
+
});
|
|
247
|
+
return `<cols>${items.join('')}</cols>`;
|
|
248
|
+
}
|
|
249
|
+
_sheetDataXml(styles, shared) {
|
|
250
|
+
const rows = new Map();
|
|
251
|
+
for (const [key, cell] of this.cells) {
|
|
252
|
+
const [r, c] = key.split(',').map(Number);
|
|
253
|
+
if (!rows.has(r))
|
|
254
|
+
rows.set(r, []);
|
|
255
|
+
rows.get(r).push([c, cell]);
|
|
256
|
+
}
|
|
257
|
+
const sortedRows = [...rows.entries()].sort((a, b) => a[0] - b[0]);
|
|
258
|
+
const rowsXml = sortedRows.map(([rowIdx, cells]) => {
|
|
259
|
+
const rowDef = this.rowDefs.get(rowIdx);
|
|
260
|
+
const rowStyleIdx = rowDef?.style ? styles.register(rowDef.style) : 0;
|
|
261
|
+
const rowAttrs = [
|
|
262
|
+
`r="${rowIdx}"`,
|
|
263
|
+
rowDef?.height ? `ht="${rowDef.height}" customHeight="1"` : '',
|
|
264
|
+
rowDef?.hidden ? `hidden="1"` : '',
|
|
265
|
+
rowDef?.outlineLevel ? `outlineLevel="${rowDef.outlineLevel}"` : '',
|
|
266
|
+
rowDef?.collapsed ? `collapsed="1"` : '',
|
|
267
|
+
rowStyleIdx ? `s="${rowStyleIdx}" customFormat="1"` : '',
|
|
268
|
+
rowDef?.thickTop ? `thickTop="1"` : '',
|
|
269
|
+
rowDef?.thickBot ? `thickBot="1"` : '',
|
|
270
|
+
].filter(Boolean).join(' ');
|
|
271
|
+
const sortedCells = cells.sort((a, b) => a[0] - b[0]);
|
|
272
|
+
const cellsXml = sortedCells.map(([colIdx, cell]) => this._cellXml(rowIdx, colIdx, cell, styles, shared)).join('');
|
|
273
|
+
return `<row ${rowAttrs}>${cellsXml}</row>`;
|
|
274
|
+
});
|
|
275
|
+
return `<sheetData>${rowsXml.join('')}</sheetData>`;
|
|
276
|
+
}
|
|
277
|
+
_cellXml(row, col, cell, styles, shared) {
|
|
278
|
+
const ref = `${colIndexToLetter(col)}${row}`;
|
|
279
|
+
const styleIdx = cell.style ? styles.register(cell.style) : 0;
|
|
280
|
+
const sAttr = styleIdx ? ` s="${styleIdx}"` : '';
|
|
281
|
+
if (cell.arrayFormula) {
|
|
282
|
+
const fml = `<f t="array" ref="${ref}">${escapeXml(cell.arrayFormula)}</f>`;
|
|
283
|
+
return `<c r="${ref}"${sAttr}>${fml}<v>0</v></c>`;
|
|
284
|
+
}
|
|
285
|
+
if (cell.formula) {
|
|
286
|
+
const fml = `<f>${escapeXml(cell.formula)}</f>`;
|
|
287
|
+
return `<c r="${ref}"${sAttr}>${fml}</c>`;
|
|
288
|
+
}
|
|
289
|
+
if (cell.richText) {
|
|
290
|
+
const si = shared.internRichText(cell.richText);
|
|
291
|
+
return `<c r="${ref}" t="s"${sAttr}><v>${si}</v></c>`;
|
|
292
|
+
}
|
|
293
|
+
const v = cell.value;
|
|
294
|
+
if (v === null || v === undefined) {
|
|
295
|
+
return styleIdx ? `<c r="${ref}"${sAttr}/>` : '';
|
|
296
|
+
}
|
|
297
|
+
if (typeof v === 'boolean') {
|
|
298
|
+
return `<c r="${ref}" t="b"${sAttr}><v>${v ? 1 : 0}</v></c>`;
|
|
299
|
+
}
|
|
300
|
+
if (v instanceof Date) {
|
|
301
|
+
const serial = dateToSerial(v);
|
|
302
|
+
return `<c r="${ref}"${sAttr}><v>${serial}</v></c>`;
|
|
303
|
+
}
|
|
304
|
+
if (typeof v === 'number') {
|
|
305
|
+
return `<c r="${ref}"${sAttr}><v>${v}</v></c>`;
|
|
306
|
+
}
|
|
307
|
+
if (typeof v === 'string' && v.startsWith('=')) {
|
|
308
|
+
return `<c r="${ref}"${sAttr}><f>${escapeXml(v.slice(1))}</f></c>`;
|
|
309
|
+
}
|
|
310
|
+
const si = shared.intern(v);
|
|
311
|
+
return `<c r="${ref}" t="s"${sAttr}><v>${si}</v></c>`;
|
|
312
|
+
}
|
|
313
|
+
_mergesXml() {
|
|
314
|
+
if (!this.merges.length)
|
|
315
|
+
return '';
|
|
316
|
+
const items = this.merges.map(m => {
|
|
317
|
+
const start = `${colIndexToLetter(m.startCol)}${m.startRow}`;
|
|
318
|
+
const end = `${colIndexToLetter(m.endCol)}${m.endRow}`;
|
|
319
|
+
return `<mergeCell ref="${start}:${end}"/>`;
|
|
320
|
+
});
|
|
321
|
+
return `<mergeCells count="${this.merges.length}">${items.join('')}</mergeCells>`;
|
|
322
|
+
}
|
|
323
|
+
_conditionalFormatXml(styles) {
|
|
324
|
+
return this.conditionalFormats.map(cf => {
|
|
325
|
+
const dxfId = cf.style ? styles.registerDxf(cf.style) : undefined;
|
|
326
|
+
let inner = '';
|
|
327
|
+
if (cf.colorScale?.type === 'colorScale') {
|
|
328
|
+
const cs = cf.colorScale;
|
|
329
|
+
const cfvos = cs.cfvo.map(v => `<cfvo type="${v.type}"${v.val ? ` val="${v.val}"` : ''}/>`).join('');
|
|
330
|
+
const colors = cs.color.map(c => `<color rgb="${c.startsWith('#') ? 'FF' + c.slice(1) : c}"/>`).join('');
|
|
331
|
+
inner = `<colorScale>${cfvos}${colors}</colorScale>`;
|
|
332
|
+
}
|
|
333
|
+
else if (cf.dataBar?.type === 'dataBar') {
|
|
334
|
+
const db = cf.dataBar;
|
|
335
|
+
const minCfvo = `<cfvo type="${db.minType ?? 'min'}"${db.minVal != null ? ` val="${db.minVal}"` : ''}/>`;
|
|
336
|
+
const maxCfvo = `<cfvo type="${db.maxType ?? 'max'}"${db.maxVal != null ? ` val="${db.maxVal}"` : ''}/>`;
|
|
337
|
+
const color = db.color ?? db.minColor ?? 'FF638EC6';
|
|
338
|
+
const rgb = color.startsWith('#') ? 'FF' + color.slice(1) : color;
|
|
339
|
+
inner = `<dataBar${db.showValue === false ? ' showValue="0"' : ''}>${minCfvo}${maxCfvo}<color rgb="${rgb}"/></dataBar>`;
|
|
340
|
+
}
|
|
341
|
+
else if (cf.iconSet?.type === 'iconSet') {
|
|
342
|
+
const is = cf.iconSet;
|
|
343
|
+
const cfvos = is.cfvo.map(v => `<cfvo type="${v.type}"${v.val ? ` val="${v.val}"` : ''}/>`).join('');
|
|
344
|
+
inner = `<iconSet iconSet="${is.iconSet}"${is.showValue === false ? ' showValue="0"' : ''}${is.reverse ? ' reverse="1"' : ''}>${cfvos}</iconSet>`;
|
|
345
|
+
}
|
|
346
|
+
const ruleAttrs = [
|
|
347
|
+
`type="${cf.type}"`,
|
|
348
|
+
cf.operator ? `operator="${cf.operator}"` : '',
|
|
349
|
+
dxfId !== undefined ? `dxfId="${dxfId}"` : '',
|
|
350
|
+
`priority="${cf.priority ?? 1}"`,
|
|
351
|
+
cf.aboveAverage === false ? `aboveAverage="0"` : '',
|
|
352
|
+
cf.percent ? `percent="1"` : '',
|
|
353
|
+
cf.rank ? `rank="${cf.rank}"` : '',
|
|
354
|
+
cf.timePeriod ? `timePeriod="${cf.timePeriod}"` : '',
|
|
355
|
+
cf.text ? `text="${escapeXml(cf.text)}"` : '',
|
|
356
|
+
].filter(Boolean).join(' ');
|
|
357
|
+
const fml1 = cf.formula ? `<formula>${escapeXml(cf.formula)}</formula>` : '';
|
|
358
|
+
const fml2 = cf.formula2 ? `<formula>${escapeXml(cf.formula2)}</formula>` : '';
|
|
359
|
+
return `<conditionalFormatting sqref="${cf.sqref}"><cfRule ${ruleAttrs}>${fml1}${fml2}${inner}</cfRule></conditionalFormatting>`;
|
|
360
|
+
}).join('');
|
|
361
|
+
}
|
|
362
|
+
_dataValidationsXml() {
|
|
363
|
+
if (!this.dataValidations.size)
|
|
364
|
+
return '';
|
|
365
|
+
const items = [...this.dataValidations.entries()].map(([sqref, dv]) => {
|
|
366
|
+
const formula1 = dv.type === 'list' && dv.list
|
|
367
|
+
? `<formula1>"${dv.list.join(',')}"</formula1>`
|
|
368
|
+
: dv.formula1 ? `<formula1>${escapeXml(dv.formula1)}</formula1>` : '';
|
|
369
|
+
const formula2 = dv.formula2 ? `<formula2>${escapeXml(dv.formula2)}</formula2>` : '';
|
|
370
|
+
const attrs = [
|
|
371
|
+
`type="${dv.type}"`,
|
|
372
|
+
dv.operator ? `operator="${dv.operator}"` : '',
|
|
373
|
+
`sqref="${sqref}"`,
|
|
374
|
+
dv.showDropDown !== false && dv.type === 'list' ? '' : 'showDropDown="1"',
|
|
375
|
+
dv.allowBlank !== false ? 'allowBlank="1"' : '',
|
|
376
|
+
dv.showErrorAlert ? 'showErrorMessage="1"' : '',
|
|
377
|
+
dv.errorTitle ? `errorTitle="${escapeXml(dv.errorTitle)}"` : '',
|
|
378
|
+
dv.error ? `error="${escapeXml(dv.error)}"` : '',
|
|
379
|
+
dv.showInputMessage ? 'showInputMessage="1"' : '',
|
|
380
|
+
dv.promptTitle ? `promptTitle="${escapeXml(dv.promptTitle)}"` : '',
|
|
381
|
+
dv.prompt ? `prompt="${escapeXml(dv.prompt)}"` : '',
|
|
382
|
+
].filter(Boolean).join(' ');
|
|
383
|
+
return `<dataValidation ${attrs}>${formula1}${formula2}</dataValidation>`;
|
|
384
|
+
});
|
|
385
|
+
return `<dataValidations count="${this.dataValidations.size}">${items.join('')}</dataValidations>`;
|
|
386
|
+
}
|
|
387
|
+
_protectionXml() {
|
|
388
|
+
const p = this.protection;
|
|
389
|
+
if (!p)
|
|
390
|
+
return '';
|
|
391
|
+
const attrs = [
|
|
392
|
+
p.sheet ? 'sheet="1"' : '',
|
|
393
|
+
p.password ? `password="${hashPassword(p.password)}"` : '',
|
|
394
|
+
p.selectLockedCells === false ? 'selectLockedCells="0"' : '',
|
|
395
|
+
p.selectUnlockedCells === false ? 'selectUnlockedCells="0"' : '',
|
|
396
|
+
p.formatCells ? 'formatCells="0"' : '',
|
|
397
|
+
p.formatColumns ? 'formatColumns="0"' : '',
|
|
398
|
+
p.formatRows ? 'formatRows="0"' : '',
|
|
399
|
+
p.insertColumns ? 'insertColumns="0"' : '',
|
|
400
|
+
p.insertRows ? 'insertRows="0"' : '',
|
|
401
|
+
p.insertHyperlinks ? 'insertHyperlinks="0"' : '',
|
|
402
|
+
p.deleteColumns ? 'deleteColumns="0"' : '',
|
|
403
|
+
p.deleteRows ? 'deleteRows="0"' : '',
|
|
404
|
+
p.sort ? 'sort="0"' : '',
|
|
405
|
+
p.autoFilter ? 'autoFilter="0"' : '',
|
|
406
|
+
p.pivotTables ? 'pivotTables="0"' : '',
|
|
407
|
+
].filter(Boolean).join(' ');
|
|
408
|
+
return `<sheetProtection ${attrs}/>`;
|
|
409
|
+
}
|
|
410
|
+
_pageSetupXml() {
|
|
411
|
+
const p = this.pageSetup;
|
|
412
|
+
if (!p)
|
|
413
|
+
return '';
|
|
414
|
+
const attrs = [
|
|
415
|
+
p.paperSize ? `paperSize="${p.paperSize}"` : '',
|
|
416
|
+
p.orientation ? `orientation="${p.orientation}"` : '',
|
|
417
|
+
p.fitToWidth !== undefined ? `fitToWidth="${p.fitToWidth}"` : '',
|
|
418
|
+
p.fitToHeight !== undefined ? `fitToHeight="${p.fitToHeight}"` : '',
|
|
419
|
+
p.scale ? `scale="${p.scale}"` : '',
|
|
420
|
+
p.horizontalDpi ? `horizontalDpi="${p.horizontalDpi}"` : '',
|
|
421
|
+
p.verticalDpi ? `verticalDpi="${p.verticalDpi}"` : '',
|
|
422
|
+
p.firstPageNumber ? `firstPageNumber="${p.firstPageNumber}" useFirstPageNumber="1"` : '',
|
|
423
|
+
].filter(Boolean).join(' ');
|
|
424
|
+
return `<pageSetup ${attrs}/>`;
|
|
425
|
+
}
|
|
426
|
+
_pageMarginsXml() {
|
|
427
|
+
const m = this.pageMargins;
|
|
428
|
+
const defaults = { left: 0.7, right: 0.7, top: 0.75, bottom: 0.75, header: 0.3, footer: 0.3 };
|
|
429
|
+
const d = { ...defaults, ...m };
|
|
430
|
+
return `<pageMargins left="${d.left}" right="${d.right}" top="${d.top}" bottom="${d.bottom}" header="${d.header}" footer="${d.footer}"/>`;
|
|
431
|
+
}
|
|
432
|
+
_headerFooterXml() {
|
|
433
|
+
const hf = this.headerFooter;
|
|
434
|
+
if (!hf)
|
|
435
|
+
return '';
|
|
436
|
+
const attrs = [
|
|
437
|
+
hf.differentOddEven ? 'differentOddEven="1"' : '',
|
|
438
|
+
hf.differentFirst ? 'differentFirst="1"' : '',
|
|
439
|
+
].filter(Boolean).join(' ');
|
|
440
|
+
const oh = hf.oddHeader ? `<oddHeader>${escapeXml(hf.oddHeader)}</oddHeader>` : '';
|
|
441
|
+
const of_ = hf.oddFooter ? `<oddFooter>${escapeXml(hf.oddFooter)}</oddFooter>` : '';
|
|
442
|
+
const eh = hf.evenHeader ? `<evenHeader>${escapeXml(hf.evenHeader)}</evenHeader>` : '';
|
|
443
|
+
const ef = hf.evenFooter ? `<evenFooter>${escapeXml(hf.evenFooter)}</evenFooter>` : '';
|
|
444
|
+
const fh = hf.firstHeader ? `<firstHeader>${escapeXml(hf.firstHeader)}</firstHeader>` : '';
|
|
445
|
+
const ff = hf.firstFooter ? `<firstFooter>${escapeXml(hf.firstFooter)}</firstFooter>` : '';
|
|
446
|
+
return `<headerFooter${attrs ? ' ' + attrs : ''}>${oh}${of_}${eh}${ef}${fh}${ff}</headerFooter>`;
|
|
447
|
+
}
|
|
448
|
+
_printOptionsXml() {
|
|
449
|
+
const p = this.printOptions;
|
|
450
|
+
if (!p)
|
|
451
|
+
return '';
|
|
452
|
+
const attrs = [
|
|
453
|
+
p.gridLines ? 'gridLines="1"' : '',
|
|
454
|
+
p.gridLinesSet ? 'gridLinesSet="1"' : '',
|
|
455
|
+
p.headings ? 'headings="1"' : '',
|
|
456
|
+
p.centerHorizontal ? 'horizontalCentered="1"' : '',
|
|
457
|
+
p.centerVertical ? 'verticalCentered="1"' : '',
|
|
458
|
+
].filter(Boolean).join(' ');
|
|
459
|
+
return attrs ? `<printOptions ${attrs}/>` : '';
|
|
460
|
+
}
|
|
461
|
+
_sparklineXml() {
|
|
462
|
+
if (!this.sparklines.length)
|
|
463
|
+
return '';
|
|
464
|
+
const colorEl = (name, c) => {
|
|
465
|
+
if (!c)
|
|
466
|
+
return '';
|
|
467
|
+
const rgb = c.startsWith('#') ? 'FF' + c.slice(1) : c;
|
|
468
|
+
return `<x14:${name} rgb="${rgb}"/>`;
|
|
469
|
+
};
|
|
470
|
+
const groups = this.sparklines.map(s => {
|
|
471
|
+
const sparkType = s.type === 'bar' ? 'column' : s.type;
|
|
472
|
+
const attrs = [
|
|
473
|
+
`type="${sparkType}"`,
|
|
474
|
+
s.lineWidth !== undefined ? `lineWeight="${s.lineWidth}"` : '',
|
|
475
|
+
s.showMarkers ? 'markers="1"' : '',
|
|
476
|
+
s.showFirst ? 'first="1"' : '',
|
|
477
|
+
s.showLast ? 'last="1"' : '',
|
|
478
|
+
s.showHigh ? 'high="1"' : '',
|
|
479
|
+
s.showLow ? 'low="1"' : '',
|
|
480
|
+
s.showNegative ? 'negative="1"' : '',
|
|
481
|
+
s.minAxisType ? `minAxisType="${s.minAxisType}"` : '',
|
|
482
|
+
s.maxAxisType ? `maxAxisType="${s.maxAxisType}"` : '',
|
|
483
|
+
].filter(Boolean).join(' ');
|
|
484
|
+
const colors = [
|
|
485
|
+
colorEl('colorSeries', s.color),
|
|
486
|
+
colorEl('colorHigh', s.highColor),
|
|
487
|
+
colorEl('colorLow', s.lowColor),
|
|
488
|
+
colorEl('colorFirst', s.firstColor),
|
|
489
|
+
colorEl('colorLast', s.lastColor),
|
|
490
|
+
colorEl('colorNegative', s.negativeColor),
|
|
491
|
+
colorEl('colorMarkers', s.markersColor),
|
|
492
|
+
].join('');
|
|
493
|
+
const dataRef = s.dataRange.includes('!') ? s.dataRange : `${this.name}!${s.dataRange}`;
|
|
494
|
+
const sparkline = `<x14:sparklines><x14:sparkline><xm:f>${escapeXml(dataRef)}</xm:f><xm:sqref>${s.location}</xm:sqref></x14:sparkline></x14:sparklines>`;
|
|
495
|
+
return `<x14:sparklineGroup ${attrs}>${colors}${sparkline}</x14:sparklineGroup>`;
|
|
496
|
+
});
|
|
497
|
+
const inner = `<x14:sparklineGroups xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main">${groups.join('')}</x14:sparklineGroups>`;
|
|
498
|
+
return `<extLst><ext uri="{05C60535-1F16-4fd2-B633-F4F36F0B64E0}" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main">${inner}</ext></extLst>`;
|
|
499
|
+
}
|
|
500
|
+
toDrawingXml(imageRIds, chartRIds) {
|
|
501
|
+
const parts = [];
|
|
502
|
+
const EMU = pxToEmu;
|
|
503
|
+
this.images.forEach((img, i) => {
|
|
504
|
+
const rId = imageRIds[i];
|
|
505
|
+
const from = img.from;
|
|
506
|
+
const to = img.to;
|
|
507
|
+
const fromXml = `<xdr:from><xdr:col>${from.col}</xdr:col><xdr:colOff>${from.colOff ?? 0}</xdr:colOff><xdr:row>${from.row}</xdr:row><xdr:rowOff>${from.rowOff ?? 0}</xdr:rowOff></xdr:from>`;
|
|
508
|
+
let anchor;
|
|
509
|
+
if (to) {
|
|
510
|
+
const toXml = `<xdr:to><xdr:col>${to.col}</xdr:col><xdr:colOff>${to.colOff ?? 0}</xdr:colOff><xdr:row>${to.row}</xdr:row><xdr:rowOff>${to.rowOff ?? 0}</xdr:rowOff></xdr:to>`;
|
|
511
|
+
anchor = `<xdr:twoCellAnchor editAs="oneCell">${fromXml}${toXml}`;
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
const w = EMU(img.width ?? 100);
|
|
515
|
+
const h = EMU(img.height ?? 100);
|
|
516
|
+
anchor = `<xdr:oneCellAnchor>${fromXml}<xdr:ext cx="${w}" cy="${h}"/>`;
|
|
517
|
+
}
|
|
518
|
+
const picXml = `<xdr:pic>
|
|
519
|
+
<xdr:nvPicPr>
|
|
520
|
+
<xdr:cNvPr id="${i + 2}" name="Image ${i + 1}"${img.altText ? ` descr="${escapeXml(img.altText)}"` : ''}/>
|
|
521
|
+
<xdr:cNvPicPr><a:picLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/></xdr:cNvPicPr>
|
|
522
|
+
</xdr:nvPicPr>
|
|
523
|
+
<xdr:blipFill>
|
|
524
|
+
<a:blip xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" r:embed="${rId}"/>
|
|
525
|
+
<a:stretch xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:fillRect/></a:stretch>
|
|
526
|
+
</xdr:blipFill>
|
|
527
|
+
<xdr:spPr>
|
|
528
|
+
<a:xfrm xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
|
|
529
|
+
<a:off x="0" y="0"/><a:ext cx="${EMU(img.width ?? 100)}" cy="${EMU(img.height ?? 100)}"/>
|
|
530
|
+
</a:xfrm>
|
|
531
|
+
<a:prstGeom xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" prst="rect"><a:avLst/></a:prstGeom>
|
|
532
|
+
</xdr:spPr>
|
|
533
|
+
</xdr:pic>`;
|
|
534
|
+
const closeTag = to ? `</xdr:twoCellAnchor>` : `</xdr:oneCellAnchor>`;
|
|
535
|
+
parts.push(`${anchor}${picXml}<xdr:clientData/>${closeTag}`);
|
|
536
|
+
});
|
|
537
|
+
this.charts.forEach((chart, i) => {
|
|
538
|
+
const rId = chartRIds[i];
|
|
539
|
+
const from = chart.from;
|
|
540
|
+
const to = chart.to;
|
|
541
|
+
const fromXml = `<xdr:from><xdr:col>${from.col}</xdr:col><xdr:colOff>${from.colOff ?? 0}</xdr:colOff><xdr:row>${from.row}</xdr:row><xdr:rowOff>${from.rowOff ?? 0}</xdr:rowOff></xdr:from>`;
|
|
542
|
+
const toXml = `<xdr:to><xdr:col>${to.col}</xdr:col><xdr:colOff>${to.colOff ?? 0}</xdr:colOff><xdr:row>${to.row}</xdr:row><xdr:rowOff>${to.rowOff ?? 0}</xdr:rowOff></xdr:to>`;
|
|
543
|
+
const graphicXml = `<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
|
|
544
|
+
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/chart">
|
|
545
|
+
<c:chart xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" r:id="${rId}"/>
|
|
546
|
+
</a:graphicData>
|
|
547
|
+
</a:graphic>`;
|
|
548
|
+
parts.push(`<xdr:twoCellAnchor editAs="oneCell">${fromXml}${toXml}<xdr:graphicFrame macro=""><xdr:nvGraphicFramePr><xdr:cNvPr id="${this.images.length + i + 2}" name="Chart ${i + 1}"/><xdr:cNvGraphicFramePr/></xdr:nvGraphicFramePr><xdr:xfrm><a:off xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" x="0" y="0"/><a:ext xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" cx="0" cy="0"/></xdr:xfrm>${graphicXml}</xdr:graphicFrame><xdr:clientData/></xdr:twoCellAnchor>`);
|
|
549
|
+
});
|
|
550
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
551
|
+
<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
|
|
552
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
553
|
+
${parts.join('\n')}
|
|
554
|
+
</xdr:wsDr>`;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
function hashPassword(pwd) {
|
|
558
|
+
let hash = 0;
|
|
559
|
+
for (let i = pwd.length - 1; i >= 0; i--) {
|
|
560
|
+
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7FFF);
|
|
561
|
+
hash ^= pwd.charCodeAt(i);
|
|
562
|
+
}
|
|
563
|
+
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7FFF);
|
|
564
|
+
hash ^= pwd.length;
|
|
565
|
+
hash ^= 0xCE4B;
|
|
566
|
+
return hash.toString(16).toUpperCase().padStart(4, '0');
|
|
567
|
+
}
|
|
568
|
+
//# sourceMappingURL=Worksheet.js.map
|