@cj-tech-master/excelts 3.0.0-canary.20251228183403.d3eb98d → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/excelts.esm.js +22 -40
- package/dist/browser/excelts.esm.js.map +1 -1
- package/dist/browser/excelts.esm.min.js +10 -16
- package/dist/browser/excelts.iife.js +22 -40
- package/dist/browser/excelts.iife.js.map +1 -1
- package/dist/browser/excelts.iife.min.js +10 -16
- package/dist/cjs/doc/pivot-table.js +5 -12
- package/dist/cjs/xlsx/xform/pivot-table/cache-field-xform.js +21 -17
- package/dist/cjs/xlsx/xform/pivot-table/cache-field.js +8 -37
- package/dist/cjs/xlsx/xform/pivot-table/pivot-cache-records-xform.js +1 -1
- package/dist/cjs/xlsx/xform/pivot-table/pivot-table-xform.js +16 -15
- package/dist/esm/doc/pivot-table.js +5 -12
- package/dist/esm/xlsx/xform/pivot-table/cache-field-xform.js +21 -17
- package/dist/esm/xlsx/xform/pivot-table/cache-field.js +8 -37
- package/dist/esm/xlsx/xform/pivot-table/pivot-cache-records-xform.js +1 -1
- package/dist/esm/xlsx/xform/pivot-table/pivot-table-xform.js +16 -15
- package/dist/types/xlsx/xform/pivot-table/cache-field-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/pivot-table/cache-field.d.ts +1 -1
- package/package.json +1 -1
|
@@ -114,7 +114,7 @@ function makePivotTable(worksheet, model) {
|
|
|
114
114
|
validate(worksheet, model, source);
|
|
115
115
|
const { rows, values } = model;
|
|
116
116
|
const columns = model.columns ?? [];
|
|
117
|
-
const cacheFields = makeCacheFields(source, [...rows, ...columns]
|
|
117
|
+
const cacheFields = makeCacheFields(source, [...rows, ...columns]);
|
|
118
118
|
const nameToIndex = cacheFields.reduce((result, cacheField, index) => {
|
|
119
119
|
result[cacheField.name] = index;
|
|
120
120
|
return result;
|
|
@@ -171,15 +171,13 @@ function validate(_worksheet, model, source) {
|
|
|
171
171
|
throw new Error("It is currently not possible to have multiple values when columns are specified. Please either supply an empty array for columns or a single value.");
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
|
-
function makeCacheFields(source, fieldNamesWithSharedItems
|
|
174
|
+
function makeCacheFields(source, fieldNamesWithSharedItems) {
|
|
175
175
|
// Cache fields are used in pivot tables to reference source data.
|
|
176
176
|
// Fields in fieldNamesWithSharedItems get their unique values extracted as sharedItems.
|
|
177
|
-
//
|
|
178
|
-
// Other fields are unused and get empty sharedItems.
|
|
177
|
+
// Other fields (typically numeric) have sharedItems = null.
|
|
179
178
|
const names = source.getRow(1).values;
|
|
180
179
|
// Use Set for O(1) lookup instead of object
|
|
181
180
|
const sharedItemsFields = new Set(fieldNamesWithSharedItems);
|
|
182
|
-
const valueFields = new Set(valueFieldNames);
|
|
183
181
|
const aggregate = (columnIndex) => {
|
|
184
182
|
const columnValues = source.getColumn(columnIndex).values;
|
|
185
183
|
// Build unique values set directly, skipping header (index 0,1) and null/undefined
|
|
@@ -217,11 +215,10 @@ function makeCacheFields(source, fieldNamesWithSharedItems, valueFieldNames) {
|
|
|
217
215
|
for (const columnIndex of (0, utils_1.range)(1, names.length)) {
|
|
218
216
|
const name = names[columnIndex];
|
|
219
217
|
if (sharedItemsFields.has(name)) {
|
|
220
|
-
// Field used for rows/columns - extract unique values as sharedItems
|
|
221
218
|
result.push({ name, sharedItems: aggregate(columnIndex) });
|
|
222
219
|
}
|
|
223
|
-
else
|
|
224
|
-
//
|
|
220
|
+
else {
|
|
221
|
+
// Numeric field - calculate min/max
|
|
225
222
|
const minMax = getMinMax(columnIndex);
|
|
226
223
|
result.push({
|
|
227
224
|
name,
|
|
@@ -230,10 +227,6 @@ function makeCacheFields(source, fieldNamesWithSharedItems, valueFieldNames) {
|
|
|
230
227
|
maxValue: minMax?.maxValue
|
|
231
228
|
});
|
|
232
229
|
}
|
|
233
|
-
else {
|
|
234
|
-
// Unused field - just empty sharedItems (like Excel does)
|
|
235
|
-
result.push({ name, sharedItems: null });
|
|
236
|
-
}
|
|
237
230
|
}
|
|
238
231
|
return result;
|
|
239
232
|
}
|
|
@@ -47,26 +47,30 @@ class CacheFieldXform extends base_xform_1.BaseXform {
|
|
|
47
47
|
break;
|
|
48
48
|
case "sharedItems":
|
|
49
49
|
this.inSharedItems = true;
|
|
50
|
-
//
|
|
51
|
-
if (
|
|
52
|
-
this.model
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (count > 0) {
|
|
63
|
-
this.model.sharedItems = [];
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
// No count means no individual items (pure numeric field)
|
|
50
|
+
// Check if this is a numeric field (no string items)
|
|
51
|
+
if (attributes.containsNumber === "1" || attributes.containsInteger === "1") {
|
|
52
|
+
if (this.model) {
|
|
53
|
+
this.model.containsNumber = attributes.containsNumber === "1";
|
|
54
|
+
this.model.containsInteger = attributes.containsInteger === "1";
|
|
55
|
+
if (attributes.minValue !== undefined) {
|
|
56
|
+
this.model.minValue = parseFloat(attributes.minValue);
|
|
57
|
+
}
|
|
58
|
+
if (attributes.maxValue !== undefined) {
|
|
59
|
+
this.model.maxValue = parseFloat(attributes.maxValue);
|
|
60
|
+
}
|
|
61
|
+
// Numeric fields have sharedItems = null
|
|
67
62
|
this.model.sharedItems = null;
|
|
68
63
|
}
|
|
69
64
|
}
|
|
65
|
+
else {
|
|
66
|
+
// String field - initialize sharedItems array if count > 0
|
|
67
|
+
if (this.model) {
|
|
68
|
+
const count = parseInt(attributes.count || "0", 10);
|
|
69
|
+
if (count > 0) {
|
|
70
|
+
this.model.sharedItems = [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
70
74
|
break;
|
|
71
75
|
case "s":
|
|
72
76
|
// String value in sharedItems
|
|
@@ -13,7 +13,7 @@ class CacheField {
|
|
|
13
13
|
//
|
|
14
14
|
// or
|
|
15
15
|
//
|
|
16
|
-
// integer type
|
|
16
|
+
// integer type
|
|
17
17
|
//
|
|
18
18
|
// {
|
|
19
19
|
// 'name': 'D',
|
|
@@ -21,15 +21,6 @@ class CacheField {
|
|
|
21
21
|
// 'minValue': 5,
|
|
22
22
|
// 'maxValue': 45
|
|
23
23
|
// }
|
|
24
|
-
//
|
|
25
|
-
// or
|
|
26
|
-
//
|
|
27
|
-
// numeric type with shared items (used as both row/column and value field)
|
|
28
|
-
//
|
|
29
|
-
// {
|
|
30
|
-
// 'name': 'C',
|
|
31
|
-
// 'sharedItems': [5, 24, 35, 45]
|
|
32
|
-
// }
|
|
33
24
|
this.name = name;
|
|
34
25
|
this.sharedItems = sharedItems;
|
|
35
26
|
this.minValue = minValue;
|
|
@@ -40,37 +31,17 @@ class CacheField {
|
|
|
40
31
|
// Shared Items: http://www.datypic.com/sc/ooxml/e-ssml_sharedItems-1.html
|
|
41
32
|
// Escape XML special characters in name attribute
|
|
42
33
|
const escapedName = (0, utils_1.xmlEncode)(this.name);
|
|
43
|
-
//
|
|
34
|
+
// integer types
|
|
44
35
|
if (this.sharedItems === null) {
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
</cacheField>`;
|
|
50
|
-
}
|
|
51
|
-
// Numeric field used only for values (not rows/columns) - include min/max
|
|
36
|
+
// Build minValue/maxValue attributes if available
|
|
37
|
+
const minMaxAttrs = this.minValue !== undefined && this.maxValue !== undefined
|
|
38
|
+
? ` minValue="${this.minValue}" maxValue="${this.maxValue}"`
|
|
39
|
+
: "";
|
|
52
40
|
return `<cacheField name="${escapedName}" numFmtId="0">
|
|
53
|
-
<sharedItems containsSemiMixedTypes="0" containsString="0" containsNumber="1" containsInteger="1"
|
|
54
|
-
</cacheField>`;
|
|
55
|
-
}
|
|
56
|
-
// Shared items exist - check if all values are numeric
|
|
57
|
-
// Note: empty array returns true for every(), so check length first
|
|
58
|
-
const allNumeric = this.sharedItems.length > 0 &&
|
|
59
|
-
this.sharedItems.every(item => typeof item === "number" && Number.isFinite(item));
|
|
60
|
-
const allInteger = allNumeric && this.sharedItems.every(item => Number.isInteger(item));
|
|
61
|
-
if (allNumeric) {
|
|
62
|
-
// Numeric shared items - used when field is both a row/column field AND a value field
|
|
63
|
-
// This allows Excel to both group by unique values AND perform aggregation
|
|
64
|
-
const minValue = Math.min(...this.sharedItems);
|
|
65
|
-
const maxValue = Math.max(...this.sharedItems);
|
|
66
|
-
const integerAttr = allInteger ? ' containsInteger="1"' : "";
|
|
67
|
-
return `<cacheField name="${escapedName}" numFmtId="0">
|
|
68
|
-
<sharedItems containsSemiMixedTypes="0" containsString="0" containsNumber="1"${integerAttr} minValue="${minValue}" maxValue="${maxValue}" count="${this.sharedItems.length}">
|
|
69
|
-
${this.sharedItems.map(item => `<n v="${item}" />`).join("")}
|
|
70
|
-
</sharedItems>
|
|
41
|
+
<sharedItems containsSemiMixedTypes="0" containsString="0" containsNumber="1" containsInteger="1"${minMaxAttrs} />
|
|
71
42
|
</cacheField>`;
|
|
72
43
|
}
|
|
73
|
-
//
|
|
44
|
+
// string types - escape XML special characters in each shared item value
|
|
74
45
|
return `<cacheField name="${escapedName}" numFmtId="0">
|
|
75
46
|
<sharedItems count="${this.sharedItems.length}">
|
|
76
47
|
${this.sharedItems.map(item => `<s v="${(0, utils_1.xmlEncode)(String(item))}" />`).join("")}
|
|
@@ -119,7 +119,7 @@ class PivotCacheRecordsXform extends base_xform_1.BaseXform {
|
|
|
119
119
|
}
|
|
120
120
|
return `<s v="${(0, utils_1.xmlEncode)(String(value))}" />`;
|
|
121
121
|
}
|
|
122
|
-
// shared items
|
|
122
|
+
// shared items
|
|
123
123
|
const sharedItemsIndex = sharedItems.indexOf(value);
|
|
124
124
|
if (sharedItemsIndex < 0) {
|
|
125
125
|
throw new Error(`${JSON.stringify(value)} not in sharedItems ${JSON.stringify(sharedItems)}`);
|
|
@@ -585,24 +585,25 @@ function renderPivotFields(pivotTable) {
|
|
|
585
585
|
const valueSet = new Set(pivotTable.values);
|
|
586
586
|
return pivotTable.cacheFields
|
|
587
587
|
.map((cacheField, fieldIndex) => {
|
|
588
|
-
const
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
588
|
+
const fieldType = rowSet.has(fieldIndex)
|
|
589
|
+
? "row"
|
|
590
|
+
: colSet.has(fieldIndex)
|
|
591
|
+
? "column"
|
|
592
|
+
: valueSet.has(fieldIndex)
|
|
593
|
+
? "value"
|
|
594
|
+
: null;
|
|
595
|
+
return renderPivotField(fieldType, cacheField.sharedItems);
|
|
592
596
|
})
|
|
593
597
|
.join("");
|
|
594
598
|
}
|
|
595
|
-
function renderPivotField(
|
|
596
|
-
//
|
|
597
|
-
//
|
|
598
|
-
|
|
599
|
-
|
|
599
|
+
function renderPivotField(fieldType, sharedItems) {
|
|
600
|
+
// fieldType: 'row', 'column', 'value', null
|
|
601
|
+
// Note: defaultSubtotal="0" should only be on value fields and non-axis fields,
|
|
602
|
+
// NOT on row/column axis fields (Excel will auto-calculate subtotals for them)
|
|
603
|
+
if (fieldType === "row" || fieldType === "column") {
|
|
604
|
+
const axis = fieldType === "row" ? "axisRow" : "axisCol";
|
|
600
605
|
// Row and column fields should NOT have defaultSubtotal="0"
|
|
601
|
-
|
|
602
|
-
// If also a value field, add dataField="1"
|
|
603
|
-
if (isValue) {
|
|
604
|
-
axisAttributes = `dataField="1" ${axisAttributes}`;
|
|
605
|
-
}
|
|
606
|
+
const axisAttributes = 'compact="0" outline="0" showAll="0"';
|
|
606
607
|
// items = one for each shared item + one default item
|
|
607
608
|
const itemsXml = [
|
|
608
609
|
...sharedItems.map((_item, index) => `<item x="${index}" />`),
|
|
@@ -620,7 +621,7 @@ function renderPivotField(isRow, isCol, isValue, sharedItems) {
|
|
|
620
621
|
const defaultAttributes = 'compact="0" outline="0" showAll="0" defaultSubtotal="0"';
|
|
621
622
|
return `
|
|
622
623
|
<pivotField
|
|
623
|
-
${
|
|
624
|
+
${fieldType === "value" ? 'dataField="1"' : ""}
|
|
624
625
|
${defaultAttributes}
|
|
625
626
|
/>
|
|
626
627
|
`;
|
|
@@ -111,7 +111,7 @@ function makePivotTable(worksheet, model) {
|
|
|
111
111
|
validate(worksheet, model, source);
|
|
112
112
|
const { rows, values } = model;
|
|
113
113
|
const columns = model.columns ?? [];
|
|
114
|
-
const cacheFields = makeCacheFields(source, [...rows, ...columns]
|
|
114
|
+
const cacheFields = makeCacheFields(source, [...rows, ...columns]);
|
|
115
115
|
const nameToIndex = cacheFields.reduce((result, cacheField, index) => {
|
|
116
116
|
result[cacheField.name] = index;
|
|
117
117
|
return result;
|
|
@@ -168,15 +168,13 @@ function validate(_worksheet, model, source) {
|
|
|
168
168
|
throw new Error("It is currently not possible to have multiple values when columns are specified. Please either supply an empty array for columns or a single value.");
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
function makeCacheFields(source, fieldNamesWithSharedItems
|
|
171
|
+
function makeCacheFields(source, fieldNamesWithSharedItems) {
|
|
172
172
|
// Cache fields are used in pivot tables to reference source data.
|
|
173
173
|
// Fields in fieldNamesWithSharedItems get their unique values extracted as sharedItems.
|
|
174
|
-
//
|
|
175
|
-
// Other fields are unused and get empty sharedItems.
|
|
174
|
+
// Other fields (typically numeric) have sharedItems = null.
|
|
176
175
|
const names = source.getRow(1).values;
|
|
177
176
|
// Use Set for O(1) lookup instead of object
|
|
178
177
|
const sharedItemsFields = new Set(fieldNamesWithSharedItems);
|
|
179
|
-
const valueFields = new Set(valueFieldNames);
|
|
180
178
|
const aggregate = (columnIndex) => {
|
|
181
179
|
const columnValues = source.getColumn(columnIndex).values;
|
|
182
180
|
// Build unique values set directly, skipping header (index 0,1) and null/undefined
|
|
@@ -214,11 +212,10 @@ function makeCacheFields(source, fieldNamesWithSharedItems, valueFieldNames) {
|
|
|
214
212
|
for (const columnIndex of range(1, names.length)) {
|
|
215
213
|
const name = names[columnIndex];
|
|
216
214
|
if (sharedItemsFields.has(name)) {
|
|
217
|
-
// Field used for rows/columns - extract unique values as sharedItems
|
|
218
215
|
result.push({ name, sharedItems: aggregate(columnIndex) });
|
|
219
216
|
}
|
|
220
|
-
else
|
|
221
|
-
//
|
|
217
|
+
else {
|
|
218
|
+
// Numeric field - calculate min/max
|
|
222
219
|
const minMax = getMinMax(columnIndex);
|
|
223
220
|
result.push({
|
|
224
221
|
name,
|
|
@@ -227,10 +224,6 @@ function makeCacheFields(source, fieldNamesWithSharedItems, valueFieldNames) {
|
|
|
227
224
|
maxValue: minMax?.maxValue
|
|
228
225
|
});
|
|
229
226
|
}
|
|
230
|
-
else {
|
|
231
|
-
// Unused field - just empty sharedItems (like Excel does)
|
|
232
|
-
result.push({ name, sharedItems: null });
|
|
233
|
-
}
|
|
234
227
|
}
|
|
235
228
|
return result;
|
|
236
229
|
}
|
|
@@ -44,26 +44,30 @@ class CacheFieldXform extends BaseXform {
|
|
|
44
44
|
break;
|
|
45
45
|
case "sharedItems":
|
|
46
46
|
this.inSharedItems = true;
|
|
47
|
-
//
|
|
48
|
-
if (
|
|
49
|
-
this.model
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (count > 0) {
|
|
60
|
-
this.model.sharedItems = [];
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
// No count means no individual items (pure numeric field)
|
|
47
|
+
// Check if this is a numeric field (no string items)
|
|
48
|
+
if (attributes.containsNumber === "1" || attributes.containsInteger === "1") {
|
|
49
|
+
if (this.model) {
|
|
50
|
+
this.model.containsNumber = attributes.containsNumber === "1";
|
|
51
|
+
this.model.containsInteger = attributes.containsInteger === "1";
|
|
52
|
+
if (attributes.minValue !== undefined) {
|
|
53
|
+
this.model.minValue = parseFloat(attributes.minValue);
|
|
54
|
+
}
|
|
55
|
+
if (attributes.maxValue !== undefined) {
|
|
56
|
+
this.model.maxValue = parseFloat(attributes.maxValue);
|
|
57
|
+
}
|
|
58
|
+
// Numeric fields have sharedItems = null
|
|
64
59
|
this.model.sharedItems = null;
|
|
65
60
|
}
|
|
66
61
|
}
|
|
62
|
+
else {
|
|
63
|
+
// String field - initialize sharedItems array if count > 0
|
|
64
|
+
if (this.model) {
|
|
65
|
+
const count = parseInt(attributes.count || "0", 10);
|
|
66
|
+
if (count > 0) {
|
|
67
|
+
this.model.sharedItems = [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
67
71
|
break;
|
|
68
72
|
case "s":
|
|
69
73
|
// String value in sharedItems
|
|
@@ -10,7 +10,7 @@ class CacheField {
|
|
|
10
10
|
//
|
|
11
11
|
// or
|
|
12
12
|
//
|
|
13
|
-
// integer type
|
|
13
|
+
// integer type
|
|
14
14
|
//
|
|
15
15
|
// {
|
|
16
16
|
// 'name': 'D',
|
|
@@ -18,15 +18,6 @@ class CacheField {
|
|
|
18
18
|
// 'minValue': 5,
|
|
19
19
|
// 'maxValue': 45
|
|
20
20
|
// }
|
|
21
|
-
//
|
|
22
|
-
// or
|
|
23
|
-
//
|
|
24
|
-
// numeric type with shared items (used as both row/column and value field)
|
|
25
|
-
//
|
|
26
|
-
// {
|
|
27
|
-
// 'name': 'C',
|
|
28
|
-
// 'sharedItems': [5, 24, 35, 45]
|
|
29
|
-
// }
|
|
30
21
|
this.name = name;
|
|
31
22
|
this.sharedItems = sharedItems;
|
|
32
23
|
this.minValue = minValue;
|
|
@@ -37,37 +28,17 @@ class CacheField {
|
|
|
37
28
|
// Shared Items: http://www.datypic.com/sc/ooxml/e-ssml_sharedItems-1.html
|
|
38
29
|
// Escape XML special characters in name attribute
|
|
39
30
|
const escapedName = xmlEncode(this.name);
|
|
40
|
-
//
|
|
31
|
+
// integer types
|
|
41
32
|
if (this.sharedItems === null) {
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
</cacheField>`;
|
|
47
|
-
}
|
|
48
|
-
// Numeric field used only for values (not rows/columns) - include min/max
|
|
33
|
+
// Build minValue/maxValue attributes if available
|
|
34
|
+
const minMaxAttrs = this.minValue !== undefined && this.maxValue !== undefined
|
|
35
|
+
? ` minValue="${this.minValue}" maxValue="${this.maxValue}"`
|
|
36
|
+
: "";
|
|
49
37
|
return `<cacheField name="${escapedName}" numFmtId="0">
|
|
50
|
-
<sharedItems containsSemiMixedTypes="0" containsString="0" containsNumber="1" containsInteger="1"
|
|
51
|
-
</cacheField>`;
|
|
52
|
-
}
|
|
53
|
-
// Shared items exist - check if all values are numeric
|
|
54
|
-
// Note: empty array returns true for every(), so check length first
|
|
55
|
-
const allNumeric = this.sharedItems.length > 0 &&
|
|
56
|
-
this.sharedItems.every(item => typeof item === "number" && Number.isFinite(item));
|
|
57
|
-
const allInteger = allNumeric && this.sharedItems.every(item => Number.isInteger(item));
|
|
58
|
-
if (allNumeric) {
|
|
59
|
-
// Numeric shared items - used when field is both a row/column field AND a value field
|
|
60
|
-
// This allows Excel to both group by unique values AND perform aggregation
|
|
61
|
-
const minValue = Math.min(...this.sharedItems);
|
|
62
|
-
const maxValue = Math.max(...this.sharedItems);
|
|
63
|
-
const integerAttr = allInteger ? ' containsInteger="1"' : "";
|
|
64
|
-
return `<cacheField name="${escapedName}" numFmtId="0">
|
|
65
|
-
<sharedItems containsSemiMixedTypes="0" containsString="0" containsNumber="1"${integerAttr} minValue="${minValue}" maxValue="${maxValue}" count="${this.sharedItems.length}">
|
|
66
|
-
${this.sharedItems.map(item => `<n v="${item}" />`).join("")}
|
|
67
|
-
</sharedItems>
|
|
38
|
+
<sharedItems containsSemiMixedTypes="0" containsString="0" containsNumber="1" containsInteger="1"${minMaxAttrs} />
|
|
68
39
|
</cacheField>`;
|
|
69
40
|
}
|
|
70
|
-
//
|
|
41
|
+
// string types - escape XML special characters in each shared item value
|
|
71
42
|
return `<cacheField name="${escapedName}" numFmtId="0">
|
|
72
43
|
<sharedItems count="${this.sharedItems.length}">
|
|
73
44
|
${this.sharedItems.map(item => `<s v="${xmlEncode(String(item))}" />`).join("")}
|
|
@@ -116,7 +116,7 @@ class PivotCacheRecordsXform extends BaseXform {
|
|
|
116
116
|
}
|
|
117
117
|
return `<s v="${xmlEncode(String(value))}" />`;
|
|
118
118
|
}
|
|
119
|
-
// shared items
|
|
119
|
+
// shared items
|
|
120
120
|
const sharedItemsIndex = sharedItems.indexOf(value);
|
|
121
121
|
if (sharedItemsIndex < 0) {
|
|
122
122
|
throw new Error(`${JSON.stringify(value)} not in sharedItems ${JSON.stringify(sharedItems)}`);
|
|
@@ -581,24 +581,25 @@ function renderPivotFields(pivotTable) {
|
|
|
581
581
|
const valueSet = new Set(pivotTable.values);
|
|
582
582
|
return pivotTable.cacheFields
|
|
583
583
|
.map((cacheField, fieldIndex) => {
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
584
|
+
const fieldType = rowSet.has(fieldIndex)
|
|
585
|
+
? "row"
|
|
586
|
+
: colSet.has(fieldIndex)
|
|
587
|
+
? "column"
|
|
588
|
+
: valueSet.has(fieldIndex)
|
|
589
|
+
? "value"
|
|
590
|
+
: null;
|
|
591
|
+
return renderPivotField(fieldType, cacheField.sharedItems);
|
|
588
592
|
})
|
|
589
593
|
.join("");
|
|
590
594
|
}
|
|
591
|
-
function renderPivotField(
|
|
592
|
-
//
|
|
593
|
-
//
|
|
594
|
-
|
|
595
|
-
|
|
595
|
+
function renderPivotField(fieldType, sharedItems) {
|
|
596
|
+
// fieldType: 'row', 'column', 'value', null
|
|
597
|
+
// Note: defaultSubtotal="0" should only be on value fields and non-axis fields,
|
|
598
|
+
// NOT on row/column axis fields (Excel will auto-calculate subtotals for them)
|
|
599
|
+
if (fieldType === "row" || fieldType === "column") {
|
|
600
|
+
const axis = fieldType === "row" ? "axisRow" : "axisCol";
|
|
596
601
|
// Row and column fields should NOT have defaultSubtotal="0"
|
|
597
|
-
|
|
598
|
-
// If also a value field, add dataField="1"
|
|
599
|
-
if (isValue) {
|
|
600
|
-
axisAttributes = `dataField="1" ${axisAttributes}`;
|
|
601
|
-
}
|
|
602
|
+
const axisAttributes = 'compact="0" outline="0" showAll="0"';
|
|
602
603
|
// items = one for each shared item + one default item
|
|
603
604
|
const itemsXml = [
|
|
604
605
|
...sharedItems.map((_item, index) => `<item x="${index}" />`),
|
|
@@ -616,7 +617,7 @@ function renderPivotField(isRow, isCol, isValue, sharedItems) {
|
|
|
616
617
|
const defaultAttributes = 'compact="0" outline="0" showAll="0" defaultSubtotal="0"';
|
|
617
618
|
return `
|
|
618
619
|
<pivotField
|
|
619
|
-
${
|
|
620
|
+
${fieldType === "value" ? 'dataField="1"' : ""}
|
|
620
621
|
${defaultAttributes}
|
|
621
622
|
/>
|
|
622
623
|
`;
|
package/package.json
CHANGED