@node-projects/excelforge 2.4.0 → 3.1.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/.github/FUNDING.yml +4 -0
- package/FEATURES.md +294 -0
- package/README.md +628 -12
- package/dist/core/SharedStrings.js +6 -2
- package/dist/core/SharedStrings.js.map +1 -1
- package/dist/core/Workbook.d.ts +43 -1
- package/dist/core/Workbook.js +881 -58
- package/dist/core/Workbook.js.map +1 -1
- package/dist/core/WorkbookReader.d.ts +18 -4
- package/dist/core/WorkbookReader.js +1386 -20
- package/dist/core/WorkbookReader.js.map +1 -1
- package/dist/core/Worksheet.d.ts +136 -2
- package/dist/core/Worksheet.js +828 -63
- package/dist/core/Worksheet.js.map +1 -1
- package/dist/core/types.d.ts +311 -5
- package/dist/core/types.js +12 -1
- package/dist/core/types.js.map +1 -1
- package/dist/features/ChartBuilder.d.ts +9 -1
- package/dist/features/ChartBuilder.js +140 -14
- package/dist/features/ChartBuilder.js.map +1 -1
- package/dist/features/CsvModule.d.ts +11 -0
- package/dist/features/CsvModule.js +137 -0
- package/dist/features/CsvModule.js.map +1 -0
- package/dist/features/Encryption.d.ts +6 -0
- package/dist/features/Encryption.js +806 -0
- package/dist/features/Encryption.js.map +1 -0
- package/dist/features/FormControlBuilder.d.ts +6 -0
- package/dist/features/FormControlBuilder.js +135 -0
- package/dist/features/FormControlBuilder.js.map +1 -0
- package/dist/features/FormulaEngine.d.ts +22 -0
- package/dist/features/FormulaEngine.js +498 -0
- package/dist/features/FormulaEngine.js.map +1 -0
- package/dist/features/HtmlModule.d.ts +22 -0
- package/dist/features/HtmlModule.js +1441 -0
- package/dist/features/HtmlModule.js.map +1 -0
- package/dist/features/JsonModule.d.ts +10 -0
- package/dist/features/JsonModule.js +76 -0
- package/dist/features/JsonModule.js.map +1 -0
- package/dist/features/PdfModule.d.ts +30 -0
- package/dist/features/PdfModule.js +1567 -0
- package/dist/features/PdfModule.js.map +1 -0
- package/dist/features/PivotTableBuilder.d.ts +7 -0
- package/dist/features/PivotTableBuilder.js +170 -0
- package/dist/features/PivotTableBuilder.js.map +1 -0
- package/dist/features/Signing.d.ts +12 -0
- package/dist/features/Signing.js +326 -0
- package/dist/features/Signing.js.map +1 -0
- package/dist/features/TableBuilder.js +2 -2
- package/dist/features/TableBuilder.js.map +1 -1
- package/dist/index-min.js +609 -147
- package/dist/index.d.ts +19 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/styles/StyleRegistry.d.ts +14 -0
- package/dist/styles/StyleRegistry.js +95 -30
- package/dist/styles/StyleRegistry.js.map +1 -1
- package/dist/utils/helpers.d.ts +4 -0
- package/dist/utils/helpers.js +64 -14
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/zip.js +145 -73
- package/dist/utils/zip.js.map +1 -1
- package/dist/vba/VbaProject.d.ts +31 -0
- package/dist/vba/VbaProject.js +576 -0
- package/dist/vba/VbaProject.js.map +1 -0
- package/dist/vba/cfb.d.ts +7 -0
- package/dist/vba/cfb.js +352 -0
- package/dist/vba/cfb.js.map +1 -0
- package/dist/vba/ovba.d.ts +2 -0
- package/dist/vba/ovba.js +137 -0
- package/dist/vba/ovba.js.map +1 -0
- package/package.json +4 -3
- package/validator.cs +0 -155
- package/validatorEpplus.cs +0 -27
- package/validatorReadData.cs +0 -111
package/dist/core/Worksheet.js
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
+
import { CellError, } from '../core/types.js';
|
|
1
2
|
import { colIndexToLetter, indicesToCellRef, cellRefToIndices, parseRange, escapeXml, dateToSerial, pxToEmu, } from '../utils/helpers.js';
|
|
3
|
+
const _xmlContentRe = /[&<>]/g;
|
|
4
|
+
const _xmlContentEsc = { '&': '&', '<': '<', '>': '>' };
|
|
5
|
+
function escapeXmlContent(s) {
|
|
6
|
+
return _xmlContentRe.test(s) ? (_xmlContentRe.lastIndex = 0, s.replace(_xmlContentRe, ch => _xmlContentEsc[ch])) : s;
|
|
7
|
+
}
|
|
8
|
+
function colorEl(c) {
|
|
9
|
+
if (c.startsWith('theme:'))
|
|
10
|
+
return `<color theme="${c.slice(6)}"/>`;
|
|
11
|
+
const rgb = c.startsWith('#') ? 'FF' + c.slice(1) : c;
|
|
12
|
+
return `<color rgb="${rgb}"/>`;
|
|
13
|
+
}
|
|
2
14
|
const SUBTOTAL_FN = {
|
|
3
15
|
average: 101, count: 102, countNums: 103, max: 104, min: 105,
|
|
4
16
|
stdDev: 107, sum: 109, var: 110, vars: 111,
|
|
@@ -8,34 +20,67 @@ export class Worksheet {
|
|
|
8
20
|
this.cells = new Map();
|
|
9
21
|
this.merges = [];
|
|
10
22
|
this.images = [];
|
|
23
|
+
this.cellImages = [];
|
|
11
24
|
this.charts = [];
|
|
12
25
|
this.conditionalFormats = [];
|
|
13
26
|
this.tables = [];
|
|
27
|
+
this.pivotTables = [];
|
|
14
28
|
this.sparklines = [];
|
|
29
|
+
this.formControls = [];
|
|
30
|
+
this.shapes = [];
|
|
31
|
+
this.wordArt = [];
|
|
32
|
+
this.queryTables = [];
|
|
33
|
+
this.tableSlicers = [];
|
|
34
|
+
this.mathEquations = [];
|
|
35
|
+
this.oleObjects = [];
|
|
15
36
|
this.colDefs = new Map();
|
|
16
37
|
this.rowDefs = new Map();
|
|
17
38
|
this.dataValidations = new Map();
|
|
39
|
+
this.rowBreaks = [];
|
|
40
|
+
this.colBreaks = [];
|
|
41
|
+
this.preservedXml = [];
|
|
42
|
+
this._nextSharedIdx = 0;
|
|
43
|
+
this._isChartSheet = false;
|
|
44
|
+
this._isDialogSheet = false;
|
|
18
45
|
this.sheetIndex = 0;
|
|
19
46
|
this.rId = '';
|
|
20
47
|
this.drawingRId = '';
|
|
21
48
|
this.legacyDrawingRId = '';
|
|
22
49
|
this.tableRIds = [];
|
|
50
|
+
this.ctrlPropRIds = [];
|
|
51
|
+
this.slicerRId = '';
|
|
52
|
+
this._slicerDrawingInfo = [];
|
|
53
|
+
this._cellImageVm = new Map();
|
|
54
|
+
this.ignoreErrors = [];
|
|
55
|
+
this.oleRIds = [];
|
|
56
|
+
this.oleIconRIds = [];
|
|
23
57
|
this.name = name;
|
|
24
58
|
this.options = { ...options, name };
|
|
25
59
|
}
|
|
26
|
-
key(row, col) { return `${row},${col}`; }
|
|
27
60
|
getCell(row, col) {
|
|
28
|
-
|
|
29
|
-
if (!
|
|
30
|
-
|
|
31
|
-
|
|
61
|
+
let rowMap = this.cells.get(row);
|
|
62
|
+
if (!rowMap) {
|
|
63
|
+
rowMap = new Map();
|
|
64
|
+
this.cells.set(row, rowMap);
|
|
65
|
+
}
|
|
66
|
+
let cell = rowMap.get(col);
|
|
67
|
+
if (!cell) {
|
|
68
|
+
cell = {};
|
|
69
|
+
rowMap.set(col, cell);
|
|
70
|
+
}
|
|
71
|
+
return cell;
|
|
32
72
|
}
|
|
33
73
|
getCellByRef(ref) {
|
|
34
74
|
const { row, col } = cellRefToIndices(ref);
|
|
35
75
|
return this.getCell(row, col);
|
|
36
76
|
}
|
|
37
77
|
setCell(row, col, cell) {
|
|
38
|
-
this.cells.
|
|
78
|
+
let rowMap = this.cells.get(row);
|
|
79
|
+
if (!rowMap) {
|
|
80
|
+
rowMap = new Map();
|
|
81
|
+
this.cells.set(row, rowMap);
|
|
82
|
+
}
|
|
83
|
+
rowMap.set(col, cell);
|
|
39
84
|
return this;
|
|
40
85
|
}
|
|
41
86
|
setValue(row, col, value) {
|
|
@@ -46,6 +91,29 @@ export class Worksheet {
|
|
|
46
91
|
this.getCell(row, col).formula = formula;
|
|
47
92
|
return this;
|
|
48
93
|
}
|
|
94
|
+
setDynamicArrayFormula(row, col, formula) {
|
|
95
|
+
const cell = this.getCell(row, col);
|
|
96
|
+
cell.arrayFormula = formula;
|
|
97
|
+
cell._dynamic = true;
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
setSharedFormula(masterRow, masterCol, formula, rangeRef) {
|
|
101
|
+
const si = this._nextSharedIdx++;
|
|
102
|
+
const master = this.getCell(masterRow, masterCol);
|
|
103
|
+
master.formula = formula;
|
|
104
|
+
master._sharedRef = rangeRef;
|
|
105
|
+
master._sharedIdx = si;
|
|
106
|
+
const { startRow, startCol, endRow, endCol } = parseRange(rangeRef);
|
|
107
|
+
for (let r = startRow; r <= endRow; r++) {
|
|
108
|
+
for (let c = startCol; c <= endCol; c++) {
|
|
109
|
+
if (r === masterRow && c === masterCol)
|
|
110
|
+
continue;
|
|
111
|
+
const dep = this.getCell(r, c);
|
|
112
|
+
dep._sharedIdx = si;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
49
117
|
setStyle(row, col, style) {
|
|
50
118
|
this.getCell(row, col).style = style;
|
|
51
119
|
return this;
|
|
@@ -94,17 +162,24 @@ export class Worksheet {
|
|
|
94
162
|
const ec = cellRefToIndices(e);
|
|
95
163
|
return this.merge(sc.row, sc.col, ec.row, ec.col);
|
|
96
164
|
}
|
|
165
|
+
getMerges() { return this.merges; }
|
|
97
166
|
addImage(img) {
|
|
98
167
|
this.images.push(img);
|
|
99
168
|
return this;
|
|
100
169
|
}
|
|
101
170
|
getImages() { return this.images; }
|
|
171
|
+
addCellImage(img) {
|
|
172
|
+
this.cellImages.push(img);
|
|
173
|
+
return this;
|
|
174
|
+
}
|
|
175
|
+
getCellImages() { return this.cellImages; }
|
|
102
176
|
getComments() {
|
|
103
177
|
const out = [];
|
|
104
|
-
for (const [
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
178
|
+
for (const [r, rowMap] of this.cells) {
|
|
179
|
+
for (const [c, cell] of rowMap) {
|
|
180
|
+
if (cell.comment) {
|
|
181
|
+
out.push({ row: r, col: c, comment: cell.comment });
|
|
182
|
+
}
|
|
108
183
|
}
|
|
109
184
|
}
|
|
110
185
|
return out;
|
|
@@ -118,6 +193,8 @@ export class Worksheet {
|
|
|
118
193
|
this.conditionalFormats.push(cf);
|
|
119
194
|
return this;
|
|
120
195
|
}
|
|
196
|
+
getConditionalFormats() { return this.conditionalFormats; }
|
|
197
|
+
getDataValidations() { return this.dataValidations; }
|
|
121
198
|
addTable(table) {
|
|
122
199
|
this.tables.push(table);
|
|
123
200
|
if (table.totalsRow && table.columns?.length) {
|
|
@@ -141,14 +218,350 @@ export class Worksheet {
|
|
|
141
218
|
return this;
|
|
142
219
|
}
|
|
143
220
|
getTables() { return this.tables; }
|
|
221
|
+
addPivotTable(pt) {
|
|
222
|
+
this.pivotTables.push(pt);
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
getPivotTables() { return this.pivotTables; }
|
|
226
|
+
readRange(ref) {
|
|
227
|
+
const { startRow, startCol, endRow, endCol } = parseRange(ref);
|
|
228
|
+
const result = [];
|
|
229
|
+
for (let r = startRow; r <= endRow; r++) {
|
|
230
|
+
const row = [];
|
|
231
|
+
const rowMap = this.cells.get(r);
|
|
232
|
+
for (let c = startCol; c <= endCol; c++) {
|
|
233
|
+
const cell = rowMap?.get(c);
|
|
234
|
+
row.push(cell?.value ?? null);
|
|
235
|
+
}
|
|
236
|
+
result.push(row);
|
|
237
|
+
}
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
readAllCells() {
|
|
241
|
+
const out = [];
|
|
242
|
+
for (const [r, rowMap] of this.cells) {
|
|
243
|
+
for (const [c, cell] of rowMap) {
|
|
244
|
+
out.push({ row: r, col: c, cell });
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return out;
|
|
248
|
+
}
|
|
249
|
+
getUsedRange() {
|
|
250
|
+
let minR = Infinity, maxR = 0, minC = Infinity, maxC = 0;
|
|
251
|
+
for (const [r, rowMap] of this.cells) {
|
|
252
|
+
for (const [c] of rowMap) {
|
|
253
|
+
if (r < minR)
|
|
254
|
+
minR = r;
|
|
255
|
+
if (r > maxR)
|
|
256
|
+
maxR = r;
|
|
257
|
+
if (c < minC)
|
|
258
|
+
minC = c;
|
|
259
|
+
if (c > maxC)
|
|
260
|
+
maxC = c;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return maxR === 0 ? null : { startRow: minR, startCol: minC, endRow: maxR, endCol: maxC };
|
|
264
|
+
}
|
|
265
|
+
getColumn(col) {
|
|
266
|
+
return this.colDefs.get(col);
|
|
267
|
+
}
|
|
268
|
+
getRow(row) {
|
|
269
|
+
return this.rowDefs.get(row);
|
|
270
|
+
}
|
|
271
|
+
insertRows(atRow, count) {
|
|
272
|
+
const rows = [...this.cells.keys()].filter(r => r >= atRow).sort((a, b) => b - a);
|
|
273
|
+
for (const r of rows) {
|
|
274
|
+
const rowMap = this.cells.get(r);
|
|
275
|
+
this.cells.delete(r);
|
|
276
|
+
this.cells.set(r + count, rowMap);
|
|
277
|
+
}
|
|
278
|
+
const rdKeys = [...this.rowDefs.keys()].filter(r => r >= atRow).sort((a, b) => b - a);
|
|
279
|
+
for (const r of rdKeys) {
|
|
280
|
+
const d = this.rowDefs.get(r);
|
|
281
|
+
this.rowDefs.delete(r);
|
|
282
|
+
this.rowDefs.set(r + count, d);
|
|
283
|
+
}
|
|
284
|
+
for (const m of this.merges) {
|
|
285
|
+
if (m.startRow >= atRow)
|
|
286
|
+
m.startRow += count;
|
|
287
|
+
if (m.endRow >= atRow)
|
|
288
|
+
m.endRow += count;
|
|
289
|
+
}
|
|
290
|
+
return this;
|
|
291
|
+
}
|
|
292
|
+
deleteRows(atRow, count) {
|
|
293
|
+
for (let r = atRow; r < atRow + count; r++) {
|
|
294
|
+
this.cells.delete(r);
|
|
295
|
+
this.rowDefs.delete(r);
|
|
296
|
+
}
|
|
297
|
+
const rows = [...this.cells.keys()].filter(r => r >= atRow + count).sort((a, b) => a - b);
|
|
298
|
+
for (const r of rows) {
|
|
299
|
+
const rowMap = this.cells.get(r);
|
|
300
|
+
this.cells.delete(r);
|
|
301
|
+
this.cells.set(r - count, rowMap);
|
|
302
|
+
}
|
|
303
|
+
const rdKeys = [...this.rowDefs.keys()].filter(r => r >= atRow + count).sort((a, b) => a - b);
|
|
304
|
+
for (const r of rdKeys) {
|
|
305
|
+
const d = this.rowDefs.get(r);
|
|
306
|
+
this.rowDefs.delete(r);
|
|
307
|
+
this.rowDefs.set(r - count, d);
|
|
308
|
+
}
|
|
309
|
+
this.merges = this.merges.filter(m => !(m.startRow >= atRow && m.endRow < atRow + count));
|
|
310
|
+
for (const m of this.merges) {
|
|
311
|
+
if (m.startRow >= atRow + count)
|
|
312
|
+
m.startRow -= count;
|
|
313
|
+
if (m.endRow >= atRow + count)
|
|
314
|
+
m.endRow -= count;
|
|
315
|
+
}
|
|
316
|
+
return this;
|
|
317
|
+
}
|
|
318
|
+
insertColumns(atCol, count) {
|
|
319
|
+
for (const [, rowMap] of this.cells) {
|
|
320
|
+
const cols = [...rowMap.keys()].filter(c => c >= atCol).sort((a, b) => b - a);
|
|
321
|
+
for (const c of cols) {
|
|
322
|
+
const cell = rowMap.get(c);
|
|
323
|
+
rowMap.delete(c);
|
|
324
|
+
rowMap.set(c + count, cell);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const cdKeys = [...this.colDefs.keys()].filter(c => c >= atCol).sort((a, b) => b - a);
|
|
328
|
+
for (const c of cdKeys) {
|
|
329
|
+
const d = this.colDefs.get(c);
|
|
330
|
+
this.colDefs.delete(c);
|
|
331
|
+
this.colDefs.set(c + count, d);
|
|
332
|
+
}
|
|
333
|
+
for (const m of this.merges) {
|
|
334
|
+
if (m.startCol >= atCol)
|
|
335
|
+
m.startCol += count;
|
|
336
|
+
if (m.endCol >= atCol)
|
|
337
|
+
m.endCol += count;
|
|
338
|
+
}
|
|
339
|
+
return this;
|
|
340
|
+
}
|
|
341
|
+
copyRange(srcRef, targetRow, targetCol) {
|
|
342
|
+
const { startRow, startCol, endRow, endCol } = parseRange(srcRef);
|
|
343
|
+
for (let r = startRow; r <= endRow; r++) {
|
|
344
|
+
for (let c = startCol; c <= endCol; c++) {
|
|
345
|
+
const src = this.getCell(r, c);
|
|
346
|
+
const dr = targetRow + (r - startRow);
|
|
347
|
+
const dc = targetCol + (c - startCol);
|
|
348
|
+
if (src.value != null)
|
|
349
|
+
this.setValue(dr, dc, src.value);
|
|
350
|
+
if (src.formula)
|
|
351
|
+
this.setFormula(dr, dc, src.formula);
|
|
352
|
+
if (src.style)
|
|
353
|
+
this.setStyle(dr, dc, { ...src.style });
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return this;
|
|
357
|
+
}
|
|
358
|
+
moveRange(srcRef, targetRow, targetCol) {
|
|
359
|
+
const { startRow, startCol, endRow, endCol } = parseRange(srcRef);
|
|
360
|
+
this.copyRange(srcRef, targetRow, targetCol);
|
|
361
|
+
const tEndRow = targetRow + (endRow - startRow);
|
|
362
|
+
const tEndCol = targetCol + (endCol - startCol);
|
|
363
|
+
for (let r = startRow; r <= endRow; r++) {
|
|
364
|
+
for (let c = startCol; c <= endCol; c++) {
|
|
365
|
+
const dr = targetRow + (r - startRow);
|
|
366
|
+
const dc = targetCol + (c - startCol);
|
|
367
|
+
if (dr === r && dc === c)
|
|
368
|
+
continue;
|
|
369
|
+
const rowMap = this.cells.get(r);
|
|
370
|
+
if (rowMap)
|
|
371
|
+
rowMap.delete(c);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return this;
|
|
375
|
+
}
|
|
376
|
+
sortRange(ref, sortCol, order = 'asc') {
|
|
377
|
+
const { startRow, startCol, endRow, endCol } = parseRange(ref);
|
|
378
|
+
const rows = [];
|
|
379
|
+
for (let r = startRow; r <= endRow; r++) {
|
|
380
|
+
const rowMap = this.cells.get(r);
|
|
381
|
+
const subset = new Map();
|
|
382
|
+
for (let c = startCol; c <= endCol; c++) {
|
|
383
|
+
const cell = rowMap?.get(c);
|
|
384
|
+
if (cell)
|
|
385
|
+
subset.set(c, { ...cell });
|
|
386
|
+
}
|
|
387
|
+
rows.push({ rowIdx: r, cells: subset });
|
|
388
|
+
}
|
|
389
|
+
rows.sort((a, b) => {
|
|
390
|
+
const va = a.cells.get(sortCol)?.value;
|
|
391
|
+
const vb = b.cells.get(sortCol)?.value;
|
|
392
|
+
const na = typeof va === 'number' ? va : typeof va === 'string' ? va : '';
|
|
393
|
+
const nb = typeof vb === 'number' ? vb : typeof vb === 'string' ? vb : '';
|
|
394
|
+
let cmp = 0;
|
|
395
|
+
if (typeof na === 'number' && typeof nb === 'number')
|
|
396
|
+
cmp = na - nb;
|
|
397
|
+
else
|
|
398
|
+
cmp = String(na).localeCompare(String(nb));
|
|
399
|
+
return order === 'desc' ? -cmp : cmp;
|
|
400
|
+
});
|
|
401
|
+
for (let i = 0; i < rows.length; i++) {
|
|
402
|
+
const r = startRow + i;
|
|
403
|
+
for (let c = startCol; c <= endCol; c++) {
|
|
404
|
+
const cell = rows[i].cells.get(c);
|
|
405
|
+
const rowMap = this.cells.get(r) ?? new Map();
|
|
406
|
+
if (!this.cells.has(r))
|
|
407
|
+
this.cells.set(r, rowMap);
|
|
408
|
+
if (cell)
|
|
409
|
+
rowMap.set(c, cell);
|
|
410
|
+
else
|
|
411
|
+
rowMap.delete(c);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return this;
|
|
415
|
+
}
|
|
416
|
+
fillNumber(startRow, col, count, startValue = 0, step = 1) {
|
|
417
|
+
for (let i = 0; i < count; i++) {
|
|
418
|
+
this.setValue(startRow + i, col, startValue + i * step);
|
|
419
|
+
}
|
|
420
|
+
return this;
|
|
421
|
+
}
|
|
422
|
+
fillDate(startRow, col, count, startDate, unit = 'day', step = 1) {
|
|
423
|
+
for (let i = 0; i < count; i++) {
|
|
424
|
+
const d = new Date(startDate);
|
|
425
|
+
switch (unit) {
|
|
426
|
+
case 'day':
|
|
427
|
+
d.setDate(d.getDate() + i * step);
|
|
428
|
+
break;
|
|
429
|
+
case 'week':
|
|
430
|
+
d.setDate(d.getDate() + i * step * 7);
|
|
431
|
+
break;
|
|
432
|
+
case 'month':
|
|
433
|
+
d.setMonth(d.getMonth() + i * step);
|
|
434
|
+
break;
|
|
435
|
+
case 'year':
|
|
436
|
+
d.setFullYear(d.getFullYear() + i * step);
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
this.setValue(startRow + i, col, d);
|
|
440
|
+
}
|
|
441
|
+
return this;
|
|
442
|
+
}
|
|
443
|
+
fillList(startRow, col, list, count) {
|
|
444
|
+
for (let i = 0; i < count; i++) {
|
|
445
|
+
this.setValue(startRow + i, col, list[i % list.length]);
|
|
446
|
+
}
|
|
447
|
+
return this;
|
|
448
|
+
}
|
|
449
|
+
autoFitColumns(minWidth = 8, maxWidth = 60) {
|
|
450
|
+
const range = this.getUsedRange();
|
|
451
|
+
if (!range)
|
|
452
|
+
return this;
|
|
453
|
+
for (let c = range.startCol; c <= range.endCol; c++) {
|
|
454
|
+
let maxLen = 0;
|
|
455
|
+
for (let r = range.startRow; r <= range.endRow; r++) {
|
|
456
|
+
const cell = this.cells.get(r)?.get(c);
|
|
457
|
+
if (cell?.value != null) {
|
|
458
|
+
const s = String(cell.value);
|
|
459
|
+
if (s.length > maxLen)
|
|
460
|
+
maxLen = s.length;
|
|
461
|
+
}
|
|
462
|
+
if (cell?.richText) {
|
|
463
|
+
const s = cell.richText.map(r => r.text).join('');
|
|
464
|
+
if (s.length > maxLen)
|
|
465
|
+
maxLen = s.length;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (maxLen > 0) {
|
|
469
|
+
const w = Math.max(minWidth, Math.min(maxWidth, maxLen * 1.2 + 2));
|
|
470
|
+
this.setColumn(c, { ...(this.colDefs.get(c) ?? {}), width: w, customWidth: true });
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return this;
|
|
474
|
+
}
|
|
475
|
+
duplicateRow(sourceRow, targetRow) {
|
|
476
|
+
this.insertRows(targetRow, 1);
|
|
477
|
+
const srcMap = this.cells.get(sourceRow >= targetRow ? sourceRow + 1 : sourceRow);
|
|
478
|
+
if (srcMap) {
|
|
479
|
+
const newMap = new Map();
|
|
480
|
+
for (const [c, cell] of srcMap) {
|
|
481
|
+
newMap.set(c, { ...cell, style: cell.style ? { ...cell.style } : undefined });
|
|
482
|
+
}
|
|
483
|
+
this.cells.set(targetRow, newMap);
|
|
484
|
+
}
|
|
485
|
+
const srcDef = this.rowDefs.get(sourceRow >= targetRow ? sourceRow + 1 : sourceRow);
|
|
486
|
+
if (srcDef)
|
|
487
|
+
this.rowDefs.set(targetRow, { ...srcDef });
|
|
488
|
+
return this;
|
|
489
|
+
}
|
|
490
|
+
spliceRows(startRow, deleteCount, newRows) {
|
|
491
|
+
if (deleteCount > 0)
|
|
492
|
+
this.deleteRows(startRow, deleteCount);
|
|
493
|
+
if (newRows && newRows.length > 0) {
|
|
494
|
+
this.insertRows(startRow, newRows.length);
|
|
495
|
+
for (let i = 0; i < newRows.length; i++) {
|
|
496
|
+
this.writeRow(startRow + i, 1, newRows[i]);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return this;
|
|
500
|
+
}
|
|
501
|
+
setAutoFilter(ref, opts) {
|
|
502
|
+
this.autoFilter = { ref };
|
|
503
|
+
if (opts?.columns) {
|
|
504
|
+
this._filterColumns = opts.columns;
|
|
505
|
+
}
|
|
506
|
+
return this;
|
|
507
|
+
}
|
|
144
508
|
addSparkline(s) {
|
|
145
509
|
this.sparklines.push(s);
|
|
146
510
|
return this;
|
|
147
511
|
}
|
|
512
|
+
getSparklines() { return this.sparklines; }
|
|
148
513
|
addDataValidation(sqref, dv) {
|
|
149
514
|
this.dataValidations.set(sqref, dv);
|
|
150
515
|
return this;
|
|
151
516
|
}
|
|
517
|
+
addRowBreak(row, manual = true) {
|
|
518
|
+
this.rowBreaks.push({ id: row, manual });
|
|
519
|
+
return this;
|
|
520
|
+
}
|
|
521
|
+
addColBreak(col, manual = true) {
|
|
522
|
+
this.colBreaks.push({ id: col, manual });
|
|
523
|
+
return this;
|
|
524
|
+
}
|
|
525
|
+
getRowBreaks() { return this.rowBreaks; }
|
|
526
|
+
getColBreaks() { return this.colBreaks; }
|
|
527
|
+
addFormControl(ctrl) {
|
|
528
|
+
if (!ctrl.to && (ctrl.width || ctrl.height)) {
|
|
529
|
+
const COL_PX = 64, ROW_PX = 20;
|
|
530
|
+
const w = ctrl.width ?? 100, h = ctrl.height ?? 30;
|
|
531
|
+
const endColFrac = ctrl.from.col + w / COL_PX;
|
|
532
|
+
const endRowFrac = ctrl.from.row + h / ROW_PX;
|
|
533
|
+
ctrl = { ...ctrl, to: {
|
|
534
|
+
col: Math.floor(endColFrac),
|
|
535
|
+
row: Math.floor(endRowFrac),
|
|
536
|
+
colOff: Math.round((endColFrac % 1) * COL_PX),
|
|
537
|
+
rowOff: Math.round((endRowFrac % 1) * ROW_PX),
|
|
538
|
+
} };
|
|
539
|
+
}
|
|
540
|
+
this.formControls.push(ctrl);
|
|
541
|
+
return this;
|
|
542
|
+
}
|
|
543
|
+
getFormControls() { return this.formControls; }
|
|
544
|
+
addShape(shape) { this.shapes.push(shape); return this; }
|
|
545
|
+
getShapes() { return this.shapes; }
|
|
546
|
+
addOleObject(obj) { this.oleObjects.push(obj); return this; }
|
|
547
|
+
getOleObjects() { return this.oleObjects; }
|
|
548
|
+
addWordArt(wa) { this.wordArt.push(wa); return this; }
|
|
549
|
+
getWordArt() { return this.wordArt; }
|
|
550
|
+
addQueryTable(qt) { this.queryTables.push(qt); return this; }
|
|
551
|
+
getQueryTables() { return this.queryTables; }
|
|
552
|
+
addTableSlicer(slicer) { this.tableSlicers.push(slicer); return this; }
|
|
553
|
+
getTableSlicers() { return this.tableSlicers; }
|
|
554
|
+
addMathEquation(eq) { this.mathEquations.push(eq); return this; }
|
|
555
|
+
getMathEquations() { return this.mathEquations; }
|
|
556
|
+
addIgnoredError(sqref, opts) {
|
|
557
|
+
this.ignoreErrors.push({ sqref, ...opts });
|
|
558
|
+
return this;
|
|
559
|
+
}
|
|
560
|
+
getIgnoredErrors() { return this.ignoreErrors; }
|
|
561
|
+
addPreservedXml(xml) {
|
|
562
|
+
this.preservedXml.push(xml);
|
|
563
|
+
return this;
|
|
564
|
+
}
|
|
152
565
|
freeze(row, col) {
|
|
153
566
|
this.freezePane = { row, col };
|
|
154
567
|
return this;
|
|
@@ -165,27 +578,39 @@ export class Worksheet {
|
|
|
165
578
|
const mergesXml = this._mergesXml();
|
|
166
579
|
const cfXml = this._conditionalFormatXml(styles);
|
|
167
580
|
const dvXml = this._dataValidationsXml();
|
|
168
|
-
const autoFilterXml = this.autoFilter
|
|
581
|
+
const autoFilterXml = this.autoFilter && !this.tables.some(t => t.ref === this.autoFilter.ref)
|
|
582
|
+
? this._autoFilterXml() : '';
|
|
169
583
|
const tablePartsXml = this.tables.length
|
|
170
584
|
? `<tableParts count="${this.tables.length}">${this.tableRIds.map(rId => `<tablePart r:id="${rId}"/>`).join('')}</tableParts>`
|
|
171
585
|
: '';
|
|
172
|
-
const drawingXml =
|
|
586
|
+
const drawingXml = this.drawingRId
|
|
173
587
|
? `<drawing r:id="${this.drawingRId}"/>`
|
|
174
588
|
: '';
|
|
175
589
|
const legacyDrawingXml = this.legacyDrawingRId
|
|
176
590
|
? `<legacyDrawing r:id="${this.legacyDrawingRId}"/>`
|
|
177
591
|
: '';
|
|
592
|
+
const controlsXml = this._formControlsXml();
|
|
593
|
+
const oleObjectsXml = this._oleObjectsXml();
|
|
178
594
|
const sparklineXml = this._sparklineXml();
|
|
595
|
+
const customIconExtXml = this._customIconExtXml();
|
|
596
|
+
const slicerExtXml = this.slicerRId
|
|
597
|
+
? `<extLst><ext uri="{A8765BA9-456A-4dab-B4F3-ACF838C121DE}" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"><x14:slicerList><x14:slicer r:id="${this.slicerRId}"/></x14:slicerList></ext></extLst>`
|
|
598
|
+
: '';
|
|
599
|
+
const ignoredErrorsXml = this._ignoredErrorsXml();
|
|
179
600
|
const protectionXml = this._protectionXml();
|
|
180
601
|
const pageSetupXml = this._pageSetupXml();
|
|
181
602
|
const pageMarginsXml = this._pageMarginsXml();
|
|
182
603
|
const headerFooterXml = this._headerFooterXml();
|
|
183
604
|
const printOptionsXml = this._printOptionsXml();
|
|
605
|
+
const rowBreaksXml = this._pageBreaksXml('rowBreaks', this.rowBreaks, 16383);
|
|
606
|
+
const colBreaksXml = this._pageBreaksXml('colBreaks', this.colBreaks, 1048575);
|
|
184
607
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
185
608
|
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
186
609
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
|
187
610
|
xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
|
|
188
|
-
xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision"
|
|
611
|
+
xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision"
|
|
612
|
+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
613
|
+
xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">
|
|
189
614
|
${sheetPrXml}
|
|
190
615
|
${sheetViewXml}
|
|
191
616
|
${colsXml}
|
|
@@ -199,11 +624,46 @@ ${printOptionsXml}
|
|
|
199
624
|
${pageMarginsXml}
|
|
200
625
|
${pageSetupXml}
|
|
201
626
|
${headerFooterXml}
|
|
627
|
+
${rowBreaksXml}
|
|
628
|
+
${colBreaksXml}
|
|
629
|
+
${ignoredErrorsXml}
|
|
202
630
|
${drawingXml}
|
|
203
631
|
${legacyDrawingXml}
|
|
632
|
+
${oleObjectsXml}
|
|
633
|
+
${controlsXml}
|
|
204
634
|
${sparklineXml}
|
|
635
|
+
${customIconExtXml}
|
|
205
636
|
${tablePartsXml}
|
|
637
|
+
${slicerExtXml}
|
|
638
|
+
${this.preservedXml.join('\n')}
|
|
206
639
|
</worksheet>`;
|
|
640
|
+
}
|
|
641
|
+
toChartSheetXml() {
|
|
642
|
+
const pageMarginsXml = this._pageMarginsXml();
|
|
643
|
+
const pageSetupXml = this._pageSetupXml();
|
|
644
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
645
|
+
<chartsheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
646
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
647
|
+
<sheetPr/>
|
|
648
|
+
<sheetViews><sheetView zoomScale="99" workbookViewId="0" zoomToFit="1"/></sheetViews>
|
|
649
|
+
${pageMarginsXml || '<pageMargins left="0.7" right="0.7" top="0.78740157499999996" bottom="0.78740157499999996" header="0.3" footer="0.3"/>'}
|
|
650
|
+
${pageSetupXml}
|
|
651
|
+
<drawing r:id="${this.drawingRId}"/>
|
|
652
|
+
</chartsheet>`;
|
|
653
|
+
}
|
|
654
|
+
toDialogSheetXml(_styles, _shared) {
|
|
655
|
+
const pageMarginsXml = this._pageMarginsXml();
|
|
656
|
+
const legacyDrawingXml = this.legacyDrawingRId
|
|
657
|
+
? `<legacyDrawing r:id="${this.legacyDrawingRId}"/>` : '';
|
|
658
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
659
|
+
<dialogsheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
660
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
661
|
+
<sheetViews><sheetView showRowColHeaders="0" showZeros="0" showOutlineSymbols="0" workbookViewId="0"/></sheetViews>
|
|
662
|
+
<sheetFormatPr baseColWidth="10" defaultColWidth="1" defaultRowHeight="5.65" customHeight="1"/>
|
|
663
|
+
<sheetProtection sheet="1"/>
|
|
664
|
+
${pageMarginsXml || '<pageMargins left="0.7" right="0.7" top="0.78740157499999996" bottom="0.78740157499999996" header="0.3" footer="0.3"/>'}
|
|
665
|
+
${legacyDrawingXml}
|
|
666
|
+
</dialogsheet>`;
|
|
207
667
|
}
|
|
208
668
|
_sheetViewXml() {
|
|
209
669
|
const v = this.view ?? {};
|
|
@@ -247,65 +707,85 @@ ${tablePartsXml}
|
|
|
247
707
|
return `<cols>${items.join('')}</cols>`;
|
|
248
708
|
}
|
|
249
709
|
_sheetDataXml(styles, shared) {
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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]) => {
|
|
710
|
+
const sortedRows = [...this.cells.entries()].sort((a, b) => a[0] - b[0]);
|
|
711
|
+
const out = ['<sheetData>'];
|
|
712
|
+
for (let ri = 0; ri < sortedRows.length; ri++) {
|
|
713
|
+
const [rowIdx, colMap] = sortedRows[ri];
|
|
259
714
|
const rowDef = this.rowDefs.get(rowIdx);
|
|
260
715
|
const rowStyleIdx = rowDef?.style ? styles.register(rowDef.style) : 0;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
716
|
+
let attrs = `r="${rowIdx}"`;
|
|
717
|
+
if (rowDef?.height)
|
|
718
|
+
attrs += ` ht="${rowDef.height}" customHeight="1"`;
|
|
719
|
+
if (rowDef?.hidden)
|
|
720
|
+
attrs += ' hidden="1"';
|
|
721
|
+
if (rowDef?.outlineLevel)
|
|
722
|
+
attrs += ` outlineLevel="${rowDef.outlineLevel}"`;
|
|
723
|
+
if (rowDef?.collapsed)
|
|
724
|
+
attrs += ' collapsed="1"';
|
|
725
|
+
if (rowStyleIdx)
|
|
726
|
+
attrs += ` s="${rowStyleIdx}" customFormat="1"`;
|
|
727
|
+
if (rowDef?.thickTop)
|
|
728
|
+
attrs += ' thickTop="1"';
|
|
729
|
+
if (rowDef?.thickBot)
|
|
730
|
+
attrs += ' thickBot="1"';
|
|
731
|
+
out.push(`<row ${attrs}>`);
|
|
732
|
+
const sortedCells = [...colMap.entries()].sort((a, b) => a[0] - b[0]);
|
|
733
|
+
for (let ci = 0; ci < sortedCells.length; ci++) {
|
|
734
|
+
out.push(this._cellXml(rowIdx, sortedCells[ci][0], sortedCells[ci][1], styles, shared));
|
|
735
|
+
}
|
|
736
|
+
out.push('</row>');
|
|
737
|
+
}
|
|
738
|
+
out.push('</sheetData>');
|
|
739
|
+
return out.join('');
|
|
276
740
|
}
|
|
277
741
|
_cellXml(row, col, cell, styles, shared) {
|
|
278
742
|
const ref = `${colIndexToLetter(col)}${row}`;
|
|
279
743
|
const styleIdx = cell.style ? styles.register(cell.style) : 0;
|
|
280
744
|
const sAttr = styleIdx ? ` s="${styleIdx}"` : '';
|
|
745
|
+
const vmIdx = this._cellImageVm.get(ref);
|
|
746
|
+
const vmAttr = vmIdx !== undefined ? ` vm="${vmIdx}"` : '';
|
|
281
747
|
if (cell.arrayFormula) {
|
|
282
|
-
const fml = `<f t="array" ref="${ref}">${
|
|
283
|
-
return `<c r="${ref}"${sAttr}>${fml}<v>0</v></c>`;
|
|
748
|
+
const fml = `<f t="array" ref="${ref}">${escapeXmlContent(cell.arrayFormula)}</f>`;
|
|
749
|
+
return `<c r="${ref}"${sAttr}${vmAttr}>${fml}<v>0</v></c>`;
|
|
750
|
+
}
|
|
751
|
+
if (cell._sharedIdx !== undefined) {
|
|
752
|
+
const si = cell._sharedIdx;
|
|
753
|
+
const sharedRef = cell._sharedRef;
|
|
754
|
+
if (cell.formula && sharedRef) {
|
|
755
|
+
const fml = `<f t="shared" ref="${sharedRef}" si="${si}">${escapeXmlContent(cell.formula)}</f>`;
|
|
756
|
+
return `<c r="${ref}"${sAttr}${vmAttr}>${fml}</c>`;
|
|
757
|
+
}
|
|
758
|
+
return `<c r="${ref}"${sAttr}${vmAttr}><f t="shared" si="${si}"/></c>`;
|
|
284
759
|
}
|
|
285
760
|
if (cell.formula) {
|
|
286
|
-
const fml = `<f>${
|
|
287
|
-
return `<c r="${ref}"${sAttr}>${fml}</c>`;
|
|
761
|
+
const fml = `<f>${escapeXmlContent(cell.formula)}</f>`;
|
|
762
|
+
return `<c r="${ref}"${sAttr}${vmAttr}>${fml}</c>`;
|
|
288
763
|
}
|
|
289
764
|
if (cell.richText) {
|
|
290
765
|
const si = shared.internRichText(cell.richText);
|
|
291
|
-
return `<c r="${ref}" t="s"${sAttr}><v>${si}</v></c>`;
|
|
766
|
+
return `<c r="${ref}" t="s"${sAttr}${vmAttr}><v>${si}</v></c>`;
|
|
292
767
|
}
|
|
293
768
|
const v = cell.value;
|
|
294
769
|
if (v === null || v === undefined) {
|
|
770
|
+
if (vmAttr)
|
|
771
|
+
return `<c r="${ref}"${sAttr} t="e"${vmAttr}><v>#VALUE!</v></c>`;
|
|
295
772
|
return styleIdx ? `<c r="${ref}"${sAttr}/>` : '';
|
|
296
773
|
}
|
|
774
|
+
if (v instanceof CellError) {
|
|
775
|
+
return `<c r="${ref}" t="e"${sAttr}${vmAttr}><v>${escapeXml(v.error)}</v></c>`;
|
|
776
|
+
}
|
|
297
777
|
if (typeof v === 'boolean') {
|
|
298
|
-
return `<c r="${ref}" t="b"${sAttr}><v>${v ? 1 : 0}</v></c>`;
|
|
778
|
+
return `<c r="${ref}" t="b"${sAttr}${vmAttr}><v>${v ? 1 : 0}</v></c>`;
|
|
299
779
|
}
|
|
300
780
|
if (v instanceof Date) {
|
|
301
781
|
const serial = dateToSerial(v);
|
|
302
|
-
return `<c r="${ref}"${sAttr}><v>${serial}</v></c>`;
|
|
782
|
+
return `<c r="${ref}"${sAttr}${vmAttr}><v>${serial}</v></c>`;
|
|
303
783
|
}
|
|
304
784
|
if (typeof v === 'number') {
|
|
305
|
-
return `<c r="${ref}"${sAttr}><v>${v}</v></c>`;
|
|
785
|
+
return `<c r="${ref}"${sAttr}${vmAttr}><v>${v}</v></c>`;
|
|
306
786
|
}
|
|
307
787
|
const si = shared.intern(v);
|
|
308
|
-
return `<c r="${ref}" t="s"${sAttr}><v>${si}</v></c>`;
|
|
788
|
+
return `<c r="${ref}" t="s"${sAttr}${vmAttr}><v>${si}</v></c>`;
|
|
309
789
|
}
|
|
310
790
|
_mergesXml() {
|
|
311
791
|
if (!this.merges.length)
|
|
@@ -324,7 +804,7 @@ ${tablePartsXml}
|
|
|
324
804
|
if (cf.colorScale?.type === 'colorScale') {
|
|
325
805
|
const cs = cf.colorScale;
|
|
326
806
|
const cfvos = cs.cfvo.map(v => `<cfvo type="${v.type}"${v.val ? ` val="${v.val}"` : ''}/>`).join('');
|
|
327
|
-
const colors = cs.color.map(c =>
|
|
807
|
+
const colors = cs.color.map(c => colorEl(c)).join('');
|
|
328
808
|
inner = `<colorScale>${cfvos}${colors}</colorScale>`;
|
|
329
809
|
}
|
|
330
810
|
else if (cf.dataBar?.type === 'dataBar') {
|
|
@@ -332,8 +812,7 @@ ${tablePartsXml}
|
|
|
332
812
|
const minCfvo = `<cfvo type="${db.minType ?? 'min'}"${db.minVal != null ? ` val="${db.minVal}"` : ''}/>`;
|
|
333
813
|
const maxCfvo = `<cfvo type="${db.maxType ?? 'max'}"${db.maxVal != null ? ` val="${db.maxVal}"` : ''}/>`;
|
|
334
814
|
const color = db.color ?? db.minColor ?? 'FF638EC6';
|
|
335
|
-
|
|
336
|
-
inner = `<dataBar${db.showValue === false ? ' showValue="0"' : ''}>${minCfvo}${maxCfvo}<color rgb="${rgb}"/></dataBar>`;
|
|
815
|
+
inner = `<dataBar${db.showValue === false ? ' showValue="0"' : ''}>${minCfvo}${maxCfvo}${colorEl(color)}</dataBar>`;
|
|
337
816
|
}
|
|
338
817
|
else if (cf.iconSet?.type === 'iconSet') {
|
|
339
818
|
const is = cf.iconSet;
|
|
@@ -455,6 +934,45 @@ ${tablePartsXml}
|
|
|
455
934
|
].filter(Boolean).join(' ');
|
|
456
935
|
return attrs ? `<printOptions ${attrs}/>` : '';
|
|
457
936
|
}
|
|
937
|
+
_pageBreaksXml(tag, breaks, maxVal) {
|
|
938
|
+
if (!breaks.length)
|
|
939
|
+
return '';
|
|
940
|
+
const manualCount = breaks.filter(b => b.manual !== false).length;
|
|
941
|
+
const brks = breaks.map(b => `<brk id="${b.id}" max="${maxVal}"${b.manual !== false ? ' man="1"' : ''}/>`).join('');
|
|
942
|
+
return `<${tag} count="${breaks.length}" manualBreakCount="${manualCount}">${brks}</${tag}>`;
|
|
943
|
+
}
|
|
944
|
+
_formControlsXml() {
|
|
945
|
+
if (!this.formControls.length || !this.ctrlPropRIds.length)
|
|
946
|
+
return '';
|
|
947
|
+
const baseShapeId = 1025 + this.sheetIndex * 1000;
|
|
948
|
+
let commentCount = 0;
|
|
949
|
+
for (const rowMap of this.cells.values())
|
|
950
|
+
for (const c of rowMap.values())
|
|
951
|
+
if (c.comment)
|
|
952
|
+
commentCount++;
|
|
953
|
+
const controls = this.formControls.map((ctrl, i) => {
|
|
954
|
+
const shapeId = ctrl._shapeId ?? (baseShapeId + commentCount + i);
|
|
955
|
+
const ctrlPropRId = this.ctrlPropRIds[i];
|
|
956
|
+
if (!ctrlPropRId)
|
|
957
|
+
return '';
|
|
958
|
+
const name = ctrl.text ?? `${ctrl.type} ${i + 1}`;
|
|
959
|
+
return `<mc:AlternateContent><mc:Choice Requires="x14"><control shapeId="${shapeId}" r:id="${ctrlPropRId}" name="${escapeXml(name)}"><controlPr defaultSize="0" print="0" autoFill="0" autoPict="0"${ctrl.macro ? ` macro="${escapeXml(ctrl.macro)}"` : ''}><anchor moveWithCells="1"><from><xdr:col>${ctrl.from.col}</xdr:col><xdr:colOff>${ctrl.from.colOff ?? 0}</xdr:colOff><xdr:row>${ctrl.from.row}</xdr:row><xdr:rowOff>${ctrl.from.rowOff ?? 0}</xdr:rowOff></from><to><xdr:col>${ctrl.to.col}</xdr:col><xdr:colOff>${ctrl.to.colOff ?? 0}</xdr:colOff><xdr:row>${ctrl.to.row}</xdr:row><xdr:rowOff>${ctrl.to.rowOff ?? 0}</xdr:rowOff></to></anchor></controlPr></control></mc:Choice></mc:AlternateContent>`;
|
|
960
|
+
}).join('');
|
|
961
|
+
return `<mc:AlternateContent><mc:Choice Requires="x14"><controls>${controls}</controls></mc:Choice></mc:AlternateContent>`;
|
|
962
|
+
}
|
|
963
|
+
_oleObjectsXml() {
|
|
964
|
+
if (!this.oleObjects.length || !this.oleRIds.length)
|
|
965
|
+
return '';
|
|
966
|
+
const baseShapeId = 2025 + this.sheetIndex * 1000;
|
|
967
|
+
const items = this.oleObjects.map((ole, i) => {
|
|
968
|
+
const shapeId = baseShapeId + i;
|
|
969
|
+
const rId = this.oleRIds[i];
|
|
970
|
+
const progId = ole.progId ?? 'Package';
|
|
971
|
+
const link = ole.linkToFile && ole.linkPath ? ` link="${escapeXml(ole.linkPath)}"` : '';
|
|
972
|
+
return `<oleObject progId="${escapeXml(progId)}" shapeId="${shapeId}" r:id="${rId}"${link}/>`;
|
|
973
|
+
}).join('');
|
|
974
|
+
return `<oleObjects>${items}</oleObjects>`;
|
|
975
|
+
}
|
|
458
976
|
_sparklineXml() {
|
|
459
977
|
if (!this.sparklines.length)
|
|
460
978
|
return '';
|
|
@@ -494,23 +1012,117 @@ ${tablePartsXml}
|
|
|
494
1012
|
const inner = `<x14:sparklineGroups xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main">${groups.join('')}</x14:sparklineGroups>`;
|
|
495
1013
|
return `<extLst><ext uri="{05C60535-1F16-4fd2-B633-F4F36F0B64E0}" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main">${inner}</ext></extLst>`;
|
|
496
1014
|
}
|
|
1015
|
+
_customIconExtXml() {
|
|
1016
|
+
const customCFs = this.conditionalFormats.filter(cf => cf.iconSet?.type === 'iconSet' && 'custom' in cf.iconSet && cf.iconSet.custom?.length);
|
|
1017
|
+
if (!customCFs.length)
|
|
1018
|
+
return '';
|
|
1019
|
+
const rules = customCFs.map((cf, i) => {
|
|
1020
|
+
const is = cf.iconSet;
|
|
1021
|
+
const cfvos = is.cfvo.map(v => `<x14:cfvo type="${v.type}"${v.val ? ` val="${v.val}"` : ''}/>`).join('');
|
|
1022
|
+
const icons = is.custom.map(ci => `<x14:cfIcon iconSet="${ci.iconSet}" iconId="${ci.iconId}"/>`).join('');
|
|
1023
|
+
return `<x14:conditionalFormatting xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main"><x14:cfRule type="iconSet" id="{${this._uuid()}}"><x14:iconSet iconSet="${is.iconSet}" custom="1"${is.showValue === false ? ' showValue="0"' : ''}${is.reverse ? ' reverse="1"' : ''}>${cfvos}${icons}</x14:iconSet></x14:cfRule><xm:sqref>${cf.sqref}</xm:sqref></x14:conditionalFormatting>`;
|
|
1024
|
+
}).join('');
|
|
1025
|
+
return `<extLst><ext uri="{78C0D931-6437-407d-A8EE-F0AAD7539E65}" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main">${rules}</ext></extLst>`;
|
|
1026
|
+
}
|
|
1027
|
+
_uuid() {
|
|
1028
|
+
const h = '0123456789ABCDEF';
|
|
1029
|
+
let u = '';
|
|
1030
|
+
for (let i = 0; i < 36; i++) {
|
|
1031
|
+
if (i === 8 || i === 13 || i === 18 || i === 23)
|
|
1032
|
+
u += '-';
|
|
1033
|
+
else if (i === 14)
|
|
1034
|
+
u += '4';
|
|
1035
|
+
else if (i === 19)
|
|
1036
|
+
u += h[(Math.random() * 4 | 0) + 8];
|
|
1037
|
+
else
|
|
1038
|
+
u += h[Math.random() * 16 | 0];
|
|
1039
|
+
}
|
|
1040
|
+
return u;
|
|
1041
|
+
}
|
|
1042
|
+
_autoFilterXml() {
|
|
1043
|
+
if (!this.autoFilter)
|
|
1044
|
+
return '';
|
|
1045
|
+
const cols = this._filterColumns;
|
|
1046
|
+
if (!cols || cols.length === 0)
|
|
1047
|
+
return `<autoFilter ref="${this.autoFilter.ref}"/>`;
|
|
1048
|
+
const colXml = cols.map(fc => {
|
|
1049
|
+
const colId = fc.col - 1;
|
|
1050
|
+
let inner = '';
|
|
1051
|
+
if (fc.type === 'custom') {
|
|
1052
|
+
const op = fc.operator ?? 'greaterThan';
|
|
1053
|
+
inner = `<customFilters><customFilter operator="${op}" val="${fc.val ?? ''}"/></customFilters>`;
|
|
1054
|
+
}
|
|
1055
|
+
else if (fc.type === 'top10') {
|
|
1056
|
+
const attrs = [
|
|
1057
|
+
fc.top === false ? 'top="0"' : '',
|
|
1058
|
+
fc.percent ? 'percent="1"' : '',
|
|
1059
|
+
`val="${fc.val ?? 10}"`,
|
|
1060
|
+
].filter(Boolean).join(' ');
|
|
1061
|
+
inner = `<top10 ${attrs}/>`;
|
|
1062
|
+
}
|
|
1063
|
+
else if (fc.type === 'value' && fc.items) {
|
|
1064
|
+
inner = `<filters>${fc.items.map(v => `<filter val="${escapeXml(String(v))}"/>`).join('')}</filters>`;
|
|
1065
|
+
}
|
|
1066
|
+
else if (fc.type === 'dynamic') {
|
|
1067
|
+
inner = `<dynamicFilter type="${fc.dynamicType ?? 'aboveAverage'}"/>`;
|
|
1068
|
+
}
|
|
1069
|
+
return `<filterColumn colId="${colId}">${inner}</filterColumn>`;
|
|
1070
|
+
}).join('');
|
|
1071
|
+
return `<autoFilter ref="${this.autoFilter.ref}">${colXml}</autoFilter>`;
|
|
1072
|
+
}
|
|
1073
|
+
_ignoredErrorsXml() {
|
|
1074
|
+
if (!this.ignoreErrors.length)
|
|
1075
|
+
return '';
|
|
1076
|
+
const items = this.ignoreErrors.map(ie => {
|
|
1077
|
+
const attrs = [`sqref="${ie.sqref}"`];
|
|
1078
|
+
if (ie.numberStoredAsText)
|
|
1079
|
+
attrs.push('numberStoredAsText="1"');
|
|
1080
|
+
if (ie.formula)
|
|
1081
|
+
attrs.push('formula="1"');
|
|
1082
|
+
if (ie.formulaRange)
|
|
1083
|
+
attrs.push('formulaRange="1"');
|
|
1084
|
+
if (ie.unlockedFormula)
|
|
1085
|
+
attrs.push('unlockedFormula="1"');
|
|
1086
|
+
if (ie.evalError)
|
|
1087
|
+
attrs.push('evalError="1"');
|
|
1088
|
+
if (ie.twoDigitTextYear)
|
|
1089
|
+
attrs.push('twoDigitTextYear="1"');
|
|
1090
|
+
if (ie.emptyRef)
|
|
1091
|
+
attrs.push('emptyRef="1"');
|
|
1092
|
+
if (ie.listDataValidation)
|
|
1093
|
+
attrs.push('listDataValidation="1"');
|
|
1094
|
+
if (ie.calculatedColumn)
|
|
1095
|
+
attrs.push('calculatedColumn="1"');
|
|
1096
|
+
return `<ignoredError ${attrs.join(' ')}/>`;
|
|
1097
|
+
});
|
|
1098
|
+
return `<ignoredErrors>${items.join('')}</ignoredErrors>`;
|
|
1099
|
+
}
|
|
497
1100
|
toDrawingXml(imageRIds, chartRIds) {
|
|
498
1101
|
const parts = [];
|
|
499
1102
|
const EMU = pxToEmu;
|
|
500
1103
|
this.images.forEach((img, i) => {
|
|
501
1104
|
const rId = imageRIds[i];
|
|
502
|
-
const
|
|
503
|
-
const
|
|
504
|
-
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>`;
|
|
1105
|
+
const w = EMU(img.width ?? 100);
|
|
1106
|
+
const h = EMU(img.height ?? 100);
|
|
505
1107
|
let anchor;
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
anchor = `<xdr:
|
|
1108
|
+
let closeTag;
|
|
1109
|
+
if (img.position) {
|
|
1110
|
+
anchor = `<xdr:absoluteAnchor><xdr:pos x="${EMU(img.position.x)}" y="${EMU(img.position.y)}"/><xdr:ext cx="${w}" cy="${h}"/>`;
|
|
1111
|
+
closeTag = `</xdr:absoluteAnchor>`;
|
|
509
1112
|
}
|
|
510
1113
|
else {
|
|
511
|
-
const
|
|
512
|
-
const
|
|
513
|
-
|
|
1114
|
+
const from = img.from;
|
|
1115
|
+
const to = img.to;
|
|
1116
|
+
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>`;
|
|
1117
|
+
if (to) {
|
|
1118
|
+
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>`;
|
|
1119
|
+
anchor = `<xdr:twoCellAnchor editAs="oneCell">${fromXml}${toXml}`;
|
|
1120
|
+
closeTag = `</xdr:twoCellAnchor>`;
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
anchor = `<xdr:oneCellAnchor>${fromXml}<xdr:ext cx="${w}" cy="${h}"/>`;
|
|
1124
|
+
closeTag = `</xdr:oneCellAnchor>`;
|
|
1125
|
+
}
|
|
514
1126
|
}
|
|
515
1127
|
const picXml = `<xdr:pic>
|
|
516
1128
|
<xdr:nvPicPr>
|
|
@@ -523,29 +1135,182 @@ ${tablePartsXml}
|
|
|
523
1135
|
</xdr:blipFill>
|
|
524
1136
|
<xdr:spPr>
|
|
525
1137
|
<a:xfrm xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
|
|
526
|
-
<a:off x="0" y="0"/><a:ext cx="${
|
|
1138
|
+
<a:off x="0" y="0"/><a:ext cx="${w}" cy="${h}"/>
|
|
527
1139
|
</a:xfrm>
|
|
528
1140
|
<a:prstGeom xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" prst="rect"><a:avLst/></a:prstGeom>
|
|
529
1141
|
</xdr:spPr>
|
|
530
1142
|
</xdr:pic>`;
|
|
531
|
-
const closeTag = to ? `</xdr:twoCellAnchor>` : `</xdr:oneCellAnchor>`;
|
|
532
1143
|
parts.push(`${anchor}${picXml}<xdr:clientData/>${closeTag}`);
|
|
533
1144
|
});
|
|
534
1145
|
this.charts.forEach((chart, i) => {
|
|
535
1146
|
const rId = chartRIds[i];
|
|
536
1147
|
const from = chart.from;
|
|
537
1148
|
const to = chart.to;
|
|
538
|
-
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>`;
|
|
539
|
-
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>`;
|
|
540
1149
|
const graphicXml = `<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
|
|
541
1150
|
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/chart">
|
|
542
1151
|
<c:chart xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" r:id="${rId}"/>
|
|
543
1152
|
</a:graphicData>
|
|
544
1153
|
</a:graphic>`;
|
|
545
|
-
|
|
1154
|
+
if (this._isChartSheet) {
|
|
1155
|
+
parts.push(`<xdr:absoluteAnchor><xdr:pos x="0" y="0"/><xdr:ext cx="9294091" cy="6003636"/><xdr:graphicFrame macro=""><xdr:nvGraphicFramePr><xdr:cNvPr id="${this.images.length + i + 2}" name="Chart ${i + 1}"/><xdr:cNvGraphicFramePr><a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noGrp="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:absoluteAnchor>`);
|
|
1156
|
+
}
|
|
1157
|
+
else {
|
|
1158
|
+
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>`;
|
|
1159
|
+
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>`;
|
|
1160
|
+
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>`);
|
|
1161
|
+
}
|
|
546
1162
|
});
|
|
1163
|
+
let shapeCounter = this.images.length + this.charts.length + 2;
|
|
1164
|
+
const toHex6 = (c) => { let h = c.replace(/^#/, ''); if (h.length === 8)
|
|
1165
|
+
h = h.substring(2); return h; };
|
|
1166
|
+
this.shapes.forEach(shape => {
|
|
1167
|
+
const id = shapeCounter++;
|
|
1168
|
+
const from = shape.from;
|
|
1169
|
+
const to = shape.to;
|
|
1170
|
+
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>`;
|
|
1171
|
+
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>`;
|
|
1172
|
+
const fillXml = shape.fillColor
|
|
1173
|
+
? `<a:solidFill><a:srgbClr val="${toHex6(shape.fillColor)}"/></a:solidFill>`
|
|
1174
|
+
: '<a:noFill/>';
|
|
1175
|
+
const lineXml = shape.lineColor
|
|
1176
|
+
? `<a:ln${shape.lineWidth ? ` w="${shape.lineWidth * 12700}"` : ''}><a:solidFill><a:srgbClr val="${toHex6(shape.lineColor)}"/></a:solidFill></a:ln>`
|
|
1177
|
+
: '';
|
|
1178
|
+
const rotAttr = shape.rotation ? ` rot="${shape.rotation * 60000}"` : '';
|
|
1179
|
+
const textXml = shape.text ? `<xdr:txBody><a:bodyPr vertOverflow="clip" wrap="square" rtlCol="0" anchor="ctr"/><a:lstStyle/><a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US"${shape.font?.bold ? ' b="1"' : ''}${shape.font?.size ? ` sz="${shape.font.size * 100}"` : ''}/><a:t>${escapeXml(shape.text)}</a:t></a:r></a:p></xdr:txBody>` : '';
|
|
1180
|
+
parts.push(`<xdr:twoCellAnchor editAs="oneCell">${fromXml}${toXml}<xdr:sp><xdr:nvSpPr><xdr:cNvPr id="${id}" name="Shape ${id}"/><xdr:cNvSpPr/></xdr:nvSpPr><xdr:spPr><a:xfrm${rotAttr}><a:off x="0" y="0"/><a:ext cx="0" cy="0"/></a:xfrm><a:prstGeom prst="${shape.type}"><a:avLst/></a:prstGeom>${fillXml}${lineXml}</xdr:spPr>${textXml}</xdr:sp><xdr:clientData/></xdr:twoCellAnchor>`);
|
|
1181
|
+
});
|
|
1182
|
+
this.wordArt.forEach(wa => {
|
|
1183
|
+
const id = shapeCounter++;
|
|
1184
|
+
const from = wa.from;
|
|
1185
|
+
const to = wa.to;
|
|
1186
|
+
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>`;
|
|
1187
|
+
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>`;
|
|
1188
|
+
const preset = wa.preset ?? 'textPlain';
|
|
1189
|
+
const fontSize = wa.font?.size ? wa.font.size * 100 : 3600;
|
|
1190
|
+
const fillHex = wa.fillColor ? toHex6(wa.fillColor) : '';
|
|
1191
|
+
const outlineHex = wa.outlineColor ? toHex6(wa.outlineColor) : '';
|
|
1192
|
+
const textFillXml = fillHex
|
|
1193
|
+
? `<a:solidFill><a:srgbClr val="${fillHex}"/></a:solidFill>`
|
|
1194
|
+
: '<a:solidFill><a:schemeClr val="tx1"/></a:solidFill>';
|
|
1195
|
+
const textOutlineXml = outlineHex
|
|
1196
|
+
? `<a:ln w="12700"><a:solidFill><a:srgbClr val="${outlineHex}"/></a:solidFill><a:prstDash val="solid"/></a:ln>`
|
|
1197
|
+
: '';
|
|
1198
|
+
const effectXml = `<a:effectLst><a:outerShdw dist="38100" dir="2700000" algn="bl" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="40000"/></a:srgbClr></a:outerShdw></a:effectLst>`;
|
|
1199
|
+
const fontAttrs = [
|
|
1200
|
+
'lang="en-US"',
|
|
1201
|
+
`sz="${fontSize}"`,
|
|
1202
|
+
wa.font?.bold ? 'b="1"' : 'b="1"',
|
|
1203
|
+
wa.font?.italic ? 'i="1"' : '',
|
|
1204
|
+
'cap="none" spc="0"',
|
|
1205
|
+
].filter(Boolean).join(' ');
|
|
1206
|
+
const fontFace = wa.font?.name ?? 'Calibri';
|
|
1207
|
+
const prstWarpXml = preset !== 'textPlain'
|
|
1208
|
+
? `<a:prstTxWarp prst="${preset}"><a:avLst/></a:prstTxWarp>`
|
|
1209
|
+
: '';
|
|
1210
|
+
parts.push(`<xdr:twoCellAnchor editAs="oneCell">${fromXml}${toXml}<xdr:sp macro="" textlink=""><xdr:nvSpPr><xdr:cNvPr id="${id}" name="WordArt ${id}"/><xdr:cNvSpPr/></xdr:nvSpPr><xdr:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/></xdr:spPr><xdr:txBody><a:bodyPr wrap="square" lIns="91440" tIns="45720" rIns="91440" bIns="45720">${prstWarpXml}<a:spAutoFit/></a:bodyPr><a:lstStyle/><a:p><a:pPr algn="ctr"/><a:r><a:rPr ${fontAttrs}>${textOutlineXml}${textFillXml}${effectXml}<a:latin typeface="${escapeXml(fontFace)}"/></a:rPr><a:t>${escapeXml(wa.text)}</a:t></a:r></a:p></xdr:txBody></xdr:sp><xdr:clientData/></xdr:twoCellAnchor>`);
|
|
1211
|
+
});
|
|
1212
|
+
this.mathEquations.forEach(eq => {
|
|
1213
|
+
const id = shapeCounter++;
|
|
1214
|
+
const from = eq.from;
|
|
1215
|
+
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>`;
|
|
1216
|
+
const w = eq.width ?? 1800000;
|
|
1217
|
+
const h = eq.height ?? 500000;
|
|
1218
|
+
const extXml = `<xdr:ext cx="${w}" cy="${h}"/>`;
|
|
1219
|
+
const fontSize = eq.fontSize ? eq.fontSize * 100 : 1100;
|
|
1220
|
+
const fontName = eq.fontName ?? 'Cambria Math';
|
|
1221
|
+
const rPr = `<a:rPr lang="en-US" sz="${fontSize}" i="1"><a:latin typeface="${escapeXml(fontName)}" panose="02040503050406030204" pitchFamily="18" charset="0"/></a:rPr>`;
|
|
1222
|
+
const ctrlPr = `<m:ctrlPr>${rPr}</m:ctrlPr>`;
|
|
1223
|
+
const buildOmml = (el) => {
|
|
1224
|
+
switch (el.type) {
|
|
1225
|
+
case 'text':
|
|
1226
|
+
return `<m:r>${rPr}<m:t>${escapeXml(el.text ?? '')}</m:t></m:r>`;
|
|
1227
|
+
case 'frac':
|
|
1228
|
+
return `<m:f><m:fPr>${el.hideDegree ? '<m:type m:val="noBar"/>' : ''}${ctrlPr}</m:fPr><m:num>${(el.base ?? []).map(buildOmml).join('')}</m:num><m:den>${(el.argument ?? []).map(buildOmml).join('')}</m:den></m:f>`;
|
|
1229
|
+
case 'sup':
|
|
1230
|
+
return `<m:sSup><m:sSupPr>${ctrlPr}</m:sSupPr><m:e>${(el.base ?? []).map(buildOmml).join('')}</m:e><m:sup>${(el.argument ?? []).map(buildOmml).join('')}</m:sup></m:sSup>`;
|
|
1231
|
+
case 'sub':
|
|
1232
|
+
return `<m:sSub><m:sSubPr>${ctrlPr}</m:sSubPr><m:e>${(el.base ?? []).map(buildOmml).join('')}</m:e><m:sub>${(el.argument ?? []).map(buildOmml).join('')}</m:sub></m:sSub>`;
|
|
1233
|
+
case 'subSup':
|
|
1234
|
+
return `<m:sSubSup><m:sSubSupPr>${ctrlPr}</m:sSubSupPr><m:e>${(el.base ?? []).map(buildOmml).join('')}</m:e><m:sub>${(el.subscript ?? []).map(buildOmml).join('')}</m:sub><m:sup>${(el.superscript ?? []).map(buildOmml).join('')}</m:sup></m:sSubSup>`;
|
|
1235
|
+
case 'nary': {
|
|
1236
|
+
const chr = el.operator ?? '∑';
|
|
1237
|
+
return `<m:nary><m:naryPr><m:chr m:val="${escapeXml(chr)}"/>${ctrlPr}</m:naryPr><m:sub>${(el.lower ?? []).map(buildOmml).join('')}</m:sub><m:sup>${(el.upper ?? []).map(buildOmml).join('')}</m:sup><m:e>${(el.body ?? []).map(buildOmml).join('')}</m:e></m:nary>`;
|
|
1238
|
+
}
|
|
1239
|
+
case 'rad':
|
|
1240
|
+
return `<m:rad><m:radPr>${el.hideDegree ? '<m:degHide m:val="1"/>' : ''}${ctrlPr}</m:radPr><m:deg>${(el.degree ?? []).map(buildOmml).join('')}</m:deg><m:e>${(el.body ?? []).map(buildOmml).join('')}</m:e></m:rad>`;
|
|
1241
|
+
case 'delim': {
|
|
1242
|
+
const open = el.open ?? '(';
|
|
1243
|
+
const close = el.close ?? ')';
|
|
1244
|
+
return `<m:d><m:dPr>${open !== '(' ? `<m:begChr m:val="${escapeXml(open)}"/>` : ''}${close !== ')' ? `<m:endChr m:val="${escapeXml(close)}"/>` : ''}${ctrlPr}</m:dPr><m:e>${(el.body ?? []).map(buildOmml).join('')}</m:e></m:d>`;
|
|
1245
|
+
}
|
|
1246
|
+
case 'func':
|
|
1247
|
+
return `<m:func><m:funcPr>${ctrlPr}</m:funcPr><m:fName>${(el.base ?? []).map(buildOmml).join('')}</m:fName><m:e>${(el.argument ?? []).map(buildOmml).join('')}</m:e></m:func>`;
|
|
1248
|
+
case 'accent':
|
|
1249
|
+
return `<m:acc><m:accPr>${el.operator ? `<m:chr m:val="${escapeXml(el.operator)}"/>` : ''}${ctrlPr}</m:accPr><m:e>${(el.body ?? []).map(buildOmml).join('')}</m:e></m:acc>`;
|
|
1250
|
+
case 'bar':
|
|
1251
|
+
return `<m:bar><m:barPr>${ctrlPr}</m:barPr><m:e>${(el.body ?? []).map(buildOmml).join('')}</m:e></m:bar>`;
|
|
1252
|
+
case 'matrix':
|
|
1253
|
+
return `<m:m><m:mPr>${ctrlPr}</m:mPr>${(el.rows ?? []).map(row => `<m:mr>${row.map(c => `<m:e>${buildOmml(c)}</m:e>`).join('')}</m:mr>`).join('')}</m:m>`;
|
|
1254
|
+
case 'eqArr':
|
|
1255
|
+
return `<m:eqArr><m:eqArrPr>${ctrlPr}</m:eqArrPr>${(el.rows ?? []).map(row => `<m:e>${row.map(buildOmml).join('')}</m:e>`).join('')}</m:eqArr>`;
|
|
1256
|
+
case 'limLow':
|
|
1257
|
+
return `<m:limLow><m:limLowPr>${ctrlPr}</m:limLowPr><m:e>${(el.base ?? []).map(buildOmml).join('')}</m:e><m:lim>${(el.argument ?? []).map(buildOmml).join('')}</m:lim></m:limLow>`;
|
|
1258
|
+
case 'limUpp':
|
|
1259
|
+
return `<m:limUpp><m:limUppPr>${ctrlPr}</m:limUppPr><m:e>${(el.base ?? []).map(buildOmml).join('')}</m:e><m:lim>${(el.argument ?? []).map(buildOmml).join('')}</m:lim></m:limUpp>`;
|
|
1260
|
+
case 'groupChar':
|
|
1261
|
+
return `<m:groupChr><m:groupChrPr>${el.operator ? `<m:chr m:val="${escapeXml(el.operator)}"/>` : ''}${ctrlPr}</m:groupChrPr><m:e>${(el.body ?? []).map(buildOmml).join('')}</m:e></m:groupChr>`;
|
|
1262
|
+
default:
|
|
1263
|
+
return `<m:r>${rPr}<m:t>${escapeXml(el.text ?? '')}</m:t></m:r>`;
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
const ommlBody = eq.elements.map(buildOmml).join('');
|
|
1267
|
+
const ommlXml = `<m:oMathPara xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"><m:oMathParaPr><m:jc m:val="centerGroup"/></m:oMathParaPr><m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">${ommlBody}</m:oMath></m:oMathPara>`;
|
|
1268
|
+
const flattenText = (el) => {
|
|
1269
|
+
if (el.text)
|
|
1270
|
+
return el.text;
|
|
1271
|
+
const parts = [el.base, el.argument, el.body, el.lower, el.upper, el.superscript, el.subscript, el.degree]
|
|
1272
|
+
.filter(Boolean).map(arr => arr.map(flattenText).join('')).join('');
|
|
1273
|
+
if (el.type === 'frac')
|
|
1274
|
+
return `(${(el.base ?? []).map(flattenText).join('')})/(${(el.argument ?? []).map(flattenText).join('')})`;
|
|
1275
|
+
if (el.type === 'sup')
|
|
1276
|
+
return `${(el.base ?? []).map(flattenText).join('')}^${(el.argument ?? []).map(flattenText).join('')}`;
|
|
1277
|
+
if (el.type === 'nary')
|
|
1278
|
+
return `${el.operator ?? '∑'}(${(el.body ?? []).map(flattenText).join('')})`;
|
|
1279
|
+
if (el.type === 'delim')
|
|
1280
|
+
return `${el.open ?? '('}${(el.body ?? []).map(flattenText).join('')}${el.close ?? ')'}`;
|
|
1281
|
+
if (el.type === 'rad')
|
|
1282
|
+
return `√(${(el.body ?? []).map(flattenText).join('')})`;
|
|
1283
|
+
return parts;
|
|
1284
|
+
};
|
|
1285
|
+
const fallbackText = eq.elements.map(flattenText).join('');
|
|
1286
|
+
parts.push(`<xdr:oneCellAnchor>${fromXml}${extXml}<mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"><mc:Choice xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" Requires="a14"><xdr:sp macro="" textlink=""><xdr:nvSpPr><xdr:cNvPr id="${id}" name="MathEq ${id}"/><xdr:cNvSpPr txBox="1"/></xdr:nvSpPr><xdr:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${w}" cy="${h}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/></xdr:spPr><xdr:txBody><a:bodyPr vertOverflow="clip" horzOverflow="clip" wrap="none" lIns="0" tIns="0" rIns="0" bIns="0" rtlCol="0" anchor="t"><a:spAutoFit/></a:bodyPr><a:lstStyle/><a:p><a14:m>${ommlXml}</a14:m><a:endParaRPr lang="en-US" sz="${fontSize}"/></a:p></xdr:txBody></xdr:sp></mc:Choice><mc:Fallback><xdr:sp macro="" textlink=""><xdr:nvSpPr><xdr:cNvPr id="${id}" name="MathEq ${id}"/><xdr:cNvSpPr txBox="1"/></xdr:nvSpPr><xdr:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${w}" cy="${h}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/></xdr:spPr><xdr:txBody><a:bodyPr vertOverflow="clip" horzOverflow="clip" wrap="none" lIns="0" tIns="0" rIns="0" bIns="0" rtlCol="0" anchor="t"><a:spAutoFit/></a:bodyPr><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" sz="${fontSize}" i="0"><a:latin typeface="${escapeXml(fontName)}" panose="02040503050406030204" pitchFamily="18" charset="0"/></a:rPr><a:t>${escapeXml(fallbackText)}</a:t></a:r><a:endParaRPr lang="en-US" sz="${fontSize}"/></a:p></xdr:txBody></xdr:sp></mc:Fallback></mc:AlternateContent><xdr:clientData/></xdr:oneCellAnchor>`);
|
|
1287
|
+
});
|
|
1288
|
+
this.oleObjects.forEach((ole, i) => {
|
|
1289
|
+
const id = shapeCounter++;
|
|
1290
|
+
const from = ole.from;
|
|
1291
|
+
const to = ole.to;
|
|
1292
|
+
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>`;
|
|
1293
|
+
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>`;
|
|
1294
|
+
const oleRId = this.oleRIds[i] ?? '';
|
|
1295
|
+
const iconRId = this.oleIconRIds[i] ?? '';
|
|
1296
|
+
const progId = ole.progId ?? 'Package';
|
|
1297
|
+
const displayAsIcon = ole.displayAsIcon ? ' showAsIcon="1"' : '';
|
|
1298
|
+
const linkAttr = ole.linkToFile && ole.linkPath ? ` link="${escapeXml(ole.linkPath)}"` : '';
|
|
1299
|
+
const blipRef = iconRId
|
|
1300
|
+
? `<a:blip r:embed="${iconRId}"/><a:stretch><a:fillRect/></a:stretch>`
|
|
1301
|
+
: `<a:blip/><a:stretch><a:fillRect/></a:stretch>`;
|
|
1302
|
+
parts.push(`<xdr:twoCellAnchor editAs="oneCell">${fromXml}${toXml}<xdr:sp macro=""><xdr:nvSpPr><xdr:cNvPr id="${id}" name="${escapeXml(ole.name)}" hidden="1"/><xdr:cNvSpPr/></xdr:nvSpPr><xdr:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></xdr:spPr></xdr:sp><xdr:clientData/></xdr:twoCellAnchor>`);
|
|
1303
|
+
});
|
|
1304
|
+
for (const slicerInfo of this._slicerDrawingInfo) {
|
|
1305
|
+
const id = shapeCounter++;
|
|
1306
|
+
const { row: sRow, col: sCol } = slicerInfo.cell ? cellRefToIndices(slicerInfo.cell) : { row: 1, col: 6 };
|
|
1307
|
+
const fromCol = sCol - 1, fromRow = sRow - 1;
|
|
1308
|
+
const toCol = fromCol + 2, toRow = fromRow + 12;
|
|
1309
|
+
parts.push(`<xdr:twoCellAnchor editAs="oneCell"><xdr:from><xdr:col>${fromCol}</xdr:col><xdr:colOff>0</xdr:colOff><xdr:row>${fromRow}</xdr:row><xdr:rowOff>0</xdr:rowOff></xdr:from><xdr:to><xdr:col>${toCol}</xdr:col><xdr:colOff>0</xdr:colOff><xdr:row>${toRow}</xdr:row><xdr:rowOff>0</xdr:rowOff></xdr:to><mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"><mc:Choice xmlns:sle15="http://schemas.microsoft.com/office/drawing/2012/slicer" Requires="sle15"><xdr:graphicFrame macro=""><xdr:nvGraphicFramePr><xdr:cNvPr id="${id}" name="${escapeXml(slicerInfo.name)}"/><xdr:cNvGraphicFramePr/></xdr:nvGraphicFramePr><xdr:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/></xdr:xfrm><a:graphic><a:graphicData uri="http://schemas.microsoft.com/office/drawing/2010/slicer"><sle:slicer xmlns:sle="http://schemas.microsoft.com/office/drawing/2010/slicer" name="${escapeXml(slicerInfo.name)}"/></a:graphicData></a:graphic></xdr:graphicFrame></mc:Choice><mc:Fallback/></mc:AlternateContent><xdr:clientData/></xdr:twoCellAnchor>`);
|
|
1310
|
+
}
|
|
547
1311
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
548
1312
|
<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
|
|
1313
|
+
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
|
|
549
1314
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
550
1315
|
${parts.join('\n')}
|
|
551
1316
|
</xdr:wsDr>`;
|