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