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