@cj-tech-master/excelts 1.5.0 → 1.6.1
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/dist/browser/excelts.iife.js +1057 -201
- package/dist/browser/excelts.iife.js.map +1 -1
- package/dist/browser/excelts.iife.min.js +63 -33
- package/dist/cjs/doc/column.js +7 -3
- package/dist/cjs/doc/pivot-table.js +149 -61
- package/dist/cjs/doc/workbook.js +3 -1
- package/dist/cjs/doc/worksheet.js +0 -2
- package/dist/cjs/stream/xlsx/worksheet-writer.js +1 -1
- package/dist/cjs/utils/unzip/zip-parser.js +2 -5
- package/dist/cjs/xlsx/xform/book/workbook-xform.js +3 -0
- package/dist/cjs/xlsx/xform/core/content-types-xform.js +19 -14
- package/dist/cjs/xlsx/xform/pivot-table/cache-field-xform.js +135 -0
- package/dist/cjs/xlsx/xform/pivot-table/cache-field.js +7 -4
- package/dist/cjs/xlsx/xform/pivot-table/pivot-cache-definition-xform.js +135 -13
- package/dist/cjs/xlsx/xform/pivot-table/pivot-cache-records-xform.js +193 -45
- package/dist/cjs/xlsx/xform/pivot-table/pivot-table-xform.js +390 -39
- package/dist/cjs/xlsx/xform/sheet/cell-xform.js +6 -0
- package/dist/cjs/xlsx/xform/sheet/worksheet-xform.js +14 -3
- package/dist/cjs/xlsx/xlsx.js +261 -38
- package/dist/esm/doc/column.js +7 -3
- package/dist/esm/doc/pivot-table.js +150 -62
- package/dist/esm/doc/workbook.js +3 -1
- package/dist/esm/doc/worksheet.js +0 -2
- package/dist/esm/stream/xlsx/worksheet-writer.js +1 -1
- package/dist/esm/utils/unzip/zip-parser.js +2 -5
- package/dist/esm/xlsx/xform/book/workbook-xform.js +3 -0
- package/dist/esm/xlsx/xform/core/content-types-xform.js +19 -14
- package/dist/esm/xlsx/xform/pivot-table/cache-field-xform.js +132 -0
- package/dist/esm/xlsx/xform/pivot-table/cache-field.js +7 -4
- package/dist/esm/xlsx/xform/pivot-table/pivot-cache-definition-xform.js +135 -13
- package/dist/esm/xlsx/xform/pivot-table/pivot-cache-records-xform.js +193 -45
- package/dist/esm/xlsx/xform/pivot-table/pivot-table-xform.js +390 -39
- package/dist/esm/xlsx/xform/sheet/cell-xform.js +6 -0
- package/dist/esm/xlsx/xform/sheet/worksheet-xform.js +14 -3
- package/dist/esm/xlsx/xlsx.js +261 -38
- package/dist/types/doc/column.d.ts +13 -6
- package/dist/types/doc/pivot-table.d.ts +135 -9
- package/dist/types/doc/workbook.d.ts +2 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/xlsx/xform/pivot-table/cache-field-xform.d.ts +42 -0
- package/dist/types/xlsx/xform/pivot-table/pivot-cache-definition-xform.d.ts +45 -6
- package/dist/types/xlsx/xform/pivot-table/pivot-cache-records-xform.d.ts +52 -5
- package/dist/types/xlsx/xform/pivot-table/pivot-table-xform.d.ts +98 -5
- package/dist/types/xlsx/xlsx.d.ts +27 -0
- package/package.json +17 -17
package/dist/cjs/xlsx/xlsx.js
CHANGED
|
@@ -111,6 +111,8 @@ class XLSX {
|
|
|
111
111
|
Object.values(model.tables).forEach((table) => {
|
|
112
112
|
tableXform.reconcile(table, tableOptions);
|
|
113
113
|
});
|
|
114
|
+
// Reconcile pivot tables - link pivot tables to worksheets and cache data
|
|
115
|
+
this._reconcilePivotTables(model);
|
|
114
116
|
const sheetOptions = {
|
|
115
117
|
styles: model.styles,
|
|
116
118
|
sharedStrings: model.sharedStrings,
|
|
@@ -120,7 +122,8 @@ class XLSX {
|
|
|
120
122
|
drawings: model.drawings,
|
|
121
123
|
comments: model.comments,
|
|
122
124
|
tables: model.tables,
|
|
123
|
-
vmlDrawings: model.vmlDrawings
|
|
125
|
+
vmlDrawings: model.vmlDrawings,
|
|
126
|
+
pivotTables: model.pivotTablesIndexed
|
|
124
127
|
};
|
|
125
128
|
model.worksheets.forEach((worksheet) => {
|
|
126
129
|
worksheet.relationships = model.worksheetRels[worksheet.sheetNo];
|
|
@@ -138,6 +141,136 @@ class XLSX {
|
|
|
138
141
|
delete model.drawings;
|
|
139
142
|
delete model.drawingRels;
|
|
140
143
|
delete model.vmlDrawings;
|
|
144
|
+
// Clean up raw pivot table data after reconciliation
|
|
145
|
+
delete model.pivotTableRels;
|
|
146
|
+
delete model.pivotCacheDefinitionRels;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Reconcile pivot tables by linking them to worksheets and their cache data.
|
|
150
|
+
* This builds a complete pivot table model ready for writing.
|
|
151
|
+
*/
|
|
152
|
+
_reconcilePivotTables(model) {
|
|
153
|
+
// Skip if no pivot tables were loaded (object is empty or undefined)
|
|
154
|
+
const rawPivotTables = model.pivotTables || {};
|
|
155
|
+
if (typeof rawPivotTables !== "object" || Object.keys(rawPivotTables).length === 0) {
|
|
156
|
+
// Ensure pivotTables is an empty array (not an object)
|
|
157
|
+
model.pivotTables = [];
|
|
158
|
+
// Also create an empty indexed object for worksheet reconciliation
|
|
159
|
+
model.pivotTablesIndexed = {};
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// Build mapping from definition name to cacheId
|
|
163
|
+
const definitionToCacheId = this._buildDefinitionToCacheIdMap(model);
|
|
164
|
+
// Build a map of cache IDs to their definitions and records
|
|
165
|
+
const cacheMap = new Map();
|
|
166
|
+
// Process cache definitions
|
|
167
|
+
Object.entries(model.pivotCacheDefinitions || {}).forEach(([name, definition]) => {
|
|
168
|
+
// Get the cacheId from the mapping (derived from workbook.xml pivotCaches)
|
|
169
|
+
const cacheId = definitionToCacheId.get(name);
|
|
170
|
+
if (cacheId !== undefined) {
|
|
171
|
+
const recordsName = name.replace("Definition", "Records");
|
|
172
|
+
cacheMap.set(cacheId, {
|
|
173
|
+
definition,
|
|
174
|
+
records: model.pivotCacheRecords?.[recordsName],
|
|
175
|
+
definitionName: name
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
// Process pivot tables and link to worksheets
|
|
180
|
+
const loadedPivotTables = [];
|
|
181
|
+
// Create indexed object for worksheet reconciliation (keyed by relative path)
|
|
182
|
+
const pivotTablesIndexed = {};
|
|
183
|
+
Object.entries(rawPivotTables).forEach(([pivotName, pivotTable]) => {
|
|
184
|
+
const pt = pivotTable;
|
|
185
|
+
const tableNumber = this._extractTableNumber(pivotName);
|
|
186
|
+
// Get cache data for this pivot table
|
|
187
|
+
const cacheData = cacheMap.get(pt.cacheId);
|
|
188
|
+
// Build complete pivot table model
|
|
189
|
+
const completePivotTable = {
|
|
190
|
+
// Core model data
|
|
191
|
+
...pt,
|
|
192
|
+
tableNumber,
|
|
193
|
+
// Link to cache data
|
|
194
|
+
cacheDefinition: cacheData?.definition,
|
|
195
|
+
cacheRecords: cacheData?.records,
|
|
196
|
+
// Reconstruct cacheFields from definition for compatibility
|
|
197
|
+
cacheFields: cacheData?.definition?.cacheFields || [],
|
|
198
|
+
// Determine rows, columns, values from parsed data
|
|
199
|
+
rows: pt.rowFields.filter(f => f >= 0),
|
|
200
|
+
columns: pt.colFields.filter(f => f >= 0 && f !== -2),
|
|
201
|
+
values: pt.dataFields.map(df => df.fld),
|
|
202
|
+
// Determine metric from dataFields
|
|
203
|
+
metric: this._determineMetric(pt.dataFields),
|
|
204
|
+
// Preserve formatting options
|
|
205
|
+
applyWidthHeightFormats: pt.applyWidthHeightFormats || "0"
|
|
206
|
+
};
|
|
207
|
+
loadedPivotTables.push(completePivotTable);
|
|
208
|
+
// Index by relative path for worksheet reconciliation
|
|
209
|
+
pivotTablesIndexed[`../pivotTables/${pivotName}.xml`] = completePivotTable;
|
|
210
|
+
});
|
|
211
|
+
// Sort by table number to maintain order
|
|
212
|
+
loadedPivotTables.sort((a, b) => a.tableNumber - b.tableNumber);
|
|
213
|
+
// Replace pivotTables object with the processed array
|
|
214
|
+
// This is what the Workbook model setter expects
|
|
215
|
+
model.pivotTables = loadedPivotTables;
|
|
216
|
+
// Also keep indexed version for worksheet reconciliation
|
|
217
|
+
model.pivotTablesIndexed = pivotTablesIndexed;
|
|
218
|
+
// Also keep as loadedPivotTables for backward compatibility
|
|
219
|
+
model.loadedPivotTables = loadedPivotTables;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Extract table number from pivot table name (e.g., "pivotTable1" -> 1)
|
|
223
|
+
*/
|
|
224
|
+
_extractTableNumber(name) {
|
|
225
|
+
const match = name.match(/pivotTable(\d+)/);
|
|
226
|
+
return match ? parseInt(match[1], 10) : 1;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Build a mapping from rId to cacheId using pivotCaches from workbook.xml
|
|
230
|
+
* and workbookRels to determine which definition file corresponds to which cacheId
|
|
231
|
+
*/
|
|
232
|
+
_buildCacheIdMap(model) {
|
|
233
|
+
const rIdToCacheId = new Map();
|
|
234
|
+
// pivotCaches from workbook.xml contains {cacheId, rId} mappings
|
|
235
|
+
const pivotCaches = model.pivotCaches || [];
|
|
236
|
+
for (const cache of pivotCaches) {
|
|
237
|
+
if (cache.cacheId && cache.rId) {
|
|
238
|
+
rIdToCacheId.set(cache.rId, parseInt(cache.cacheId, 10));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return rIdToCacheId;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Build a mapping from definition name to cacheId
|
|
245
|
+
*/
|
|
246
|
+
_buildDefinitionToCacheIdMap(model) {
|
|
247
|
+
const definitionToCacheId = new Map();
|
|
248
|
+
const rIdToCacheId = this._buildCacheIdMap(model);
|
|
249
|
+
const workbookRels = model.workbookRels || [];
|
|
250
|
+
// Map workbook rels to get definitionNumber -> cacheId mapping
|
|
251
|
+
for (const rel of workbookRels) {
|
|
252
|
+
if (rel.Type === XLSX.RelType.PivotCacheDefinition && rel.Target) {
|
|
253
|
+
// Extract definition number from target (e.g., "pivotCache/pivotCacheDefinition1.xml" -> 1)
|
|
254
|
+
const match = rel.Target.match(/pivotCacheDefinition(\d+)\.xml/);
|
|
255
|
+
if (match) {
|
|
256
|
+
const defName = `pivotCacheDefinition${match[1]}`;
|
|
257
|
+
const cacheId = rIdToCacheId.get(rel.Id);
|
|
258
|
+
if (cacheId !== undefined) {
|
|
259
|
+
definitionToCacheId.set(defName, cacheId);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return definitionToCacheId;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Determine the aggregation metric from dataFields
|
|
268
|
+
*/
|
|
269
|
+
_determineMetric(dataFields) {
|
|
270
|
+
if (dataFields.length > 0 && dataFields[0].subtotal === "count") {
|
|
271
|
+
return "count";
|
|
272
|
+
}
|
|
273
|
+
return "sum";
|
|
141
274
|
}
|
|
142
275
|
async _processWorksheetEntry(stream, model, sheetNo, options, path) {
|
|
143
276
|
const xform = new worksheet_xform_js_1.WorkSheetXform(options);
|
|
@@ -240,6 +373,37 @@ class XLSX {
|
|
|
240
373
|
stream.pipe(streamBuf);
|
|
241
374
|
});
|
|
242
375
|
}
|
|
376
|
+
async _processPivotTableEntry(stream, model, name) {
|
|
377
|
+
const xform = new pivot_table_xform_js_1.PivotTableXform();
|
|
378
|
+
const pivotTable = await xform.parseStream(stream);
|
|
379
|
+
if (pivotTable) {
|
|
380
|
+
model.pivotTables[name] = pivotTable;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
async _processPivotTableRelsEntry(stream, model, name) {
|
|
384
|
+
const xform = new relationships_xform_js_1.RelationshipsXform();
|
|
385
|
+
const relationships = await xform.parseStream(stream);
|
|
386
|
+
model.pivotTableRels[name] = relationships;
|
|
387
|
+
}
|
|
388
|
+
async _processPivotCacheDefinitionEntry(stream, model, name) {
|
|
389
|
+
const xform = new pivot_cache_definition_xform_js_1.PivotCacheDefinitionXform();
|
|
390
|
+
const cacheDefinition = await xform.parseStream(stream);
|
|
391
|
+
if (cacheDefinition) {
|
|
392
|
+
model.pivotCacheDefinitions[name] = cacheDefinition;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
async _processPivotCacheDefinitionRelsEntry(stream, model, name) {
|
|
396
|
+
const xform = new relationships_xform_js_1.RelationshipsXform();
|
|
397
|
+
const relationships = await xform.parseStream(stream);
|
|
398
|
+
model.pivotCacheDefinitionRels[name] = relationships;
|
|
399
|
+
}
|
|
400
|
+
async _processPivotCacheRecordsEntry(stream, model, name) {
|
|
401
|
+
const xform = new pivot_cache_records_xform_js_1.PivotCacheRecordsXform();
|
|
402
|
+
const cacheRecords = await xform.parseStream(stream);
|
|
403
|
+
if (cacheRecords) {
|
|
404
|
+
model.pivotCacheRecords[name] = cacheRecords;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
243
407
|
async read(stream, options) {
|
|
244
408
|
// Use streaming unzip with fflate
|
|
245
409
|
const allFiles = {};
|
|
@@ -349,7 +513,13 @@ class XLSX {
|
|
|
349
513
|
drawingRels: {},
|
|
350
514
|
comments: {},
|
|
351
515
|
tables: {},
|
|
352
|
-
vmlDrawings: {}
|
|
516
|
+
vmlDrawings: {},
|
|
517
|
+
// Pivot table storage for loaded files
|
|
518
|
+
pivotTables: {},
|
|
519
|
+
pivotTableRels: {},
|
|
520
|
+
pivotCacheDefinitions: {},
|
|
521
|
+
pivotCacheDefinitionRels: {},
|
|
522
|
+
pivotCacheRecords: {}
|
|
353
523
|
};
|
|
354
524
|
// Convert fflate format to JSZip-like structure for compatibility
|
|
355
525
|
const entries = Object.keys(zipData).map(name => ({
|
|
@@ -397,6 +567,9 @@ class XLSX {
|
|
|
397
567
|
model.views = workbook.views;
|
|
398
568
|
model.properties = workbook.properties;
|
|
399
569
|
model.calcProperties = workbook.calcProperties;
|
|
570
|
+
// pivotCaches contains the mapping from rId to cacheId
|
|
571
|
+
// needed for linking pivot tables to their cache data
|
|
572
|
+
model.pivotCaches = workbook.pivotCaches;
|
|
400
573
|
break;
|
|
401
574
|
}
|
|
402
575
|
case "xl/sharedStrings.xml":
|
|
@@ -465,6 +638,33 @@ class XLSX {
|
|
|
465
638
|
await this._processThemeEntry(stream, model, match[1]);
|
|
466
639
|
break;
|
|
467
640
|
}
|
|
641
|
+
// Pivot table files
|
|
642
|
+
match = entryName.match(/xl\/pivotTables\/(pivotTable\d+)[.]xml/);
|
|
643
|
+
if (match) {
|
|
644
|
+
await this._processPivotTableEntry(stream, model, match[1]);
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
match = entryName.match(/xl\/pivotTables\/_rels\/(pivotTable\d+)[.]xml[.]rels/);
|
|
648
|
+
if (match) {
|
|
649
|
+
await this._processPivotTableRelsEntry(stream, model, match[1]);
|
|
650
|
+
break;
|
|
651
|
+
}
|
|
652
|
+
// Pivot cache files
|
|
653
|
+
match = entryName.match(/xl\/pivotCache\/(pivotCacheDefinition\d+)[.]xml/);
|
|
654
|
+
if (match) {
|
|
655
|
+
await this._processPivotCacheDefinitionEntry(stream, model, match[1]);
|
|
656
|
+
break;
|
|
657
|
+
}
|
|
658
|
+
match = entryName.match(/xl\/pivotCache\/_rels\/(pivotCacheDefinition\d+)[.]xml[.]rels/);
|
|
659
|
+
if (match) {
|
|
660
|
+
await this._processPivotCacheDefinitionRelsEntry(stream, model, match[1]);
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
match = entryName.match(/xl\/pivotCache\/(pivotCacheRecords\d+)[.]xml/);
|
|
664
|
+
if (match) {
|
|
665
|
+
await this._processPivotCacheRecordsEntry(stream, model, match[1]);
|
|
666
|
+
break;
|
|
667
|
+
}
|
|
468
668
|
}
|
|
469
669
|
}
|
|
470
670
|
}
|
|
@@ -521,21 +721,24 @@ class XLSX {
|
|
|
521
721
|
Target: "sharedStrings.xml"
|
|
522
722
|
});
|
|
523
723
|
}
|
|
524
|
-
|
|
525
|
-
|
|
724
|
+
// Add relationships for all pivot tables
|
|
725
|
+
(model.pivotTables || []).forEach((pivotTable) => {
|
|
526
726
|
pivotTable.rId = `rId${count++}`;
|
|
527
727
|
relationships.push({
|
|
528
728
|
Id: pivotTable.rId,
|
|
529
729
|
Type: XLSX.RelType.PivotCacheDefinition,
|
|
530
|
-
Target:
|
|
730
|
+
Target: `pivotCache/pivotCacheDefinition${pivotTable.tableNumber}.xml`
|
|
531
731
|
});
|
|
532
|
-
}
|
|
533
|
-
model.worksheets.forEach((worksheet) => {
|
|
732
|
+
});
|
|
733
|
+
model.worksheets.forEach((worksheet, index) => {
|
|
734
|
+
// Use sequential index (1-based) for file naming, not worksheet.id (sheetId)
|
|
735
|
+
// sheetId can be non-sequential (e.g., 1, 3, 5) which would create gaps in filenames
|
|
534
736
|
worksheet.rId = `rId${count++}`;
|
|
737
|
+
worksheet.fileIndex = index + 1; // Store for use in addWorksheets and content types
|
|
535
738
|
relationships.push({
|
|
536
739
|
Id: worksheet.rId,
|
|
537
740
|
Type: XLSX.RelType.Worksheet,
|
|
538
|
-
Target: `worksheets/sheet${worksheet.
|
|
741
|
+
Target: `worksheets/sheet${worksheet.fileIndex}.xml`
|
|
539
742
|
});
|
|
540
743
|
});
|
|
541
744
|
const xform = new relationships_xform_js_1.RelationshipsXform();
|
|
@@ -564,22 +767,24 @@ class XLSX {
|
|
|
564
767
|
const commentsXform = new comments_xform_js_1.CommentsXform();
|
|
565
768
|
const vmlNotesXform = new vml_notes_xform_js_1.VmlNotesXform();
|
|
566
769
|
// write sheets
|
|
567
|
-
model.worksheets.forEach((worksheet) => {
|
|
770
|
+
model.worksheets.forEach((worksheet, index) => {
|
|
771
|
+
// Use fileIndex if set by addWorkbookRels, otherwise use index + 1
|
|
772
|
+
const fileIndex = worksheet.fileIndex || index + 1;
|
|
568
773
|
let xmlStream = new xml_stream_js_1.XmlStream();
|
|
569
774
|
worksheetXform.render(xmlStream, worksheet);
|
|
570
|
-
zip.append(xmlStream.xml, { name: `xl/worksheets/sheet${
|
|
775
|
+
zip.append(xmlStream.xml, { name: `xl/worksheets/sheet${fileIndex}.xml` });
|
|
571
776
|
if (worksheet.rels && worksheet.rels.length) {
|
|
572
777
|
xmlStream = new xml_stream_js_1.XmlStream();
|
|
573
778
|
relationshipsXform.render(xmlStream, worksheet.rels);
|
|
574
|
-
zip.append(xmlStream.xml, { name: `xl/worksheets/_rels/sheet${
|
|
779
|
+
zip.append(xmlStream.xml, { name: `xl/worksheets/_rels/sheet${fileIndex}.xml.rels` });
|
|
575
780
|
}
|
|
576
781
|
if (worksheet.comments.length > 0) {
|
|
577
782
|
xmlStream = new xml_stream_js_1.XmlStream();
|
|
578
783
|
commentsXform.render(xmlStream, worksheet);
|
|
579
|
-
zip.append(xmlStream.xml, { name: `xl/comments${
|
|
784
|
+
zip.append(xmlStream.xml, { name: `xl/comments${fileIndex}.xml` });
|
|
580
785
|
xmlStream = new xml_stream_js_1.XmlStream();
|
|
581
786
|
vmlNotesXform.render(xmlStream, worksheet);
|
|
582
|
-
zip.append(xmlStream.xml, { name: `xl/drawings/vmlDrawing${
|
|
787
|
+
zip.append(xmlStream.xml, { name: `xl/drawings/vmlDrawing${fileIndex}.vml` });
|
|
583
788
|
}
|
|
584
789
|
});
|
|
585
790
|
}
|
|
@@ -632,37 +837,55 @@ class XLSX {
|
|
|
632
837
|
if (!model.pivotTables.length) {
|
|
633
838
|
return;
|
|
634
839
|
}
|
|
635
|
-
const pivotTable = model.pivotTables[0];
|
|
636
840
|
const pivotCacheRecordsXform = new pivot_cache_records_xform_js_1.PivotCacheRecordsXform();
|
|
637
841
|
const pivotCacheDefinitionXform = new pivot_cache_definition_xform_js_1.PivotCacheDefinitionXform();
|
|
638
842
|
const pivotTableXform = new pivot_table_xform_js_1.PivotTableXform();
|
|
639
843
|
const relsXform = new relationships_xform_js_1.RelationshipsXform();
|
|
640
|
-
// pivot
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
844
|
+
// Generate files for each pivot table
|
|
845
|
+
model.pivotTables.forEach((pivotTable) => {
|
|
846
|
+
const n = pivotTable.tableNumber;
|
|
847
|
+
// For loaded pivot tables, use the stored cache data
|
|
848
|
+
// For new pivot tables, use the source data
|
|
849
|
+
const isLoaded = pivotTable.isLoaded;
|
|
850
|
+
if (isLoaded) {
|
|
851
|
+
// Loaded pivot table - use stored cache definition and records
|
|
852
|
+
if (pivotTable.cacheDefinition) {
|
|
853
|
+
const xml = pivotCacheDefinitionXform.toXml(pivotTable.cacheDefinition);
|
|
854
|
+
zip.append(xml, { name: `xl/pivotCache/pivotCacheDefinition${n}.xml` });
|
|
855
|
+
}
|
|
856
|
+
if (pivotTable.cacheRecords) {
|
|
857
|
+
const xml = pivotCacheRecordsXform.toXml(pivotTable.cacheRecords);
|
|
858
|
+
zip.append(xml, { name: `xl/pivotCache/pivotCacheRecords${n}.xml` });
|
|
859
|
+
}
|
|
652
860
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
{
|
|
660
|
-
Id: "rId1",
|
|
661
|
-
Type: XLSX.RelType.PivotCacheDefinition,
|
|
662
|
-
Target: "../pivotCache/pivotCacheDefinition1.xml"
|
|
861
|
+
else {
|
|
862
|
+
// New pivot table - generate from source
|
|
863
|
+
let xml = pivotCacheRecordsXform.toXml(pivotTable);
|
|
864
|
+
zip.append(xml, { name: `xl/pivotCache/pivotCacheRecords${n}.xml` });
|
|
865
|
+
xml = pivotCacheDefinitionXform.toXml(pivotTable);
|
|
866
|
+
zip.append(xml, { name: `xl/pivotCache/pivotCacheDefinition${n}.xml` });
|
|
663
867
|
}
|
|
664
|
-
|
|
665
|
-
|
|
868
|
+
// pivot cache definition rels (same for both)
|
|
869
|
+
let xml = relsXform.toXml([
|
|
870
|
+
{
|
|
871
|
+
Id: "rId1",
|
|
872
|
+
Type: XLSX.RelType.PivotCacheRecords,
|
|
873
|
+
Target: `pivotCacheRecords${n}.xml`
|
|
874
|
+
}
|
|
875
|
+
]);
|
|
876
|
+
zip.append(xml, { name: `xl/pivotCache/_rels/pivotCacheDefinition${n}.xml.rels` });
|
|
877
|
+
// pivot table
|
|
878
|
+
xml = pivotTableXform.toXml(pivotTable);
|
|
879
|
+
zip.append(xml, { name: `xl/pivotTables/pivotTable${n}.xml` });
|
|
880
|
+
xml = relsXform.toXml([
|
|
881
|
+
{
|
|
882
|
+
Id: "rId1",
|
|
883
|
+
Type: XLSX.RelType.PivotCacheDefinition,
|
|
884
|
+
Target: `../pivotCache/pivotCacheDefinition${n}.xml`
|
|
885
|
+
}
|
|
886
|
+
]);
|
|
887
|
+
zip.append(xml, { name: `xl/pivotTables/_rels/pivotTable${n}.xml.rels` });
|
|
888
|
+
});
|
|
666
889
|
}
|
|
667
890
|
_finalize(zip) {
|
|
668
891
|
return new Promise((resolve, reject) => {
|
package/dist/esm/doc/column.js
CHANGED
|
@@ -64,6 +64,9 @@ class Column {
|
|
|
64
64
|
this.outlineLevel = 0;
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Get header values as an array (for multi-row header support)
|
|
69
|
+
*/
|
|
67
70
|
get headers() {
|
|
68
71
|
if (Array.isArray(this._header)) {
|
|
69
72
|
return this._header;
|
|
@@ -74,7 +77,8 @@ class Column {
|
|
|
74
77
|
return [];
|
|
75
78
|
}
|
|
76
79
|
/**
|
|
77
|
-
* Can be a
|
|
80
|
+
* Can be a single value or an array for multi-row headers.
|
|
81
|
+
* Supports any CellValue type including Date, number, string, etc.
|
|
78
82
|
*/
|
|
79
83
|
get header() {
|
|
80
84
|
return this._header;
|
|
@@ -82,8 +86,8 @@ class Column {
|
|
|
82
86
|
set header(value) {
|
|
83
87
|
if (value !== undefined) {
|
|
84
88
|
this._header = value;
|
|
85
|
-
this.headers.forEach((
|
|
86
|
-
this._worksheet.getCell(index + 1, this.number).value =
|
|
89
|
+
this.headers.forEach((cellValue, index) => {
|
|
90
|
+
this._worksheet.getCell(index + 1, this.number).value = cellValue;
|
|
87
91
|
});
|
|
88
92
|
}
|
|
89
93
|
else {
|