@cj-tech-master/excelts 4.2.3 → 5.0.0-canary.20260123012457.1fdf506
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/modules/csv/csv-core.d.ts +0 -9
- package/dist/browser/modules/csv/csv.browser.js +3 -3
- package/dist/browser/modules/excel/column.d.ts +5 -0
- package/dist/browser/modules/excel/column.js +10 -2
- package/dist/browser/modules/excel/row.d.ts +2 -0
- package/dist/browser/modules/excel/row.js +3 -1
- package/dist/browser/modules/excel/utils/parse-sax.d.ts +0 -3
- package/dist/browser/modules/excel/utils/parse-sax.js +13 -32
- package/dist/browser/modules/excel/utils/passthrough-manager.d.ts +77 -0
- package/dist/browser/modules/excel/utils/passthrough-manager.js +129 -0
- package/dist/browser/modules/excel/workbook.d.ts +12 -0
- package/dist/browser/modules/excel/workbook.js +12 -1
- package/dist/browser/modules/excel/worksheet.d.ts +4 -0
- package/dist/browser/modules/excel/worksheet.js +4 -1
- package/dist/browser/modules/excel/xlsx/xform/base-xform.js +68 -1
- package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +16 -10
- package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +35 -11
- package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +271 -94
- package/dist/browser/modules/excel/xlsx/xform/sheet/row-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/row-xform.js +7 -1
- package/dist/browser/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.js +9 -4
- package/dist/browser/modules/excel/xlsx/xform/sheet/sheet-view-xform.js +4 -2
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +40 -12
- package/dist/browser/modules/excel/xlsx/xform/style/style-xform.d.ts +7 -0
- package/dist/browser/modules/excel/xlsx/xform/style/style-xform.js +26 -6
- package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.d.ts +6 -0
- package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.js +52 -4
- package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +36 -1
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +220 -131
- package/dist/browser/modules/stream/streams.browser.js +0 -3
- package/dist/cjs/modules/csv/csv.browser.js +3 -3
- package/dist/cjs/modules/excel/column.js +10 -2
- package/dist/cjs/modules/excel/row.js +3 -1
- package/dist/cjs/modules/excel/utils/parse-sax.js +13 -32
- package/dist/cjs/modules/excel/utils/passthrough-manager.js +133 -0
- package/dist/cjs/modules/excel/workbook.js +12 -1
- package/dist/cjs/modules/excel/worksheet.js +4 -1
- package/dist/cjs/modules/excel/xlsx/xform/base-xform.js +68 -1
- package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +16 -10
- package/dist/cjs/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +271 -94
- package/dist/cjs/modules/excel/xlsx/xform/sheet/row-xform.js +7 -1
- package/dist/cjs/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.js +9 -4
- package/dist/cjs/modules/excel/xlsx/xform/sheet/sheet-view-xform.js +4 -2
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +40 -12
- package/dist/cjs/modules/excel/xlsx/xform/style/style-xform.js +26 -6
- package/dist/cjs/modules/excel/xlsx/xform/style/styles-xform.js +52 -4
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +220 -131
- package/dist/cjs/modules/stream/streams.browser.js +0 -3
- package/dist/esm/modules/csv/csv.browser.js +3 -3
- package/dist/esm/modules/excel/column.js +10 -2
- package/dist/esm/modules/excel/row.js +3 -1
- package/dist/esm/modules/excel/utils/parse-sax.js +13 -32
- package/dist/esm/modules/excel/utils/passthrough-manager.js +129 -0
- package/dist/esm/modules/excel/workbook.js +12 -1
- package/dist/esm/modules/excel/worksheet.js +4 -1
- package/dist/esm/modules/excel/xlsx/xform/base-xform.js +68 -1
- package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +16 -10
- package/dist/esm/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +271 -94
- package/dist/esm/modules/excel/xlsx/xform/sheet/row-xform.js +7 -1
- package/dist/esm/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.js +9 -4
- package/dist/esm/modules/excel/xlsx/xform/sheet/sheet-view-xform.js +4 -2
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +40 -12
- package/dist/esm/modules/excel/xlsx/xform/style/style-xform.js +26 -6
- package/dist/esm/modules/excel/xlsx/xform/style/styles-xform.js +52 -4
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +220 -131
- package/dist/esm/modules/stream/streams.browser.js +0 -3
- package/dist/iife/excelts.iife.js +1009 -650
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +25 -52
- package/dist/types/modules/csv/csv-core.d.ts +0 -9
- package/dist/types/modules/excel/column.d.ts +5 -0
- package/dist/types/modules/excel/row.d.ts +2 -0
- package/dist/types/modules/excel/utils/parse-sax.d.ts +0 -3
- package/dist/types/modules/excel/utils/passthrough-manager.d.ts +77 -0
- package/dist/types/modules/excel/workbook.d.ts +12 -0
- package/dist/types/modules/excel/worksheet.d.ts +4 -0
- package/dist/types/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +35 -11
- package/dist/types/modules/excel/xlsx/xform/sheet/row-xform.d.ts +1 -0
- package/dist/types/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.d.ts +1 -0
- package/dist/types/modules/excel/xlsx/xform/style/style-xform.d.ts +7 -0
- package/dist/types/modules/excel/xlsx/xform/style/styles-xform.d.ts +6 -0
- package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +36 -1
- package/package.json +15 -15
|
@@ -4,18 +4,30 @@ import { BaseXform } from "../base-xform.js";
|
|
|
4
4
|
class PivotTableXform extends BaseXform {
|
|
5
5
|
constructor() {
|
|
6
6
|
super();
|
|
7
|
+
// Parser state consolidated into object for easier reset
|
|
8
|
+
this.state = {
|
|
9
|
+
inPivotFields: false,
|
|
10
|
+
inRowFields: false,
|
|
11
|
+
inColFields: false,
|
|
12
|
+
inDataFields: false,
|
|
13
|
+
inRowItems: false,
|
|
14
|
+
inColItems: false,
|
|
15
|
+
inLocation: false,
|
|
16
|
+
inItems: false,
|
|
17
|
+
inPivotTableStyleInfo: false,
|
|
18
|
+
inChartFormats: false,
|
|
19
|
+
inPivotArea: false
|
|
20
|
+
};
|
|
21
|
+
// Current parsing context
|
|
22
|
+
this.currentPivotField = null;
|
|
23
|
+
this.currentRowItem = null;
|
|
24
|
+
this.currentColItem = null;
|
|
25
|
+
this.currentChartFormat = null;
|
|
26
|
+
// Buffer for collecting pivotArea XML
|
|
27
|
+
this.pivotAreaXmlBuffer = [];
|
|
28
|
+
this.pivotAreaDepth = 0;
|
|
7
29
|
this.map = {};
|
|
8
30
|
this.model = null;
|
|
9
|
-
this.inPivotFields = false;
|
|
10
|
-
this.inRowFields = false;
|
|
11
|
-
this.inColFields = false;
|
|
12
|
-
this.inDataFields = false;
|
|
13
|
-
this.inRowItems = false;
|
|
14
|
-
this.inColItems = false;
|
|
15
|
-
this.inLocation = false;
|
|
16
|
-
this.currentPivotField = null;
|
|
17
|
-
this.inItems = false;
|
|
18
|
-
this.inPivotTableStyleInfo = false;
|
|
19
31
|
}
|
|
20
32
|
prepare(_model) {
|
|
21
33
|
// No preparation needed
|
|
@@ -26,16 +38,17 @@ class PivotTableXform extends BaseXform {
|
|
|
26
38
|
}
|
|
27
39
|
reset() {
|
|
28
40
|
this.model = null;
|
|
29
|
-
|
|
30
|
-
this.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.inColItems = false;
|
|
35
|
-
this.inLocation = false;
|
|
41
|
+
// Reset all parser state flags using object
|
|
42
|
+
Object.keys(this.state).forEach(key => {
|
|
43
|
+
this.state[key] = false;
|
|
44
|
+
});
|
|
45
|
+
// Reset current context
|
|
36
46
|
this.currentPivotField = null;
|
|
37
|
-
this.
|
|
38
|
-
this.
|
|
47
|
+
this.currentRowItem = null;
|
|
48
|
+
this.currentColItem = null;
|
|
49
|
+
this.currentChartFormat = null;
|
|
50
|
+
this.pivotAreaXmlBuffer = [];
|
|
51
|
+
this.pivotAreaDepth = 0;
|
|
39
52
|
}
|
|
40
53
|
/**
|
|
41
54
|
* Render pivot table XML.
|
|
@@ -156,8 +169,7 @@ class PivotTableXform extends BaseXform {
|
|
|
156
169
|
* Render loaded pivot table (preserving original structure)
|
|
157
170
|
*/
|
|
158
171
|
renderLoaded(xmlStream, model) {
|
|
159
|
-
|
|
160
|
-
xmlStream.openNode(this.tag, {
|
|
172
|
+
const attrs = {
|
|
161
173
|
...PivotTableXform.PIVOT_TABLE_ATTRIBUTES,
|
|
162
174
|
name: model.name || "PivotTable1",
|
|
163
175
|
cacheId: model.cacheId,
|
|
@@ -166,7 +178,8 @@ class PivotTableXform extends BaseXform {
|
|
|
166
178
|
applyFontFormats: model.applyFontFormats || "0",
|
|
167
179
|
applyPatternFormats: model.applyPatternFormats || "0",
|
|
168
180
|
applyAlignmentFormats: model.applyAlignmentFormats || "0",
|
|
169
|
-
|
|
181
|
+
// Preserve original value when present; default to Excel's typical "0".
|
|
182
|
+
applyWidthHeightFormats: model.applyWidthHeightFormats ?? "0",
|
|
170
183
|
dataCaption: model.dataCaption || "Values",
|
|
171
184
|
updatedVersion: model.updatedVersion || "8",
|
|
172
185
|
minRefreshableVersion: model.minRefreshableVersion || "3",
|
|
@@ -174,10 +187,27 @@ class PivotTableXform extends BaseXform {
|
|
|
174
187
|
itemPrintTitles: model.itemPrintTitles ? "1" : "0",
|
|
175
188
|
createdVersion: model.createdVersion || "8",
|
|
176
189
|
indent: model.indent !== undefined ? String(model.indent) : "0",
|
|
177
|
-
compact: model.compact ? "1" : "0",
|
|
178
|
-
compactData: model.compactData ? "1" : "0",
|
|
179
190
|
multipleFieldFilters: model.multipleFieldFilters ? "1" : "0"
|
|
180
|
-
}
|
|
191
|
+
};
|
|
192
|
+
// Add outline attributes if present
|
|
193
|
+
if (model.outline) {
|
|
194
|
+
attrs.outline = "1";
|
|
195
|
+
}
|
|
196
|
+
if (model.outlineData) {
|
|
197
|
+
attrs.outlineData = "1";
|
|
198
|
+
}
|
|
199
|
+
if (model.chartFormat !== undefined) {
|
|
200
|
+
attrs.chartFormat = String(model.chartFormat);
|
|
201
|
+
}
|
|
202
|
+
// Only add compact/compactData if they are true (some files don't have them)
|
|
203
|
+
if (model.compact) {
|
|
204
|
+
attrs.compact = "1";
|
|
205
|
+
}
|
|
206
|
+
if (model.compactData) {
|
|
207
|
+
attrs.compactData = "1";
|
|
208
|
+
}
|
|
209
|
+
xmlStream.openXml(XmlStream.StdDocAttributes);
|
|
210
|
+
xmlStream.openNode(this.tag, attrs);
|
|
181
211
|
// Location
|
|
182
212
|
if (model.location) {
|
|
183
213
|
xmlStream.leafNode("location", {
|
|
@@ -203,42 +233,79 @@ class PivotTableXform extends BaseXform {
|
|
|
203
233
|
}
|
|
204
234
|
xmlStream.closeNode();
|
|
205
235
|
}
|
|
206
|
-
// Row items
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
xmlStream.openNode("colFields", { count: colFieldCount });
|
|
214
|
-
if (model.colFields.length === 0) {
|
|
215
|
-
xmlStream.leafNode("field", { x: -2 });
|
|
236
|
+
// Row items - use parsed items if available; otherwise emit a minimal grand total
|
|
237
|
+
if (model.rowItems && model.rowItems.length > 0) {
|
|
238
|
+
xmlStream.openNode("rowItems", { count: model.rowItems.length });
|
|
239
|
+
for (const item of model.rowItems) {
|
|
240
|
+
this.renderRowColItem(xmlStream, item);
|
|
241
|
+
}
|
|
242
|
+
xmlStream.closeNode();
|
|
216
243
|
}
|
|
217
244
|
else {
|
|
218
|
-
|
|
219
|
-
|
|
245
|
+
xmlStream.writeXml('<rowItems count="1"><i t="grand"><x/></i></rowItems>');
|
|
246
|
+
}
|
|
247
|
+
// Col fields
|
|
248
|
+
// Only render colFields if it was present in the original file or if there are actual column fields
|
|
249
|
+
// Some pivot tables don't have colFields element at all
|
|
250
|
+
if (model.hasColFields || model.colFields.length > 0) {
|
|
251
|
+
const colFieldCount = model.colFields.length === 0 ? 1 : model.colFields.length;
|
|
252
|
+
xmlStream.openNode("colFields", { count: colFieldCount });
|
|
253
|
+
if (model.colFields.length === 0) {
|
|
254
|
+
xmlStream.leafNode("field", { x: -2 });
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
for (const fieldIndex of model.colFields) {
|
|
258
|
+
xmlStream.leafNode("field", { x: fieldIndex });
|
|
259
|
+
}
|
|
220
260
|
}
|
|
261
|
+
xmlStream.closeNode();
|
|
262
|
+
}
|
|
263
|
+
// Col items - use parsed items if available
|
|
264
|
+
if (model.colItems && model.colItems.length > 0) {
|
|
265
|
+
xmlStream.openNode("colItems", { count: model.colItems.length });
|
|
266
|
+
for (const item of model.colItems) {
|
|
267
|
+
this.renderRowColItem(xmlStream, item);
|
|
268
|
+
}
|
|
269
|
+
xmlStream.closeNode();
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
xmlStream.writeXml('<colItems count="1"><i t="grand"><x/></i></colItems>');
|
|
221
273
|
}
|
|
222
|
-
xmlStream.closeNode();
|
|
223
|
-
// Col items (simplified - just grand total)
|
|
224
|
-
xmlStream.writeXml(`
|
|
225
|
-
<colItems count="1">
|
|
226
|
-
<i t="grand"><x /></i>
|
|
227
|
-
</colItems>`);
|
|
228
274
|
// Data fields
|
|
229
275
|
if (model.dataFields.length > 0) {
|
|
230
276
|
xmlStream.openNode("dataFields", { count: model.dataFields.length });
|
|
231
277
|
for (const dataField of model.dataFields) {
|
|
232
|
-
const
|
|
278
|
+
const dfAttrs = {
|
|
233
279
|
name: dataField.name,
|
|
234
280
|
fld: dataField.fld,
|
|
235
281
|
baseField: dataField.baseField ?? 0,
|
|
236
282
|
baseItem: dataField.baseItem ?? 0
|
|
237
283
|
};
|
|
238
284
|
if (dataField.subtotal && dataField.subtotal !== "sum") {
|
|
239
|
-
|
|
285
|
+
dfAttrs.subtotal = dataField.subtotal;
|
|
240
286
|
}
|
|
241
|
-
xmlStream.leafNode("dataField",
|
|
287
|
+
xmlStream.leafNode("dataField", dfAttrs);
|
|
288
|
+
}
|
|
289
|
+
xmlStream.closeNode();
|
|
290
|
+
}
|
|
291
|
+
// Chart formats (for pivot charts) - preserve original pivotArea XML
|
|
292
|
+
if (model.chartFormats && model.chartFormats.length > 0) {
|
|
293
|
+
xmlStream.openNode("chartFormats", { count: model.chartFormats.length });
|
|
294
|
+
for (const cf of model.chartFormats) {
|
|
295
|
+
xmlStream.openNode("chartFormat", {
|
|
296
|
+
chart: cf.chart,
|
|
297
|
+
format: cf.format,
|
|
298
|
+
series: cf.series ? "1" : undefined
|
|
299
|
+
});
|
|
300
|
+
// Use preserved pivotArea XML or fallback to default
|
|
301
|
+
if (cf.pivotAreaXml) {
|
|
302
|
+
xmlStream.writeXml(cf.pivotAreaXml);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
// Fallback for newly created chart formats (shouldn't happen for loaded models)
|
|
306
|
+
xmlStream.writeXml(`<pivotArea type="data" outline="0" fieldPosition="0"><references count="1"><reference field="4294967294" count="1" selected="0"><x v="0"/></reference></references></pivotArea>`);
|
|
307
|
+
}
|
|
308
|
+
xmlStream.closeNode();
|
|
242
309
|
}
|
|
243
310
|
xmlStream.closeNode();
|
|
244
311
|
}
|
|
@@ -252,46 +319,48 @@ class PivotTableXform extends BaseXform {
|
|
|
252
319
|
showLastColumn: "1"
|
|
253
320
|
});
|
|
254
321
|
// Extensions
|
|
255
|
-
xmlStream.writeXml(
|
|
256
|
-
<extLst>
|
|
257
|
-
<ext
|
|
258
|
-
uri="{962EF5D1-5CA2-4c93-8EF4-DBF5C05439D2}"
|
|
259
|
-
xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
|
|
260
|
-
>
|
|
261
|
-
<x14:pivotTableDefinition
|
|
262
|
-
hideValuesRow="1"
|
|
263
|
-
xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main"
|
|
264
|
-
/>
|
|
265
|
-
</ext>
|
|
266
|
-
<ext
|
|
267
|
-
uri="{747A6164-185A-40DC-8AA5-F01512510D54}"
|
|
268
|
-
xmlns:xpdl="http://schemas.microsoft.com/office/spreadsheetml/2016/pivotdefaultlayout"
|
|
269
|
-
>
|
|
270
|
-
<xpdl:pivotTableDefinition16
|
|
271
|
-
EnabledSubtotalsDefault="0"
|
|
272
|
-
SubtotalsOnTopDefault="0"
|
|
273
|
-
/>
|
|
274
|
-
</ext>
|
|
275
|
-
</extLst>
|
|
276
|
-
`);
|
|
322
|
+
xmlStream.writeXml(`<extLst><ext uri="{962EF5D1-5CA2-4c93-8EF4-DBF5C05439D2}" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"><x14:pivotTableDefinition hideValuesRow="1" xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main"/></ext><ext uri="{747A6164-185A-40DC-8AA5-F01512510D54}" xmlns:xpdl="http://schemas.microsoft.com/office/spreadsheetml/2016/pivotdefaultlayout"><xpdl:pivotTableDefinition16/></ext></extLst>`);
|
|
277
323
|
xmlStream.closeNode();
|
|
278
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Render a row or column item element
|
|
327
|
+
*/
|
|
328
|
+
renderRowColItem(xmlStream, item) {
|
|
329
|
+
const attrs = {};
|
|
330
|
+
if (item.t) {
|
|
331
|
+
attrs.t = item.t;
|
|
332
|
+
}
|
|
333
|
+
if (item.x && item.x.length > 0) {
|
|
334
|
+
xmlStream.openNode("i", attrs);
|
|
335
|
+
for (const x of item.x) {
|
|
336
|
+
if (x.v && x.v !== 0) {
|
|
337
|
+
xmlStream.leafNode("x", { v: x.v });
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
xmlStream.leafNode("x");
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
xmlStream.closeNode();
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
// Empty item (like <i/> in colItems)
|
|
347
|
+
xmlStream.leafNode("i", attrs);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
279
350
|
/**
|
|
280
351
|
* Render a loaded pivot field
|
|
281
352
|
*/
|
|
282
353
|
renderPivotFieldLoaded(xmlStream, field) {
|
|
283
|
-
const attrs = {
|
|
284
|
-
|
|
285
|
-
outline: field.outline ? "1" : "0",
|
|
286
|
-
showAll: field.showAll ? "1" : "0",
|
|
287
|
-
defaultSubtotal: field.defaultSubtotal ? "1" : "0"
|
|
288
|
-
};
|
|
354
|
+
const attrs = {};
|
|
355
|
+
// Only add attributes that were present in the original
|
|
289
356
|
if (field.axis) {
|
|
290
357
|
attrs.axis = field.axis;
|
|
291
358
|
}
|
|
292
359
|
if (field.dataField) {
|
|
293
360
|
attrs.dataField = "1";
|
|
294
361
|
}
|
|
362
|
+
// showAll is typically always present
|
|
363
|
+
attrs.showAll = field.showAll ? "1" : "0";
|
|
295
364
|
if (field.items && field.items.length > 0) {
|
|
296
365
|
xmlStream.openNode("pivotField", attrs);
|
|
297
366
|
xmlStream.openNode("items", { count: field.items.length + 1 });
|
|
@@ -299,7 +368,7 @@ class PivotTableXform extends BaseXform {
|
|
|
299
368
|
xmlStream.leafNode("item", { x: itemIndex });
|
|
300
369
|
}
|
|
301
370
|
// Grand total item
|
|
302
|
-
xmlStream.writeXml('<item t="default"
|
|
371
|
+
xmlStream.writeXml('<item t="default"/>');
|
|
303
372
|
xmlStream.closeNode(); // items
|
|
304
373
|
xmlStream.closeNode(); // pivotField
|
|
305
374
|
}
|
|
@@ -337,6 +406,12 @@ class PivotTableXform extends BaseXform {
|
|
|
337
406
|
compact: attributes.compact === "1",
|
|
338
407
|
compactData: attributes.compactData === "1",
|
|
339
408
|
multipleFieldFilters: attributes.multipleFieldFilters === "1",
|
|
409
|
+
outline: attributes.outline === "1",
|
|
410
|
+
outlineData: attributes.outlineData === "1",
|
|
411
|
+
chartFormat: attributes.chartFormat ? parseInt(attributes.chartFormat, 10) : undefined,
|
|
412
|
+
rowItems: [],
|
|
413
|
+
colItems: [],
|
|
414
|
+
chartFormats: [],
|
|
340
415
|
isLoaded: true
|
|
341
416
|
};
|
|
342
417
|
break;
|
|
@@ -357,10 +432,10 @@ class PivotTableXform extends BaseXform {
|
|
|
357
432
|
}
|
|
358
433
|
break;
|
|
359
434
|
case "pivotFields":
|
|
360
|
-
this.inPivotFields = true;
|
|
435
|
+
this.state.inPivotFields = true;
|
|
361
436
|
break;
|
|
362
437
|
case "pivotField":
|
|
363
|
-
if (this.inPivotFields) {
|
|
438
|
+
if (this.state.inPivotFields) {
|
|
364
439
|
this.currentPivotField = {
|
|
365
440
|
axis: attributes.axis,
|
|
366
441
|
dataField: attributes.dataField === "1",
|
|
@@ -374,43 +449,105 @@ class PivotTableXform extends BaseXform {
|
|
|
374
449
|
break;
|
|
375
450
|
case "items":
|
|
376
451
|
if (this.currentPivotField) {
|
|
377
|
-
this.inItems = true;
|
|
452
|
+
this.state.inItems = true;
|
|
378
453
|
}
|
|
379
454
|
break;
|
|
380
455
|
case "item":
|
|
381
|
-
if (this.inItems && this.currentPivotField && attributes.x !== undefined) {
|
|
456
|
+
if (this.state.inItems && this.currentPivotField && attributes.x !== undefined) {
|
|
382
457
|
this.currentPivotField.items.push(parseInt(attributes.x, 10));
|
|
383
458
|
}
|
|
384
459
|
break;
|
|
385
460
|
case "rowFields":
|
|
386
|
-
this.inRowFields = true;
|
|
461
|
+
this.state.inRowFields = true;
|
|
387
462
|
break;
|
|
388
463
|
case "colFields":
|
|
389
|
-
this.inColFields = true;
|
|
464
|
+
this.state.inColFields = true;
|
|
465
|
+
// Track that colFields element was present in original file
|
|
466
|
+
if (this.model) {
|
|
467
|
+
this.model.hasColFields = true;
|
|
468
|
+
}
|
|
390
469
|
break;
|
|
391
470
|
case "dataFields":
|
|
392
|
-
this.inDataFields = true;
|
|
471
|
+
this.state.inDataFields = true;
|
|
393
472
|
break;
|
|
394
473
|
case "rowItems":
|
|
395
|
-
this.inRowItems = true;
|
|
474
|
+
this.state.inRowItems = true;
|
|
396
475
|
break;
|
|
397
476
|
case "colItems":
|
|
398
|
-
this.inColItems = true;
|
|
477
|
+
this.state.inColItems = true;
|
|
478
|
+
break;
|
|
479
|
+
case "i":
|
|
480
|
+
// Handle row/col item element
|
|
481
|
+
if (this.state.inRowItems && this.model) {
|
|
482
|
+
this.currentRowItem = { t: attributes.t, x: [] };
|
|
483
|
+
}
|
|
484
|
+
else if (this.state.inColItems && this.model) {
|
|
485
|
+
this.currentColItem = { t: attributes.t, x: [] };
|
|
486
|
+
}
|
|
487
|
+
break;
|
|
488
|
+
case "x":
|
|
489
|
+
// Handle x element inside row/col items or pivotArea
|
|
490
|
+
if (this.state.inPivotArea) {
|
|
491
|
+
// Collect x element for pivotArea XML
|
|
492
|
+
const xAttrs = Object.entries(attributes)
|
|
493
|
+
.map(([k, v]) => `${k}="${v}"`)
|
|
494
|
+
.join(" ");
|
|
495
|
+
this.pivotAreaXmlBuffer.push(xAttrs ? `<x ${xAttrs}/>` : "<x/>");
|
|
496
|
+
}
|
|
497
|
+
else if (this.currentRowItem) {
|
|
498
|
+
this.currentRowItem.x.push({ v: attributes.v ? parseInt(attributes.v, 10) : 0 });
|
|
499
|
+
}
|
|
500
|
+
else if (this.currentColItem) {
|
|
501
|
+
this.currentColItem.x.push({ v: attributes.v ? parseInt(attributes.v, 10) : 0 });
|
|
502
|
+
}
|
|
503
|
+
break;
|
|
504
|
+
case "chartFormats":
|
|
505
|
+
this.state.inChartFormats = true;
|
|
506
|
+
break;
|
|
507
|
+
case "chartFormat":
|
|
508
|
+
if (this.state.inChartFormats && this.model) {
|
|
509
|
+
this.currentChartFormat = {
|
|
510
|
+
chart: attributes.chart ? parseInt(attributes.chart, 10) : 0,
|
|
511
|
+
format: attributes.format ? parseInt(attributes.format, 10) : 0,
|
|
512
|
+
series: attributes.series === "1"
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
break;
|
|
516
|
+
case "pivotArea":
|
|
517
|
+
// Start collecting pivotArea XML for chartFormat
|
|
518
|
+
if (this.currentChartFormat) {
|
|
519
|
+
this.state.inPivotArea = true;
|
|
520
|
+
const attrsStr = Object.entries(attributes)
|
|
521
|
+
.map(([k, v]) => `${k}="${v}"`)
|
|
522
|
+
.join(" ");
|
|
523
|
+
this.pivotAreaXmlBuffer = [attrsStr ? `<pivotArea ${attrsStr}>` : "<pivotArea>"];
|
|
524
|
+
}
|
|
525
|
+
break;
|
|
526
|
+
case "references":
|
|
527
|
+
case "reference":
|
|
528
|
+
// Collect nested elements in pivotArea
|
|
529
|
+
if (this.state.inPivotArea) {
|
|
530
|
+
this.pivotAreaDepth++;
|
|
531
|
+
const attrsStr = Object.entries(attributes)
|
|
532
|
+
.map(([k, v]) => `${k}="${v}"`)
|
|
533
|
+
.join(" ");
|
|
534
|
+
this.pivotAreaXmlBuffer.push(`<${name}${attrsStr ? " " + attrsStr : ""}>`);
|
|
535
|
+
}
|
|
399
536
|
break;
|
|
400
537
|
case "field":
|
|
401
538
|
// Handle field element (used in rowFields, colFields)
|
|
402
539
|
if (this.model) {
|
|
403
540
|
const fieldIndex = parseInt(attributes.x || "0", 10);
|
|
404
|
-
if (this.inRowFields) {
|
|
541
|
+
if (this.state.inRowFields) {
|
|
405
542
|
this.model.rowFields.push(fieldIndex);
|
|
406
543
|
}
|
|
407
|
-
else if (this.inColFields) {
|
|
544
|
+
else if (this.state.inColFields) {
|
|
408
545
|
this.model.colFields.push(fieldIndex);
|
|
409
546
|
}
|
|
410
547
|
}
|
|
411
548
|
break;
|
|
412
549
|
case "dataField":
|
|
413
|
-
if (this.inDataFields && this.model) {
|
|
550
|
+
if (this.state.inDataFields && this.model) {
|
|
414
551
|
this.model.dataFields.push({
|
|
415
552
|
name: xmlDecode(attributes.name || ""),
|
|
416
553
|
fld: parseInt(attributes.fld || "0", 10),
|
|
@@ -432,12 +569,32 @@ class PivotTableXform extends BaseXform {
|
|
|
432
569
|
// No text content in pivot table elements
|
|
433
570
|
}
|
|
434
571
|
parseClose(name) {
|
|
572
|
+
// Handle pivotArea nested elements - close tags
|
|
573
|
+
if (this.state.inPivotArea) {
|
|
574
|
+
if (name === "pivotArea") {
|
|
575
|
+
this.pivotAreaXmlBuffer.push("</pivotArea>");
|
|
576
|
+
if (this.currentChartFormat) {
|
|
577
|
+
this.currentChartFormat.pivotAreaXml = this.pivotAreaXmlBuffer.join("");
|
|
578
|
+
}
|
|
579
|
+
this.state.inPivotArea = false;
|
|
580
|
+
this.pivotAreaXmlBuffer = [];
|
|
581
|
+
this.pivotAreaDepth = 0;
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
else if (name === "references" || name === "reference") {
|
|
585
|
+
this.pivotAreaXmlBuffer.push(`</${name}>`);
|
|
586
|
+
this.pivotAreaDepth--;
|
|
587
|
+
return true;
|
|
588
|
+
}
|
|
589
|
+
// x elements are self-closing, no need to handle close
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
435
592
|
switch (name) {
|
|
436
593
|
case this.tag:
|
|
437
594
|
// End of pivotTableDefinition
|
|
438
595
|
return false;
|
|
439
596
|
case "pivotFields":
|
|
440
|
-
this.inPivotFields = false;
|
|
597
|
+
this.state.inPivotFields = false;
|
|
441
598
|
break;
|
|
442
599
|
case "pivotField":
|
|
443
600
|
if (this.currentPivotField && this.model) {
|
|
@@ -446,22 +603,42 @@ class PivotTableXform extends BaseXform {
|
|
|
446
603
|
}
|
|
447
604
|
break;
|
|
448
605
|
case "items":
|
|
449
|
-
this.inItems = false;
|
|
606
|
+
this.state.inItems = false;
|
|
450
607
|
break;
|
|
451
608
|
case "rowFields":
|
|
452
|
-
this.inRowFields = false;
|
|
609
|
+
this.state.inRowFields = false;
|
|
453
610
|
break;
|
|
454
611
|
case "colFields":
|
|
455
|
-
this.inColFields = false;
|
|
612
|
+
this.state.inColFields = false;
|
|
456
613
|
break;
|
|
457
614
|
case "dataFields":
|
|
458
|
-
this.inDataFields = false;
|
|
615
|
+
this.state.inDataFields = false;
|
|
459
616
|
break;
|
|
460
617
|
case "rowItems":
|
|
461
|
-
this.inRowItems = false;
|
|
618
|
+
this.state.inRowItems = false;
|
|
462
619
|
break;
|
|
463
620
|
case "colItems":
|
|
464
|
-
this.inColItems = false;
|
|
621
|
+
this.state.inColItems = false;
|
|
622
|
+
break;
|
|
623
|
+
case "i":
|
|
624
|
+
// Finish row/col item
|
|
625
|
+
if (this.currentRowItem && this.model) {
|
|
626
|
+
this.model.rowItems.push(this.currentRowItem);
|
|
627
|
+
this.currentRowItem = null;
|
|
628
|
+
}
|
|
629
|
+
else if (this.currentColItem && this.model) {
|
|
630
|
+
this.model.colItems.push(this.currentColItem);
|
|
631
|
+
this.currentColItem = null;
|
|
632
|
+
}
|
|
633
|
+
break;
|
|
634
|
+
case "chartFormats":
|
|
635
|
+
this.state.inChartFormats = false;
|
|
636
|
+
break;
|
|
637
|
+
case "chartFormat":
|
|
638
|
+
if (this.currentChartFormat && this.model) {
|
|
639
|
+
this.model.chartFormats.push(this.currentChartFormat);
|
|
640
|
+
this.currentChartFormat = null;
|
|
641
|
+
}
|
|
465
642
|
break;
|
|
466
643
|
}
|
|
467
644
|
return true;
|
|
@@ -48,7 +48,10 @@ class RowXform extends BaseXform {
|
|
|
48
48
|
xmlStream.addAttribute("s", model.styleId);
|
|
49
49
|
xmlStream.addAttribute("customFormat", "1");
|
|
50
50
|
}
|
|
51
|
-
//
|
|
51
|
+
// Output dyDescent if present (MS extension for font descent)
|
|
52
|
+
if (model.dyDescent !== undefined) {
|
|
53
|
+
xmlStream.addAttribute("x14ac:dyDescent", model.dyDescent);
|
|
54
|
+
}
|
|
52
55
|
if (model.outlineLevel) {
|
|
53
56
|
xmlStream.addAttribute("outlineLevel", model.outlineLevel);
|
|
54
57
|
}
|
|
@@ -99,6 +102,9 @@ class RowXform extends BaseXform {
|
|
|
99
102
|
if (parseBoolean(node.attributes.collapsed)) {
|
|
100
103
|
model.collapsed = true;
|
|
101
104
|
}
|
|
105
|
+
if (node.attributes["x14ac:dyDescent"] !== undefined) {
|
|
106
|
+
model.dyDescent = parseFloat(node.attributes["x14ac:dyDescent"]);
|
|
107
|
+
}
|
|
102
108
|
return true;
|
|
103
109
|
}
|
|
104
110
|
this.parser = this.map[node.name];
|
|
@@ -11,14 +11,14 @@ class SheetFormatPropertiesXform extends BaseXform {
|
|
|
11
11
|
outlineLevelRow: model.outlineLevelRow || undefined,
|
|
12
12
|
outlineLevelCol: model.outlineLevelCol || undefined,
|
|
13
13
|
// Only output dyDescent if explicitly set (MS extension, not ECMA-376 standard)
|
|
14
|
-
"x14ac:dyDescent": model.dyDescent
|
|
14
|
+
"x14ac:dyDescent": model.dyDescent !== undefined && model.dyDescent !== 0 ? model.dyDescent : undefined
|
|
15
15
|
};
|
|
16
16
|
// Only output defaultColWidth if explicitly set
|
|
17
17
|
if (model.defaultColWidth) {
|
|
18
18
|
attributes.defaultColWidth = model.defaultColWidth;
|
|
19
19
|
}
|
|
20
|
-
//
|
|
21
|
-
if (
|
|
20
|
+
// Only output customHeight if it was present in the original file
|
|
21
|
+
if (model.customHeight) {
|
|
22
22
|
attributes.customHeight = "1";
|
|
23
23
|
}
|
|
24
24
|
if (Object.values(attributes).some((value) => value !== undefined)) {
|
|
@@ -30,13 +30,18 @@ class SheetFormatPropertiesXform extends BaseXform {
|
|
|
30
30
|
if (node.name === "sheetFormatPr") {
|
|
31
31
|
this.model = {
|
|
32
32
|
defaultRowHeight: parseFloat(node.attributes.defaultRowHeight || "0"),
|
|
33
|
-
dyDescent:
|
|
33
|
+
dyDescent: node.attributes["x14ac:dyDescent"] !== undefined
|
|
34
|
+
? parseFloat(node.attributes["x14ac:dyDescent"])
|
|
35
|
+
: undefined,
|
|
34
36
|
outlineLevelRow: parseInt(node.attributes.outlineLevelRow || "0", 10),
|
|
35
37
|
outlineLevelCol: parseInt(node.attributes.outlineLevelCol || "0", 10)
|
|
36
38
|
};
|
|
37
39
|
if (node.attributes.defaultColWidth) {
|
|
38
40
|
this.model.defaultColWidth = parseFloat(node.attributes.defaultColWidth);
|
|
39
41
|
}
|
|
42
|
+
if (node.attributes.customHeight === "1") {
|
|
43
|
+
this.model.customHeight = true;
|
|
44
|
+
}
|
|
40
45
|
return true;
|
|
41
46
|
}
|
|
42
47
|
return false;
|
|
@@ -37,8 +37,8 @@ class SheetViewXform extends BaseXform {
|
|
|
37
37
|
add("showRuler", "0", model.showRuler === false);
|
|
38
38
|
add("showRowColHeaders", "0", model.showRowColHeaders === false);
|
|
39
39
|
add("showGridLines", "0", model.showGridLines === false);
|
|
40
|
-
add("zoomScale", model.zoomScale, model.zoomScale);
|
|
41
|
-
add("zoomScaleNormal", model.zoomScaleNormal, model.zoomScaleNormal);
|
|
40
|
+
add("zoomScale", model.zoomScale, model.zoomScale !== undefined && model.zoomScale !== 100);
|
|
41
|
+
add("zoomScaleNormal", model.zoomScaleNormal, model.zoomScaleNormal !== undefined && model.zoomScaleNormal !== 100);
|
|
42
42
|
add("view", model.style, model.style);
|
|
43
43
|
let topLeftCell;
|
|
44
44
|
let xSplit;
|
|
@@ -143,6 +143,7 @@ class SheetViewXform extends BaseXform {
|
|
|
143
143
|
model = this.model = {
|
|
144
144
|
workbookViewId: this.sheetView.workbookViewId,
|
|
145
145
|
rightToLeft: this.sheetView.rightToLeft,
|
|
146
|
+
tabSelected: this.sheetView.tabSelected,
|
|
146
147
|
state: VIEW_STATES[this.pane.state] || "split", // split is default
|
|
147
148
|
xSplit: this.pane.xSplit,
|
|
148
149
|
ySplit: this.pane.ySplit,
|
|
@@ -168,6 +169,7 @@ class SheetViewXform extends BaseXform {
|
|
|
168
169
|
model = this.model = {
|
|
169
170
|
workbookViewId: this.sheetView.workbookViewId,
|
|
170
171
|
rightToLeft: this.sheetView.rightToLeft,
|
|
172
|
+
tabSelected: this.sheetView.tabSelected,
|
|
171
173
|
state: "normal",
|
|
172
174
|
showRuler: this.sheetView.showRuler,
|
|
173
175
|
showRowColHeaders: this.sheetView.showRowColHeaders,
|