@node-projects/excelforge 2.4.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/FUNDING.yml +4 -0
- package/FEATURES.md +294 -0
- package/README.md +628 -12
- package/dist/core/SharedStrings.js +6 -2
- package/dist/core/SharedStrings.js.map +1 -1
- package/dist/core/Workbook.d.ts +43 -1
- package/dist/core/Workbook.js +881 -58
- package/dist/core/Workbook.js.map +1 -1
- package/dist/core/WorkbookReader.d.ts +18 -4
- package/dist/core/WorkbookReader.js +1386 -20
- package/dist/core/WorkbookReader.js.map +1 -1
- package/dist/core/Worksheet.d.ts +136 -2
- package/dist/core/Worksheet.js +828 -63
- package/dist/core/Worksheet.js.map +1 -1
- package/dist/core/types.d.ts +311 -5
- package/dist/core/types.js +12 -1
- package/dist/core/types.js.map +1 -1
- package/dist/features/ChartBuilder.d.ts +9 -1
- package/dist/features/ChartBuilder.js +140 -14
- package/dist/features/ChartBuilder.js.map +1 -1
- package/dist/features/CsvModule.d.ts +11 -0
- package/dist/features/CsvModule.js +137 -0
- package/dist/features/CsvModule.js.map +1 -0
- package/dist/features/Encryption.d.ts +6 -0
- package/dist/features/Encryption.js +806 -0
- package/dist/features/Encryption.js.map +1 -0
- package/dist/features/FormControlBuilder.d.ts +6 -0
- package/dist/features/FormControlBuilder.js +135 -0
- package/dist/features/FormControlBuilder.js.map +1 -0
- package/dist/features/FormulaEngine.d.ts +22 -0
- package/dist/features/FormulaEngine.js +498 -0
- package/dist/features/FormulaEngine.js.map +1 -0
- package/dist/features/HtmlModule.d.ts +22 -0
- package/dist/features/HtmlModule.js +1441 -0
- package/dist/features/HtmlModule.js.map +1 -0
- package/dist/features/JsonModule.d.ts +10 -0
- package/dist/features/JsonModule.js +76 -0
- package/dist/features/JsonModule.js.map +1 -0
- package/dist/features/PdfModule.d.ts +30 -0
- package/dist/features/PdfModule.js +1567 -0
- package/dist/features/PdfModule.js.map +1 -0
- package/dist/features/PivotTableBuilder.d.ts +7 -0
- package/dist/features/PivotTableBuilder.js +170 -0
- package/dist/features/PivotTableBuilder.js.map +1 -0
- package/dist/features/Signing.d.ts +12 -0
- package/dist/features/Signing.js +326 -0
- package/dist/features/Signing.js.map +1 -0
- package/dist/features/TableBuilder.js +2 -2
- package/dist/features/TableBuilder.js.map +1 -1
- package/dist/index-min.js +609 -147
- package/dist/index.d.ts +19 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/styles/StyleRegistry.d.ts +14 -0
- package/dist/styles/StyleRegistry.js +95 -30
- package/dist/styles/StyleRegistry.js.map +1 -1
- package/dist/utils/helpers.d.ts +4 -0
- package/dist/utils/helpers.js +64 -14
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/zip.js +145 -73
- package/dist/utils/zip.js.map +1 -1
- package/dist/vba/VbaProject.d.ts +31 -0
- package/dist/vba/VbaProject.js +576 -0
- package/dist/vba/VbaProject.js.map +1 -0
- package/dist/vba/cfb.d.ts +7 -0
- package/dist/vba/cfb.js +352 -0
- package/dist/vba/cfb.js.map +1 -0
- package/dist/vba/ovba.d.ts +2 -0
- package/dist/vba/ovba.js +137 -0
- package/dist/vba/ovba.js.map +1 -0
- package/package.json +4 -3
- package/validator.cs +0 -155
- package/validatorEpplus.cs +0 -27
- package/validatorReadData.cs +0 -111
package/dist/core/Workbook.js
CHANGED
|
@@ -3,20 +3,30 @@ import { StyleRegistry } from '../styles/StyleRegistry.js';
|
|
|
3
3
|
import { SharedStrings } from './SharedStrings.js';
|
|
4
4
|
import { buildChartXml } from '../features/ChartBuilder.js';
|
|
5
5
|
import { buildTableXml } from '../features/TableBuilder.js';
|
|
6
|
+
import { buildPivotTableFiles } from '../features/PivotTableBuilder.js';
|
|
7
|
+
import { buildCtrlPropXml, buildFormControlVmlShape, buildVmlWithControls } from '../features/FormControlBuilder.js';
|
|
8
|
+
import { VbaProject } from '../vba/VbaProject.js';
|
|
6
9
|
import { buildZip } from '../utils/zip.js';
|
|
7
10
|
import { strToBytes, base64ToBytes, escapeXml, colIndexToLetter } from '../utils/helpers.js';
|
|
8
|
-
import { readWorkbook } from './WorkbookReader.js';
|
|
11
|
+
import { readWorkbook, connTypeToNum, cmdTypeToNum } from './WorkbookReader.js';
|
|
9
12
|
import { buildCoreXml, buildAppXml, buildCustomXml, } from './properties.js';
|
|
10
13
|
export class Workbook {
|
|
11
14
|
constructor() {
|
|
12
15
|
this.sheets = [];
|
|
13
16
|
this.namedRanges = [];
|
|
17
|
+
this.connections = [];
|
|
18
|
+
this.powerQueries = [];
|
|
19
|
+
this.externalLinks = [];
|
|
20
|
+
this.customPivotStyles = [];
|
|
21
|
+
this.pivotSlicers = [];
|
|
14
22
|
this.properties = {};
|
|
15
23
|
this.compressionLevel = 6;
|
|
16
24
|
this.coreProperties = {};
|
|
17
25
|
this.extendedProperties = {};
|
|
18
26
|
this.customProperties = [];
|
|
27
|
+
this.isTemplate = false;
|
|
19
28
|
this._dirtySheets = new Set();
|
|
29
|
+
this._customTableStyles = new Map();
|
|
20
30
|
}
|
|
21
31
|
markDirty(sheetIndexOrName) {
|
|
22
32
|
if (typeof sheetIndexOrName === 'string') {
|
|
@@ -49,6 +59,50 @@ export class Workbook {
|
|
|
49
59
|
status: result.core.contentStatus,
|
|
50
60
|
};
|
|
51
61
|
wb.sheets = result.sheets.map(s => s.ws);
|
|
62
|
+
wb.namedRanges = result.namedRanges;
|
|
63
|
+
wb.connections = result.connections;
|
|
64
|
+
wb.powerQueries = result.powerQueries;
|
|
65
|
+
const vbaData = result.unknownParts.get('xl/vbaProject.bin');
|
|
66
|
+
if (vbaData) {
|
|
67
|
+
try {
|
|
68
|
+
wb.vbaProject = VbaProject.fromBytes(vbaData);
|
|
69
|
+
}
|
|
70
|
+
catch { }
|
|
71
|
+
}
|
|
72
|
+
const calcPrMatch = result.workbookXml.match(/<calcPr([^>]*)\/?>/);
|
|
73
|
+
if (calcPrMatch) {
|
|
74
|
+
const a = calcPrMatch[1];
|
|
75
|
+
const cs = {};
|
|
76
|
+
const modeMatch = a.match(/calcMode="([^"]+)"/);
|
|
77
|
+
if (modeMatch)
|
|
78
|
+
cs.calcMode = modeMatch[1];
|
|
79
|
+
if (/fullCalcOnLoad="1"/.test(a))
|
|
80
|
+
cs.fullCalcOnLoad = true;
|
|
81
|
+
else if (/fullCalcOnLoad="0"/.test(a))
|
|
82
|
+
cs.fullCalcOnLoad = false;
|
|
83
|
+
if (/iterate="1"/.test(a))
|
|
84
|
+
cs.iterate = true;
|
|
85
|
+
const icMatch = a.match(/iterateCount="(\d+)"/);
|
|
86
|
+
if (icMatch)
|
|
87
|
+
cs.iterateCount = parseInt(icMatch[1], 10);
|
|
88
|
+
const idMatch = a.match(/iterateDelta="([^"]+)"/);
|
|
89
|
+
if (idMatch)
|
|
90
|
+
cs.iterateDelta = parseFloat(idMatch[1]);
|
|
91
|
+
if (/fullPrecision="1"/.test(a))
|
|
92
|
+
cs.fullPrecision = true;
|
|
93
|
+
else if (/fullPrecision="0"/.test(a))
|
|
94
|
+
cs.fullPrecision = false;
|
|
95
|
+
if (/calcOnSave="1"/.test(a))
|
|
96
|
+
cs.calcOnSave = true;
|
|
97
|
+
else if (/calcOnSave="0"/.test(a))
|
|
98
|
+
cs.calcOnSave = false;
|
|
99
|
+
if (/concurrentCalc="1"/.test(a))
|
|
100
|
+
cs.concurrentCalc = true;
|
|
101
|
+
else if (/concurrentCalc="0"/.test(a))
|
|
102
|
+
cs.concurrentCalc = false;
|
|
103
|
+
if (Object.keys(cs).length > 0)
|
|
104
|
+
wb.calcSettings = cs;
|
|
105
|
+
}
|
|
52
106
|
return wb;
|
|
53
107
|
}
|
|
54
108
|
static async fromBase64(b64) {
|
|
@@ -78,14 +132,102 @@ export class Workbook {
|
|
|
78
132
|
getSheetNames() {
|
|
79
133
|
return this.sheets.map(s => s.name);
|
|
80
134
|
}
|
|
135
|
+
getSheets() {
|
|
136
|
+
return this.sheets;
|
|
137
|
+
}
|
|
81
138
|
removeSheet(name) {
|
|
82
139
|
this.sheets = this.sheets.filter(s => s.name !== name);
|
|
83
140
|
return this;
|
|
84
141
|
}
|
|
142
|
+
addChartSheet(name, chart) {
|
|
143
|
+
const ws = this.addSheet(name);
|
|
144
|
+
ws._isChartSheet = true;
|
|
145
|
+
ws.addChart(chart);
|
|
146
|
+
return ws;
|
|
147
|
+
}
|
|
148
|
+
addDialogSheet(name) {
|
|
149
|
+
const ws = this.addSheet(name);
|
|
150
|
+
ws._isDialogSheet = true;
|
|
151
|
+
return ws;
|
|
152
|
+
}
|
|
153
|
+
copySheet(sourceName, newName) {
|
|
154
|
+
const src = this.getSheet(sourceName);
|
|
155
|
+
if (!src)
|
|
156
|
+
throw new Error(`Sheet "${sourceName}" not found`);
|
|
157
|
+
const ws = this.addSheet(newName);
|
|
158
|
+
const cells = src.readAllCells();
|
|
159
|
+
for (const { row, col, cell } of cells) {
|
|
160
|
+
const target = ws.getCell(row, col);
|
|
161
|
+
if (cell.value != null)
|
|
162
|
+
target.value = cell.value;
|
|
163
|
+
if (cell.formula)
|
|
164
|
+
target.formula = cell.formula;
|
|
165
|
+
if (cell.arrayFormula)
|
|
166
|
+
target.arrayFormula = cell.arrayFormula;
|
|
167
|
+
if (cell.richText)
|
|
168
|
+
target.richText = cell.richText.map(r => ({ ...r, font: r.font ? { ...r.font } : undefined }));
|
|
169
|
+
if (cell.style)
|
|
170
|
+
target.style = { ...cell.style };
|
|
171
|
+
if (cell.comment)
|
|
172
|
+
target.comment = { ...cell.comment };
|
|
173
|
+
if (cell.hyperlink)
|
|
174
|
+
target.hyperlink = { ...cell.hyperlink };
|
|
175
|
+
}
|
|
176
|
+
for (const m of src.getMerges()) {
|
|
177
|
+
ws.merge(m.startRow, m.startCol, m.endRow, m.endCol);
|
|
178
|
+
}
|
|
179
|
+
const range = src.getUsedRange();
|
|
180
|
+
if (range) {
|
|
181
|
+
for (let c = range.startCol; c <= range.endCol; c++) {
|
|
182
|
+
const cd = src.getColumn(c);
|
|
183
|
+
if (cd)
|
|
184
|
+
ws.setColumn(c, { ...cd });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (src.pageSetup)
|
|
188
|
+
ws.pageSetup = { ...src.pageSetup };
|
|
189
|
+
if (src.printArea)
|
|
190
|
+
ws.printArea = src.printArea;
|
|
191
|
+
return ws;
|
|
192
|
+
}
|
|
193
|
+
registerTableStyle(name, def) {
|
|
194
|
+
this._customTableStyles.set(name, def);
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
85
197
|
addNamedRange(nr) {
|
|
86
198
|
this.namedRanges.push(nr);
|
|
87
199
|
return this;
|
|
88
200
|
}
|
|
201
|
+
getNamedRanges() {
|
|
202
|
+
return this.namedRanges;
|
|
203
|
+
}
|
|
204
|
+
getNamedRange(name) {
|
|
205
|
+
return this.namedRanges.find(nr => nr.name === name);
|
|
206
|
+
}
|
|
207
|
+
removeNamedRange(name) {
|
|
208
|
+
this.namedRanges = this.namedRanges.filter(nr => nr.name !== name);
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
addConnection(conn) {
|
|
212
|
+
this.connections.push(conn);
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
getConnections() {
|
|
216
|
+
return this.connections;
|
|
217
|
+
}
|
|
218
|
+
getConnection(name) {
|
|
219
|
+
return this.connections.find(c => c.name === name);
|
|
220
|
+
}
|
|
221
|
+
removeConnection(name) {
|
|
222
|
+
this.connections = this.connections.filter(c => c.name !== name);
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
getPowerQueries() {
|
|
226
|
+
return this.powerQueries;
|
|
227
|
+
}
|
|
228
|
+
getPowerQuery(name) {
|
|
229
|
+
return this.powerQueries.find(q => q.name === name);
|
|
230
|
+
}
|
|
89
231
|
getCustomProperty(name) {
|
|
90
232
|
return this.customProperties.find(p => p.name === name);
|
|
91
233
|
}
|
|
@@ -101,6 +243,24 @@ export class Workbook {
|
|
|
101
243
|
this.customProperties = this.customProperties.filter(p => p.name !== name);
|
|
102
244
|
return this;
|
|
103
245
|
}
|
|
246
|
+
addExternalLink(link) {
|
|
247
|
+
this.externalLinks.push(link);
|
|
248
|
+
return this;
|
|
249
|
+
}
|
|
250
|
+
getExternalLinks() {
|
|
251
|
+
return this.externalLinks;
|
|
252
|
+
}
|
|
253
|
+
registerPivotStyle(style) {
|
|
254
|
+
this.customPivotStyles.push(style);
|
|
255
|
+
return this;
|
|
256
|
+
}
|
|
257
|
+
addPivotSlicer(slicer) {
|
|
258
|
+
this.pivotSlicers.push(slicer);
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
getPivotSlicers() {
|
|
262
|
+
return this.pivotSlicers;
|
|
263
|
+
}
|
|
104
264
|
async build() {
|
|
105
265
|
this._syncLegacyProperties();
|
|
106
266
|
return this._readResult ? this._buildPatched() : this._buildFresh();
|
|
@@ -113,6 +273,13 @@ export class Workbook {
|
|
|
113
273
|
const shared = new SharedStrings();
|
|
114
274
|
const sheetXmls = new Map();
|
|
115
275
|
if (hasDirty) {
|
|
276
|
+
const dxfRe = /<dxf>([\s\S]*?)<\/dxf>|<dxf\/>/g;
|
|
277
|
+
const rawDxfs = [];
|
|
278
|
+
let m;
|
|
279
|
+
while ((m = dxfRe.exec(rr.stylesXml)) !== null)
|
|
280
|
+
rawDxfs.push(m[1] ?? '');
|
|
281
|
+
if (rawDxfs.length)
|
|
282
|
+
styles.prependRawDxfs(rawDxfs);
|
|
116
283
|
for (let i = 0; i < this.sheets.length; i++) {
|
|
117
284
|
sheetXmls.set(i, this.sheets[i].toXml(styles, shared));
|
|
118
285
|
}
|
|
@@ -127,7 +294,7 @@ export class Workbook {
|
|
|
127
294
|
...rr.extended,
|
|
128
295
|
...this.extendedProperties,
|
|
129
296
|
titlesOfParts: this.sheets.map(s => s.name),
|
|
130
|
-
headingPairs:
|
|
297
|
+
headingPairs: this._headingPairs(),
|
|
131
298
|
}, rr.extendedUnknownRaw)),
|
|
132
299
|
});
|
|
133
300
|
const customProps = this.customProperties.length > 0
|
|
@@ -137,6 +304,10 @@ export class Workbook {
|
|
|
137
304
|
entries.push({ name: 'docProps/custom.xml', data: strToBytes(buildCustomXml(customProps)) });
|
|
138
305
|
}
|
|
139
306
|
entries.push({ name: 'xl/workbook.xml', data: strToBytes(this._patchWorkbookXml(rr.workbookXml)) });
|
|
307
|
+
const connectionsXml = this._connectionsXml(rr.connectionsXml);
|
|
308
|
+
if (connectionsXml) {
|
|
309
|
+
entries.push({ name: 'xl/connections.xml', data: strToBytes(connectionsXml) });
|
|
310
|
+
}
|
|
140
311
|
if (hasDirty) {
|
|
141
312
|
entries.push({ name: 'xl/styles.xml', data: strToBytes(styles.toXml()) });
|
|
142
313
|
entries.push({ name: 'xl/sharedStrings.xml', data: strToBytes(shared.toXml()) });
|
|
@@ -146,38 +317,43 @@ export class Workbook {
|
|
|
146
317
|
entries.push({ name: 'xl/sharedStrings.xml', data: strToBytes(rr.sharedXml) });
|
|
147
318
|
}
|
|
148
319
|
for (let i = 0; i < this.sheets.length; i++) {
|
|
149
|
-
const
|
|
320
|
+
const ws = this.sheets[i];
|
|
321
|
+
const folder = ws._isChartSheet ? 'chartsheets' : ws._isDialogSheet ? 'dialogsheets' : 'worksheets';
|
|
322
|
+
const path = `xl/${folder}/sheet${i + 1}.xml`;
|
|
150
323
|
if (hasDirty) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const dirtyTablePaths = new Set();
|
|
160
|
-
if (hasDirty) {
|
|
161
|
-
for (let i = 0; i < this.sheets.length; i++) {
|
|
162
|
-
if (rr.sheets[i]?.tablePaths) {
|
|
163
|
-
for (const tp of rr.sheets[i].tablePaths)
|
|
164
|
-
dirtyTablePaths.add(tp);
|
|
324
|
+
if (ws._isChartSheet) {
|
|
325
|
+
entries.push({ name: path, data: strToBytes(ws.toChartSheetXml()) });
|
|
326
|
+
}
|
|
327
|
+
else if (ws._isDialogSheet) {
|
|
328
|
+
entries.push({ name: path, data: strToBytes(ws.toDialogSheetXml(styles, shared)) });
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
entries.push({ name: path, data: strToBytes(sheetXmls.get(i) ?? '') });
|
|
165
332
|
}
|
|
166
333
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (!dirtyTablePaths.has(path)) {
|
|
170
|
-
entries.push({ name: path, data });
|
|
334
|
+
else {
|
|
335
|
+
entries.push({ name: path, data: strToBytes(rr.sheets[i]?.originalXml ?? '') });
|
|
171
336
|
}
|
|
172
337
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
338
|
+
const allTablePaths = new Set();
|
|
339
|
+
for (let i = 0; i < this.sheets.length; i++) {
|
|
340
|
+
const ws = this.sheets[i];
|
|
341
|
+
const tables = ws.getTables();
|
|
342
|
+
const paths = rr.sheets[i]?.tablePaths ?? [];
|
|
343
|
+
const xmls = rr.sheets[i]?.tableXmls ?? [];
|
|
344
|
+
for (let j = 0; j < tables.length; j++) {
|
|
345
|
+
const tblPath = paths[j];
|
|
346
|
+
if (tblPath) {
|
|
347
|
+
allTablePaths.add(tblPath);
|
|
348
|
+
if (j < xmls.length) {
|
|
349
|
+
let xml = xmls[j];
|
|
350
|
+
const origRefMatch = xml.match(/\bref="([^"]+)"/);
|
|
351
|
+
if (origRefMatch && origRefMatch[1] !== tables[j].ref) {
|
|
352
|
+
xml = xml.replace(`ref="${origRefMatch[1]}"`, `ref="${tables[j].ref}"`);
|
|
353
|
+
}
|
|
354
|
+
entries.push({ name: tblPath, data: strToBytes(xml) });
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
181
357
|
const idMatch = tblPath.match(/table(\d+)\.xml$/);
|
|
182
358
|
const tableId = idMatch ? parseInt(idMatch[1], 10) : j + 1;
|
|
183
359
|
entries.push({ name: tblPath, data: strToBytes(buildTableXml(tables[j], tableId)) });
|
|
@@ -185,8 +361,23 @@ export class Workbook {
|
|
|
185
361
|
}
|
|
186
362
|
}
|
|
187
363
|
}
|
|
364
|
+
for (const [path, data] of rr.unknownParts) {
|
|
365
|
+
if (allTablePaths.has(path))
|
|
366
|
+
continue;
|
|
367
|
+
if (path === 'xl/vbaProject.bin' && this.vbaProject)
|
|
368
|
+
continue;
|
|
369
|
+
if (rr.allRels.has(path))
|
|
370
|
+
continue;
|
|
371
|
+
if (hasDirty && path === 'xl/calcChain.xml')
|
|
372
|
+
continue;
|
|
373
|
+
entries.push({ name: path, data });
|
|
374
|
+
}
|
|
375
|
+
if (this.vbaProject) {
|
|
376
|
+
this._ensureVbaSheetModules();
|
|
377
|
+
entries.push({ name: 'xl/vbaProject.bin', data: this.vbaProject.build() });
|
|
378
|
+
}
|
|
188
379
|
entries.push({ name: '_rels/.rels', data: strToBytes(this._buildRootRels(customProps != null && customProps.length > 0)) });
|
|
189
|
-
entries.push({ name: 'xl/_rels/workbook.xml.rels', data: strToBytes(this._buildWorkbookRels(rr)) });
|
|
380
|
+
entries.push({ name: 'xl/_rels/workbook.xml.rels', data: strToBytes(this._buildWorkbookRels(rr, hasDirty)) });
|
|
190
381
|
for (const [relPath, relMap] of rr.allRels) {
|
|
191
382
|
if (relPath === 'xl/_rels/workbook.xml.rels' || relPath === '_rels/.rels')
|
|
192
383
|
continue;
|
|
@@ -194,7 +385,7 @@ export class Workbook {
|
|
|
194
385
|
}
|
|
195
386
|
entries.push({
|
|
196
387
|
name: '[Content_Types].xml',
|
|
197
|
-
data: strToBytes(this._patchContentTypes(rr.contentTypesXml, customProps != null && customProps.length > 0)),
|
|
388
|
+
data: strToBytes(this._patchContentTypes(rr.contentTypesXml, customProps != null && customProps.length > 0, hasDirty)),
|
|
198
389
|
});
|
|
199
390
|
return buildZip(entries, { level: this.compressionLevel });
|
|
200
391
|
}
|
|
@@ -202,29 +393,35 @@ export class Workbook {
|
|
|
202
393
|
const styles = new StyleRegistry();
|
|
203
394
|
const shared = new SharedStrings();
|
|
204
395
|
const entries = [];
|
|
396
|
+
for (const [name, def] of this._customTableStyles) {
|
|
397
|
+
styles.registerTableStyle(name, def);
|
|
398
|
+
}
|
|
205
399
|
let globalRId = 1;
|
|
206
400
|
for (const ws of this.sheets)
|
|
207
401
|
ws.rId = `rId${globalRId++}`;
|
|
208
402
|
const allImages = [];
|
|
209
403
|
const allCharts = [];
|
|
210
404
|
const allTables = [];
|
|
405
|
+
const allPivotTables = [];
|
|
211
406
|
const sheetImageRIds = new Map();
|
|
212
407
|
const sheetChartRIds = new Map();
|
|
213
408
|
const sheetTableRIds = new Map();
|
|
214
|
-
|
|
409
|
+
const sheetPivotRIds = new Map();
|
|
410
|
+
let imgCtr = 1, chartCtr = 1, tableCtr = 1, vmlCtr = 1, pivotCtr = 1, pivotCacheIdCtr = 0, ctrlPropGlobal = 0, oleObjGlobal = 0;
|
|
215
411
|
for (const ws of this.sheets) {
|
|
216
412
|
const imgs = ws.getImages();
|
|
217
413
|
const charts = ws.getCharts();
|
|
218
414
|
const tables = ws.getTables();
|
|
219
415
|
const imgRIds = [], chartRIds = [], tblRIds = [];
|
|
220
|
-
if (imgs.length || charts.length)
|
|
416
|
+
if (imgs.length || charts.length || ws.getShapes().length || ws.getWordArt().length || ws.getMathEquations().length || ws.getTableSlicers().length || ws.getOleObjects().length)
|
|
221
417
|
ws.drawingRId = `rId${globalRId++}`;
|
|
222
|
-
|
|
418
|
+
const controls = ws.getFormControls();
|
|
419
|
+
if (ws.getComments().length || controls.length)
|
|
223
420
|
ws.legacyDrawingRId = `rId${globalRId++}`;
|
|
224
421
|
for (const img of imgs) {
|
|
225
422
|
const r = `rId${globalRId++}`;
|
|
226
423
|
imgRIds.push(r);
|
|
227
|
-
allImages.push({ ws, img, ext: img.format
|
|
424
|
+
allImages.push({ ws, img, ext: imageExt(img.format), idx: imgCtr++ });
|
|
228
425
|
}
|
|
229
426
|
for (let i = 0; i < charts.length; i++) {
|
|
230
427
|
const r = `rId${globalRId++}`;
|
|
@@ -236,64 +433,254 @@ export class Workbook {
|
|
|
236
433
|
tblRIds.push(r);
|
|
237
434
|
allTables.push({ ws, tableIdx: i, globalTableId: tableCtr++ });
|
|
238
435
|
}
|
|
436
|
+
const oleRIds = [];
|
|
437
|
+
const oleIconRIds = [];
|
|
438
|
+
for (const ole of ws.getOleObjects()) {
|
|
439
|
+
oleRIds.push(`rId${globalRId++}`);
|
|
440
|
+
if (ole.iconData)
|
|
441
|
+
oleIconRIds.push(`rId${globalRId++}`);
|
|
442
|
+
else
|
|
443
|
+
oleIconRIds.push('');
|
|
444
|
+
}
|
|
445
|
+
ws.oleRIds = oleRIds;
|
|
446
|
+
ws.oleIconRIds = oleIconRIds;
|
|
447
|
+
const ctrlPropRIds = [];
|
|
448
|
+
for (let ci = 0; ci < controls.length; ci++)
|
|
449
|
+
ctrlPropRIds.push(`rId${globalRId++}`);
|
|
450
|
+
ws.ctrlPropRIds = ctrlPropRIds;
|
|
239
451
|
sheetImageRIds.set(ws, imgRIds);
|
|
240
452
|
sheetChartRIds.set(ws, chartRIds);
|
|
241
453
|
sheetTableRIds.set(ws, tblRIds);
|
|
242
454
|
ws.tableRIds = tblRIds;
|
|
455
|
+
const ptRIds = [];
|
|
456
|
+
for (const pt of ws.getPivotTables()) {
|
|
457
|
+
const pivotRId = `rId${globalRId++}`;
|
|
458
|
+
const cacheRId = `rId${globalRId++}`;
|
|
459
|
+
ptRIds.push(pivotRId);
|
|
460
|
+
allPivotTables.push({ ws, pt, pivotIdx: pivotCtr++, cacheId: pivotCacheIdCtr++, pivotRId, cacheRId });
|
|
461
|
+
}
|
|
462
|
+
sheetPivotRIds.set(ws, ptRIds);
|
|
463
|
+
}
|
|
464
|
+
const allCellImages = [];
|
|
465
|
+
let cellImgCtr = imgCtr;
|
|
466
|
+
let vmCounter = 1;
|
|
467
|
+
for (const ws of this.sheets) {
|
|
468
|
+
ws._cellImageVm = new Map();
|
|
469
|
+
for (const ci of ws.getCellImages()) {
|
|
470
|
+
const ext = imageExt(ci.format);
|
|
471
|
+
allCellImages.push({ img: ci, ext, idx: cellImgCtr++ });
|
|
472
|
+
ws._cellImageVm.set(ci.cell, vmCounter++);
|
|
473
|
+
ws.getCellByRef(ci.cell);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
const hasCellImages = allCellImages.length > 0;
|
|
477
|
+
const sheetSlicerMap = new Map();
|
|
478
|
+
const allSlicerCaches = [];
|
|
479
|
+
let slicerDefCtr = 0, slicerCacheCtr = 0;
|
|
480
|
+
for (const ws of this.sheets) {
|
|
481
|
+
const tSlicers = ws.getTableSlicers();
|
|
482
|
+
if (tSlicers.length) {
|
|
483
|
+
sheetSlicerMap.set(ws, { tableSlicers: [], pivotSlicers: [], slicerDefRId: '', slicerDefIdx: 0 });
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
for (const ps of this.pivotSlicers) {
|
|
487
|
+
for (const ws of this.sheets) {
|
|
488
|
+
if (ws.getPivotTables().some(p => p.name === ps.pivotTableName)) {
|
|
489
|
+
if (!sheetSlicerMap.has(ws)) {
|
|
490
|
+
sheetSlicerMap.set(ws, { tableSlicers: [], pivotSlicers: [], slicerDefRId: '', slicerDefIdx: 0 });
|
|
491
|
+
}
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
for (const [ws, info] of sheetSlicerMap) {
|
|
497
|
+
if (!ws.drawingRId)
|
|
498
|
+
ws.drawingRId = `rId${globalRId++}`;
|
|
499
|
+
info.slicerDefRId = `rId${globalRId++}`;
|
|
500
|
+
info.slicerDefIdx = ++slicerDefCtr;
|
|
501
|
+
ws.slicerRId = info.slicerDefRId;
|
|
502
|
+
const drawingInfo = [];
|
|
503
|
+
for (const s of ws.getTableSlicers()) {
|
|
504
|
+
const table = ws.getTables().find(t => t.name === s.tableName);
|
|
505
|
+
const tableEntry = allTables.find(t => t.ws === ws && ws.getTables()[t.tableIdx] === table);
|
|
506
|
+
const tableId = tableEntry?.globalTableId ?? 1;
|
|
507
|
+
const columnIndex = table ? (table.columns?.findIndex(c => c.name === s.columnName) ?? 0) + 1 : 1;
|
|
508
|
+
info.tableSlicers.push({ slicer: s, tableId, columnIndex });
|
|
509
|
+
drawingInfo.push({ name: s.name, cell: s.cell });
|
|
510
|
+
allSlicerCaches.push({
|
|
511
|
+
name: s.name + '_cache', sourceName: s.columnName, type: 'table',
|
|
512
|
+
rId: `rId${globalRId++}`, idx: ++slicerCacheCtr,
|
|
513
|
+
tableId, columnIndex, sortOrder: s.sortOrder ?? 'ascending',
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
for (const ps of this.pivotSlicers) {
|
|
517
|
+
const pt = ws.getPivotTables().find(p => p.name === ps.pivotTableName);
|
|
518
|
+
if (!pt)
|
|
519
|
+
continue;
|
|
520
|
+
const ptEntry = allPivotTables.find(p => p.ws === ws && p.pt === pt);
|
|
521
|
+
const sheetIdx = this.sheets.indexOf(ws) + 1;
|
|
522
|
+
let items = [];
|
|
523
|
+
const sourceWs = this.sheets.find(s => s.name === pt.sourceSheet);
|
|
524
|
+
if (sourceWs) {
|
|
525
|
+
const sourceData = sourceWs.readRange(pt.sourceRef);
|
|
526
|
+
const headers = (sourceData[0] ?? []).map(v => String(v ?? ''));
|
|
527
|
+
const fieldIdx = headers.indexOf(ps.fieldName);
|
|
528
|
+
if (fieldIdx >= 0) {
|
|
529
|
+
const uniqueSet = new Set();
|
|
530
|
+
for (let r = 1; r < sourceData.length; r++)
|
|
531
|
+
uniqueSet.add(String(sourceData[r][fieldIdx] ?? ''));
|
|
532
|
+
items = [...uniqueSet];
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
info.pivotSlicers.push({ slicer: ps, pivotCacheId: ptEntry?.cacheId ?? 0 });
|
|
536
|
+
drawingInfo.push({ name: ps.name, cell: ps.cell });
|
|
537
|
+
allSlicerCaches.push({
|
|
538
|
+
name: ps.name + '_cache', sourceName: ps.fieldName, type: 'pivot',
|
|
539
|
+
rId: `rId${globalRId++}`, idx: ++slicerCacheCtr,
|
|
540
|
+
pivotTableName: ps.pivotTableName, pivotCacheId: ptEntry?.cacheId ?? 0,
|
|
541
|
+
tabId: sheetIdx, items,
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
ws._slicerDrawingInfo = drawingInfo;
|
|
243
545
|
}
|
|
546
|
+
const hasSlicers = sheetSlicerMap.size > 0;
|
|
244
547
|
const hasCustom = this.customProperties.length > 0;
|
|
548
|
+
const hasVba = !!this.vbaProject;
|
|
245
549
|
const imgCTs = new Set();
|
|
246
|
-
for (const { ext } of allImages) {
|
|
247
|
-
const ct = ext
|
|
550
|
+
for (const { ext } of [...allImages, ...allCellImages]) {
|
|
551
|
+
const ct = imageContentType(ext);
|
|
248
552
|
imgCTs.add(`<Default Extension="${ext}" ContentType="${ct}"/>`);
|
|
249
553
|
}
|
|
250
554
|
const sheetsWithComments = this.sheets.filter(ws => ws.getComments().length);
|
|
251
|
-
const
|
|
555
|
+
const sheetsWithVml = this.sheets.filter(ws => ws.getComments().length || ws.getFormControls().length);
|
|
556
|
+
const vmlCT = sheetsWithVml.length ? '<Default Extension="vml" ContentType="application/vnd.openxmlformats-officedocument.vmlDrawing"/>' : '';
|
|
252
557
|
let vmlIdx = 0;
|
|
253
558
|
const commentsCTs = sheetsWithComments.map(() => `<Override PartName="/xl/comments${++vmlIdx}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"/>`).join('');
|
|
559
|
+
let ctrlPropCtr = 0;
|
|
560
|
+
const ctrlPropCTs = [];
|
|
561
|
+
for (const ws of this.sheets) {
|
|
562
|
+
if (ws._isDialogSheet)
|
|
563
|
+
continue;
|
|
564
|
+
for (let ci = 0; ci < ws.getFormControls().length; ci++) {
|
|
565
|
+
ctrlPropCTs.push(`<Override PartName="/xl/ctrlProps/ctrlProp${++ctrlPropCtr}.xml" ContentType="application/vnd.ms-excel.controlproperties+xml"/>`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
const hasOleObjects = this.sheets.some(ws => ws.getOleObjects().length > 0);
|
|
569
|
+
const oleCT = hasOleObjects ? '<Default Extension="bin" ContentType="application/vnd.openxmlformats-officedocument.oleObject"/>' : '';
|
|
254
570
|
entries.push({ name: '[Content_Types].xml', data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
255
571
|
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
256
572
|
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
257
573
|
<Default Extension="xml" ContentType="application/xml"/>
|
|
258
574
|
${vmlCT}
|
|
575
|
+
${oleCT}
|
|
259
576
|
${[...imgCTs].join('')}
|
|
260
|
-
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
|
|
577
|
+
<Override PartName="/xl/workbook.xml" ContentType="${hasVba ? 'application/vnd.ms-excel.sheet.macroEnabled.main+xml' : this.isTemplate ? 'application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml' : 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml'}"/>
|
|
578
|
+
${hasVba ? '<Override PartName="/xl/vbaProject.bin" ContentType="application/vnd.ms-office.vbaProject"/>' : ''}
|
|
261
579
|
<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
|
|
262
580
|
<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>
|
|
263
|
-
|
|
581
|
+
<Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/>
|
|
582
|
+
${this.sheets.filter(ws => !ws._isChartSheet && !ws._isDialogSheet).map(ws => { const idx = this.sheets.indexOf(ws); return `<Override PartName="/xl/worksheets/sheet${idx + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`; }).join('')}
|
|
583
|
+
${this.sheets.filter(ws => ws._isChartSheet).map(ws => { const idx = this.sheets.indexOf(ws); return `<Override PartName="/xl/chartsheets/sheet${idx + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml"/>`; }).join('')}
|
|
584
|
+
${this.sheets.filter(ws => ws._isDialogSheet).map(ws => { const idx = this.sheets.indexOf(ws); return `<Override PartName="/xl/dialogsheets/sheet${idx + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml"/>`; }).join('')}
|
|
264
585
|
${this.sheets.filter(ws => ws.drawingRId).map((_, i) => `<Override PartName="/xl/drawings/drawing${i + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>`).join('')}
|
|
265
586
|
${allCharts.map(({ globalIdx }) => `<Override PartName="/xl/charts/chart${globalIdx}.xml" ContentType="application/vnd.openxmlformats-officedocument.drawingml.chart+xml"/>`).join('')}
|
|
266
587
|
${allTables.map(({ globalTableId }) => `<Override PartName="/xl/tables/table${globalTableId}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"/>`).join('')}
|
|
588
|
+
${allPivotTables.map(p => `<Override PartName="/xl/pivotTables/pivotTable${p.pivotIdx}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"/>`).join('\n')}
|
|
589
|
+
${allPivotTables.map(p => `<Override PartName="/xl/pivotCache/pivotCacheDefinition${p.pivotIdx}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"/>`).join('\n')}
|
|
590
|
+
${allPivotTables.map(p => `<Override PartName="/xl/pivotCache/pivotCacheRecords${p.pivotIdx}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"/>`).join('\n')}
|
|
267
591
|
${commentsCTs}
|
|
592
|
+
${ctrlPropCTs.join('')}
|
|
268
593
|
<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
|
|
269
594
|
<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
|
|
270
595
|
${hasCustom ? '<Override PartName="/docProps/custom.xml" ContentType="application/vnd.openxmlformats-officedocument.custom-properties+xml"/>' : ''}
|
|
596
|
+
${this.connections.length ? '<Override PartName="/xl/connections.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml"/>' : ''}
|
|
597
|
+
${this.externalLinks.map((_, i) => `<Override PartName="/xl/externalLinks/externalLink${i + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml"/>`).join('\n')}
|
|
598
|
+
${[...sheetSlicerMap.values()].map(info => `<Override PartName="/xl/slicers/slicer${info.slicerDefIdx}.xml" ContentType="application/vnd.ms-excel.slicer+xml"/>`).join('\n')}
|
|
599
|
+
${allSlicerCaches.map(sc => `<Override PartName="/xl/slicerCaches/slicerCache${sc.idx}.xml" ContentType="application/vnd.ms-excel.slicerCache+xml"/>`).join('\n')}
|
|
600
|
+
${this.sheets.flatMap(ws => ws.getQueryTables()).map((_, i) => `<Override PartName="/xl/queryTables/queryTable${i + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml"/>`).join('\n')}
|
|
601
|
+
${hasCellImages ? `<Override PartName="/xl/metadata.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml"/>
|
|
602
|
+
<Override PartName="/xl/richData/rdrichvalue.xml" ContentType="application/vnd.ms-excel.rdrichvalue+xml"/>
|
|
603
|
+
<Override PartName="/xl/richData/rdRichValueStructure.xml" ContentType="application/vnd.ms-excel.rdrichvaluestructure+xml"/>
|
|
604
|
+
<Override PartName="/xl/richData/richValueRel.xml" ContentType="application/vnd.ms-excel.richvaluerel+xml"/>
|
|
605
|
+
<Override PartName="/xl/richData/rdRichValueTypes.xml" ContentType="application/vnd.ms-excel.rdrichvaluetypes+xml"/>
|
|
606
|
+
<Override PartName="/xl/richData/rdarray.xml" ContentType="application/vnd.ms-excel.rdarray+xml"/>` : ''}
|
|
271
607
|
</Types>`) });
|
|
272
608
|
entries.push({ name: '_rels/.rels', data: strToBytes(this._buildRootRels(hasCustom)) });
|
|
273
609
|
entries.push({ name: 'xl/_rels/workbook.xml.rels', data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
274
610
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
275
|
-
${this.sheets.map((ws, i) =>
|
|
611
|
+
${this.sheets.map((ws, i) => {
|
|
612
|
+
const type = ws._isChartSheet ? 'chartsheet' : ws._isDialogSheet ? 'dialogsheet' : 'worksheet';
|
|
613
|
+
const folder = ws._isChartSheet ? 'chartsheets' : ws._isDialogSheet ? 'dialogsheets' : 'worksheets';
|
|
614
|
+
return `<Relationship Id="${ws.rId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/${type}" Target="${folder}/sheet${i + 1}.xml"/>`;
|
|
615
|
+
}).join('')}
|
|
276
616
|
<Relationship Id="rIdStyles" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
|
|
277
617
|
<Relationship Id="rIdShared" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>
|
|
618
|
+
<Relationship Id="rIdTheme" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>
|
|
619
|
+
${allPivotTables.map(p => `<Relationship Id="${p.cacheRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition" Target="pivotCache/pivotCacheDefinition${p.pivotIdx}.xml"/>`).join('\n')}
|
|
620
|
+
${allSlicerCaches.map(sc => `<Relationship Id="${sc.rId}" Type="http://schemas.microsoft.com/office/2007/relationships/slicerCache" Target="slicerCaches/slicerCache${sc.idx}.xml"/>`).join('\n')}
|
|
621
|
+
${hasVba ? '<Relationship Id="rIdVBA" Type="http://schemas.microsoft.com/office/2006/relationships/vbaProject" Target="vbaProject.bin"/>' : ''}
|
|
622
|
+
${this.connections.length ? '<Relationship Id="rIdConns" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/connections" Target="connections.xml"/>' : ''}
|
|
623
|
+
${this.externalLinks.map((_, i) => `<Relationship Id="rIdExtLink${i + 1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink" Target="externalLinks/externalLink${i + 1}.xml"/>`).join('\n')}
|
|
624
|
+
${hasCellImages ? '<Relationship Id="rIdMeta" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata" Target="metadata.xml"/>' : ''}
|
|
625
|
+
${hasCellImages ? '<Relationship Id="rIdRichValueRel" Type="http://schemas.microsoft.com/office/2022/10/relationships/richValueRel" Target="richData/richValueRel.xml"/>' : ''}
|
|
626
|
+
${hasCellImages ? '<Relationship Id="rIdRichValue" Type="http://schemas.microsoft.com/office/2017/06/relationships/rdRichValue" Target="richData/rdrichvalue.xml"/>' : ''}
|
|
627
|
+
${hasCellImages ? '<Relationship Id="rIdRichValueStruct" Type="http://schemas.microsoft.com/office/2017/06/relationships/rdRichValueStructure" Target="richData/rdRichValueStructure.xml"/>' : ''}
|
|
628
|
+
${hasCellImages ? '<Relationship Id="rIdRichValueTypes" Type="http://schemas.microsoft.com/office/2017/06/relationships/rdRichValueTypes" Target="richData/rdRichValueTypes.xml"/>' : ''}
|
|
629
|
+
${hasCellImages ? '<Relationship Id="rIdRdArray" Type="http://schemas.microsoft.com/office/2017/06/relationships/rdArray" Target="richData/rdarray.xml"/>' : ''}
|
|
278
630
|
</Relationships>`) });
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
631
|
+
if (hasVba) {
|
|
632
|
+
this._ensureVbaSheetModules();
|
|
633
|
+
entries.push({ name: 'xl/vbaProject.bin', data: this.vbaProject.build() });
|
|
634
|
+
}
|
|
635
|
+
const wbPrAttrs = [
|
|
636
|
+
this.properties.date1904 ? 'date1904="1"' : '',
|
|
637
|
+
hasVba ? 'codeName="ThisWorkbook"' : '',
|
|
638
|
+
].filter(Boolean).join(' ');
|
|
639
|
+
const date1904 = `<workbookPr${wbPrAttrs ? ' ' + wbPrAttrs : ''}/>`;
|
|
640
|
+
const namedRangesXml = this._definedNamesXml(allSlicerCaches);
|
|
641
|
+
const pivotCachesXml = allPivotTables.length
|
|
642
|
+
? `<pivotCaches>${allPivotTables.map(p => `<pivotCache cacheId="${p.cacheId}" r:id="${p.cacheRId}"/>`).join('')}</pivotCaches>`
|
|
643
|
+
: '';
|
|
282
644
|
entries.push({ name: 'xl/workbook.xml', data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
283
645
|
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
284
646
|
${date1904}
|
|
285
647
|
<bookViews><workbookView xWindow="0" yWindow="0" windowWidth="14400" windowHeight="8260"/></bookViews>
|
|
286
648
|
<sheets>${this.sheets.map((ws, i) => `<sheet name="${escapeXml(ws.name)}" sheetId="${i + 1}" r:id="${ws.rId}"${ws.options?.state && ws.options.state !== 'visible' ? ` state="${ws.options.state}"` : ''}/>`).join('')}</sheets>
|
|
287
649
|
${namedRangesXml}
|
|
288
|
-
|
|
650
|
+
${this._calcPrXml()}
|
|
651
|
+
${pivotCachesXml}
|
|
652
|
+
${hasSlicers ? (() => {
|
|
653
|
+
const tableSlicers = allSlicerCaches.filter(sc => sc.type === 'table');
|
|
654
|
+
const pivotSlicers = allSlicerCaches.filter(sc => sc.type === 'pivot');
|
|
655
|
+
let xml = '<extLst>';
|
|
656
|
+
if (pivotSlicers.length)
|
|
657
|
+
xml += `<ext uri="{BBE1A952-AA13-448e-AADC-164F8A28A991}" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"><x14:slicerCaches>${pivotSlicers.map(sc => `<x14:slicerCache r:id="${sc.rId}"/>`).join('')}</x14:slicerCaches></ext>`;
|
|
658
|
+
if (tableSlicers.length)
|
|
659
|
+
xml += `<ext uri="{46BE6895-7355-4a93-B00E-2C351335B9C9}" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"><x15:slicerCaches>${tableSlicers.map(sc => `<x14:slicerCache r:id="${sc.rId}"/>`).join('')}</x15:slicerCaches></ext>`;
|
|
660
|
+
xml += '</extLst>';
|
|
661
|
+
return xml;
|
|
662
|
+
})() : ''}
|
|
289
663
|
</workbook>`) });
|
|
664
|
+
if (this.connections.length) {
|
|
665
|
+
entries.push({ name: 'xl/connections.xml', data: strToBytes(this._connectionsXml()) });
|
|
666
|
+
}
|
|
290
667
|
for (let i = 0; i < this.sheets.length; i++) {
|
|
291
668
|
const ws = this.sheets[i];
|
|
292
669
|
const imgRIds = sheetImageRIds.get(ws) ?? [];
|
|
293
670
|
const cRIds = sheetChartRIds.get(ws) ?? [];
|
|
294
671
|
const tblEntries = allTables.filter(t => t.ws === ws);
|
|
295
672
|
const tblRIds_ = sheetTableRIds.get(ws) ?? [];
|
|
296
|
-
|
|
673
|
+
const sheetFolder = ws._isChartSheet ? 'chartsheets' : ws._isDialogSheet ? 'dialogsheets' : 'worksheets';
|
|
674
|
+
const sheetPath = `xl/${sheetFolder}/sheet${i + 1}.xml`;
|
|
675
|
+
if (ws._isChartSheet) {
|
|
676
|
+
entries.push({ name: sheetPath, data: strToBytes(ws.toChartSheetXml()) });
|
|
677
|
+
}
|
|
678
|
+
else if (ws._isDialogSheet) {
|
|
679
|
+
entries.push({ name: sheetPath, data: strToBytes(ws.toDialogSheetXml(styles, shared)) });
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
entries.push({ name: sheetPath, data: strToBytes(ws.toXml(styles, shared)) });
|
|
683
|
+
}
|
|
297
684
|
const wsRels = [];
|
|
298
685
|
if (ws.drawingRId) {
|
|
299
686
|
const dIdx = this.sheets.filter((s, j) => j <= i && s.drawingRId).length;
|
|
@@ -307,17 +694,75 @@ ${namedRangesXml}
|
|
|
307
694
|
for (let j = 0; j < tblEntries.length; j++) {
|
|
308
695
|
wsRels.push(`<Relationship Id="${tblRIds_[j]}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/table" Target="../tables/table${tblEntries[j].globalTableId}.xml"/>`);
|
|
309
696
|
}
|
|
697
|
+
const ptRIds_ = sheetPivotRIds.get(ws) ?? [];
|
|
698
|
+
const ptEntries = allPivotTables.filter(p => p.ws === ws);
|
|
699
|
+
for (let j = 0; j < ptEntries.length; j++) {
|
|
700
|
+
wsRels.push(`<Relationship Id="${ptRIds_[j]}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable" Target="../pivotTables/pivotTable${ptEntries[j].pivotIdx}.xml"/>`);
|
|
701
|
+
}
|
|
702
|
+
const slicerInfo = sheetSlicerMap.get(ws);
|
|
703
|
+
if (slicerInfo) {
|
|
704
|
+
wsRels.push(`<Relationship Id="${slicerInfo.slicerDefRId}" Type="http://schemas.microsoft.com/office/2007/relationships/slicer" Target="../slicers/slicer${slicerInfo.slicerDefIdx}.xml"/>`);
|
|
705
|
+
}
|
|
310
706
|
const sheetComments = ws.getComments();
|
|
311
|
-
|
|
707
|
+
const sheetControls = ws.getFormControls();
|
|
708
|
+
if ((sheetComments.length || sheetControls.length) && ws.legacyDrawingRId) {
|
|
312
709
|
const vIdx = vmlCtr++;
|
|
313
|
-
const commRId = `rId${globalRId++}`;
|
|
314
710
|
wsRels.push(`<Relationship Id="${ws.legacyDrawingRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing" Target="../drawings/vmlDrawing${vIdx}.vml"/>`);
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
711
|
+
if (sheetComments.length) {
|
|
712
|
+
const commRId = `rId${globalRId++}`;
|
|
713
|
+
wsRels.push(`<Relationship Id="${commRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" Target="../comments${vIdx}.xml"/>`);
|
|
714
|
+
entries.push({ name: `xl/comments${vIdx}.xml`, data: strToBytes(this._buildCommentsXml(sheetComments)) });
|
|
715
|
+
}
|
|
716
|
+
const commentShapes = sheetComments.map(({ row, col }, ci) => {
|
|
717
|
+
const left = (col + 1) * 64;
|
|
718
|
+
const top = (row - 1) * 20;
|
|
719
|
+
const sid = 1025 + i * 1000 + ci;
|
|
720
|
+
return `<v:shape id="_x0000_s${sid}" type="#_x0000_t202" style="position:absolute;margin-left:${left}pt;margin-top:${top}pt;width:108pt;height:59.25pt;z-index:${ci + 1};visibility:hidden" fillcolor="#ffffe1" o:insetmode="auto">
|
|
721
|
+
<v:fill color2="#ffffe1"/>
|
|
722
|
+
<v:shadow color="black" obscured="t"/>
|
|
723
|
+
<v:path o:connecttype="none"/>
|
|
724
|
+
<v:textbox style="mso-direction-alt:auto"><div style="text-align:left"/></v:textbox>
|
|
725
|
+
<x:ClientData ObjectType="Note"><x:MoveWithCells/><x:SizeWithCells/><x:Anchor>${col + 1},15,${row - 1},10,${col + 3},15,${row + 4},4</x:Anchor><x:AutoFill>False</x:AutoFill><x:Row>${row - 1}</x:Row><x:Column>${col - 1}</x:Column></x:ClientData>
|
|
726
|
+
</v:shape>`;
|
|
727
|
+
});
|
|
728
|
+
const ctrlBaseId = 1025 + ws.sheetIndex * 1000 + sheetComments.length;
|
|
729
|
+
const controlShapes = sheetControls.map((ctrl, ci) => buildFormControlVmlShape(ctrl, ctrlBaseId + ci));
|
|
730
|
+
entries.push({ name: `xl/drawings/vmlDrawing${vIdx}.vml`, data: strToBytes(buildVmlWithControls(commentShapes, controlShapes)) });
|
|
731
|
+
if (!ws._isDialogSheet) {
|
|
732
|
+
const ctrlRIds = ws.ctrlPropRIds;
|
|
733
|
+
for (let ci = 0; ci < sheetControls.length; ci++) {
|
|
734
|
+
const ctrlPropIdx = ++ctrlPropGlobal;
|
|
735
|
+
wsRels.push(`<Relationship Id="${ctrlRIds[ci]}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp" Target="../ctrlProps/ctrlProp${ctrlPropIdx}.xml"/>`);
|
|
736
|
+
entries.push({ name: `xl/ctrlProps/ctrlProp${ctrlPropIdx}.xml`, data: strToBytes(buildCtrlPropXml(sheetControls[ci])) });
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
const oleObjects = ws.getOleObjects();
|
|
741
|
+
for (let oi = 0; oi < oleObjects.length; oi++) {
|
|
742
|
+
const ole = oleObjects[oi];
|
|
743
|
+
const oleIdx = ++oleObjGlobal;
|
|
744
|
+
const oleRId = ws.oleRIds[oi];
|
|
745
|
+
if (ole.linkToFile) {
|
|
746
|
+
wsRels.push(`<Relationship Id="${oleRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject" Target="${escapeXml(ole.linkPath ?? '')}" TargetMode="External"/>`);
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
const embName = `xl/embeddings/oleObject${oleIdx}.bin`;
|
|
750
|
+
wsRels.push(`<Relationship Id="${oleRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject" Target="../embeddings/oleObject${oleIdx}.bin"/>`);
|
|
751
|
+
const oleData = !ole.data ? new Uint8Array(0)
|
|
752
|
+
: typeof ole.data === 'string' ? base64ToBytes(ole.data) : ole.data;
|
|
753
|
+
entries.push({ name: embName, data: oleData });
|
|
754
|
+
}
|
|
755
|
+
if (ole.iconData) {
|
|
756
|
+
const iconExt = ole.iconFormat ?? 'emf';
|
|
757
|
+
const iconIdx = imgCtr++;
|
|
758
|
+
const iconRId = ws.oleIconRIds[oi];
|
|
759
|
+
wsRels.push(`<Relationship Id="${iconRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/image${iconIdx}.${iconExt}"/>`);
|
|
760
|
+
const iconData = typeof ole.iconData === 'string' ? base64ToBytes(ole.iconData) : ole.iconData;
|
|
761
|
+
entries.push({ name: `xl/media/image${iconIdx}.${iconExt}`, data: iconData });
|
|
762
|
+
}
|
|
318
763
|
}
|
|
319
764
|
if (wsRels.length) {
|
|
320
|
-
entries.push({ name: `xl/
|
|
765
|
+
entries.push({ name: `xl/${sheetFolder}/_rels/sheet${i + 1}.xml.rels`, data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
321
766
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
322
767
|
${wsRels.join('\n')}
|
|
323
768
|
</Relationships>`) });
|
|
@@ -347,14 +792,105 @@ ${dRels.join('\n')}
|
|
|
347
792
|
for (const { img, ext, idx } of allImages) {
|
|
348
793
|
entries.push({ name: `xl/media/image${idx}.${ext}`, data: typeof img.data === 'string' ? base64ToBytes(img.data) : img.data });
|
|
349
794
|
}
|
|
795
|
+
if (hasCellImages) {
|
|
796
|
+
const cellImgRIds = [];
|
|
797
|
+
const cellImgRels = [];
|
|
798
|
+
for (let ci = 0; ci < allCellImages.length; ci++) {
|
|
799
|
+
const { img, ext, idx } = allCellImages[ci];
|
|
800
|
+
const rId = `rId${ci + 1}`;
|
|
801
|
+
cellImgRIds.push(rId);
|
|
802
|
+
cellImgRels.push(`<Relationship Id="${rId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="/xl/media/image${idx}.${ext}"/>`);
|
|
803
|
+
entries.push({ name: `xl/media/image${idx}.${ext}`, data: typeof img.data === 'string' ? base64ToBytes(img.data) : img.data });
|
|
804
|
+
}
|
|
805
|
+
entries.push({ name: 'xl/metadata.xml', data: strToBytes(buildMetadataXml(allCellImages.length)) });
|
|
806
|
+
entries.push({ name: 'xl/richData/rdrichvalue.xml', data: strToBytes(buildRichValueXml(allCellImages.length)) });
|
|
807
|
+
entries.push({ name: 'xl/richData/richValueRel.xml', data: strToBytes(buildRichValueRelXml(cellImgRIds)) });
|
|
808
|
+
entries.push({ name: 'xl/richData/rdRichValueStructure.xml', data: strToBytes(buildRichValueStructureXml()) });
|
|
809
|
+
entries.push({ name: 'xl/richData/rdRichValueTypes.xml', data: strToBytes(buildRichValueTypesXml()) });
|
|
810
|
+
entries.push({ name: 'xl/richData/rdarray.xml', data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><arrayData xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2" count="0"></arrayData>`) });
|
|
811
|
+
entries.push({ name: 'xl/richData/_rels/richValueRel.xml.rels', data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
812
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
813
|
+
${cellImgRels.join('\n')}
|
|
814
|
+
</Relationships>`) });
|
|
815
|
+
}
|
|
350
816
|
for (const { ws, chartIdx, globalIdx } of allCharts) {
|
|
351
817
|
entries.push({ name: `xl/charts/chart${globalIdx}.xml`, data: strToBytes(buildChartXml(ws.getCharts()[chartIdx])) });
|
|
352
818
|
}
|
|
353
819
|
for (const { ws, tableIdx, globalTableId } of allTables) {
|
|
354
820
|
entries.push({ name: `xl/tables/table${globalTableId}.xml`, data: strToBytes(buildTableXml(ws.getTables()[tableIdx], globalTableId)) });
|
|
355
821
|
}
|
|
822
|
+
for (const { ws, pt, pivotIdx, cacheId: cId } of allPivotTables) {
|
|
823
|
+
const sourceWs = this.sheets.find(s => s.name === pt.sourceSheet);
|
|
824
|
+
const sourceData = sourceWs ? sourceWs.readRange(pt.sourceRef) : [[]];
|
|
825
|
+
const { pivotTableXml, cacheDefXml, cacheRecordsXml } = buildPivotTableFiles(pt, sourceData, pivotIdx, cId);
|
|
826
|
+
const wbRel = (type, target) => `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">\n<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/${type}" Target="${target}"/>\n</Relationships>`;
|
|
827
|
+
entries.push({ name: `xl/pivotTables/pivotTable${pivotIdx}.xml`, data: strToBytes(pivotTableXml) });
|
|
828
|
+
entries.push({ name: `xl/pivotTables/_rels/pivotTable${pivotIdx}.xml.rels`, data: strToBytes(wbRel('pivotCacheDefinition', `../pivotCache/pivotCacheDefinition${pivotIdx}.xml`)) });
|
|
829
|
+
entries.push({ name: `xl/pivotCache/pivotCacheDefinition${pivotIdx}.xml`, data: strToBytes(cacheDefXml) });
|
|
830
|
+
entries.push({ name: `xl/pivotCache/_rels/pivotCacheDefinition${pivotIdx}.xml.rels`, data: strToBytes(wbRel('pivotCacheRecords', `pivotCacheRecords${pivotIdx}.xml`)) });
|
|
831
|
+
entries.push({ name: `xl/pivotCache/pivotCacheRecords${pivotIdx}.xml`, data: strToBytes(cacheRecordsXml) });
|
|
832
|
+
}
|
|
356
833
|
entries.push({ name: 'xl/styles.xml', data: strToBytes(styles.toXml()) });
|
|
357
834
|
entries.push({ name: 'xl/sharedStrings.xml', data: strToBytes(shared.toXml()) });
|
|
835
|
+
entries.push({ name: 'xl/theme/theme1.xml', data: strToBytes(this._buildThemeXml()) });
|
|
836
|
+
for (let i = 0; i < this.externalLinks.length; i++) {
|
|
837
|
+
const link = this.externalLinks[i];
|
|
838
|
+
const idx = i + 1;
|
|
839
|
+
const sheetsXml = link.sheets.map(s => {
|
|
840
|
+
const dNames = s.definedNames?.map(d => `<definedName name="${escapeXml(d.name)}" refersTo="${escapeXml(d.ref)}"/>`).join('') ?? '';
|
|
841
|
+
return `<sheetName val="${escapeXml(s.name)}"/>${dNames ? `<sheetDataSet>${dNames}</sheetDataSet>` : ''}`;
|
|
842
|
+
}).join('');
|
|
843
|
+
entries.push({ name: `xl/externalLinks/externalLink${idx}.xml`, data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
844
|
+
<externalLink xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
845
|
+
<externalBook r:id="rId1"><sheetNames>${sheetsXml}</sheetNames></externalBook>
|
|
846
|
+
</externalLink>`) });
|
|
847
|
+
entries.push({ name: `xl/externalLinks/_rels/externalLink${idx}.xml.rels`, data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
848
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
849
|
+
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath" Target="${escapeXml(link.target)}" TargetMode="External"/>
|
|
850
|
+
</Relationships>`) });
|
|
851
|
+
}
|
|
852
|
+
for (const [ws, info] of sheetSlicerMap) {
|
|
853
|
+
const allSheetSlicerItems = [];
|
|
854
|
+
for (const ts of info.tableSlicers) {
|
|
855
|
+
const s = ts.slicer;
|
|
856
|
+
allSheetSlicerItems.push(`<slicer name="${escapeXml(s.name)}" cache="${escapeXml(s.name + '_cache')}" caption="${escapeXml(s.caption ?? s.columnName)}" rowHeight="241300" columnCount="${s.columnCount ?? 1}" style="${s.style ?? 'SlicerStyleLight1'}"/>`);
|
|
857
|
+
}
|
|
858
|
+
for (const ps of info.pivotSlicers) {
|
|
859
|
+
const s = ps.slicer;
|
|
860
|
+
allSheetSlicerItems.push(`<slicer name="${escapeXml(s.name)}" cache="${escapeXml(s.name + '_cache')}" caption="${escapeXml(s.caption ?? s.fieldName)}" rowHeight="241300" columnCount="${s.columnCount ?? 1}" style="${s.style ?? 'SlicerStyleLight1'}"/>`);
|
|
861
|
+
}
|
|
862
|
+
entries.push({ name: `xl/slicers/slicer${info.slicerDefIdx}.xml`, data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
863
|
+
<slicers xmlns="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main" mc:Ignorable="x">
|
|
864
|
+
${allSheetSlicerItems.join('\n')}
|
|
865
|
+
</slicers>`) });
|
|
866
|
+
}
|
|
867
|
+
for (const sc of allSlicerCaches) {
|
|
868
|
+
let cacheBody;
|
|
869
|
+
if (sc.type === 'table') {
|
|
870
|
+
cacheBody = `<extLst><x:ext uri="{2F2917AC-EB37-4324-AD4E-5DD8C200BD13}" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"><x15:tableSlicerCache tableId="${sc.tableId}" column="${sc.columnIndex}" sortOrder="${sc.sortOrder ?? 'ascending'}"/></x:ext></extLst>`;
|
|
871
|
+
}
|
|
872
|
+
else {
|
|
873
|
+
const itemsXml = (sc.items ?? []).map((_, xi) => `<i x="${xi}" s="1"/>`).join('');
|
|
874
|
+
cacheBody = `<pivotTables><pivotTable tabId="${sc.tabId}" name="${escapeXml(sc.pivotTableName ?? '')}"/></pivotTables>` +
|
|
875
|
+
(sc.items?.length ? `<data><tabular pivotCacheId="${sc.pivotCacheId}" showMissing="0"><items count="${sc.items.length}">${itemsXml}</items></tabular></data>` : '');
|
|
876
|
+
}
|
|
877
|
+
entries.push({ name: `xl/slicerCaches/slicerCache${sc.idx}.xml`, data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
878
|
+
<slicerCacheDefinition xmlns="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x" name="${escapeXml(sc.name)}" sourceName="${escapeXml(sc.sourceName)}">
|
|
879
|
+
${cacheBody}
|
|
880
|
+
</slicerCacheDefinition>`) });
|
|
881
|
+
}
|
|
882
|
+
const allQueryTables = this.sheets.flatMap(ws => ws.getQueryTables());
|
|
883
|
+
for (let i = 0; i < allQueryTables.length; i++) {
|
|
884
|
+
const qt = allQueryTables[i];
|
|
885
|
+
entries.push({ name: `xl/queryTables/queryTable${i + 1}.xml`, data: strToBytes(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
886
|
+
<queryTable xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" name="${escapeXml(qt.name)}" connectionId="${qt.connectionId}" autoFormatId="16" applyNumberFormats="0" applyBorderFormats="0" applyFontFormats="0" applyPatternFormats="0" applyAlignmentFormats="0" applyWidthHeightFormats="0">
|
|
887
|
+
<queryTableRefresh nextId="${(qt.columns?.length ?? 0) + 1}">
|
|
888
|
+
<queryTableFields count="${qt.columns?.length ?? 0}">
|
|
889
|
+
${(qt.columns ?? []).map((c, ci) => `<queryTableField id="${ci + 1}" name="${escapeXml(c)}" tableColumnId="${ci + 1}"/>`).join('\n')}
|
|
890
|
+
</queryTableFields>
|
|
891
|
+
</queryTableRefresh>
|
|
892
|
+
</queryTable>`) });
|
|
893
|
+
}
|
|
358
894
|
const cp = { ...this.coreProperties, created: this.coreProperties.created ?? new Date(), modified: new Date() };
|
|
359
895
|
if (!cp.creator && this.properties.author)
|
|
360
896
|
cp.creator = this.properties.author;
|
|
@@ -364,12 +900,27 @@ ${dRels.join('\n')}
|
|
|
364
900
|
application: this.extendedProperties.application ?? 'ExcelForge',
|
|
365
901
|
company: this.extendedProperties.company ?? this.properties.company,
|
|
366
902
|
titlesOfParts: this.sheets.map(s => s.name),
|
|
367
|
-
headingPairs:
|
|
903
|
+
headingPairs: this._headingPairs(),
|
|
368
904
|
})) });
|
|
369
905
|
if (hasCustom)
|
|
370
906
|
entries.push({ name: 'docProps/custom.xml', data: strToBytes(buildCustomXml(this.customProperties)) });
|
|
371
907
|
return buildZip(entries, { level: this.compressionLevel });
|
|
372
908
|
}
|
|
909
|
+
_headingPairs() {
|
|
910
|
+
const normalCount = this.sheets.filter(ws => !ws._isChartSheet && !ws._isDialogSheet).length;
|
|
911
|
+
const chartCount = this.sheets.filter(ws => ws._isChartSheet).length;
|
|
912
|
+
const dialogCount = this.sheets.filter(ws => ws._isDialogSheet).length;
|
|
913
|
+
const pairs = [];
|
|
914
|
+
if (normalCount)
|
|
915
|
+
pairs.push({ name: 'Worksheets', count: normalCount });
|
|
916
|
+
if (chartCount)
|
|
917
|
+
pairs.push({ name: 'Charts', count: chartCount });
|
|
918
|
+
if (dialogCount)
|
|
919
|
+
pairs.push({ name: 'Dialogs', count: dialogCount });
|
|
920
|
+
if (!pairs.length)
|
|
921
|
+
pairs.push({ name: 'Worksheets', count: 0 });
|
|
922
|
+
return pairs;
|
|
923
|
+
}
|
|
373
924
|
_syncLegacyProperties() {
|
|
374
925
|
const p = this.properties;
|
|
375
926
|
if (p.title)
|
|
@@ -393,19 +944,136 @@ ${dRels.join('\n')}
|
|
|
393
944
|
if (p.status)
|
|
394
945
|
this.coreProperties.contentStatus ??= p.status;
|
|
395
946
|
}
|
|
947
|
+
_ensureVbaSheetModules() {
|
|
948
|
+
if (!this.vbaProject)
|
|
949
|
+
return;
|
|
950
|
+
const existingDocModules = this.vbaProject.modules.filter(m => m.type === 'document' && m.name !== 'ThisWorkbook');
|
|
951
|
+
if (existingDocModules.length >= this.sheets.length)
|
|
952
|
+
return;
|
|
953
|
+
for (const ws of this.sheets) {
|
|
954
|
+
const sheetCodeName = ws.name.replace(/[^A-Za-z0-9_]/g, '_');
|
|
955
|
+
if (!this.vbaProject.getModule(sheetCodeName)) {
|
|
956
|
+
this.vbaProject.addModule({ name: sheetCodeName, type: 'document', code: '' });
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
396
960
|
_patchWorkbookXml(originalXml) {
|
|
397
961
|
let xml = originalXml;
|
|
398
962
|
for (let i = 0; i < this.sheets.length; i++) {
|
|
399
963
|
xml = xml.replace(new RegExp(`(<sheet[^>]+sheetId="${i + 1}"[^>]+)name="[^"]*"`), `$1name="${escapeXml(this.sheets[i].name)}"`);
|
|
400
964
|
}
|
|
965
|
+
if (this.vbaProject && !xml.includes('codeName=')) {
|
|
966
|
+
xml = xml.replace('<workbookPr', '<workbookPr codeName="ThisWorkbook"');
|
|
967
|
+
if (!xml.includes('<workbookPr')) {
|
|
968
|
+
xml = xml.replace('<bookViews', '<workbookPr codeName="ThisWorkbook"/><bookViews');
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
const dnXml = this._definedNamesXml();
|
|
972
|
+
if (xml.includes('<definedNames')) {
|
|
973
|
+
xml = xml.replace(/<definedNames[\s\S]*?<\/definedNames>/, dnXml);
|
|
974
|
+
}
|
|
975
|
+
else if (dnXml) {
|
|
976
|
+
xml = xml.replace('</sheets>', `</sheets>${dnXml}`);
|
|
977
|
+
}
|
|
978
|
+
if (this.calcSettings) {
|
|
979
|
+
const newCalcPr = this._calcPrXml();
|
|
980
|
+
if (xml.includes('<calcPr')) {
|
|
981
|
+
xml = xml.replace(/<calcPr[^>]*\/>|<calcPr[^>]*>[\s\S]*?<\/calcPr>/, newCalcPr);
|
|
982
|
+
}
|
|
983
|
+
else {
|
|
984
|
+
xml = xml.replace('</workbook>', `${newCalcPr}</workbook>`);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
401
987
|
return xml;
|
|
402
988
|
}
|
|
403
|
-
|
|
404
|
-
const
|
|
989
|
+
_definedNamesXml(slicerCaches) {
|
|
990
|
+
const printAreaNames = [];
|
|
991
|
+
for (const ws of this.sheets) {
|
|
992
|
+
if (ws.printArea) {
|
|
993
|
+
const ref = ws.printArea.includes('!') ? ws.printArea : `'${ws.name}'!${ws.printArea}`;
|
|
994
|
+
printAreaNames.push({ name: '_xlnm.Print_Area', ref, scope: ws.name });
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
const slicerNames = (slicerCaches ?? []).map(sc => ({ name: sc.name, ref: '#N/A' }));
|
|
998
|
+
const all = [...this.namedRanges, ...printAreaNames, ...slicerNames];
|
|
999
|
+
if (!all.length)
|
|
1000
|
+
return '';
|
|
1001
|
+
return `<definedNames>${all.map(nr => {
|
|
1002
|
+
let attrs = `name="${escapeXml(nr.name)}"`;
|
|
1003
|
+
if (nr.scope) {
|
|
1004
|
+
const idx = this.sheets.findIndex(s => s.name === nr.scope);
|
|
1005
|
+
if (idx >= 0)
|
|
1006
|
+
attrs += ` localSheetId="${idx}"`;
|
|
1007
|
+
}
|
|
1008
|
+
if (nr.comment)
|
|
1009
|
+
attrs += ` comment="${escapeXml(nr.comment)}"`;
|
|
1010
|
+
return `<definedName ${attrs}>${escapeXml(nr.ref)}</definedName>`;
|
|
1011
|
+
}).join('')}</definedNames>`;
|
|
1012
|
+
}
|
|
1013
|
+
_calcPrXml() {
|
|
1014
|
+
const cs = this.calcSettings;
|
|
1015
|
+
let attrs = 'calcId="191028"';
|
|
1016
|
+
if (cs) {
|
|
1017
|
+
if (cs.calcMode === 'manual')
|
|
1018
|
+
attrs += ' calcMode="manual"';
|
|
1019
|
+
else if (cs.calcMode === 'autoNoTable')
|
|
1020
|
+
attrs += ' calcMode="autoNoTable"';
|
|
1021
|
+
if (cs.fullCalcOnLoad)
|
|
1022
|
+
attrs += ' fullCalcOnLoad="1"';
|
|
1023
|
+
if (cs.iterate) {
|
|
1024
|
+
attrs += ' iterate="1"';
|
|
1025
|
+
if (cs.iterateCount != null)
|
|
1026
|
+
attrs += ` iterateCount="${cs.iterateCount}"`;
|
|
1027
|
+
if (cs.iterateDelta != null)
|
|
1028
|
+
attrs += ` iterateDelta="${cs.iterateDelta}"`;
|
|
1029
|
+
}
|
|
1030
|
+
if (cs.fullPrecision === false)
|
|
1031
|
+
attrs += ' fullPrecision="0"';
|
|
1032
|
+
if (cs.calcOnSave === false)
|
|
1033
|
+
attrs += ' calcOnSave="0"';
|
|
1034
|
+
if (cs.concurrentCalc === false)
|
|
1035
|
+
attrs += ' concurrentCalc="0"';
|
|
1036
|
+
}
|
|
1037
|
+
return `<calcPr ${attrs}/>`;
|
|
1038
|
+
}
|
|
1039
|
+
_connectionsXml(originalXml) {
|
|
1040
|
+
if (!this.connections.length)
|
|
1041
|
+
return '';
|
|
1042
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1043
|
+
<connections xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">${this.connections.map(c => {
|
|
1044
|
+
if (c._rawXml)
|
|
1045
|
+
return c._rawXml;
|
|
1046
|
+
let attrs = ` id="${c.id}" name="${escapeXml(c.name)}" type="${connTypeToNum(c.type)}" refreshedVersion="6"`;
|
|
1047
|
+
if (c.description)
|
|
1048
|
+
attrs += ` description="${escapeXml(c.description)}"`;
|
|
1049
|
+
if (c.refreshOnLoad)
|
|
1050
|
+
attrs += ' refreshOnLoad="1"';
|
|
1051
|
+
if (c.background)
|
|
1052
|
+
attrs += ' background="1"';
|
|
1053
|
+
if (c.saveData)
|
|
1054
|
+
attrs += ' saveData="1"';
|
|
1055
|
+
if (c.keepAlive)
|
|
1056
|
+
attrs += ' keepAlive="1"';
|
|
1057
|
+
if (c.interval)
|
|
1058
|
+
attrs += ` interval="${c.interval}"`;
|
|
1059
|
+
const dbPr = c.connectionString || c.command
|
|
1060
|
+
? `<dbPr${c.connectionString ? ` connection="${escapeXml(c.connectionString)}"` : ''}${c.command ? ` command="${escapeXml(c.command)}"` : ''}${c.commandType ? ` commandType="${cmdTypeToNum(c.commandType)}"` : ''}/>`
|
|
1061
|
+
: '';
|
|
1062
|
+
return `<connection${attrs}>${dbPr}</connection>`;
|
|
1063
|
+
}).join('')}</connections>`;
|
|
1064
|
+
}
|
|
1065
|
+
_buildWorkbookRels(rr, dropCalcChain = false) {
|
|
1066
|
+
const rels = [...rr.workbookRels.entries()]
|
|
1067
|
+
.filter(([_, rel]) => !(dropCalcChain && rel.type.includes('/calcChain')))
|
|
1068
|
+
.map(([id, rel]) => `<Relationship Id="${id}" Type="${rel.type}" Target="${rel.target}"/>`);
|
|
405
1069
|
if (![...rr.workbookRels.values()].some(r => r.type.includes('/styles')))
|
|
406
1070
|
rels.push(`<Relationship Id="rIdStyles" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>`);
|
|
407
1071
|
if (![...rr.workbookRels.values()].some(r => r.type.includes('/sharedStrings')))
|
|
408
1072
|
rels.push(`<Relationship Id="rIdShared" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>`);
|
|
1073
|
+
if (this.vbaProject && ![...rr.workbookRels.values()].some(r => r.type.includes('vbaProject')))
|
|
1074
|
+
rels.push(`<Relationship Id="rIdVBA" Type="http://schemas.microsoft.com/office/2006/relationships/vbaProject" Target="vbaProject.bin"/>`);
|
|
1075
|
+
if (this.connections.length && ![...rr.workbookRels.values()].some(r => r.type.includes('/connections')))
|
|
1076
|
+
rels.push(`<Relationship Id="rIdConns" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/connections" Target="connections.xml"/>`);
|
|
409
1077
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
410
1078
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
411
1079
|
${rels.join('\n')}
|
|
@@ -414,8 +1082,51 @@ ${rels.join('\n')}
|
|
|
414
1082
|
_relsToXml(relMap) {
|
|
415
1083
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
416
1084
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
417
|
-
${[...relMap.entries()].map(([id, r]) => `<Relationship Id="${id}" Type="${r.type}" Target="${r.target}"/>`).join('\n')}
|
|
1085
|
+
${[...relMap.entries()].map(([id, r]) => `<Relationship Id="${escapeXml(id)}" Type="${escapeXml(r.type)}" Target="${escapeXml(r.target)}"${r.targetMode ? ` TargetMode="${escapeXml(r.targetMode)}"` : ''}/>`).join('\n')}
|
|
418
1086
|
</Relationships>`;
|
|
1087
|
+
}
|
|
1088
|
+
_buildThemeXml() {
|
|
1089
|
+
const t = this.theme;
|
|
1090
|
+
const majorFont = t?.majorFont ?? 'Calibri Light';
|
|
1091
|
+
const minorFont = t?.minorFont ?? 'Calibri';
|
|
1092
|
+
const defaultColors = [
|
|
1093
|
+
{ name: 'dk1', color: '000000' }, { name: 'lt1', color: 'FFFFFF' },
|
|
1094
|
+
{ name: 'dk2', color: '44546A' }, { name: 'lt2', color: 'E7E6E6' },
|
|
1095
|
+
{ name: 'accent1', color: '4472C4' }, { name: 'accent2', color: 'ED7D31' },
|
|
1096
|
+
{ name: 'accent3', color: 'A5A5A5' }, { name: 'accent4', color: 'FFC000' },
|
|
1097
|
+
{ name: 'accent5', color: '5B9BD5' }, { name: 'accent6', color: '70AD47' },
|
|
1098
|
+
{ name: 'hlink', color: '0563C1' }, { name: 'folHlink', color: '954F72' },
|
|
1099
|
+
];
|
|
1100
|
+
const colors = t?.colors?.map(c => {
|
|
1101
|
+
let hex = c.color.replace(/^#/, '');
|
|
1102
|
+
if (hex.length === 8)
|
|
1103
|
+
hex = hex.substring(2);
|
|
1104
|
+
return { name: c.name, color: hex };
|
|
1105
|
+
}) ?? defaultColors;
|
|
1106
|
+
const colorElements = colors.map(c => {
|
|
1107
|
+
if (c.name === 'dk1' || c.name === 'lt1') {
|
|
1108
|
+
return `<a:${c.name}><a:sysClr val="${c.name === 'dk1' ? 'windowText' : 'window'}" lastClr="${c.color}"/></a:${c.name}>`;
|
|
1109
|
+
}
|
|
1110
|
+
return `<a:${c.name}><a:srgbClr val="${c.color}"/></a:${c.name}>`;
|
|
1111
|
+
}).join('');
|
|
1112
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1113
|
+
<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="${escapeXml(t?.name ?? 'Office Theme')}">
|
|
1114
|
+
<a:themeElements>
|
|
1115
|
+
<a:clrScheme name="Office">${colorElements}</a:clrScheme>
|
|
1116
|
+
<a:fontScheme name="Office">
|
|
1117
|
+
<a:majorFont><a:latin typeface="${escapeXml(majorFont)}"/><a:ea typeface=""/><a:cs typeface=""/></a:majorFont>
|
|
1118
|
+
<a:minorFont><a:latin typeface="${escapeXml(minorFont)}"/><a:ea typeface=""/><a:cs typeface=""/></a:minorFont>
|
|
1119
|
+
</a:fontScheme>
|
|
1120
|
+
<a:fmtScheme name="Office">
|
|
1121
|
+
<a:fillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:lumMod val="110000"/><a:satMod val="105000"/><a:tint val="67000"/></a:schemeClr></a:gs><a:gs pos="50000"><a:schemeClr val="phClr"><a:lumMod val="105000"/><a:satMod val="103000"/><a:tint val="73000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:lumMod val="105000"/><a:satMod val="109000"/><a:tint val="81000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="5400000" scaled="0"/></a:gradFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:satMod val="103000"/><a:lumMod val="102000"/><a:tint val="94000"/></a:schemeClr></a:gs><a:gs pos="50000"><a:schemeClr val="phClr"><a:satMod val="110000"/><a:lumMod val="100000"/><a:shade val="100000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:lumMod val="99000"/><a:satMod val="120000"/><a:shade val="78000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="5400000" scaled="0"/></a:gradFill></a:fillStyleLst>
|
|
1122
|
+
<a:lnStyleLst><a:ln w="6350" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/><a:miter lim="800000"/></a:ln><a:ln w="12700" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/><a:miter lim="800000"/></a:ln><a:ln w="19050" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/><a:miter lim="800000"/></a:ln></a:lnStyleLst>
|
|
1123
|
+
<a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad="57150" dist="19050" dir="5400000" algn="ctr" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="63000"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle></a:effectStyleLst>
|
|
1124
|
+
<a:bgFillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:solidFill><a:schemeClr val="phClr"><a:tint val="95000"/><a:satMod val="170000"/></a:schemeClr></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="93000"/><a:satMod val="150000"/><a:shade val="98000"/><a:lumMod val="102000"/></a:schemeClr></a:gs><a:gs pos="50000"><a:schemeClr val="phClr"><a:tint val="98000"/><a:satMod val="130000"/><a:shade val="90000"/><a:lumMod val="103000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="63000"/><a:satMod val="120000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="5400000" scaled="0"/></a:gradFill></a:bgFillStyleLst>
|
|
1125
|
+
</a:fmtScheme>
|
|
1126
|
+
</a:themeElements>
|
|
1127
|
+
<a:objectDefaults/>
|
|
1128
|
+
<a:extraClrSchemeLst/>
|
|
1129
|
+
</a:theme>`;
|
|
419
1130
|
}
|
|
420
1131
|
_buildRootRels(hasCustom) {
|
|
421
1132
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
@@ -426,12 +1137,24 @@ ${[...relMap.entries()].map(([id, r]) => `<Relationship Id="${id}" Type="${r.typ
|
|
|
426
1137
|
${hasCustom ? `<Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties" Target="docProps/custom.xml"/>` : ''}
|
|
427
1138
|
</Relationships>`;
|
|
428
1139
|
}
|
|
429
|
-
_patchContentTypes(originalXml, addCustom) {
|
|
1140
|
+
_patchContentTypes(originalXml, addCustom, dropCalcChain = false) {
|
|
430
1141
|
let xml = originalXml;
|
|
1142
|
+
if (dropCalcChain)
|
|
1143
|
+
xml = xml.replace(/<Override[^>]*calcChain[^>]*\/>/g, '');
|
|
431
1144
|
if (!xml.includes('sharedStrings'))
|
|
432
1145
|
xml = xml.replace('</Types>', `<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>\n</Types>`);
|
|
433
1146
|
if (addCustom && !xml.includes('custom-properties'))
|
|
434
1147
|
xml = xml.replace('</Types>', `<Override PartName="/docProps/custom.xml" ContentType="application/vnd.openxmlformats-officedocument.custom-properties+xml"/>\n</Types>`);
|
|
1148
|
+
if (this.vbaProject) {
|
|
1149
|
+
if (!xml.includes('vbaProject.bin'))
|
|
1150
|
+
xml = xml.replace('</Types>', `<Override PartName="/xl/vbaProject.bin" ContentType="application/vnd.ms-office.vbaProject"/>\n</Types>`);
|
|
1151
|
+
xml = xml.replace('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml', 'application/vnd.ms-excel.sheet.macroEnabled.main+xml');
|
|
1152
|
+
}
|
|
1153
|
+
if (this.isTemplate && !this.vbaProject) {
|
|
1154
|
+
xml = xml.replace('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml');
|
|
1155
|
+
}
|
|
1156
|
+
if (this.connections.length && !xml.includes('connections.xml'))
|
|
1157
|
+
xml = xml.replace('</Types>', `<Override PartName="/xl/connections.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml"/>\n</Types>`);
|
|
435
1158
|
return xml;
|
|
436
1159
|
}
|
|
437
1160
|
async buildBase64() {
|
|
@@ -452,7 +1175,37 @@ ${hasCustom ? `<Relationship Id="rId4" Type="http://schemas.openxmlformats.org/o
|
|
|
452
1175
|
const commentsXml = comments.map(({ row, col, comment }) => {
|
|
453
1176
|
const ref = `${colIndexToLetter(col)}${row}`;
|
|
454
1177
|
const authorIdx = authors.indexOf(comment.author ?? '');
|
|
455
|
-
|
|
1178
|
+
let textXml;
|
|
1179
|
+
if (comment.richText && comment.richText.length > 0) {
|
|
1180
|
+
textXml = comment.richText.map(run => {
|
|
1181
|
+
let rPr = '';
|
|
1182
|
+
if (run.font) {
|
|
1183
|
+
const f = run.font;
|
|
1184
|
+
if (f.bold)
|
|
1185
|
+
rPr += '<b/>';
|
|
1186
|
+
if (f.italic)
|
|
1187
|
+
rPr += '<i/>';
|
|
1188
|
+
if (f.underline && f.underline !== 'none')
|
|
1189
|
+
rPr += `<u val="${f.underline === 'single' ? 'single' : f.underline}"/>`;
|
|
1190
|
+
if (f.strike)
|
|
1191
|
+
rPr += '<strike/>';
|
|
1192
|
+
if (f.size)
|
|
1193
|
+
rPr += `<sz val="${f.size}"/>`;
|
|
1194
|
+
if (f.color)
|
|
1195
|
+
rPr += `<color rgb="${f.color}"/>`;
|
|
1196
|
+
if (f.name)
|
|
1197
|
+
rPr += `<rFont val="${escapeXml(f.name)}"/>`;
|
|
1198
|
+
if (f.family != null)
|
|
1199
|
+
rPr += `<family val="${f.family}"/>`;
|
|
1200
|
+
}
|
|
1201
|
+
const rPrTag = rPr ? `<rPr>${rPr}</rPr>` : '';
|
|
1202
|
+
return `<r>${rPrTag}<t xml:space="preserve">${escapeXml(run.text)}</t></r>`;
|
|
1203
|
+
}).join('');
|
|
1204
|
+
}
|
|
1205
|
+
else {
|
|
1206
|
+
textXml = `<r><t>${escapeXml(comment.text)}</t></r>`;
|
|
1207
|
+
}
|
|
1208
|
+
return `<comment ref="${ref}" authorId="${authorIdx}"><text>${textXml}</text></comment>`;
|
|
456
1209
|
}).join('');
|
|
457
1210
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
458
1211
|
<comments xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
|
@@ -489,4 +1242,74 @@ ${shapes}
|
|
|
489
1242
|
URL.revokeObjectURL(url);
|
|
490
1243
|
}
|
|
491
1244
|
}
|
|
1245
|
+
function imageContentType(ext) {
|
|
1246
|
+
switch (ext) {
|
|
1247
|
+
case 'jpg': return 'image/jpeg';
|
|
1248
|
+
case 'png': return 'image/png';
|
|
1249
|
+
case 'gif': return 'image/gif';
|
|
1250
|
+
case 'bmp': return 'image/bmp';
|
|
1251
|
+
case 'tiff': return 'image/tiff';
|
|
1252
|
+
case 'emf': return 'image/x-emf';
|
|
1253
|
+
case 'wmf': return 'image/x-wmf';
|
|
1254
|
+
case 'svg': return 'image/svg+xml';
|
|
1255
|
+
case 'ico': return 'image/x-icon';
|
|
1256
|
+
case 'webp': return 'image/webp';
|
|
1257
|
+
default: return `image/${ext}`;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
function imageExt(format) {
|
|
1261
|
+
return format === 'jpeg' ? 'jpg' : format;
|
|
1262
|
+
}
|
|
1263
|
+
function buildMetadataXml(count) {
|
|
1264
|
+
const bks = Array.from({ length: count }, (_, i) => `<bk><extLst><ext uri="{3e2802c4-a4d2-4d8b-9148-e3be6c30e623}"><xlrd:rvb i="${i}"/></ext></extLst></bk>`).join('');
|
|
1265
|
+
const cellBks = Array.from({ length: count }, (_, i) => `<bk><rc t="1" v="${i}"/></bk>`).join('');
|
|
1266
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
1267
|
+
`<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"` +
|
|
1268
|
+
` xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata">` +
|
|
1269
|
+
`<metadataTypes count="1">` +
|
|
1270
|
+
`<metadataType name="XLRICHVALUE" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1"/>` +
|
|
1271
|
+
`</metadataTypes>` +
|
|
1272
|
+
`<futureMetadata name="XLRICHVALUE" count="${count}">${bks}</futureMetadata>` +
|
|
1273
|
+
`<valueMetadata count="${count}">${cellBks}</valueMetadata>` +
|
|
1274
|
+
`</metadata>`;
|
|
1275
|
+
}
|
|
1276
|
+
function buildRichValueXml(count) {
|
|
1277
|
+
const rvs = Array.from({ length: count }, (_, i) => `<rv s="0"><v>${i}</v><v>5</v><v></v></rv>`).join('');
|
|
1278
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
1279
|
+
`<rvData xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" count="${count}">${rvs}</rvData>`;
|
|
1280
|
+
}
|
|
1281
|
+
function buildRichValueRelXml(rIds) {
|
|
1282
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
1283
|
+
`<richValueRels xmlns="http://schemas.microsoft.com/office/spreadsheetml/2022/richvaluerel"` +
|
|
1284
|
+
` xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">` +
|
|
1285
|
+
rIds.map(id => `<rel r:id="${id}"/>`).join('') +
|
|
1286
|
+
`</richValueRels>`;
|
|
1287
|
+
}
|
|
1288
|
+
function buildRichValueStructureXml() {
|
|
1289
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
1290
|
+
`<rvStructures xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" count="1">` +
|
|
1291
|
+
`<s t="_localImage"><k n="_rvRel:LocalImageIdentifier" t="i"/><k n="CalcOrigin" t="i"/><k n="Text" t="s"/></s>` +
|
|
1292
|
+
`</rvStructures>`;
|
|
1293
|
+
}
|
|
1294
|
+
function buildRichValueTypesXml() {
|
|
1295
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
1296
|
+
`<rvTypesInfo xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"` +
|
|
1297
|
+
` xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"` +
|
|
1298
|
+
` mc:Ignorable="x"` +
|
|
1299
|
+
` xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">` +
|
|
1300
|
+
`<global><keyFlags>` +
|
|
1301
|
+
`<key name="_Self"><flag name="ExcludeFromFile" value="1"/><flag name="ExcludeFromCalcComparison" value="1"/></key>` +
|
|
1302
|
+
`<key name="_DisplayString"><flag name="ExcludeFromCalcComparison" value="1"/></key>` +
|
|
1303
|
+
`<key name="_Flags"><flag name="ExcludeFromCalcComparison" value="1"/></key>` +
|
|
1304
|
+
`<key name="_Format"><flag name="ExcludeFromCalcComparison" value="1"/></key>` +
|
|
1305
|
+
`<key name="_SubLabel"><flag name="ExcludeFromCalcComparison" value="1"/></key>` +
|
|
1306
|
+
`<key name="_Attribution"><flag name="ExcludeFromCalcComparison" value="1"/></key>` +
|
|
1307
|
+
`<key name="_Icon"><flag name="ExcludeFromCalcComparison" value="1"/></key>` +
|
|
1308
|
+
`<key name="_Display"><flag name="ExcludeFromCalcComparison" value="1"/></key>` +
|
|
1309
|
+
`<key name="_CanonicalPropertyNames"><flag name="ExcludeFromCalcComparison" value="1"/></key>` +
|
|
1310
|
+
`<key name="_ClassificationId"><flag name="ExcludeFromCalcComparison" value="1"/></key>` +
|
|
1311
|
+
`</keyFlags></global>` +
|
|
1312
|
+
`<types></types>` +
|
|
1313
|
+
`</rvTypesInfo>`;
|
|
1314
|
+
}
|
|
492
1315
|
//# sourceMappingURL=Workbook.js.map
|