@node-projects/excelforge 2.3.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 -66
- 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,68 +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>`;
|
|
306
|
-
}
|
|
307
|
-
if (typeof v === 'string' && v.startsWith('=')) {
|
|
308
|
-
return `<c r="${ref}"${sAttr}><f>${escapeXml(v.slice(1))}</f></c>`;
|
|
778
|
+
return `<c r="${ref}"${sAttr}${vmAttr}><v>${v}</v></c>`;
|
|
309
779
|
}
|
|
310
780
|
const si = shared.intern(v);
|
|
311
|
-
return `<c r="${ref}" t="s"${sAttr}><v>${si}</v></c>`;
|
|
781
|
+
return `<c r="${ref}" t="s"${sAttr}${vmAttr}><v>${si}</v></c>`;
|
|
312
782
|
}
|
|
313
783
|
_mergesXml() {
|
|
314
784
|
if (!this.merges.length)
|
|
@@ -327,7 +797,7 @@ ${tablePartsXml}
|
|
|
327
797
|
if (cf.colorScale?.type === 'colorScale') {
|
|
328
798
|
const cs = cf.colorScale;
|
|
329
799
|
const cfvos = cs.cfvo.map(v => `<cfvo type="${v.type}"${v.val ? ` val="${v.val}"` : ''}/>`).join('');
|
|
330
|
-
const colors = cs.color.map(c =>
|
|
800
|
+
const colors = cs.color.map(c => colorEl(c)).join('');
|
|
331
801
|
inner = `<colorScale>${cfvos}${colors}</colorScale>`;
|
|
332
802
|
}
|
|
333
803
|
else if (cf.dataBar?.type === 'dataBar') {
|
|
@@ -335,8 +805,7 @@ ${tablePartsXml}
|
|
|
335
805
|
const minCfvo = `<cfvo type="${db.minType ?? 'min'}"${db.minVal != null ? ` val="${db.minVal}"` : ''}/>`;
|
|
336
806
|
const maxCfvo = `<cfvo type="${db.maxType ?? 'max'}"${db.maxVal != null ? ` val="${db.maxVal}"` : ''}/>`;
|
|
337
807
|
const color = db.color ?? db.minColor ?? 'FF638EC6';
|
|
338
|
-
|
|
339
|
-
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>`;
|
|
340
809
|
}
|
|
341
810
|
else if (cf.iconSet?.type === 'iconSet') {
|
|
342
811
|
const is = cf.iconSet;
|
|
@@ -458,6 +927,32 @@ ${tablePartsXml}
|
|
|
458
927
|
].filter(Boolean).join(' ');
|
|
459
928
|
return attrs ? `<printOptions ${attrs}/>` : '';
|
|
460
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
|
+
}
|
|
461
956
|
_sparklineXml() {
|
|
462
957
|
if (!this.sparklines.length)
|
|
463
958
|
return '';
|
|
@@ -497,23 +992,117 @@ ${tablePartsXml}
|
|
|
497
992
|
const inner = `<x14:sparklineGroups xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main">${groups.join('')}</x14:sparklineGroups>`;
|
|
498
993
|
return `<extLst><ext uri="{05C60535-1F16-4fd2-B633-F4F36F0B64E0}" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main">${inner}</ext></extLst>`;
|
|
499
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
|
+
}
|
|
500
1080
|
toDrawingXml(imageRIds, chartRIds) {
|
|
501
1081
|
const parts = [];
|
|
502
1082
|
const EMU = pxToEmu;
|
|
503
1083
|
this.images.forEach((img, i) => {
|
|
504
1084
|
const rId = imageRIds[i];
|
|
505
|
-
const
|
|
506
|
-
const
|
|
507
|
-
const fromXml = `<xdr:from><xdr:col>${from.col}</xdr:col><xdr:colOff>${from.colOff ?? 0}</xdr:colOff><xdr:row>${from.row}</xdr:row><xdr:rowOff>${from.rowOff ?? 0}</xdr:rowOff></xdr:from>`;
|
|
1085
|
+
const w = EMU(img.width ?? 100);
|
|
1086
|
+
const h = EMU(img.height ?? 100);
|
|
508
1087
|
let anchor;
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
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>`;
|
|
512
1092
|
}
|
|
513
1093
|
else {
|
|
514
|
-
const
|
|
515
|
-
const
|
|
516
|
-
|
|
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
|
+
}
|
|
517
1106
|
}
|
|
518
1107
|
const picXml = `<xdr:pic>
|
|
519
1108
|
<xdr:nvPicPr>
|
|
@@ -526,29 +1115,166 @@ ${tablePartsXml}
|
|
|
526
1115
|
</xdr:blipFill>
|
|
527
1116
|
<xdr:spPr>
|
|
528
1117
|
<a:xfrm xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
|
|
529
|
-
<a:off x="0" y="0"/><a:ext cx="${
|
|
1118
|
+
<a:off x="0" y="0"/><a:ext cx="${w}" cy="${h}"/>
|
|
530
1119
|
</a:xfrm>
|
|
531
1120
|
<a:prstGeom xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" prst="rect"><a:avLst/></a:prstGeom>
|
|
532
1121
|
</xdr:spPr>
|
|
533
1122
|
</xdr:pic>`;
|
|
534
|
-
const closeTag = to ? `</xdr:twoCellAnchor>` : `</xdr:oneCellAnchor>`;
|
|
535
1123
|
parts.push(`${anchor}${picXml}<xdr:clientData/>${closeTag}`);
|
|
536
1124
|
});
|
|
537
1125
|
this.charts.forEach((chart, i) => {
|
|
538
1126
|
const rId = chartRIds[i];
|
|
539
1127
|
const from = chart.from;
|
|
540
1128
|
const to = chart.to;
|
|
541
|
-
const fromXml = `<xdr:from><xdr:col>${from.col}</xdr:col><xdr:colOff>${from.colOff ?? 0}</xdr:colOff><xdr:row>${from.row}</xdr:row><xdr:rowOff>${from.rowOff ?? 0}</xdr:rowOff></xdr:from>`;
|
|
542
|
-
const toXml = `<xdr:to><xdr:col>${to.col}</xdr:col><xdr:colOff>${to.colOff ?? 0}</xdr:colOff><xdr:row>${to.row}</xdr:row><xdr:rowOff>${to.rowOff ?? 0}</xdr:rowOff></xdr:to>`;
|
|
543
1129
|
const graphicXml = `<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
|
|
544
1130
|
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/chart">
|
|
545
1131
|
<c:chart xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" r:id="${rId}"/>
|
|
546
1132
|
</a:graphicData>
|
|
547
1133
|
</a:graphic>`;
|
|
548
|
-
|
|
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>`);
|
|
549
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
|
+
}
|
|
550
1275
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
551
1276
|
<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
|
|
1277
|
+
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
|
|
552
1278
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
553
1279
|
${parts.join('\n')}
|
|
554
1280
|
</xdr:wsDr>`;
|