@rowsncolumns/toolkit 24.4.2 → 24.4.4
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/cjs/excel-parser/cfb-decryptor.d.ts +6 -0
- package/dist/cjs/excel-parser/cfb-decryptor.d.ts.map +1 -1
- package/dist/cjs/excel-parser/cfb-decryptor.js +6 -0
- package/dist/cjs/excel-parser/helpers.d.ts +9 -1
- package/dist/cjs/excel-parser/helpers.d.ts.map +1 -1
- package/dist/cjs/excel-parser/helpers.js +37 -0
- package/dist/cjs/excel-parser/interface.d.ts +15 -2
- package/dist/cjs/excel-parser/interface.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/base/index.d.ts +2 -0
- package/dist/cjs/excel-parser/plugins/base/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/base/index.js +3 -0
- package/dist/cjs/excel-parser/plugins/ods/index.d.ts +19 -0
- package/dist/cjs/excel-parser/plugins/ods/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/ods/index.js +676 -304
- package/dist/cjs/excel-parser/plugins/ods/styles.d.ts +43 -1
- package/dist/cjs/excel-parser/plugins/ods/styles.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/ods/styles.js +343 -45
- package/dist/cjs/excel-parser/plugins/xls/index.d.ts +55 -1
- package/dist/cjs/excel-parser/plugins/xls/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xls/index.js +518 -6
- package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts +4 -0
- package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsb/index.js +33 -14
- package/dist/cjs/excel-parser/plugins/xlsx/chartex.d.ts +37 -0
- package/dist/cjs/excel-parser/plugins/xlsx/chartex.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/chartex.js +244 -0
- package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts +10 -0
- package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/charts.js +68 -9
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts +28 -1
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.js +155 -20
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.d.ts +70 -0
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.js +295 -0
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts +35 -2
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/index.js +737 -257
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.js +125 -37
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.d.ts +3 -0
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.js +4 -1
- package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts +15 -1
- package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/styles.js +102 -6
- package/dist/cjs/excel-parser/registry.d.ts +7 -0
- package/dist/cjs/excel-parser/registry.d.ts.map +1 -1
- package/dist/cjs/excel-parser/registry.js +29 -0
- package/dist/cjs/excel-parser/types.d.ts +17 -2
- package/dist/cjs/excel-parser/types.d.ts.map +1 -1
- package/dist/cjs/excel-parser/workbook.d.ts +3 -0
- package/dist/cjs/excel-parser/workbook.d.ts.map +1 -1
- package/dist/cjs/excel-parser/workbook.js +24 -14
- package/dist/cjs/excel-parser/worker.js +131 -131
- package/dist/cjs/exporter/ods/ods-export.d.ts.map +1 -1
- package/dist/cjs/exporter/ods/ods-export.js +432 -175
- package/dist/cjs/exporter/xlsx/chart-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/chart-builder.js +215 -39
- package/dist/cjs/exporter/xlsx/chartex-builder.d.ts +36 -0
- package/dist/cjs/exporter/xlsx/chartex-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/chartex-builder.js +109 -0
- package/dist/cjs/exporter/xlsx/form-controls-builder.d.ts +61 -0
- package/dist/cjs/exporter/xlsx/form-controls-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/form-controls-builder.js +197 -0
- package/dist/cjs/exporter/xlsx/pivot-builder.d.ts +8 -0
- package/dist/cjs/exporter/xlsx/pivot-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/pivot-builder.js +141 -42
- package/dist/cjs/exporter/xlsx/style-builder.js +9 -3
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.d.ts +7 -1
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.js +15 -3
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts +11 -2
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/xlsx-export.js +991 -297
- package/dist/cjs/helpers/implicit-intersection.d.ts +16 -0
- package/dist/cjs/helpers/implicit-intersection.d.ts.map +1 -0
- package/dist/cjs/helpers/implicit-intersection.js +197 -0
- package/dist/cjs/print-settings.d.ts +105 -0
- package/dist/cjs/print-settings.d.ts.map +1 -0
- package/dist/cjs/print-settings.js +494 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/excel-parser/cfb-decryptor.d.ts +6 -0
- package/dist/esm/excel-parser/cfb-decryptor.d.ts.map +1 -1
- package/dist/esm/excel-parser/cfb-decryptor.js +6 -0
- package/dist/esm/excel-parser/helpers.d.ts +9 -1
- package/dist/esm/excel-parser/helpers.d.ts.map +1 -1
- package/dist/esm/excel-parser/helpers.js +34 -0
- package/dist/esm/excel-parser/interface.d.ts +15 -2
- package/dist/esm/excel-parser/interface.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/base/index.d.ts +2 -0
- package/dist/esm/excel-parser/plugins/base/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/base/index.js +3 -0
- package/dist/esm/excel-parser/plugins/ods/index.d.ts +19 -0
- package/dist/esm/excel-parser/plugins/ods/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/ods/index.js +347 -33
- package/dist/esm/excel-parser/plugins/ods/styles.d.ts +43 -1
- package/dist/esm/excel-parser/plugins/ods/styles.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/ods/styles.js +276 -2
- package/dist/esm/excel-parser/plugins/xls/index.d.ts +55 -1
- package/dist/esm/excel-parser/plugins/xls/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xls/index.js +441 -3
- package/dist/esm/excel-parser/plugins/xlsb/index.d.ts +4 -0
- package/dist/esm/excel-parser/plugins/xlsb/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsb/index.js +30 -9
- package/dist/esm/excel-parser/plugins/xlsx/chartex.d.ts +37 -0
- package/dist/esm/excel-parser/plugins/xlsx/chartex.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/chartex.js +199 -0
- package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts +10 -0
- package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/charts.js +69 -6
- package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts +28 -1
- package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/drawing.js +99 -0
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.d.ts +70 -0
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.js +246 -0
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts +35 -2
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/index.js +454 -32
- package/dist/esm/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/pivots.js +86 -6
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.d.ts +3 -0
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.js +2 -0
- package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts +15 -1
- package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/styles.js +92 -2
- package/dist/esm/excel-parser/registry.d.ts +7 -0
- package/dist/esm/excel-parser/registry.d.ts.map +1 -1
- package/dist/esm/excel-parser/registry.js +19 -0
- package/dist/esm/excel-parser/types.d.ts +17 -2
- package/dist/esm/excel-parser/types.d.ts.map +1 -1
- package/dist/esm/excel-parser/workbook.d.ts +3 -0
- package/dist/esm/excel-parser/workbook.d.ts.map +1 -1
- package/dist/esm/excel-parser/workbook.js +19 -10
- package/dist/esm/excel-parser/worker.js +12 -18
- package/dist/esm/exporter/ods/ods-export.d.ts.map +1 -1
- package/dist/esm/exporter/ods/ods-export.js +306 -35
- package/dist/esm/exporter/xlsx/chart-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/chart-builder.js +161 -28
- package/dist/esm/exporter/xlsx/chartex-builder.d.ts +36 -0
- package/dist/esm/exporter/xlsx/chartex-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/chartex-builder.js +97 -0
- package/dist/esm/exporter/xlsx/form-controls-builder.d.ts +61 -0
- package/dist/esm/exporter/xlsx/form-controls-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/form-controls-builder.js +173 -0
- package/dist/esm/exporter/xlsx/pivot-builder.d.ts +8 -0
- package/dist/esm/exporter/xlsx/pivot-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/pivot-builder.js +104 -19
- package/dist/esm/exporter/xlsx/style-builder.js +9 -3
- package/dist/esm/exporter/xlsx/threaded-comments-builder.d.ts +7 -1
- package/dist/esm/exporter/xlsx/threaded-comments-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/threaded-comments-builder.js +15 -3
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts +11 -2
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/xlsx-export.js +675 -64
- package/dist/esm/helpers/implicit-intersection.d.ts +16 -0
- package/dist/esm/helpers/implicit-intersection.d.ts.map +1 -0
- package/dist/esm/helpers/implicit-intersection.js +184 -0
- package/dist/esm/print-settings.d.ts +105 -0
- package/dist/esm/print-settings.d.ts.map +1 -0
- package/dist/esm/print-settings.js +422 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/xlsx.d.ts +14 -0
|
@@ -2,9 +2,10 @@ import { addressToCell, addressToSelection, alpha2number, checkIfStringIsReferen
|
|
|
2
2
|
import { XMLParser } from "fast-xml-parser";
|
|
3
3
|
import { get } from "lodash-es";
|
|
4
4
|
import { Parser as HtmlParser } from "htmlparser2";
|
|
5
|
-
import { createFilterSpecsFromAutoFilter, excelColumnWidthToPixels, findMax, getRangeFromAddressRef, } from "../../helpers";
|
|
5
|
+
import { createFilterSpecsFromAutoFilter, excelColumnWidthToPixels, findMax, getRangeFromAddressRef, parseTableColumnTotals, } from "../../helpers";
|
|
6
6
|
import { defaultSpreadsheetTheme } from "../../theme-default";
|
|
7
7
|
import { Unescape } from "../../utils";
|
|
8
|
+
import { compactPrintSettings, isBuiltinPrintName, isDefaultPageMargins, parsePrintAreaFormula, parsePrintTitlesFormula, PRINT_AREA_NAME, } from "../../../print-settings";
|
|
8
9
|
import { StreamingZipParser } from "../../zip-parser-streaming";
|
|
9
10
|
import { SheetDataValidationStamper } from "../../dv-cell-stamp";
|
|
10
11
|
import { BaseWorkbookPlugin } from "../base/index";
|
|
@@ -12,12 +13,14 @@ import { processChart } from "./charts";
|
|
|
12
13
|
import { customFiltersToCondition, dynamicFilterToCondition, } from "../../../autofilter-condition";
|
|
13
14
|
import { getConditionalFormattingFromSheet } from "./conditional-formatting";
|
|
14
15
|
import { getDataValidationsForSheet as parseDataValidationsFromSheetData } from "./data-validations";
|
|
15
|
-
import { processAnchors } from "./drawing";
|
|
16
|
+
import { anchorsInDocumentOrder, processAnchors, } from "./drawing";
|
|
16
17
|
import { getRelationsById } from "./relationships";
|
|
17
18
|
import { hasPowerQueryParts, } from "../../../power-query";
|
|
18
19
|
import { extractSheetViewProperties } from "./sheet-views";
|
|
19
20
|
import { EMPTY_SHEET_THREADED_COMMENTS, parsePersons, parseThreadedComments, } from "./threaded-comments";
|
|
20
|
-
import {
|
|
21
|
+
import { getChartExReferenceFromAnchor, processChartEx } from "./chartex";
|
|
22
|
+
import { buildFormControlEmbeds, parseFormControlPr, parseVmlControlCaptions, readLegacyDrawingRelId, readWorksheetControls, } from "./form-controls";
|
|
23
|
+
import { extractColor, fontNodeToTextFormat, getCellDataForStyleIndex, getCellValueAndFormat, resolveNamedCellStyles, } from "./styles";
|
|
21
24
|
import { extractThemeColors, extractThemeFonts, generateDarkThemeColors, } from "./theme";
|
|
22
25
|
export const XMLTagProcessor = (name, value) => Unescape(value);
|
|
23
26
|
function getWithFallback(source, paths) {
|
|
@@ -739,6 +742,18 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
739
742
|
* `getDataValidations()` aggregates these per-sheet caches, keeping ids
|
|
740
743
|
* stable across per-sheet and workbook-wide callers.
|
|
741
744
|
*/
|
|
745
|
+
/**
|
|
746
|
+
* `<protectedRanges>` per sheet, populated while `getSheets` builds each
|
|
747
|
+
* `Sheet` (the element sits after `<sheetData>` in the worksheet part, so it
|
|
748
|
+
* rides the same geometry pass). Read back via `getProtectedRanges`.
|
|
749
|
+
*/
|
|
750
|
+
protectedRangesBySheet = new Map();
|
|
751
|
+
/**
|
|
752
|
+
* The builtin `_xlnm.Print_Area` / `_xlnm.Print_Titles` defined names,
|
|
753
|
+
* hoisted out of `namedRanges` (they are sheet-scoped facets, not user
|
|
754
|
+
* names) and merged into each sheet's `printSettings` by `getSheets()`.
|
|
755
|
+
*/
|
|
756
|
+
printNamesBySheetId = new Map();
|
|
742
757
|
dataValidationsBySheetCache = new Map();
|
|
743
758
|
/** Per-sheet memo for conditional formatting, mirroring the DV cache. */
|
|
744
759
|
conditionalFormattingBySheetCache = new Map();
|
|
@@ -784,6 +799,26 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
784
799
|
let paneAttrs;
|
|
785
800
|
let tabColor;
|
|
786
801
|
let autoFilterRef;
|
|
802
|
+
// `<sheetProtection>` + `<protectedRanges>/<protectedRange>` — the sheet's
|
|
803
|
+
// protection facets, read here because both sit after `<sheetData>`.
|
|
804
|
+
let sheetProtection;
|
|
805
|
+
const protectedRangeEntries = [];
|
|
806
|
+
// Print facets (`CT_Worksheet` tail: printOptions / pageMargins /
|
|
807
|
+
// pageSetup / headerFooter / rowBreaks / colBreaks) plus the
|
|
808
|
+
// `<sheetPr><pageSetUpPr fitToPage>` flag. `_xlnm.Print_Area` /
|
|
809
|
+
// `_xlnm.Print_Titles` come from the workbook's defined names and are
|
|
810
|
+
// merged in by `getSheets()`.
|
|
811
|
+
let pageSetup;
|
|
812
|
+
let pageMargins;
|
|
813
|
+
let printOptions;
|
|
814
|
+
let fitToPage = false;
|
|
815
|
+
let headerFooter;
|
|
816
|
+
// The `<oddHeader>`-style element whose text is streaming in.
|
|
817
|
+
let headerFooterTextTarget;
|
|
818
|
+
const rowBreaks = [];
|
|
819
|
+
const columnBreaks = [];
|
|
820
|
+
// Inside `<rowBreaks>` ("row") / `<colBreaks>` ("column"); routes `<brk>`.
|
|
821
|
+
let breakAxis;
|
|
787
822
|
const filterColumns = new Map();
|
|
788
823
|
const getOrCreateFilterColumn = (colId) => {
|
|
789
824
|
let entry = filterColumns.get(colId);
|
|
@@ -800,10 +835,21 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
800
835
|
// r-less sheets still report real extents instead of 0.
|
|
801
836
|
let lastScannedRowIndex = 0;
|
|
802
837
|
let scanSeqColIndex = 1;
|
|
838
|
+
// `<customSheetViews>` (Excel's View → Custom Views) carry their own
|
|
839
|
+
// pane / selection / autoFilter / print setup / breaks. They describe a
|
|
840
|
+
// saved view, not the sheet, so the whole subtree is skipped — a custom
|
|
841
|
+
// view's `<oddHeader>` or `<brk>` must not become the sheet's.
|
|
842
|
+
let inCustomSheetViews = false;
|
|
803
843
|
const normalizeTag = (name) => name.includes(":") ? name.split(":")[1] : name;
|
|
804
844
|
const parser = new HtmlParser({
|
|
805
845
|
onopentag(tagName, attrs) {
|
|
806
846
|
const name = normalizeTag(tagName);
|
|
847
|
+
if (name === "customSheetViews") {
|
|
848
|
+
inCustomSheetViews = true;
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
if (inCustomSheetViews)
|
|
852
|
+
return;
|
|
807
853
|
if (name === "dimension") {
|
|
808
854
|
const ref = attrs?.ref;
|
|
809
855
|
if (typeof ref === "string") {
|
|
@@ -849,6 +895,50 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
849
895
|
if (name === "tabColor") {
|
|
850
896
|
tabColor = { a$: { ...attrs } };
|
|
851
897
|
}
|
|
898
|
+
if (name === "sheetProtection") {
|
|
899
|
+
sheetProtection = readSheetProtectionAttrs(attrs);
|
|
900
|
+
}
|
|
901
|
+
if (name === "protectedRange") {
|
|
902
|
+
const sqref = attrs.sqref;
|
|
903
|
+
if (typeof sqref === "string" && sqref) {
|
|
904
|
+
protectedRangeEntries.push({
|
|
905
|
+
sqref,
|
|
906
|
+
name: attrs.name,
|
|
907
|
+
securityDescriptor: attrs.securityDescriptor,
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
if (name === "pageSetUpPr") {
|
|
912
|
+
fitToPage = isXmlTrue(attrs?.fitToPage);
|
|
913
|
+
}
|
|
914
|
+
if (name === "pageSetup") {
|
|
915
|
+
pageSetup = readPageSetupAttrs(attrs);
|
|
916
|
+
}
|
|
917
|
+
if (name === "pageMargins") {
|
|
918
|
+
pageMargins = readPageMarginsAttrs(attrs);
|
|
919
|
+
}
|
|
920
|
+
if (name === "printOptions") {
|
|
921
|
+
printOptions = readPrintOptionsAttrs(attrs);
|
|
922
|
+
}
|
|
923
|
+
if (name === "headerFooter") {
|
|
924
|
+
headerFooter = readHeaderFooterAttrs(attrs);
|
|
925
|
+
}
|
|
926
|
+
if (isHeaderFooterTextKey(name)) {
|
|
927
|
+
headerFooterTextTarget = name;
|
|
928
|
+
headerFooter ??= {};
|
|
929
|
+
}
|
|
930
|
+
if (name === "rowBreaks")
|
|
931
|
+
breakAxis = "row";
|
|
932
|
+
if (name === "colBreaks")
|
|
933
|
+
breakAxis = "column";
|
|
934
|
+
if (name === "brk" && breakAxis) {
|
|
935
|
+
// Only manual breaks are user state; Excel drops automatic ones
|
|
936
|
+
// (`man` absent) on save as well.
|
|
937
|
+
const id = parseInt(attrs?.id ?? "", 10);
|
|
938
|
+
if (Number.isFinite(id) && id > 0 && isXmlTrue(attrs?.man)) {
|
|
939
|
+
(breakAxis === "row" ? rowBreaks : columnBreaks).push(id);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
852
942
|
if (name === "sheetView" && !sheetViewAttrs) {
|
|
853
943
|
sheetViewAttrs = { ...attrs };
|
|
854
944
|
}
|
|
@@ -1037,11 +1127,29 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
1037
1127
|
}
|
|
1038
1128
|
}
|
|
1039
1129
|
},
|
|
1130
|
+
ontext(text) {
|
|
1131
|
+
if (headerFooterTextTarget && headerFooter) {
|
|
1132
|
+
headerFooter[headerFooterTextTarget] =
|
|
1133
|
+
`${headerFooter[headerFooterTextTarget] ?? ""}${text}`;
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1040
1136
|
onclosetag(tagName) {
|
|
1041
1137
|
const name = normalizeTag(tagName);
|
|
1138
|
+
if (name === "customSheetViews") {
|
|
1139
|
+
inCustomSheetViews = false;
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
if (inCustomSheetViews)
|
|
1143
|
+
return;
|
|
1042
1144
|
if (name === "filterColumn") {
|
|
1043
1145
|
currentFilterColumn = null;
|
|
1044
1146
|
}
|
|
1147
|
+
if (isHeaderFooterTextKey(name)) {
|
|
1148
|
+
headerFooterTextTarget = undefined;
|
|
1149
|
+
}
|
|
1150
|
+
if (name === "rowBreaks" || name === "colBreaks") {
|
|
1151
|
+
breakAxis = undefined;
|
|
1152
|
+
}
|
|
1045
1153
|
},
|
|
1046
1154
|
onerror(err) {
|
|
1047
1155
|
console.error("Streaming sheet metadata parse error", err);
|
|
@@ -1114,6 +1222,18 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
1114
1222
|
tablePartIds,
|
|
1115
1223
|
outlineSummaryBelow,
|
|
1116
1224
|
outlineSummaryRight,
|
|
1225
|
+
sheetProtection,
|
|
1226
|
+
protectedRangeEntries,
|
|
1227
|
+
printSettings: compactPrintSettings({
|
|
1228
|
+
pageSetup: fitToPage ? { ...pageSetup, fitToPage: true } : pageSetup,
|
|
1229
|
+
// Every Excel worksheet carries `<pageMargins>`; only non-default
|
|
1230
|
+
// margins are user state worth modelling.
|
|
1231
|
+
pageMargins: isDefaultPageMargins(pageMargins) ? undefined : pageMargins,
|
|
1232
|
+
printOptions,
|
|
1233
|
+
headerFooter,
|
|
1234
|
+
rowBreaks,
|
|
1235
|
+
columnBreaks,
|
|
1236
|
+
}),
|
|
1117
1237
|
};
|
|
1118
1238
|
}
|
|
1119
1239
|
/**
|
|
@@ -1292,6 +1412,7 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
1292
1412
|
conditionalFormatting: false,
|
|
1293
1413
|
dataValidations: false,
|
|
1294
1414
|
drawing: false,
|
|
1415
|
+
controls: false,
|
|
1295
1416
|
};
|
|
1296
1417
|
const sheetPath = this.resolveSheetPath(relation.target);
|
|
1297
1418
|
const sheetRelPath = sheetPath.replace("worksheets", "worksheets/_rels") + ".rels";
|
|
@@ -1345,6 +1466,9 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
1345
1466
|
case "drawing":
|
|
1346
1467
|
features.drawing = true;
|
|
1347
1468
|
break;
|
|
1469
|
+
case "controls":
|
|
1470
|
+
features.controls = true;
|
|
1471
|
+
break;
|
|
1348
1472
|
}
|
|
1349
1473
|
if (name !== "hyperlink") {
|
|
1350
1474
|
return;
|
|
@@ -1816,6 +1940,7 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
1816
1940
|
this.sheetMetadataCache.clear();
|
|
1817
1941
|
this.dataValidationsBySheetCache.clear();
|
|
1818
1942
|
this.conditionalFormattingBySheetCache.clear();
|
|
1943
|
+
this.protectedRangesBySheet.clear();
|
|
1819
1944
|
await this.loadWorkbookXml();
|
|
1820
1945
|
this.relations = await this.getRelations();
|
|
1821
1946
|
this.workbookStyles = await WorkbookStyles.load(this.zipParser, this.xmlParser);
|
|
@@ -1835,6 +1960,7 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
1835
1960
|
this.sheetMetadataCache.clear();
|
|
1836
1961
|
this.dataValidationsBySheetCache.clear();
|
|
1837
1962
|
this.conditionalFormattingBySheetCache.clear();
|
|
1963
|
+
this.protectedRangesBySheet.clear();
|
|
1838
1964
|
this.worksheetBySheetId.clear();
|
|
1839
1965
|
}
|
|
1840
1966
|
clearSharedFormula() {
|
|
@@ -1924,7 +2050,10 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
1924
2050
|
: [];
|
|
1925
2051
|
const columns = columnDefsArray.map((colDef) => {
|
|
1926
2052
|
const name = colDef.a$.name || "";
|
|
1927
|
-
const columnObj = {
|
|
2053
|
+
const columnObj = {
|
|
2054
|
+
name,
|
|
2055
|
+
...parseTableColumnTotals(colDef),
|
|
2056
|
+
};
|
|
1928
2057
|
// Check for calculated column
|
|
1929
2058
|
// Handle both with and without namespace prefix
|
|
1930
2059
|
const calculatedColumnFormula = get(colDef, "calculatedColumnFormula") ||
|
|
@@ -2798,6 +2927,19 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
2798
2927
|
for (const anchor of anchors) {
|
|
2799
2928
|
const chartRef = getChartReferenceFromAnchor(anchor);
|
|
2800
2929
|
if (!chartRef) {
|
|
2930
|
+
// Excel 2016+ chartex (treemap / sunburst / histogram …) anchors
|
|
2931
|
+
// carry `<cx:chart r:id>` inside an mc:AlternateContent choice.
|
|
2932
|
+
const chartExRef = getChartExReferenceFromAnchor(anchor);
|
|
2933
|
+
const chartExRId = get(chartExRef, "a$.r:id") || get(chartExRef, "a$.id");
|
|
2934
|
+
const chartExRel = chartExRId
|
|
2935
|
+
? drawingRelsArray.find((rel) => get(rel, "a$.Id") === chartExRId ||
|
|
2936
|
+
get(rel, "a$.id") === chartExRId)
|
|
2937
|
+
: undefined;
|
|
2938
|
+
if (chartExRel) {
|
|
2939
|
+
const chartEx = await processChartEx(chartExRel.a$.Target, drawingPath, anchor, sheetId, this.zipParser, this.xmlParser, sheetDimensions, resolveSheetId);
|
|
2940
|
+
if (chartEx)
|
|
2941
|
+
charts.push(chartEx);
|
|
2942
|
+
}
|
|
2801
2943
|
continue;
|
|
2802
2944
|
}
|
|
2803
2945
|
const chartRId = get(chartRef, "a$.r:id") ||
|
|
@@ -2878,28 +3020,17 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
2878
3020
|
? drawingPath.substring(1)
|
|
2879
3021
|
: `xl/${drawingPath}`;
|
|
2880
3022
|
}
|
|
2881
|
-
const drawingContent = await this.zipParser.getText(drawingPath);
|
|
3023
|
+
const drawingContent = (await this.zipParser.getText(drawingPath)) ?? "";
|
|
2882
3024
|
// Parse drawing XML
|
|
2883
|
-
const drawing = this.xmlParser.parse(drawingContent
|
|
2884
|
-
//
|
|
2885
|
-
//
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
const
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
// One cell
|
|
2893
|
-
for (const image of await processAnchors(oneCellAnchors, "oneCellAnchor", drawingPath, sheetId, this.zipParser, this.xmlParser)) {
|
|
2894
|
-
images.push(image);
|
|
2895
|
-
}
|
|
2896
|
-
// Two cell
|
|
2897
|
-
for (const image of await processAnchors(twoCellAnchors, "twoCellAnchors", drawingPath, sheetId, this.zipParser, this.xmlParser)) {
|
|
2898
|
-
images.push(image);
|
|
2899
|
-
}
|
|
2900
|
-
// absoluteAnchors
|
|
2901
|
-
for (const image of await processAnchors(absoluteAnchors, "absoluteAnchors", drawingPath, sheetId, this.zipParser, this.xmlParser)) {
|
|
2902
|
-
images.push(image);
|
|
3025
|
+
const drawing = this.xmlParser.parse(drawingContent);
|
|
3026
|
+
// Anchor order in the drawing part is Excel's z-order (first = back).
|
|
3027
|
+
// The parse groups anchors by element name, so the document order
|
|
3028
|
+
// across `oneCellAnchor` / `twoCellAnchor` / `absoluteAnchor` is
|
|
3029
|
+
// recovered from the raw part and each anchor processed in that order.
|
|
3030
|
+
for (const anchor of anchorsInDocumentOrder(drawing, drawingContent)) {
|
|
3031
|
+
for (const image of await processAnchors(anchor.node, anchor.kind, drawingPath, sheetId, this.zipParser, this.xmlParser)) {
|
|
3032
|
+
images.push(image);
|
|
3033
|
+
}
|
|
2903
3034
|
}
|
|
2904
3035
|
}
|
|
2905
3036
|
}
|
|
@@ -2924,6 +3055,10 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
2924
3055
|
getTheme() {
|
|
2925
3056
|
return this.theme ?? defaultSpreadsheetTheme;
|
|
2926
3057
|
}
|
|
3058
|
+
/** `<cellStyles>` resolved to cell formats (toolbar "Workbook styles" gallery). */
|
|
3059
|
+
getNamedCellStyles() {
|
|
3060
|
+
return resolveNamedCellStyles(this.workbookStyles);
|
|
3061
|
+
}
|
|
2927
3062
|
/**
|
|
2928
3063
|
* The workbook default font — styles.xml fonts[0], the font every cell
|
|
2929
3064
|
* without an explicit font inherits. Exporters pass this through so the
|
|
@@ -2949,7 +3084,43 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
2949
3084
|
_getSheets() {
|
|
2950
3085
|
return this.workSheets;
|
|
2951
3086
|
}
|
|
3087
|
+
/**
|
|
3088
|
+
* Resolve a builtin print name to its sheet (`localSheetId` indexes the
|
|
3089
|
+
* `<sheets>` order; a name without scope falls back to the sheet named in
|
|
3090
|
+
* the formula) and record the parsed print area / titles for `getSheets()`.
|
|
3091
|
+
*/
|
|
3092
|
+
stashBuiltinPrintName(name, expression, localSheetId, sheetIdBySheetName) {
|
|
3093
|
+
if (!expression || expression.includes("#REF!"))
|
|
3094
|
+
return;
|
|
3095
|
+
const parsed = name === PRINT_AREA_NAME
|
|
3096
|
+
? parsePrintAreaFormula(expression)
|
|
3097
|
+
: parsePrintTitlesFormula(expression);
|
|
3098
|
+
if (!parsed)
|
|
3099
|
+
return;
|
|
3100
|
+
let sheetId;
|
|
3101
|
+
if (localSheetId !== undefined) {
|
|
3102
|
+
const index = parseInt(localSheetId, 10);
|
|
3103
|
+
const sheetEl = this._getSheets()[index];
|
|
3104
|
+
const id = Number(sheetEl?.a$?.sheetId);
|
|
3105
|
+
if (Number.isFinite(id))
|
|
3106
|
+
sheetId = id;
|
|
3107
|
+
}
|
|
3108
|
+
if (sheetId === undefined && parsed.sheetName) {
|
|
3109
|
+
sheetId = sheetIdBySheetName[parsed.sheetName];
|
|
3110
|
+
}
|
|
3111
|
+
if (sheetId === undefined)
|
|
3112
|
+
return;
|
|
3113
|
+
const entry = this.printNamesBySheetId.get(sheetId) ?? {};
|
|
3114
|
+
if ("ranges" in parsed) {
|
|
3115
|
+
entry.printArea = parsed.ranges;
|
|
3116
|
+
}
|
|
3117
|
+
else {
|
|
3118
|
+
entry.printTitles = parsed.titles;
|
|
3119
|
+
}
|
|
3120
|
+
this.printNamesBySheetId.set(sheetId, entry);
|
|
3121
|
+
}
|
|
2952
3122
|
_getNamedRanges() {
|
|
3123
|
+
this.printNamesBySheetId.clear();
|
|
2953
3124
|
const xml = this.workbookXml;
|
|
2954
3125
|
const sheetIdBySheetName = this._getSheets().reduce((acc, element) => {
|
|
2955
3126
|
if (element) {
|
|
@@ -2971,6 +3142,14 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
2971
3142
|
const name = defined_name.a$?.name;
|
|
2972
3143
|
const expression = defined_name.t$ || "";
|
|
2973
3144
|
const hidden = defined_name.a$.hidden === "1";
|
|
3145
|
+
// `_xlnm.Print_Area` / `_xlnm.Print_Titles` are sheet-scoped print
|
|
3146
|
+
// facets, not user names: they land on `sheet.printSettings` (see
|
|
3147
|
+
// `getSheets()`), never in `namedRanges` — a global copy would make
|
|
3148
|
+
// Excel repair the file on the next export.
|
|
3149
|
+
if (isBuiltinPrintName(name)) {
|
|
3150
|
+
this.stashBuiltinPrintName(name, typeof expression === "string" ? expression : "", defined_name.a$?.localSheetId, sheetIdBySheetName);
|
|
3151
|
+
continue;
|
|
3152
|
+
}
|
|
2974
3153
|
// Empty defined names are noise; nothing useful to round-trip.
|
|
2975
3154
|
// Hidden defined names ARE preserved — Excel uses them as scratch
|
|
2976
3155
|
// names for features like print areas and add-ins, and dropping
|
|
@@ -3162,7 +3341,21 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
3162
3341
|
sheet.visibility = visibility;
|
|
3163
3342
|
}
|
|
3164
3343
|
const metadata = await this.getSheetMetadata(rid);
|
|
3165
|
-
const { merges, rowEntries, columnMetadata, maxRowIndex, maxColumnIndex, autoFilterRange, filterSpecs, sheetViewData, tabColor, sheetHasFilterMode, zeroHeight, defaultRowHeightPx, defaultColumnWidthPx, tablePartIds, outlineSummaryBelow, outlineSummaryRight, } = metadata;
|
|
3344
|
+
const { merges, rowEntries, columnMetadata, maxRowIndex, maxColumnIndex, autoFilterRange, filterSpecs, sheetViewData, tabColor, sheetHasFilterMode, zeroHeight, defaultRowHeightPx, defaultColumnWidthPx, tablePartIds, outlineSummaryBelow, outlineSummaryRight, sheetProtection, protectedRangeEntries, printSettings, } = metadata;
|
|
3345
|
+
if (sheetProtection) {
|
|
3346
|
+
sheet.sheetProtection = sheetProtection;
|
|
3347
|
+
}
|
|
3348
|
+
{
|
|
3349
|
+
const printNames = this.printNamesBySheetId.get(sheetId);
|
|
3350
|
+
const merged = compactPrintSettings({
|
|
3351
|
+
...printSettings,
|
|
3352
|
+
printArea: printNames?.printArea,
|
|
3353
|
+
printTitles: printNames?.printTitles,
|
|
3354
|
+
});
|
|
3355
|
+
if (merged)
|
|
3356
|
+
sheet.printSettings = merged;
|
|
3357
|
+
}
|
|
3358
|
+
this.protectedRangesBySheet.set(sheetId, protectedRangesFromEntries(sheetId, protectedRangeEntries));
|
|
3166
3359
|
if (defaultRowHeightPx !== undefined) {
|
|
3167
3360
|
sheet.defaultRowHeight = defaultRowHeightPx;
|
|
3168
3361
|
}
|
|
@@ -3203,7 +3396,7 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
3203
3396
|
// counts
|
|
3204
3397
|
let columnCount = 0;
|
|
3205
3398
|
// gridlines / headers / zeros / zoom
|
|
3206
|
-
const { frozenRowCount, frozenColumnCount, paneTopLeftCell, showGridLines, showRowColHeaders, showZeros, zoomScale, } = extractSheetViewProperties(sheetViewData);
|
|
3399
|
+
const { frozenRowCount, frozenColumnCount, paneTopLeftCell, showGridLines, showRowColHeaders, showZeros, zoomScale, rightToLeft, } = extractSheetViewProperties(sheetViewData);
|
|
3207
3400
|
sheet.frozenRowCount = frozenRowCount;
|
|
3208
3401
|
sheet.frozenColumnCount = frozenColumnCount;
|
|
3209
3402
|
if (paneTopLeftCell) {
|
|
@@ -3219,6 +3412,8 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
3219
3412
|
if (zoomScale !== undefined && zoomScale !== 100) {
|
|
3220
3413
|
sheet.zoomScale = zoomScale;
|
|
3221
3414
|
}
|
|
3415
|
+
if (rightToLeft)
|
|
3416
|
+
sheet.rightToLeft = true;
|
|
3222
3417
|
// tab color
|
|
3223
3418
|
if (tabColor) {
|
|
3224
3419
|
sheet.tabColor = extractColor(tabColor, this.workbookStyles.indexedColors);
|
|
@@ -3833,18 +4028,81 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
3833
4028
|
for (const element of workSheets) {
|
|
3834
4029
|
const sheetId = Number(element.a$.sheetId);
|
|
3835
4030
|
const rid = element.a$["r:id"];
|
|
3836
|
-
// Drawings are referenced from a worksheet-level <drawing> element
|
|
3837
|
-
// skip the full-DOM parse when the SAX
|
|
4031
|
+
// Drawings are referenced from a worksheet-level <drawing> element and
|
|
4032
|
+
// form controls from <controls>; skip the full-DOM parse when the SAX
|
|
4033
|
+
// pass saw neither.
|
|
3838
4034
|
const features = this.sheetFeatures.get(rid);
|
|
3839
|
-
if (features && !features.drawing) {
|
|
4035
|
+
if (features && !features.drawing && !features.controls) {
|
|
3840
4036
|
continue;
|
|
3841
4037
|
}
|
|
3842
4038
|
const sheet_data = await this.getSheetData(rid);
|
|
3843
|
-
|
|
3844
|
-
|
|
4039
|
+
if (!features || features.drawing) {
|
|
4040
|
+
const drawings = await this._getDrawings(rid, sheetId, sheet_data);
|
|
4041
|
+
allDrawings.push(...drawings);
|
|
4042
|
+
}
|
|
4043
|
+
if (!features || features.controls) {
|
|
4044
|
+
allDrawings.push(...(await this._getFormControls(rid, sheetId, sheet_data)));
|
|
4045
|
+
}
|
|
3845
4046
|
}
|
|
3846
4047
|
return allDrawings;
|
|
3847
4048
|
}
|
|
4049
|
+
/**
|
|
4050
|
+
* Form controls: `<controls><control r:id>` → `xl/ctrlProps/ctrlPropN.xml`
|
|
4051
|
+
* (+ the caption from the sheet's legacy VML part), as `formControl`
|
|
4052
|
+
* embeds. Nothing is rendered interactively — they round-trip.
|
|
4053
|
+
*/
|
|
4054
|
+
async _getFormControls(rid, sheetId, sheetData) {
|
|
4055
|
+
const controls = readWorksheetControls(sheetData);
|
|
4056
|
+
if (!controls.length)
|
|
4057
|
+
return [];
|
|
4058
|
+
const target = this.relations[rid].target;
|
|
4059
|
+
const sheetPath = target.startsWith("/xl")
|
|
4060
|
+
? target.replace(/^\//gi, "")
|
|
4061
|
+
: `xl/${target}`;
|
|
4062
|
+
const sheetRelPath = sheetPath.replace("worksheets", "worksheets/_rels") + ".rels";
|
|
4063
|
+
const relTargets = new Map();
|
|
4064
|
+
try {
|
|
4065
|
+
const sheetRels = this.xmlParser.parse(await this.zipParser.getText(sheetRelPath));
|
|
4066
|
+
const list = get(sheetRels, "Relationships.Relationship");
|
|
4067
|
+
for (const rel of Array.isArray(list) ? list : list ? [list] : []) {
|
|
4068
|
+
const id = rel?.a$?.Id;
|
|
4069
|
+
const relTarget = rel?.a$?.Target;
|
|
4070
|
+
if (typeof id === "string" && typeof relTarget === "string") {
|
|
4071
|
+
relTargets.set(id, relTarget);
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
catch {
|
|
4076
|
+
return [];
|
|
4077
|
+
}
|
|
4078
|
+
const ctrlProps = new Map();
|
|
4079
|
+
for (const control of controls) {
|
|
4080
|
+
if (!control.relId || ctrlProps.has(control.relId))
|
|
4081
|
+
continue;
|
|
4082
|
+
const relTarget = relTargets.get(control.relId);
|
|
4083
|
+
if (!relTarget)
|
|
4084
|
+
continue;
|
|
4085
|
+
try {
|
|
4086
|
+
const xml = await this.zipParser.getText(this.resolveRelationshipTarget(sheetPath, relTarget));
|
|
4087
|
+
ctrlProps.set(control.relId, parseFormControlPr(this.xmlPreserveValueParser.parse(xml)));
|
|
4088
|
+
}
|
|
4089
|
+
catch {
|
|
4090
|
+
// Missing ctrlProp part — the control is skipped below.
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
let captions = new Map();
|
|
4094
|
+
const legacyRelId = readLegacyDrawingRelId(sheetData);
|
|
4095
|
+
const vmlTarget = legacyRelId ? relTargets.get(legacyRelId) : undefined;
|
|
4096
|
+
if (vmlTarget) {
|
|
4097
|
+
try {
|
|
4098
|
+
captions = parseVmlControlCaptions(await this.zipParser.getText(this.resolveRelationshipTarget(sheetPath, vmlTarget)));
|
|
4099
|
+
}
|
|
4100
|
+
catch {
|
|
4101
|
+
// No VML part — controls import without captions.
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4104
|
+
return buildFormControlEmbeds({ controls, sheetId, ctrlProps, captions });
|
|
4105
|
+
}
|
|
3848
4106
|
async getCharts() {
|
|
3849
4107
|
const allCharts = [];
|
|
3850
4108
|
const workSheets = this._getSheets();
|
|
@@ -4117,6 +4375,18 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
4117
4375
|
const sheet_data = await this.getSheetData(rid);
|
|
4118
4376
|
return parseDataValidationsFromSheetData(this, sheetId, sheet_data, sheetName);
|
|
4119
4377
|
}
|
|
4378
|
+
/**
|
|
4379
|
+
* Allow-edit ranges (`<protectedRanges>/<protectedRange>`) in the model the
|
|
4380
|
+
* `protect-range` command writes: `protectedRangeId` = the source `name`,
|
|
4381
|
+
* `range` = the first `sqref` area plus `sheetId`. Available after
|
|
4382
|
+
* `getSheets()`; sheet-level `<sheetProtection>` rides `Sheet.sheetProtection`.
|
|
4383
|
+
*/
|
|
4384
|
+
getProtectedRanges(sheetId) {
|
|
4385
|
+
if (sheetId !== undefined) {
|
|
4386
|
+
return this.protectedRangesBySheet.get(sheetId) ?? [];
|
|
4387
|
+
}
|
|
4388
|
+
return Array.from(this.protectedRangesBySheet.values()).flat();
|
|
4389
|
+
}
|
|
4120
4390
|
getNamedRanges() {
|
|
4121
4391
|
return this.namedRanges;
|
|
4122
4392
|
}
|
|
@@ -4652,3 +4922,155 @@ export class XlsxPlugin extends BaseWorkbookPlugin {
|
|
|
4652
4922
|
return externalLinks;
|
|
4653
4923
|
}
|
|
4654
4924
|
}
|
|
4925
|
+
/** `CT_SheetProtection` boolean attributes, in OOXML order (camelCase = model key). */
|
|
4926
|
+
const SHEET_PROTECTION_FLAGS = [
|
|
4927
|
+
"sheet",
|
|
4928
|
+
"objects",
|
|
4929
|
+
"scenarios",
|
|
4930
|
+
"formatCells",
|
|
4931
|
+
"formatColumns",
|
|
4932
|
+
"formatRows",
|
|
4933
|
+
"insertColumns",
|
|
4934
|
+
"insertRows",
|
|
4935
|
+
"insertHyperlinks",
|
|
4936
|
+
"deleteColumns",
|
|
4937
|
+
"deleteRows",
|
|
4938
|
+
"selectLockedCells",
|
|
4939
|
+
"sort",
|
|
4940
|
+
"autoFilter",
|
|
4941
|
+
"pivotTables",
|
|
4942
|
+
"selectUnlockedCells",
|
|
4943
|
+
];
|
|
4944
|
+
/**
|
|
4945
|
+
* `<sheetProtection …>` attributes → `Sheet.sheetProtection`. Only attributes
|
|
4946
|
+
* present in the source are set (`"1"|"true"` → true, anything else → false),
|
|
4947
|
+
* so an explicit flag round-trips without inventing schema defaults; the
|
|
4948
|
+
* password hash (legacy `password` or the agile quartet) rides along verbatim.
|
|
4949
|
+
* Mirrors `rnc-import`'s `read_sheet_protection`.
|
|
4950
|
+
*/
|
|
4951
|
+
const readSheetProtectionAttrs = (attrs) => {
|
|
4952
|
+
const protection = {};
|
|
4953
|
+
for (const flag of SHEET_PROTECTION_FLAGS) {
|
|
4954
|
+
const value = attrs[flag];
|
|
4955
|
+
if (value !== undefined) {
|
|
4956
|
+
protection[flag] = value === "1" || value === "true";
|
|
4957
|
+
}
|
|
4958
|
+
}
|
|
4959
|
+
if (attrs.password)
|
|
4960
|
+
protection.password = attrs.password;
|
|
4961
|
+
if (attrs.algorithmName)
|
|
4962
|
+
protection.algorithmName = attrs.algorithmName;
|
|
4963
|
+
if (attrs.hashValue)
|
|
4964
|
+
protection.hashValue = attrs.hashValue;
|
|
4965
|
+
if (attrs.saltValue)
|
|
4966
|
+
protection.saltValue = attrs.saltValue;
|
|
4967
|
+
if (attrs.spinCount !== undefined) {
|
|
4968
|
+
const spinCount = parseInt(attrs.spinCount, 10);
|
|
4969
|
+
if (Number.isFinite(spinCount))
|
|
4970
|
+
protection.spinCount = spinCount;
|
|
4971
|
+
}
|
|
4972
|
+
return protection;
|
|
4973
|
+
};
|
|
4974
|
+
/**
|
|
4975
|
+
* `<protectedRange sqref name>` entries → `ProtectedRange[]` for one sheet. The
|
|
4976
|
+
* `name` becomes the `protectedRangeId` so it keys the stored facet and
|
|
4977
|
+
* re-exports under the same name; only the first `sqref` area is modeled
|
|
4978
|
+
* (Excel writes one per element in practice).
|
|
4979
|
+
*/
|
|
4980
|
+
const protectedRangesFromEntries = (sheetId, entries) => {
|
|
4981
|
+
const ranges = [];
|
|
4982
|
+
for (const entry of entries) {
|
|
4983
|
+
const first = entry.sqref.trim().split(/\s+/)[0];
|
|
4984
|
+
const range = first ? getRangeFromAddressRef(first) : undefined;
|
|
4985
|
+
if (!range)
|
|
4986
|
+
continue;
|
|
4987
|
+
const protectedRange = {
|
|
4988
|
+
range: { sheetId, ...range },
|
|
4989
|
+
};
|
|
4990
|
+
if (entry.name)
|
|
4991
|
+
protectedRange.protectedRangeId = entry.name;
|
|
4992
|
+
if (entry.securityDescriptor) {
|
|
4993
|
+
protectedRange.securityDescriptor = entry.securityDescriptor;
|
|
4994
|
+
}
|
|
4995
|
+
ranges.push(protectedRange);
|
|
4996
|
+
}
|
|
4997
|
+
return ranges;
|
|
4998
|
+
};
|
|
4999
|
+
const isXmlTrue = (value) => value === "1" || value === "true";
|
|
5000
|
+
/** `"1"|"true"|"0"|"false"` → boolean; absent stays undefined. */
|
|
5001
|
+
const xmlBoolOpt = (value) => value === undefined ? undefined : isXmlTrue(value);
|
|
5002
|
+
const xmlIntOpt = (value) => {
|
|
5003
|
+
if (value === undefined)
|
|
5004
|
+
return undefined;
|
|
5005
|
+
const n = parseInt(value, 10);
|
|
5006
|
+
return Number.isFinite(n) ? n : undefined;
|
|
5007
|
+
};
|
|
5008
|
+
const xmlFloatOpt = (value) => {
|
|
5009
|
+
if (value === undefined)
|
|
5010
|
+
return undefined;
|
|
5011
|
+
const n = parseFloat(value);
|
|
5012
|
+
return Number.isFinite(n) ? n : undefined;
|
|
5013
|
+
};
|
|
5014
|
+
const stripUndefined = (value) => {
|
|
5015
|
+
for (const key of Object.keys(value)) {
|
|
5016
|
+
if (value[key] === undefined)
|
|
5017
|
+
delete value[key];
|
|
5018
|
+
}
|
|
5019
|
+
return value;
|
|
5020
|
+
};
|
|
5021
|
+
/** `<headerFooter>` children whose text is a header/footer code string. */
|
|
5022
|
+
const HEADER_FOOTER_TEXT_ELEMENTS = [
|
|
5023
|
+
"oddHeader",
|
|
5024
|
+
"oddFooter",
|
|
5025
|
+
"evenHeader",
|
|
5026
|
+
"evenFooter",
|
|
5027
|
+
"firstHeader",
|
|
5028
|
+
"firstFooter",
|
|
5029
|
+
];
|
|
5030
|
+
const isHeaderFooterTextKey = (name) => HEADER_FOOTER_TEXT_ELEMENTS.includes(name);
|
|
5031
|
+
/**
|
|
5032
|
+
* `<pageSetup …>` → `PageSetup` (present attributes only; `fitToPage` is
|
|
5033
|
+
* filled from `<sheetPr><pageSetUpPr>` by the caller). Mirrors
|
|
5034
|
+
* `rnc-import`'s `read_page_setup`.
|
|
5035
|
+
*/
|
|
5036
|
+
const readPageSetupAttrs = (attrs) => {
|
|
5037
|
+
const orientation = attrs.orientation;
|
|
5038
|
+
const pageOrder = attrs.pageOrder;
|
|
5039
|
+
return stripUndefined({
|
|
5040
|
+
orientation: orientation === "landscape" || orientation === "portrait"
|
|
5041
|
+
? orientation
|
|
5042
|
+
: undefined,
|
|
5043
|
+
paperSize: xmlIntOpt(attrs.paperSize),
|
|
5044
|
+
scale: xmlIntOpt(attrs.scale),
|
|
5045
|
+
fitToWidth: xmlIntOpt(attrs.fitToWidth),
|
|
5046
|
+
fitToHeight: xmlIntOpt(attrs.fitToHeight),
|
|
5047
|
+
firstPageNumber: xmlIntOpt(attrs.firstPageNumber),
|
|
5048
|
+
useFirstPageNumber: xmlBoolOpt(attrs.useFirstPageNumber),
|
|
5049
|
+
pageOrder: pageOrder === "overThenDown" || pageOrder === "downThenOver"
|
|
5050
|
+
? pageOrder
|
|
5051
|
+
: undefined,
|
|
5052
|
+
blackAndWhite: xmlBoolOpt(attrs.blackAndWhite),
|
|
5053
|
+
draft: xmlBoolOpt(attrs.draft),
|
|
5054
|
+
});
|
|
5055
|
+
};
|
|
5056
|
+
const readPageMarginsAttrs = (attrs) => stripUndefined({
|
|
5057
|
+
left: xmlFloatOpt(attrs.left),
|
|
5058
|
+
right: xmlFloatOpt(attrs.right),
|
|
5059
|
+
top: xmlFloatOpt(attrs.top),
|
|
5060
|
+
bottom: xmlFloatOpt(attrs.bottom),
|
|
5061
|
+
header: xmlFloatOpt(attrs.header),
|
|
5062
|
+
footer: xmlFloatOpt(attrs.footer),
|
|
5063
|
+
});
|
|
5064
|
+
const readPrintOptionsAttrs = (attrs) => stripUndefined({
|
|
5065
|
+
gridLines: xmlBoolOpt(attrs.gridLines),
|
|
5066
|
+
headings: xmlBoolOpt(attrs.headings),
|
|
5067
|
+
horizontalCentered: xmlBoolOpt(attrs.horizontalCentered),
|
|
5068
|
+
verticalCentered: xmlBoolOpt(attrs.verticalCentered),
|
|
5069
|
+
});
|
|
5070
|
+
/** `<headerFooter …>` attributes; the child texts stream in via `ontext`. */
|
|
5071
|
+
const readHeaderFooterAttrs = (attrs) => stripUndefined({
|
|
5072
|
+
differentOddEven: xmlBoolOpt(attrs.differentOddEven),
|
|
5073
|
+
differentFirst: xmlBoolOpt(attrs.differentFirst),
|
|
5074
|
+
scaleWithDoc: xmlBoolOpt(attrs.scaleWithDoc),
|
|
5075
|
+
alignWithMargins: xmlBoolOpt(attrs.alignWithMargins),
|
|
5076
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pivots.d.ts","sourceRoot":"","sources":["../../../../../excel-parser/plugins/xlsx/pivots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"pivots.d.ts","sourceRoot":"","sources":["../../../../../excel-parser/plugins/xlsx/pivots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAEV,UAAU,EAGX,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAoErE,KAAK,aAAa,GAAG;IACnB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAkQF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GACnC,SAAS;IACP,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,mEAAmE;IACnE,WAAW,EAAE,MAAM,MAAM,CAAC;IAC1B,kDAAkD;IAClD,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACtD,cAAc,EAAE,MAAM,CAAC;CACxB,KACA,OAAO,CAAC,UAAU,EAAE,CAsEtB,CAAC"}
|