@a3s-lab/office 0.15.0 → 0.16.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/COLLABORATION_ROADMAP.md +15 -5
- package/README.md +22 -1
- package/dist/0~6090.js +7 -8
- package/dist/0~spreadsheet-editor.js +2106 -438
- package/dist/2180.js +370 -34
- package/dist/4104.js +657 -22
- package/dist/5184.js +1 -1
- package/dist/8715.js +156 -156
- package/dist/internal/collaboration/office-spreadsheet-collaboration-records.d.ts +2 -0
- package/dist/internal/collaboration/office-spreadsheet-collaboration-validation-support.d.ts +6 -0
- package/dist/internal/features/work/editors/spreadsheet-auto-filter.d.ts +1 -0
- package/dist/internal/features/work/editors/spreadsheet-command-catalog.d.ts +21 -1
- package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +10 -0
- package/dist/internal/features/work/editors/spreadsheet-editor-ribbon.d.ts +4 -2
- package/dist/internal/features/work/editors/spreadsheet-table-command.d.ts +3 -0
- package/dist/internal/features/work/editors/spreadsheet-table-conversion.d.ts +7 -0
- package/dist/internal/features/work/editors/spreadsheet-table-dialog.d.ts +8 -0
- package/dist/internal/features/work/editors/spreadsheet-table-limits.d.ts +1 -0
- package/dist/internal/features/work/editors/spreadsheet-table-reconciliation.d.ts +21 -0
- package/dist/internal/features/work/editors/spreadsheet-table-render.d.ts +16 -0
- package/dist/internal/features/work/editors/spreadsheet-table-ribbon.d.ts +8 -0
- package/dist/internal/features/work/editors/spreadsheet-table-style.d.ts +31 -0
- package/dist/internal/features/work/editors/spreadsheet-table.d.ts +55 -0
- package/dist/internal/features/work/editors/use-spreadsheet-table.d.ts +23 -0
- package/dist/internal/features/work/work-types.d.ts +100 -0
- package/dist/internal/features/work/work-xlsx-interop.d.ts +2 -0
- package/dist/internal/features/work/work-xlsx-table-filters.d.ts +3 -0
- package/dist/internal/features/work/work-xlsx-tables.d.ts +4 -0
- package/dist/office-kernel.wasm +0 -0
- package/dist/styles.css +189 -0
- package/dist/work-spreadsheet-package-scan.worker.js +3 -2
- package/docs/latest/en/browser-editor-architecture.md +43 -0
- package/package.json +4 -1
package/dist/4104.js
CHANGED
|
@@ -5637,7 +5637,8 @@ const IMPORTED_WORKSHEET_ELEMENTS = new Set([
|
|
|
5637
5637
|
'printOptions',
|
|
5638
5638
|
'headerFooter',
|
|
5639
5639
|
'pageSetUpPr',
|
|
5640
|
-
'drawing'
|
|
5640
|
+
'drawing',
|
|
5641
|
+
'tableParts'
|
|
5641
5642
|
]);
|
|
5642
5643
|
const DIAGNOSTIC_WORKSHEET_ELEMENTS = new Set([
|
|
5643
5644
|
'conditionalFormatting',
|
|
@@ -5652,7 +5653,7 @@ const DIAGNOSTIC_WORKSHEET_ELEMENTS = new Set([
|
|
|
5652
5653
|
'rowBreaks',
|
|
5653
5654
|
'colBreaks'
|
|
5654
5655
|
]);
|
|
5655
|
-
const WORKSHEET_SCAN_PATTERN = /<(?:[A-Za-z_][\w.-]*:)?(?:(cols|f|pane|dataValidation|conditionalFormatting|sheetProtection|protectedRange|rowBreaks|colBreaks|pageSetup|pageMargins|printOptions|headerFooter|pageSetUpPr|drawing)(?=[\s/>])|(row)(?=[\s/>])[^>]*\s(?:collapsed|customFormat|customHeight|hidden|ht|outlineLevel|thickBot|thickTop)\s*=|(c)(?=[\s/>])[^>]*\ss\s*=)/g;
|
|
5656
|
+
const WORKSHEET_SCAN_PATTERN = /<(?:[A-Za-z_][\w.-]*:)?(?:(cols|f|pane|dataValidation|conditionalFormatting|sheetProtection|protectedRange|rowBreaks|colBreaks|pageSetup|pageMargins|printOptions|headerFooter|pageSetUpPr|drawing|tableParts)(?=[\s/>])|(row)(?=[\s/>])[^>]*\s(?:collapsed|customFormat|customHeight|hidden|ht|outlineLevel|thickBot|thickTop)\s*=|(c)(?=[\s/>])[^>]*\ss\s*=)/g;
|
|
5656
5657
|
function scanXlsxWorksheetXml(source) {
|
|
5657
5658
|
let hasDirectCellStyles = false;
|
|
5658
5659
|
let hasDiagnosticFeatures = false;
|
|
@@ -5679,6 +5680,636 @@ function scanXlsxWorksheetXml(source) {
|
|
|
5679
5680
|
requiresSheetJsCellStyles
|
|
5680
5681
|
};
|
|
5681
5682
|
}
|
|
5683
|
+
const DYNAMIC_FILTERS = new Map([
|
|
5684
|
+
[
|
|
5685
|
+
'aboveAverage',
|
|
5686
|
+
'above-average'
|
|
5687
|
+
],
|
|
5688
|
+
[
|
|
5689
|
+
'belowAverage',
|
|
5690
|
+
'below-average'
|
|
5691
|
+
],
|
|
5692
|
+
[
|
|
5693
|
+
'tomorrow',
|
|
5694
|
+
'tomorrow'
|
|
5695
|
+
],
|
|
5696
|
+
[
|
|
5697
|
+
'today',
|
|
5698
|
+
'today'
|
|
5699
|
+
],
|
|
5700
|
+
[
|
|
5701
|
+
'yesterday',
|
|
5702
|
+
'yesterday'
|
|
5703
|
+
],
|
|
5704
|
+
[
|
|
5705
|
+
'nextWeek',
|
|
5706
|
+
'next-week'
|
|
5707
|
+
],
|
|
5708
|
+
[
|
|
5709
|
+
'thisWeek',
|
|
5710
|
+
'this-week'
|
|
5711
|
+
],
|
|
5712
|
+
[
|
|
5713
|
+
'lastWeek',
|
|
5714
|
+
'last-week'
|
|
5715
|
+
],
|
|
5716
|
+
[
|
|
5717
|
+
'nextMonth',
|
|
5718
|
+
'next-month'
|
|
5719
|
+
],
|
|
5720
|
+
[
|
|
5721
|
+
'thisMonth',
|
|
5722
|
+
'this-month'
|
|
5723
|
+
],
|
|
5724
|
+
[
|
|
5725
|
+
'lastMonth',
|
|
5726
|
+
'last-month'
|
|
5727
|
+
],
|
|
5728
|
+
[
|
|
5729
|
+
'nextQuarter',
|
|
5730
|
+
'next-quarter'
|
|
5731
|
+
],
|
|
5732
|
+
[
|
|
5733
|
+
'thisQuarter',
|
|
5734
|
+
'this-quarter'
|
|
5735
|
+
],
|
|
5736
|
+
[
|
|
5737
|
+
'lastQuarter',
|
|
5738
|
+
'last-quarter'
|
|
5739
|
+
],
|
|
5740
|
+
[
|
|
5741
|
+
'nextYear',
|
|
5742
|
+
'next-year'
|
|
5743
|
+
],
|
|
5744
|
+
[
|
|
5745
|
+
'thisYear',
|
|
5746
|
+
'this-year'
|
|
5747
|
+
],
|
|
5748
|
+
[
|
|
5749
|
+
'lastYear',
|
|
5750
|
+
'last-year'
|
|
5751
|
+
],
|
|
5752
|
+
[
|
|
5753
|
+
'yearToDate',
|
|
5754
|
+
'year-to-date'
|
|
5755
|
+
],
|
|
5756
|
+
[
|
|
5757
|
+
'Q1',
|
|
5758
|
+
'quarter-1'
|
|
5759
|
+
],
|
|
5760
|
+
[
|
|
5761
|
+
'Q2',
|
|
5762
|
+
'quarter-2'
|
|
5763
|
+
],
|
|
5764
|
+
[
|
|
5765
|
+
'Q3',
|
|
5766
|
+
'quarter-3'
|
|
5767
|
+
],
|
|
5768
|
+
[
|
|
5769
|
+
'Q4',
|
|
5770
|
+
'quarter-4'
|
|
5771
|
+
],
|
|
5772
|
+
[
|
|
5773
|
+
'M1',
|
|
5774
|
+
'month-1'
|
|
5775
|
+
],
|
|
5776
|
+
[
|
|
5777
|
+
'M2',
|
|
5778
|
+
'month-2'
|
|
5779
|
+
],
|
|
5780
|
+
[
|
|
5781
|
+
'M3',
|
|
5782
|
+
'month-3'
|
|
5783
|
+
],
|
|
5784
|
+
[
|
|
5785
|
+
'M4',
|
|
5786
|
+
'month-4'
|
|
5787
|
+
],
|
|
5788
|
+
[
|
|
5789
|
+
'M5',
|
|
5790
|
+
'month-5'
|
|
5791
|
+
],
|
|
5792
|
+
[
|
|
5793
|
+
'M6',
|
|
5794
|
+
'month-6'
|
|
5795
|
+
],
|
|
5796
|
+
[
|
|
5797
|
+
'M7',
|
|
5798
|
+
'month-7'
|
|
5799
|
+
],
|
|
5800
|
+
[
|
|
5801
|
+
'M8',
|
|
5802
|
+
'month-8'
|
|
5803
|
+
],
|
|
5804
|
+
[
|
|
5805
|
+
'M9',
|
|
5806
|
+
'month-9'
|
|
5807
|
+
],
|
|
5808
|
+
[
|
|
5809
|
+
'M10',
|
|
5810
|
+
'month-10'
|
|
5811
|
+
],
|
|
5812
|
+
[
|
|
5813
|
+
'M11',
|
|
5814
|
+
'month-11'
|
|
5815
|
+
],
|
|
5816
|
+
[
|
|
5817
|
+
'M12',
|
|
5818
|
+
'month-12'
|
|
5819
|
+
]
|
|
5820
|
+
]);
|
|
5821
|
+
const OOXML_DYNAMIC_FILTERS = new Map([
|
|
5822
|
+
...DYNAMIC_FILTERS
|
|
5823
|
+
].map(([ooxml, model])=>[
|
|
5824
|
+
model,
|
|
5825
|
+
ooxml
|
|
5826
|
+
]));
|
|
5827
|
+
function readXlsxTableFilters(table, width) {
|
|
5828
|
+
const autoFilter = directChild(table.documentElement, 'autoFilter');
|
|
5829
|
+
if (!autoFilter) return [];
|
|
5830
|
+
const result = [];
|
|
5831
|
+
const observed = new Set();
|
|
5832
|
+
for (const column of directChildren(autoFilter, 'filterColumn')){
|
|
5833
|
+
const index = integerAttribute(column, 'colId');
|
|
5834
|
+
if (null === index || index < 0 || index >= width || observed.has(index)) continue;
|
|
5835
|
+
const criteria = parseFilterCriteria(column);
|
|
5836
|
+
if (criteria) {
|
|
5837
|
+
observed.add(index);
|
|
5838
|
+
result.push({
|
|
5839
|
+
column: index,
|
|
5840
|
+
criteria
|
|
5841
|
+
});
|
|
5842
|
+
}
|
|
5843
|
+
}
|
|
5844
|
+
return result;
|
|
5845
|
+
}
|
|
5846
|
+
function xlsxTableAutoFilterXml(filters, rangeReference, totalsRow) {
|
|
5847
|
+
const filterRange = totalsRow ? tableRangeWithoutFinalRow(rangeReference) : rangeReference;
|
|
5848
|
+
const columns = filters.slice().sort((left, right)=>left.column - right.column).map((filter)=>`<filterColumn colId="${filter.column}">${criteriaXml(filter.criteria)}</filterColumn>`).join('');
|
|
5849
|
+
return `<autoFilter ref="${work_xlsx_table_filters_escapeXml(filterRange)}">${columns}</autoFilter>`;
|
|
5850
|
+
}
|
|
5851
|
+
function parseFilterCriteria(column) {
|
|
5852
|
+
const filters = directChild(column, 'filters');
|
|
5853
|
+
if (filters) {
|
|
5854
|
+
const values = directChildren(filters, 'filter').flatMap((filter)=>{
|
|
5855
|
+
const value = work_ooxml_package_attribute(filter, 'val');
|
|
5856
|
+
return null === value ? [] : [
|
|
5857
|
+
value
|
|
5858
|
+
];
|
|
5859
|
+
});
|
|
5860
|
+
const includeBlanks = work_xlsx_table_filters_booleanAttribute(filters, 'blank');
|
|
5861
|
+
if (!values.length && includeBlanks) return {
|
|
5862
|
+
type: 'blanks'
|
|
5863
|
+
};
|
|
5864
|
+
if (values.length) return {
|
|
5865
|
+
type: 'values',
|
|
5866
|
+
values,
|
|
5867
|
+
includeBlanks
|
|
5868
|
+
};
|
|
5869
|
+
}
|
|
5870
|
+
const customFilters = directChild(column, 'customFilters');
|
|
5871
|
+
if (customFilters) {
|
|
5872
|
+
const items = directChildren(customFilters, 'customFilter').flatMap((filter)=>{
|
|
5873
|
+
const value = work_ooxml_package_attribute(filter, 'val');
|
|
5874
|
+
return null === value ? [] : [
|
|
5875
|
+
{
|
|
5876
|
+
operator: work_ooxml_package_attribute(filter, 'operator') ?? 'equal',
|
|
5877
|
+
value
|
|
5878
|
+
}
|
|
5879
|
+
];
|
|
5880
|
+
});
|
|
5881
|
+
const item = 1 === items.length ? items[0] : void 0;
|
|
5882
|
+
if (item) return singleCustomFilter(item);
|
|
5883
|
+
if (2 === items.length) {
|
|
5884
|
+
const [first, second] = items;
|
|
5885
|
+
const conjunction = work_xlsx_table_filters_booleanAttribute(customFilters, 'and');
|
|
5886
|
+
if (conjunction && first?.operator === 'greaterThanOrEqual' && second?.operator === 'lessThanOrEqual') return {
|
|
5887
|
+
type: 'between',
|
|
5888
|
+
lower: first.value,
|
|
5889
|
+
upper: second.value
|
|
5890
|
+
};
|
|
5891
|
+
if (!conjunction && first?.operator === 'lessThan' && second?.operator === 'greaterThan') return {
|
|
5892
|
+
type: 'not-between',
|
|
5893
|
+
lower: first.value,
|
|
5894
|
+
upper: second.value
|
|
5895
|
+
};
|
|
5896
|
+
}
|
|
5897
|
+
}
|
|
5898
|
+
const top = directChild(column, 'top10');
|
|
5899
|
+
if (top) {
|
|
5900
|
+
const value = integerAttribute(top, 'val');
|
|
5901
|
+
if (null === value || value < 1) return null;
|
|
5902
|
+
const upper = '0' !== work_ooxml_package_attribute(top, 'top');
|
|
5903
|
+
const percent = work_xlsx_table_filters_booleanAttribute(top, 'percent');
|
|
5904
|
+
if (percent && value > 100 || !percent && value > 500) return null;
|
|
5905
|
+
if (upper && percent) return {
|
|
5906
|
+
type: 'top-percent',
|
|
5907
|
+
percent: value
|
|
5908
|
+
};
|
|
5909
|
+
if (upper) return {
|
|
5910
|
+
type: 'top',
|
|
5911
|
+
count: value
|
|
5912
|
+
};
|
|
5913
|
+
if (percent) return {
|
|
5914
|
+
type: 'bottom-percent',
|
|
5915
|
+
percent: value
|
|
5916
|
+
};
|
|
5917
|
+
return {
|
|
5918
|
+
type: 'bottom',
|
|
5919
|
+
count: value
|
|
5920
|
+
};
|
|
5921
|
+
}
|
|
5922
|
+
const dynamic = directChild(column, 'dynamicFilter');
|
|
5923
|
+
const kind = dynamic ? DYNAMIC_FILTERS.get(work_ooxml_package_attribute(dynamic, 'type') ?? '') : null;
|
|
5924
|
+
return kind ? {
|
|
5925
|
+
type: 'dynamic',
|
|
5926
|
+
kind
|
|
5927
|
+
} : null;
|
|
5928
|
+
}
|
|
5929
|
+
function singleCustomFilter(item) {
|
|
5930
|
+
if ('notEqual' === item.operator && '' === item.value) return {
|
|
5931
|
+
type: 'non-blanks'
|
|
5932
|
+
};
|
|
5933
|
+
if ('equal' === item.operator) {
|
|
5934
|
+
const wildcard = wildcardCriterion(item.value);
|
|
5935
|
+
return wildcard ?? {
|
|
5936
|
+
type: 'equals',
|
|
5937
|
+
value: unescapeWildcards(item.value)
|
|
5938
|
+
};
|
|
5939
|
+
}
|
|
5940
|
+
if ('notEqual' === item.operator) {
|
|
5941
|
+
const wildcard = wildcardCriterion(item.value);
|
|
5942
|
+
if (!wildcard) return {
|
|
5943
|
+
type: 'not-equals',
|
|
5944
|
+
value: unescapeWildcards(item.value)
|
|
5945
|
+
};
|
|
5946
|
+
return 'contains' === wildcard.type ? {
|
|
5947
|
+
type: 'does-not-contain',
|
|
5948
|
+
value: wildcard.value
|
|
5949
|
+
} : null;
|
|
5950
|
+
}
|
|
5951
|
+
const types = {
|
|
5952
|
+
greaterThan: 'greater-than',
|
|
5953
|
+
greaterThanOrEqual: 'greater-than-or-equal',
|
|
5954
|
+
lessThan: 'less-than',
|
|
5955
|
+
lessThanOrEqual: 'less-than-or-equal'
|
|
5956
|
+
};
|
|
5957
|
+
const type = types[item.operator];
|
|
5958
|
+
return type ? {
|
|
5959
|
+
type,
|
|
5960
|
+
value: item.value
|
|
5961
|
+
} : null;
|
|
5962
|
+
}
|
|
5963
|
+
function wildcardCriterion(source) {
|
|
5964
|
+
const starts = source.startsWith('*');
|
|
5965
|
+
const ends = unescapedFinalAsterisk(source);
|
|
5966
|
+
if (!starts && !ends) return null;
|
|
5967
|
+
const value = unescapeWildcards(source.slice(starts ? 1 : 0, ends ? -1 : void 0));
|
|
5968
|
+
if (starts && ends) return {
|
|
5969
|
+
type: 'contains',
|
|
5970
|
+
value
|
|
5971
|
+
};
|
|
5972
|
+
return starts ? {
|
|
5973
|
+
type: 'ends-with',
|
|
5974
|
+
value
|
|
5975
|
+
} : {
|
|
5976
|
+
type: 'begins-with',
|
|
5977
|
+
value
|
|
5978
|
+
};
|
|
5979
|
+
}
|
|
5980
|
+
function criteriaXml(criteria) {
|
|
5981
|
+
if ('values' === criteria.type) {
|
|
5982
|
+
const blank = criteria.includeBlanks ? ' blank="1"' : '';
|
|
5983
|
+
return `<filters${blank}>${criteria.values.map((value)=>`<filter val="${work_xlsx_table_filters_escapeXml(value)}"/>`).join('')}</filters>`;
|
|
5984
|
+
}
|
|
5985
|
+
if ('blanks' === criteria.type) return '<filters blank="1"/>';
|
|
5986
|
+
if ('non-blanks' === criteria.type) return customFilterXml('notEqual', '');
|
|
5987
|
+
if ('between' === criteria.type) return customFilterPairXml(true, 'greaterThanOrEqual', criteria.lower, 'lessThanOrEqual', criteria.upper);
|
|
5988
|
+
if ('not-between' === criteria.type) return customFilterPairXml(false, 'lessThan', criteria.lower, 'greaterThan', criteria.upper);
|
|
5989
|
+
if ('top' === criteria.type) return topXml(true, false, criteria.count);
|
|
5990
|
+
if ('top-percent' === criteria.type) return topXml(true, true, criteria.percent);
|
|
5991
|
+
if ('bottom' === criteria.type) return topXml(false, false, criteria.count);
|
|
5992
|
+
if ('bottom-percent' === criteria.type) return topXml(false, true, criteria.percent);
|
|
5993
|
+
if ('dynamic' === criteria.type) {
|
|
5994
|
+
const kind = OOXML_DYNAMIC_FILTERS.get(criteria.kind);
|
|
5995
|
+
return kind ? `<dynamicFilter type="${kind}"/>` : '';
|
|
5996
|
+
}
|
|
5997
|
+
const operator = comparisonOperator(criteria.type);
|
|
5998
|
+
const value = 'contains' === criteria.type ? `*${escapeWildcards(criteria.value)}*` : 'does-not-contain' === criteria.type ? `*${escapeWildcards(criteria.value)}*` : 'begins-with' === criteria.type ? `${escapeWildcards(criteria.value)}*` : 'ends-with' === criteria.type ? `*${escapeWildcards(criteria.value)}` : 'equals' === criteria.type || 'not-equals' === criteria.type ? escapeWildcards(criteria.value) : criteria.value;
|
|
5999
|
+
return customFilterXml(operator, value);
|
|
6000
|
+
}
|
|
6001
|
+
function comparisonOperator(type) {
|
|
6002
|
+
const operators = {
|
|
6003
|
+
'begins-with': 'equal',
|
|
6004
|
+
contains: 'equal',
|
|
6005
|
+
'does-not-contain': 'notEqual',
|
|
6006
|
+
'ends-with': 'equal',
|
|
6007
|
+
equals: 'equal',
|
|
6008
|
+
'greater-than': 'greaterThan',
|
|
6009
|
+
'greater-than-or-equal': 'greaterThanOrEqual',
|
|
6010
|
+
'less-than': 'lessThan',
|
|
6011
|
+
'less-than-or-equal': 'lessThanOrEqual',
|
|
6012
|
+
'not-equals': 'notEqual'
|
|
6013
|
+
};
|
|
6014
|
+
return operators[type];
|
|
6015
|
+
}
|
|
6016
|
+
function customFilterXml(operator, value) {
|
|
6017
|
+
return `<customFilters><customFilter operator="${operator}" val="${work_xlsx_table_filters_escapeXml(value)}"/></customFilters>`;
|
|
6018
|
+
}
|
|
6019
|
+
function customFilterPairXml(conjunction, firstOperator, firstValue, secondOperator, secondValue) {
|
|
6020
|
+
return `<customFilters and="${conjunction ? 1 : 0}"><customFilter operator="${firstOperator}" val="${work_xlsx_table_filters_escapeXml(firstValue)}"/><customFilter operator="${secondOperator}" val="${work_xlsx_table_filters_escapeXml(secondValue)}"/></customFilters>`;
|
|
6021
|
+
}
|
|
6022
|
+
function topXml(top, percent, value) {
|
|
6023
|
+
return `<top10 percent="${percent ? 1 : 0}" top="${top ? 1 : 0}" val="${value}"/>`;
|
|
6024
|
+
}
|
|
6025
|
+
function tableRangeWithoutFinalRow(reference) {
|
|
6026
|
+
const match = /^([A-Z]+)(\d+):([A-Z]+)(\d+)$/i.exec(reference);
|
|
6027
|
+
if (!match) return reference;
|
|
6028
|
+
const finalRow = Number(match[4]);
|
|
6029
|
+
return `${match[1]}${match[2]}:${match[3]}${Math.max(Number(match[2]), finalRow - 1)}`;
|
|
6030
|
+
}
|
|
6031
|
+
function work_xlsx_table_filters_booleanAttribute(element, name) {
|
|
6032
|
+
return [
|
|
6033
|
+
'1',
|
|
6034
|
+
'true',
|
|
6035
|
+
'on'
|
|
6036
|
+
].includes((work_ooxml_package_attribute(element, name) ?? '').toLocaleLowerCase());
|
|
6037
|
+
}
|
|
6038
|
+
function integerAttribute(element, name) {
|
|
6039
|
+
const source = work_ooxml_package_attribute(element, name);
|
|
6040
|
+
if (null === source) return null;
|
|
6041
|
+
const value = Number(source);
|
|
6042
|
+
return Number.isSafeInteger(value) ? value : null;
|
|
6043
|
+
}
|
|
6044
|
+
function escapeWildcards(value) {
|
|
6045
|
+
return value.replaceAll('~', '~~').replaceAll('*', '~*').replaceAll('?', '~?');
|
|
6046
|
+
}
|
|
6047
|
+
function unescapeWildcards(value) {
|
|
6048
|
+
return value.replace(/~([~*?])/g, '$1');
|
|
6049
|
+
}
|
|
6050
|
+
function unescapedFinalAsterisk(value) {
|
|
6051
|
+
if (!value.endsWith('*')) return false;
|
|
6052
|
+
let escapes = 0;
|
|
6053
|
+
for(let index = value.length - 2; index >= 0 && '~' === value[index]; index -= 1)escapes += 1;
|
|
6054
|
+
return escapes % 2 === 0;
|
|
6055
|
+
}
|
|
6056
|
+
function work_xlsx_table_filters_escapeXml(value) {
|
|
6057
|
+
return value.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
6058
|
+
}
|
|
6059
|
+
const work_xlsx_tables_PACKAGE_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/package/2006/relationships';
|
|
6060
|
+
const TRANSITIONAL_DOCUMENT_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
|
|
6061
|
+
const STRICT_DOCUMENT_RELATIONSHIP_NAMESPACE = 'http://purl.oclc.org/ooxml/officeDocument/relationships';
|
|
6062
|
+
const TABLE_CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml';
|
|
6063
|
+
async function readXlsxWorksheetTables(archive, worksheetPart) {
|
|
6064
|
+
if (!archive.has(worksheetPart)) return [];
|
|
6065
|
+
const worksheet = await archive.xml(worksheetPart);
|
|
6066
|
+
const relationships = await archive.relationships(worksheetPart);
|
|
6067
|
+
const tableParts = directChild(worksheet.documentElement, 'tableParts');
|
|
6068
|
+
if (!tableParts) return [];
|
|
6069
|
+
const tables = [];
|
|
6070
|
+
for (const tablePart of directChildren(tableParts, 'tablePart')){
|
|
6071
|
+
const relationship = relationships.get(work_ooxml_package_attribute(tablePart, 'r:id') ?? '');
|
|
6072
|
+
if (!relationship || 'External' === relationship.targetMode || !relationship.type.endsWith('/table') || !archive.has(relationship.target)) continue;
|
|
6073
|
+
const parsed = parseXlsxTable(await archive.xml(relationship.target), relationship.target);
|
|
6074
|
+
if (parsed) tables.push(parsed);
|
|
6075
|
+
}
|
|
6076
|
+
return tables;
|
|
6077
|
+
}
|
|
6078
|
+
async function patchXlsxSpreadsheetTables(buffer, content) {
|
|
6079
|
+
const archive = await work_ooxml_package_OoxmlPackage.load(buffer);
|
|
6080
|
+
const hasExistingTables = archive.paths('xl/tables/').some((path)=>path.endsWith('.xml'));
|
|
6081
|
+
if (!hasExistingTables && !content.sheets.some((sheet)=>sheet.tables?.length)) return buffer;
|
|
6082
|
+
const worksheetParts = await workbookWorksheetParts(archive);
|
|
6083
|
+
const zip = await jszip.loadAsync(buffer);
|
|
6084
|
+
for (const path of Object.keys(zip.files))if (path.startsWith('xl/tables/')) zip.remove(path);
|
|
6085
|
+
const contentTypeParts = [];
|
|
6086
|
+
const usedTableIds = new Set();
|
|
6087
|
+
let partIndex = 0;
|
|
6088
|
+
for (const sheet of content.sheets){
|
|
6089
|
+
const exportedName = sheet.name.slice(0, 31) || '工作表';
|
|
6090
|
+
const worksheetPart = worksheetParts.get(exportedName);
|
|
6091
|
+
const worksheetEntry = worksheetPart ? zip.file(worksheetPart) : null;
|
|
6092
|
+
if (!worksheetPart || !worksheetEntry) continue;
|
|
6093
|
+
const worksheet = parseXml(await worksheetEntry.async('text'), worksheetPart);
|
|
6094
|
+
for (const tableParts of directChildren(worksheet.documentElement, 'tableParts'))tableParts.remove();
|
|
6095
|
+
const relationshipPath = work_xlsx_tables_relationshipsPartPath(worksheetPart);
|
|
6096
|
+
const relationships = await readRelationshipsDocument(zip, relationshipPath);
|
|
6097
|
+
removeTableRelationships(relationships);
|
|
6098
|
+
const relationshipNamespace = documentRelationshipNamespace(worksheet);
|
|
6099
|
+
const validTables = (sheet.tables ?? []).filter(validExportTable);
|
|
6100
|
+
const tableParts = validTables.length ? worksheet.createElementNS(worksheet.documentElement.namespaceURI, 'tableParts') : null;
|
|
6101
|
+
if (tableParts) tableParts.setAttribute('count', String(validTables.length));
|
|
6102
|
+
for (const table of validTables){
|
|
6103
|
+
partIndex += 1;
|
|
6104
|
+
const tablePath = `xl/tables/table${partIndex}.xml`;
|
|
6105
|
+
const relationshipId = appendRelationship(relationships, `${relationshipNamespace}/table`, `../tables/table${partIndex}.xml`);
|
|
6106
|
+
const tablePart = worksheet.createElementNS(worksheet.documentElement.namespaceURI, 'tablePart');
|
|
6107
|
+
tablePart.setAttributeNS(relationshipNamespace, 'r:id', relationshipId);
|
|
6108
|
+
tableParts?.append(tablePart);
|
|
6109
|
+
const tableId = allocateTableId(table.ooxmlId, usedTableIds);
|
|
6110
|
+
zip.file(tablePath, xlsxTableXml(table, tableId, worksheet.documentElement.namespaceURI ?? 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'));
|
|
6111
|
+
contentTypeParts.push(tablePath);
|
|
6112
|
+
}
|
|
6113
|
+
if (tableParts) {
|
|
6114
|
+
const anchor = directChildren(worksheet.documentElement).find((child)=>'extLst' === child.localName);
|
|
6115
|
+
worksheet.documentElement.insertBefore(tableParts, anchor ?? null);
|
|
6116
|
+
}
|
|
6117
|
+
zip.file(worksheetPart, new XMLSerializer().serializeToString(worksheet));
|
|
6118
|
+
if (directChildren(relationships.documentElement, 'Relationship').length > 0 || zip.file(relationshipPath)) zip.file(relationshipPath, new XMLSerializer().serializeToString(relationships));
|
|
6119
|
+
}
|
|
6120
|
+
await work_xlsx_tables_updateContentTypes(zip, contentTypeParts);
|
|
6121
|
+
return zip.generateAsync({
|
|
6122
|
+
type: 'arraybuffer',
|
|
6123
|
+
compression: 'DEFLATE'
|
|
6124
|
+
});
|
|
6125
|
+
}
|
|
6126
|
+
function parseXlsxTable(document1, partPath) {
|
|
6127
|
+
const root = document1.documentElement;
|
|
6128
|
+
if ('table' !== root.localName) return null;
|
|
6129
|
+
const name = work_ooxml_package_attribute(root, 'name')?.trim();
|
|
6130
|
+
const range = parseSpreadsheetCellRanges(work_ooxml_package_attribute(root, 'ref') ?? '')?.[0];
|
|
6131
|
+
const columnsElement = directChild(root, 'tableColumns');
|
|
6132
|
+
if (!name || !range || !columnsElement) return null;
|
|
6133
|
+
const columns = directChildren(columnsElement, 'tableColumn').flatMap((column)=>{
|
|
6134
|
+
const columnName = work_ooxml_package_attribute(column, 'name');
|
|
6135
|
+
return null === columnName ? [] : [
|
|
6136
|
+
{
|
|
6137
|
+
name: columnName
|
|
6138
|
+
}
|
|
6139
|
+
];
|
|
6140
|
+
});
|
|
6141
|
+
const width = range.column[1] - range.column[0] + 1;
|
|
6142
|
+
if (columns.length !== width) return null;
|
|
6143
|
+
const ooxmlId = positiveIntegerAttribute(root, 'id');
|
|
6144
|
+
const displayName = work_ooxml_package_attribute(root, 'displayName')?.trim();
|
|
6145
|
+
const headerRow = '0' !== work_ooxml_package_attribute(root, 'headerRowCount');
|
|
6146
|
+
const totalsRow = null !== positiveIntegerAttribute(root, 'totalsRowCount') || work_xlsx_tables_booleanAttribute(root, 'totalsRowShown');
|
|
6147
|
+
const styleInfo = directChild(root, 'tableStyleInfo');
|
|
6148
|
+
const style = parseTableStyle(work_ooxml_package_attribute(styleInfo ?? root, 'name'));
|
|
6149
|
+
const stablePart = partPath.replace(/[^A-Za-z0-9]+/g, '-');
|
|
6150
|
+
return {
|
|
6151
|
+
id: `spreadsheet-table-${stablePart}-${ooxmlId ?? name}`,
|
|
6152
|
+
...null === ooxmlId ? {} : {
|
|
6153
|
+
ooxmlId
|
|
6154
|
+
},
|
|
6155
|
+
name,
|
|
6156
|
+
...displayName && displayName !== name ? {
|
|
6157
|
+
displayName
|
|
6158
|
+
} : {},
|
|
6159
|
+
range,
|
|
6160
|
+
columns,
|
|
6161
|
+
filters: headerRow ? readXlsxTableFilters(document1, width) : [],
|
|
6162
|
+
headerRow,
|
|
6163
|
+
totalsRow,
|
|
6164
|
+
style,
|
|
6165
|
+
showFirstColumn: work_xlsx_tables_booleanAttribute(styleInfo, 'showFirstColumn'),
|
|
6166
|
+
showLastColumn: work_xlsx_tables_booleanAttribute(styleInfo, 'showLastColumn'),
|
|
6167
|
+
showRowStripes: work_xlsx_tables_booleanAttribute(styleInfo, 'showRowStripes'),
|
|
6168
|
+
showColumnStripes: work_xlsx_tables_booleanAttribute(styleInfo, 'showColumnStripes')
|
|
6169
|
+
};
|
|
6170
|
+
}
|
|
6171
|
+
function xlsxTableXml(table, tableId, namespace) {
|
|
6172
|
+
const reference = formatSpreadsheetCellRanges([
|
|
6173
|
+
table.range
|
|
6174
|
+
]);
|
|
6175
|
+
const displayName = table.displayName?.trim() || table.name;
|
|
6176
|
+
const filter = table.headerRow ? xlsxTableAutoFilterXml(table.filters, reference, table.totalsRow) : '';
|
|
6177
|
+
const columns = table.columns.map((column, index)=>`<tableColumn id="${index + 1}" name="${work_xlsx_tables_escapeXml(column.name)}"/>`).join('');
|
|
6178
|
+
const styleName = tableStyleName(table.style);
|
|
6179
|
+
const style = styleName ? `<tableStyleInfo name="${styleName}" showColumnStripes="${booleanToken(table.showColumnStripes)}" showFirstColumn="${booleanToken(table.showFirstColumn)}" showLastColumn="${booleanToken(table.showLastColumn)}" showRowStripes="${booleanToken(table.showRowStripes)}"/>` : '';
|
|
6180
|
+
return [
|
|
6181
|
+
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>',
|
|
6182
|
+
`<table xmlns="${work_xlsx_tables_escapeXml(namespace)}" id="${tableId}" name="${work_xlsx_tables_escapeXml(table.name)}" displayName="${work_xlsx_tables_escapeXml(displayName)}" ref="${reference}"`,
|
|
6183
|
+
` headerRowCount="${booleanToken(table.headerRow)}"`,
|
|
6184
|
+
` totalsRowCount="${booleanToken(table.totalsRow)}"`,
|
|
6185
|
+
` totalsRowShown="${booleanToken(table.totalsRow)}">`,
|
|
6186
|
+
filter,
|
|
6187
|
+
`<tableColumns count="${table.columns.length}">${columns}</tableColumns>`,
|
|
6188
|
+
style,
|
|
6189
|
+
'</table>'
|
|
6190
|
+
].join('');
|
|
6191
|
+
}
|
|
6192
|
+
function validExportTable(table) {
|
|
6193
|
+
const range = table.range;
|
|
6194
|
+
const width = range.column[1] - range.column[0] + 1;
|
|
6195
|
+
const height = range.row[1] - range.row[0] + 1;
|
|
6196
|
+
return Number.isSafeInteger(range.row[0]) && Number.isSafeInteger(range.row[1]) && Number.isSafeInteger(range.column[0]) && Number.isSafeInteger(range.column[1]) && range.row[0] >= 0 && range.column[0] >= 0 && width > 0 && height > Number(table.headerRow) + Number(table.totalsRow) && table.columns.length === width && Boolean(table.name.trim()) && table.columns.every((column)=>Boolean(column.name.trim())) && null !== tableStyleName(table.style);
|
|
6197
|
+
}
|
|
6198
|
+
function parseTableStyle(value) {
|
|
6199
|
+
if (!value) return {
|
|
6200
|
+
family: 'none'
|
|
6201
|
+
};
|
|
6202
|
+
const match = /^TableStyle(Light|Medium|Dark)(\d+)$/.exec(value);
|
|
6203
|
+
if (!match) return {
|
|
6204
|
+
family: 'none'
|
|
6205
|
+
};
|
|
6206
|
+
const family = match[1]?.toLocaleLowerCase();
|
|
6207
|
+
const number = Number(match[2]);
|
|
6208
|
+
const maximum = 'light' === family ? 21 : 'medium' === family ? 28 : 11;
|
|
6209
|
+
return number >= 1 && number <= maximum ? {
|
|
6210
|
+
family,
|
|
6211
|
+
number
|
|
6212
|
+
} : {
|
|
6213
|
+
family: 'none'
|
|
6214
|
+
};
|
|
6215
|
+
}
|
|
6216
|
+
function tableStyleName(style) {
|
|
6217
|
+
if ('none' === style.family) return '';
|
|
6218
|
+
const maximum = 'light' === style.family ? 21 : 'medium' === style.family ? 28 : 11;
|
|
6219
|
+
if (!Number.isInteger(style.number) || style.number < 1 || style.number > maximum) return null;
|
|
6220
|
+
const family = `${style.family.charAt(0).toUpperCase()}${style.family.slice(1)}`;
|
|
6221
|
+
return `TableStyle${family}${style.number}`;
|
|
6222
|
+
}
|
|
6223
|
+
async function workbookWorksheetParts(archive) {
|
|
6224
|
+
if (!archive.has('xl/workbook.xml')) return new Map();
|
|
6225
|
+
const workbook = await archive.xml('xl/workbook.xml');
|
|
6226
|
+
const relationships = await archive.relationships('xl/workbook.xml');
|
|
6227
|
+
const parts = new Map();
|
|
6228
|
+
for (const sheet of firstDescendant(workbook, 'sheets')?.children ?? []){
|
|
6229
|
+
if (!(sheet instanceof Element) || 'sheet' !== sheet.localName) continue;
|
|
6230
|
+
const name = work_ooxml_package_attribute(sheet, 'name');
|
|
6231
|
+
const relationship = relationships.get(work_ooxml_package_attribute(sheet, 'r:id') ?? '');
|
|
6232
|
+
if (name && relationship?.type.endsWith('/worksheet')) parts.set(name, relationship.target);
|
|
6233
|
+
}
|
|
6234
|
+
return parts;
|
|
6235
|
+
}
|
|
6236
|
+
async function readRelationshipsDocument(zip, partPath) {
|
|
6237
|
+
const entry = zip.file(partPath);
|
|
6238
|
+
return entry ? parseXml(await entry.async('text'), partPath) : parseXml(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="${work_xlsx_tables_PACKAGE_RELATIONSHIP_NAMESPACE}"/>`, partPath);
|
|
6239
|
+
}
|
|
6240
|
+
function appendRelationship(document1, type, target) {
|
|
6241
|
+
const id = work_xlsx_tables_nextRelationshipId(document1);
|
|
6242
|
+
const relationship = document1.createElementNS(document1.documentElement.namespaceURI ?? work_xlsx_tables_PACKAGE_RELATIONSHIP_NAMESPACE, 'Relationship');
|
|
6243
|
+
relationship.setAttribute('Id', id);
|
|
6244
|
+
relationship.setAttribute('Type', type);
|
|
6245
|
+
relationship.setAttribute('Target', target);
|
|
6246
|
+
document1.documentElement.append(relationship);
|
|
6247
|
+
return id;
|
|
6248
|
+
}
|
|
6249
|
+
function removeTableRelationships(document1) {
|
|
6250
|
+
for (const relationship of directChildren(document1.documentElement, 'Relationship'))if ((work_ooxml_package_attribute(relationship, 'Type') ?? '').endsWith('/table')) relationship.remove();
|
|
6251
|
+
}
|
|
6252
|
+
function work_xlsx_tables_nextRelationshipId(document1) {
|
|
6253
|
+
const used = new Set(directChildren(document1.documentElement, 'Relationship').map((item)=>work_ooxml_package_attribute(item, 'Id')));
|
|
6254
|
+
for(let index = 1; index < 1000000; index += 1){
|
|
6255
|
+
const id = `rId${index}`;
|
|
6256
|
+
if (!used.has(id)) return id;
|
|
6257
|
+
}
|
|
6258
|
+
return `rId${Date.now()}`;
|
|
6259
|
+
}
|
|
6260
|
+
async function work_xlsx_tables_updateContentTypes(zip, tableParts) {
|
|
6261
|
+
const entry = zip.file('[Content_Types].xml');
|
|
6262
|
+
if (!entry) return;
|
|
6263
|
+
const document1 = parseXml(await entry.async('text'), '[Content_Types].xml');
|
|
6264
|
+
for (const override of directChildren(document1.documentElement, 'Override'))if (work_ooxml_package_attribute(override, 'ContentType') === TABLE_CONTENT_TYPE) override.remove();
|
|
6265
|
+
const namespace = document1.documentElement.namespaceURI;
|
|
6266
|
+
for (const path of tableParts){
|
|
6267
|
+
const override = document1.createElementNS(namespace, 'Override');
|
|
6268
|
+
override.setAttribute('PartName', `/${path}`);
|
|
6269
|
+
override.setAttribute('ContentType', TABLE_CONTENT_TYPE);
|
|
6270
|
+
document1.documentElement.append(override);
|
|
6271
|
+
}
|
|
6272
|
+
zip.file('[Content_Types].xml', new XMLSerializer().serializeToString(document1));
|
|
6273
|
+
}
|
|
6274
|
+
function work_xlsx_tables_relationshipsPartPath(sourcePart) {
|
|
6275
|
+
const segments = sourcePart.split('/');
|
|
6276
|
+
const name = segments.pop() ?? '';
|
|
6277
|
+
return [
|
|
6278
|
+
...segments,
|
|
6279
|
+
'_rels',
|
|
6280
|
+
`${name}.rels`
|
|
6281
|
+
].join('/');
|
|
6282
|
+
}
|
|
6283
|
+
function documentRelationshipNamespace(document1) {
|
|
6284
|
+
return document1.documentElement.namespaceURI?.includes('purl.oclc.org') ? STRICT_DOCUMENT_RELATIONSHIP_NAMESPACE : TRANSITIONAL_DOCUMENT_RELATIONSHIP_NAMESPACE;
|
|
6285
|
+
}
|
|
6286
|
+
function allocateTableId(requested, used) {
|
|
6287
|
+
if (requested && Number.isSafeInteger(requested) && requested > 0 && !used.has(requested)) {
|
|
6288
|
+
used.add(requested);
|
|
6289
|
+
return requested;
|
|
6290
|
+
}
|
|
6291
|
+
let candidate = 1;
|
|
6292
|
+
while(used.has(candidate))candidate += 1;
|
|
6293
|
+
used.add(candidate);
|
|
6294
|
+
return candidate;
|
|
6295
|
+
}
|
|
6296
|
+
function positiveIntegerAttribute(element, name) {
|
|
6297
|
+
const value = Number(work_ooxml_package_attribute(element, name));
|
|
6298
|
+
return Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
6299
|
+
}
|
|
6300
|
+
function work_xlsx_tables_booleanAttribute(element, name) {
|
|
6301
|
+
return element ? [
|
|
6302
|
+
'1',
|
|
6303
|
+
'true',
|
|
6304
|
+
'on'
|
|
6305
|
+
].includes((work_ooxml_package_attribute(element, name) ?? '').toLocaleLowerCase()) : false;
|
|
6306
|
+
}
|
|
6307
|
+
function booleanToken(value) {
|
|
6308
|
+
return value ? '1' : '0';
|
|
6309
|
+
}
|
|
6310
|
+
function work_xlsx_tables_escapeXml(value) {
|
|
6311
|
+
return value.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
6312
|
+
}
|
|
5682
6313
|
async function readXlsxSheetFeaturesFromPackage(archive, worksheetScans) {
|
|
5683
6314
|
const workbook = archive.has('xl/workbook.xml') ? await archive.xml('xl/workbook.xml') : null;
|
|
5684
6315
|
const worksheetParts = await work_xlsx_interop_readWorksheetParts(archive, workbook);
|
|
@@ -5713,7 +6344,8 @@ async function readXlsxSheetFeaturesFromPackage(archive, worksheetScans) {
|
|
|
5713
6344
|
pageBreaks: readXlsxManualPageBreaks(document1),
|
|
5714
6345
|
pageSetup: readXlsxPageSetup(document1),
|
|
5715
6346
|
images: await readXlsxWorksheetImages(archive, partPath, document1, imageBudget),
|
|
5716
|
-
charts: await readXlsxWorksheetCharts(archive, partPath, document1)
|
|
6347
|
+
charts: await readXlsxWorksheetCharts(archive, partPath, document1),
|
|
6348
|
+
tables: await readXlsxWorksheetTables(archive, partPath)
|
|
5717
6349
|
});
|
|
5718
6350
|
}
|
|
5719
6351
|
return features;
|
|
@@ -5731,7 +6363,8 @@ function emptyXlsxSheetFeatures() {
|
|
|
5731
6363
|
columns: []
|
|
5732
6364
|
},
|
|
5733
6365
|
images: [],
|
|
5734
|
-
charts: []
|
|
6366
|
+
charts: [],
|
|
6367
|
+
tables: []
|
|
5735
6368
|
};
|
|
5736
6369
|
}
|
|
5737
6370
|
async function patchXlsxSheetFeatures(buffer, content) {
|
|
@@ -6360,7 +6993,7 @@ const PIVOT_CACHE_RECORDS_CONTENT_TYPE = 'application/vnd.openxmlformats-officed
|
|
|
6360
6993
|
async function patchXlsxPivotTables(buffer, content) {
|
|
6361
6994
|
if (!content.sheets.some((sheet)=>sheet.pivotTables?.length)) return buffer;
|
|
6362
6995
|
const archive = await work_ooxml_package_OoxmlPackage.load(buffer);
|
|
6363
|
-
const worksheetParts = await
|
|
6996
|
+
const worksheetParts = await work_xlsx_pivots_workbookWorksheetParts(archive);
|
|
6364
6997
|
const candidates = content.sheets.flatMap((ownerSheet)=>(ownerSheet.pivotTables ?? []).flatMap((pivot)=>{
|
|
6365
6998
|
if (!ownerSheet.id || !spreadsheetPivotValidation(content, ownerSheet.id, pivot).valid) return [];
|
|
6366
6999
|
const worksheetPart = worksheetParts.get(ownerSheet.name.slice(0, 31) || '工作表');
|
|
@@ -6394,17 +7027,17 @@ async function patchXlsxPivotTables(buffer, content) {
|
|
|
6394
7027
|
const pivotTablePath = `xl/pivotTables/pivotTable${partIndex}.xml`;
|
|
6395
7028
|
const pivotCacheDefinitionPath = `xl/pivotCache/pivotCacheDefinition${partIndex}.xml`;
|
|
6396
7029
|
const pivotCacheRecordsPath = `xl/pivotCache/pivotCacheRecords${partIndex}.xml`;
|
|
6397
|
-
const workbookRelationshipId =
|
|
7030
|
+
const workbookRelationshipId = work_xlsx_pivots_appendRelationship(workbookRelationships, PIVOT_CACHE_DEFINITION_RELATIONSHIP, `pivotCache/pivotCacheDefinition${partIndex}.xml`);
|
|
6398
7031
|
const pivotCache = workbook.createElementNS(workbook.documentElement.namespaceURI, 'pivotCache');
|
|
6399
7032
|
pivotCache.setAttribute('cacheId', String(cacheId));
|
|
6400
7033
|
pivotCache.setAttributeNS(DOCUMENT_RELATIONSHIP_NAMESPACE, 'r:id', workbookRelationshipId);
|
|
6401
7034
|
pivotCaches.append(pivotCache);
|
|
6402
|
-
const worksheetRelationshipDocument = worksheetRelationships.get(candidate.worksheetPart) ?? await
|
|
7035
|
+
const worksheetRelationshipDocument = worksheetRelationships.get(candidate.worksheetPart) ?? await work_xlsx_pivots_readRelationshipsDocument(zip, work_xlsx_pivots_relationshipsPartPath(candidate.worksheetPart));
|
|
6403
7036
|
if (!worksheetRelationships.has(candidate.worksheetPart)) {
|
|
6404
7037
|
removeRelationships(worksheetRelationshipDocument, '/pivotTable');
|
|
6405
7038
|
worksheetRelationships.set(candidate.worksheetPart, worksheetRelationshipDocument);
|
|
6406
7039
|
}
|
|
6407
|
-
|
|
7040
|
+
work_xlsx_pivots_appendRelationship(worksheetRelationshipDocument, PIVOT_TABLE_RELATIONSHIP, `../pivotTables/pivotTable${partIndex}.xml`);
|
|
6408
7041
|
zip.file(pivotTablePath, parts.table);
|
|
6409
7042
|
zip.file(pivotCacheDefinitionPath, parts.cacheDefinition);
|
|
6410
7043
|
zip.file(pivotCacheRecordsPath, parts.cacheRecords);
|
|
@@ -6455,11 +7088,11 @@ async function inspectXlsxPivotTables(archive) {
|
|
|
6455
7088
|
const workbookRelationships = await archive.relationships('xl/workbook.xml');
|
|
6456
7089
|
const cacheById = new Map();
|
|
6457
7090
|
for (const cache of directChildren(firstDescendant(workbook, 'pivotCaches') ?? workbook.documentElement, 'pivotCache')){
|
|
6458
|
-
const cacheId =
|
|
7091
|
+
const cacheId = work_xlsx_pivots_integerAttribute(cache, 'cacheId');
|
|
6459
7092
|
const relationship = workbookRelationships.get(work_ooxml_package_attribute(cache, 'r:id') ?? work_ooxml_package_attribute(cache, 'id') ?? '');
|
|
6460
7093
|
if (null !== cacheId && relationship && archive.has(relationship.target)) cacheById.set(cacheId, parsePivotCache(await archive.xml(relationship.target)));
|
|
6461
7094
|
}
|
|
6462
|
-
const worksheetParts = await
|
|
7095
|
+
const worksheetParts = await work_xlsx_pivots_workbookWorksheetParts(archive);
|
|
6463
7096
|
const tables = [];
|
|
6464
7097
|
const unsupported = [];
|
|
6465
7098
|
let detected = 0;
|
|
@@ -6545,7 +7178,7 @@ function applyImportedXlsxPivotTables(content, imported) {
|
|
|
6545
7178
|
sheets
|
|
6546
7179
|
};
|
|
6547
7180
|
}
|
|
6548
|
-
async function
|
|
7181
|
+
async function work_xlsx_pivots_workbookWorksheetParts(archive) {
|
|
6549
7182
|
if (!archive.has('xl/workbook.xml')) return new Map();
|
|
6550
7183
|
const workbook = await archive.xml('xl/workbook.xml');
|
|
6551
7184
|
const relationships = await archive.relationships('xl/workbook.xml');
|
|
@@ -6618,7 +7251,7 @@ function parsePivotReportFilters(root, cache, location) {
|
|
|
6618
7251
|
if (!pageFields) return {
|
|
6619
7252
|
reportFilters: []
|
|
6620
7253
|
};
|
|
6621
|
-
const pageWrap =
|
|
7254
|
+
const pageWrap = work_xlsx_pivots_integerAttribute(root, 'pageWrap') ?? 0;
|
|
6622
7255
|
if (pageWrap > 0 || work_xlsx_pivots_booleanAttribute(root, 'pageOverThenDown')) return {
|
|
6623
7256
|
unsupported: {
|
|
6624
7257
|
code: 'xlsx.pivots.report-filter-layout',
|
|
@@ -6629,7 +7262,7 @@ function parsePivotReportFilters(root, cache, location) {
|
|
|
6629
7262
|
const pivotFields = directChildren(directChild(root, 'pivotFields') ?? root, 'pivotField');
|
|
6630
7263
|
const reportFilters = [];
|
|
6631
7264
|
for (const pageField of directChildren(pageFields, 'pageField')){
|
|
6632
|
-
const fieldIndex =
|
|
7265
|
+
const fieldIndex = work_xlsx_pivots_integerAttribute(pageField, 'fld');
|
|
6633
7266
|
const pivotField = null === fieldIndex ? void 0 : pivotFields[fieldIndex];
|
|
6634
7267
|
if (null === fieldIndex || !pivotField || !cache.fields[fieldIndex]) return {
|
|
6635
7268
|
unsupported: {
|
|
@@ -6646,7 +7279,7 @@ function parsePivotReportFilters(root, cache, location) {
|
|
|
6646
7279
|
location
|
|
6647
7280
|
}
|
|
6648
7281
|
};
|
|
6649
|
-
const itemIndex =
|
|
7282
|
+
const itemIndex = work_xlsx_pivots_integerAttribute(pageField, 'item');
|
|
6650
7283
|
if (null === itemIndex) {
|
|
6651
7284
|
reportFilters.push({
|
|
6652
7285
|
fieldIndex
|
|
@@ -6667,7 +7300,7 @@ function parsePivotReportFilters(root, cache, location) {
|
|
|
6667
7300
|
});
|
|
6668
7301
|
continue;
|
|
6669
7302
|
}
|
|
6670
|
-
const sharedItemIndex =
|
|
7303
|
+
const sharedItemIndex = work_xlsx_pivots_integerAttribute(pivotItem, 'x');
|
|
6671
7304
|
const sharedItems = cache.fieldItems[fieldIndex] ?? [];
|
|
6672
7305
|
if (null === sharedItemIndex || sharedItemIndex < 0 || sharedItemIndex >= sharedItems.length) return {
|
|
6673
7306
|
unsupported: {
|
|
@@ -6689,7 +7322,7 @@ function parsePivotTable(document1, destinationSheetName, cacheById) {
|
|
|
6689
7322
|
const root = document1.documentElement;
|
|
6690
7323
|
const name = work_ooxml_package_attribute(root, 'name')?.trim() || 'PivotTable';
|
|
6691
7324
|
const locationLabel = destinationSheetName ? `${destinationSheetName} · ${name}` : name;
|
|
6692
|
-
const cacheId =
|
|
7325
|
+
const cacheId = work_xlsx_pivots_integerAttribute(root, 'cacheId');
|
|
6693
7326
|
const cache = null === cacheId ? void 0 : cacheById.get(cacheId);
|
|
6694
7327
|
if (!cache || cache.unsupported || !cache.sourceSheetName || !cache.sourceReference) return {
|
|
6695
7328
|
unsupported: {
|
|
@@ -6721,7 +7354,7 @@ function parsePivotTable(document1, destinationSheetName, cacheById) {
|
|
|
6721
7354
|
};
|
|
6722
7355
|
const values = [];
|
|
6723
7356
|
for (const dataField of directChildren(directChild(root, 'dataFields') ?? root, 'dataField')){
|
|
6724
|
-
const fieldIndex =
|
|
7357
|
+
const fieldIndex = work_xlsx_pivots_integerAttribute(dataField, 'fld');
|
|
6725
7358
|
const aggregation = workPivotAggregation(work_ooxml_package_attribute(dataField, 'subtotal'));
|
|
6726
7359
|
if (null === fieldIndex || !aggregation || !cache.fields[fieldIndex]) return {
|
|
6727
7360
|
unsupported: {
|
|
@@ -6809,17 +7442,17 @@ function parsePivotTable(document1, destinationSheetName, cacheById) {
|
|
|
6809
7442
|
function readPivotFieldIndexes(parent) {
|
|
6810
7443
|
if (!parent) return [];
|
|
6811
7444
|
return directChildren(parent, 'field').flatMap((field)=>{
|
|
6812
|
-
const index =
|
|
7445
|
+
const index = work_xlsx_pivots_integerAttribute(field, 'x');
|
|
6813
7446
|
return null === index ? [] : [
|
|
6814
7447
|
index
|
|
6815
7448
|
];
|
|
6816
7449
|
});
|
|
6817
7450
|
}
|
|
6818
|
-
async function
|
|
7451
|
+
async function work_xlsx_pivots_readRelationshipsDocument(zip, path) {
|
|
6819
7452
|
const entry = zip.file(path);
|
|
6820
7453
|
return entry ? parseXml(await entry.async('text'), path) : parseXml(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="${work_xlsx_pivots_PACKAGE_RELATIONSHIP_NAMESPACE}"/>`, path);
|
|
6821
7454
|
}
|
|
6822
|
-
function
|
|
7455
|
+
function work_xlsx_pivots_appendRelationship(document1, type, target) {
|
|
6823
7456
|
const id = work_xlsx_pivots_nextRelationshipId(document1);
|
|
6824
7457
|
const relationship = document1.createElementNS(work_xlsx_pivots_PACKAGE_RELATIONSHIP_NAMESPACE, 'Relationship');
|
|
6825
7458
|
relationship.setAttribute('Id', id);
|
|
@@ -6887,7 +7520,7 @@ function work_xlsx_pivots_relationshipsPartPath(sourcePart) {
|
|
|
6887
7520
|
`${name}.rels`
|
|
6888
7521
|
].join('/');
|
|
6889
7522
|
}
|
|
6890
|
-
function
|
|
7523
|
+
function work_xlsx_pivots_integerAttribute(element, name) {
|
|
6891
7524
|
const source = work_ooxml_package_attribute(element, name);
|
|
6892
7525
|
if (null === source || !source.trim()) return null;
|
|
6893
7526
|
const value = Number(source);
|
|
@@ -6922,7 +7555,8 @@ async function createWorkSpreadsheetBlob(artifact) {
|
|
|
6922
7555
|
compression: true
|
|
6923
7556
|
});
|
|
6924
7557
|
const withFeatures = await patchXlsxSheetFeatures(bytes, content);
|
|
6925
|
-
const
|
|
7558
|
+
const withTables = await patchXlsxSpreadsheetTables(withFeatures, content);
|
|
7559
|
+
const withDrawings = await patchXlsxWorksheetDrawings(withTables, content);
|
|
6926
7560
|
const withFormulas = await patchXlsxFormulaFeatures(withDrawings, content);
|
|
6927
7561
|
const output = await patchXlsxPivotTables(withFormulas, content);
|
|
6928
7562
|
return new Blob([
|
|
@@ -7753,6 +8387,7 @@ async function importWorkSpreadsheetFile(file, extension, context) {
|
|
|
7753
8387
|
luckysheet_conditionformat_save: features?.conditionalFormats.length ? features.conditionalFormats : void 0,
|
|
7754
8388
|
images: features?.images.length ? xlsxWorksheetImagesToSheet(features.images, config) : void 0,
|
|
7755
8389
|
charts: features?.charts.length ? xlsxWorksheetChartsToSheet(features.charts, config) : void 0,
|
|
8390
|
+
tables: features?.tables.length ? features.tables : void 0,
|
|
7756
8391
|
formulaMetadata
|
|
7757
8392
|
});
|
|
7758
8393
|
await context.controller.checkpoint('parsing', sheetProgressStart + sheetProgressSize);
|