reamkit 1.31.0 → 1.32.1
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/README.md +10 -0
- package/dist/esm/core/bidi/index.d.ts +10 -0
- package/dist/esm/core/bidi/index.js +18 -2
- package/dist/esm/core/converter/facade.js +10 -5
- package/dist/esm/core/converter/project.js +1 -0
- package/dist/esm/core/converter/ream.js +17 -6
- package/dist/esm/core/converter/sheet-images.d.ts +17 -0
- package/dist/esm/core/converter/sheet-images.js +33 -0
- package/dist/esm/core/crypto/offcrypto.js +56 -12
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +112 -0
- package/dist/esm/core/drawingml/chart-geometry.d.ts +36 -13
- package/dist/esm/core/drawingml/chart-geometry.js +372 -146
- package/dist/esm/core/drawingml/chart-parser.d.ts +19 -0
- package/dist/esm/core/drawingml/chart-parser.js +126 -18
- package/dist/esm/core/drawingml/colors.d.ts +6 -0
- package/dist/esm/core/drawingml/colors.js +23 -3
- package/dist/esm/core/drawingml/shape-render.d.ts +3 -1
- package/dist/esm/core/drawingml/shape-render.js +4 -2
- package/dist/esm/core/font/measure.d.ts +9 -0
- package/dist/esm/core/font/measure.js +9 -1
- package/dist/esm/core/fonts/families.js +4 -2
- package/dist/esm/core/fonts/scripts.js +4 -2
- package/dist/esm/core/ir/flow.d.ts +6 -0
- package/dist/esm/core/ir/sheet.d.ts +43 -0
- package/dist/esm/core/number-format.d.ts +40 -15
- package/dist/esm/core/number-format.js +295 -83
- package/dist/esm/core/opc/tag-scan.d.ts +15 -0
- package/dist/esm/core/opc/tag-scan.js +41 -0
- package/dist/esm/core/opc/xml-entities.js +39 -2
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +96 -0
- package/dist/esm/core/style-cascade/resolver.js +4 -2
- package/dist/esm/excel/column-bands.d.ts +39 -6
- package/dist/esm/excel/column-bands.js +41 -17
- package/dist/esm/excel/comments-parser.js +19 -0
- package/dist/esm/excel/conditional-format.d.ts +7 -3
- package/dist/esm/excel/conditional-format.js +77 -39
- package/dist/esm/excel/formula/context.d.ts +18 -0
- package/dist/esm/excel/formula/eval.js +51 -0
- package/dist/esm/excel/formula/functions.js +37 -14
- package/dist/esm/excel/formula/index.d.ts +2 -2
- package/dist/esm/excel/formula/lexer.d.ts +1 -1
- package/dist/esm/excel/formula/lexer.js +41 -0
- package/dist/esm/excel/formula/parser.d.ts +25 -0
- package/dist/esm/excel/formula/parser.js +95 -0
- package/dist/esm/excel/print-model.d.ts +38 -1
- package/dist/esm/excel/print-model.js +536 -83
- package/dist/esm/excel/shared-strings-parser.d.ts +9 -0
- package/dist/esm/excel/shared-strings-parser.js +11 -1
- package/dist/esm/excel/sheet-drawing.d.ts +38 -2
- package/dist/esm/excel/sheet-drawing.js +47 -13
- package/dist/esm/excel/sheet-shape-parser.d.ts +6 -2
- package/dist/esm/excel/sheet-shape-parser.js +18 -6
- package/dist/esm/excel/sheet-to-flow.d.ts +17 -0
- package/dist/esm/excel/sheet-to-flow.js +434 -47
- package/dist/esm/excel/styles-parser.d.ts +9 -0
- package/dist/esm/excel/styles-parser.js +80 -26
- package/dist/esm/excel/table-parser.js +5 -0
- package/dist/esm/excel/table-style-presets.d.ts +26 -0
- package/dist/esm/excel/table-style-presets.js +1555 -0
- package/dist/esm/excel/table-style.d.ts +13 -0
- package/dist/esm/excel/table-style.js +75 -0
- package/dist/esm/excel/tint.d.ts +10 -0
- package/dist/esm/excel/tint.js +75 -0
- package/dist/esm/excel/vml-drawing.d.ts +41 -3
- package/dist/esm/excel/vml-drawing.js +144 -11
- package/dist/esm/excel/worksheet-parser.js +89 -15
- package/dist/esm/excel/xls/biff-reader.js +10 -2
- package/dist/esm/excel/xlsx-reader.js +234 -19
- package/dist/esm/excel/xlsx-writer.js +8 -7
- package/dist/esm/html/html-writer.js +202 -20
- package/dist/esm/layout/fit-pages.d.ts +11 -0
- package/dist/esm/layout/fit-pages.js +86 -0
- package/dist/esm/layout/line-paint.d.ts +58 -0
- package/dist/esm/layout/line-paint.js +107 -0
- package/dist/esm/layout/page-doc.d.ts +51 -0
- package/dist/esm/layout/page-doc.js +141 -1
- package/dist/esm/layout/styled-layout.d.ts +7 -0
- package/dist/esm/layout/styled-layout.js +275 -52
- package/dist/esm/layout/turned-section.js +14 -2
- package/dist/esm/markdown/markdown-writer.js +75 -13
- package/dist/esm/pdf/styled-page-emitter.js +49 -71
- package/dist/esm/pdf/styled-page-renderer.js +1 -1
- package/dist/esm/pdf-reader/annot-draw.js +2 -2
- package/dist/esm/pdf-reader/annots.js +3 -1
- package/dist/esm/pdf-reader/font.js +4 -4
- package/dist/esm/pdf-reader/layout.js +1 -1
- package/dist/esm/svg/svg-text.d.ts +58 -0
- package/dist/esm/svg/svg-text.js +322 -0
- package/dist/esm/svg/svg-writer.js +135 -71
- package/dist/esm/word/document-parser.js +1 -1
- package/dist/esm/word/docx-reader.js +13 -8
- package/dist/esm/word/docx-to-pdf.js +3 -3
- package/dist/esm/word/docx-writer.js +11 -2
- package/dist/esm/word/font-table.js +89 -10
- package/dist/esm/word/numbering-parser.js +1 -1
- package/package.json +7 -3
|
@@ -195,6 +195,8 @@ function readSheet(wb, view, start, blips, resources, sharedStrings, chartData,
|
|
|
195
195
|
const hyperlinks = [];
|
|
196
196
|
const rowHeights = [];
|
|
197
197
|
let frozen = false;
|
|
198
|
+
let showGrid = true;
|
|
199
|
+
let rightToLeft = false;
|
|
198
200
|
let paneSplit;
|
|
199
201
|
let maxRow = -1;
|
|
200
202
|
let maxColumn = -1;
|
|
@@ -300,7 +302,11 @@ function readSheet(wb, view, start, blips, resources, sharedStrings, chartData,
|
|
|
300
302
|
}
|
|
301
303
|
break;
|
|
302
304
|
case REC.WINDOW2:
|
|
303
|
-
if (d.length >= 2)
|
|
305
|
+
if (d.length >= 2) {
|
|
306
|
+
frozen = (readU16(d, 0) & 8) !== 0;
|
|
307
|
+
showGrid = (readU16(d, 0) & 2) !== 0;
|
|
308
|
+
rightToLeft = (readU16(d, 0) & 64) !== 0;
|
|
309
|
+
}
|
|
304
310
|
break;
|
|
305
311
|
case REC.PANE:
|
|
306
312
|
if (d.length >= 4) paneSplit = {
|
|
@@ -331,7 +337,9 @@ function readSheet(wb, view, start, blips, resources, sharedStrings, chartData,
|
|
|
331
337
|
...parsePrintModel(records),
|
|
332
338
|
...dataValidations.length > 0 ? { dataValidations } : {},
|
|
333
339
|
...conditionalFormats.length > 0 ? { conditionalFormats } : {},
|
|
334
|
-
...pane ? { pane } : {}
|
|
340
|
+
...pane ? { pane } : {},
|
|
341
|
+
...showGrid ? {} : { showGridLines: false },
|
|
342
|
+
...rightToLeft ? { rightToLeft: true } : {}
|
|
335
343
|
};
|
|
336
344
|
const drawing = gatherDrawing(records, REC.MSODRAWING);
|
|
337
345
|
const place = anchorPlacer(grid);
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import { ResourceStore } from "../core/ir/resources.js";
|
|
2
2
|
import { FEATURES } from "../core/ir/features.js";
|
|
3
3
|
import { detectImageFormat } from "../core/images.js";
|
|
4
|
+
import { INDEXED_COLORS } from "../core/indexed-colors.js";
|
|
4
5
|
import { bytesInclude, packageHasPart } from "../core/bytes.js";
|
|
5
|
-
import {
|
|
6
|
-
import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
|
|
6
|
+
import { OFFICE_2023_THEME_PALETTE, makeColorResolver } from "../core/drawingml/colors.js";
|
|
7
|
+
import { parseChart, pointsPerSeries, withChartColorStyle } from "../core/drawingml/chart-parser.js";
|
|
7
8
|
import { parseTheme, parseThemeEffectStyles, parseThemeFillStyles, parseThemeLineWidths } from "../core/drawingml/theme-parser.js";
|
|
8
9
|
import { isOoxmlRel } from "../core/opc/relationship-types.js";
|
|
9
10
|
import { OpcPackage } from "../core/opc/package.js";
|
|
10
11
|
import { parseCoreProperties } from "../core/opc/core-properties.js";
|
|
11
12
|
import "../core/opc/index.js";
|
|
13
|
+
import { parseCellRef } from "./cell-reference.js";
|
|
12
14
|
import { parseAreaRef } from "./defined-name-ref.js";
|
|
13
15
|
import { parseSharedStrings } from "./shared-strings-parser.js";
|
|
14
16
|
import { parseWorkbook } from "./workbook-parser.js";
|
|
15
17
|
import { EMPTY_XLSX_STYLES, parseXlsxStyles } from "./styles-parser.js";
|
|
16
18
|
import { parseWorksheet } from "./worksheet-parser.js";
|
|
17
19
|
import "./index.js";
|
|
18
|
-
import { resolveCellText } from "./print-model.js";
|
|
19
|
-
import { parseSheetDrawing } from "./sheet-drawing.js";
|
|
20
|
+
import { columnUnitTwips, resolveCellText } from "./print-model.js";
|
|
21
|
+
import { makeColWidthPt, makeRowHeightPt, parseSheetDrawing } from "./sheet-drawing.js";
|
|
20
22
|
import { parseTablePartFull } from "./table-parser.js";
|
|
21
23
|
import { parsePivotTablePart } from "./pivot-table-parser.js";
|
|
22
24
|
import { parseSlicerCachePart, parseSlicerPart } from "./slicer-parser.js";
|
|
@@ -28,6 +30,7 @@ import { parseRichValueText } from "./rich-value.js";
|
|
|
28
30
|
import { activeXBinRelId, activeXType, activeXTypeFromPart, parseActiveX, parseActiveXBin } from "./activex-parser.js";
|
|
29
31
|
import { parseDiagramFrames, parseDiagramShapes, parseSheetShapes } from "./sheet-shape-parser.js";
|
|
30
32
|
import { projectSheetDoc } from "./sheet-to-flow.js";
|
|
33
|
+
import { resolveTableStyleFormat } from "./table-style.js";
|
|
31
34
|
//#region src/excel/xlsx-reader.ts
|
|
32
35
|
var WORKBOOK_PART = "xl/workbook.xml";
|
|
33
36
|
var SHARED_STRINGS_PART = "xl/sharedStrings.xml";
|
|
@@ -92,6 +95,7 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
92
95
|
const richValueText = parseRichValueText(pkg.getPart(METADATA_PART), pkg.getPart(RICH_VALUE_STRUCTURE_PART), pkg.getPart(RICH_VALUE_PART));
|
|
93
96
|
const stylesData = pkg.getPart(STYLES_PART);
|
|
94
97
|
const styles = stylesData ? parseXlsxStyles(stylesData, themePalette) : EMPTY_XLSX_STYLES;
|
|
98
|
+
const colUnit = columnUnitTwips(styles);
|
|
95
99
|
const persons = /* @__PURE__ */ new Map();
|
|
96
100
|
for (const rel of workbookRels) {
|
|
97
101
|
if (!rel.type.endsWith(PERSON_REL_TAIL)) continue;
|
|
@@ -118,15 +122,23 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
118
122
|
if (!resolved) continue;
|
|
119
123
|
let worksheet = parseWorksheet(resolved.data, themePalette);
|
|
120
124
|
worksheet = withPrinterPageSetup(worksheet, pkg, resolved.path, pkg.getPartRelationships(resolved.path));
|
|
125
|
+
if (worksheet.chartSheet && worksheet.pageSetup?.orientation === void 0) worksheet = {
|
|
126
|
+
...worksheet,
|
|
127
|
+
pageSetup: {
|
|
128
|
+
...worksheet.pageSetup,
|
|
129
|
+
orientation: "landscape"
|
|
130
|
+
}
|
|
131
|
+
};
|
|
121
132
|
worksheet = withRichValues(worksheet, richValueText);
|
|
122
133
|
const charts = [];
|
|
123
134
|
const images = [];
|
|
124
135
|
let shapes;
|
|
136
|
+
const screenOnlyShapes = /* @__PURE__ */ new Set();
|
|
125
137
|
if (worksheet.drawingRelId) {
|
|
126
138
|
const drawingRel = pkg.getPartRelationships(resolved.path).find((r) => r.id === worksheet.drawingRelId);
|
|
127
139
|
const drawing = drawingRel ? pkg.resolveRelatedPart(resolved.path, drawingRel) : void 0;
|
|
128
140
|
if (drawing) {
|
|
129
|
-
const { charts: chartRefs, pictures } = parseSheetDrawing(drawing.data, drawing.path, pkg, worksheet);
|
|
141
|
+
const { charts: chartRefs, pictures } = parseSheetDrawing(drawing.data, drawing.path, pkg, worksheet, colUnit);
|
|
130
142
|
for (const ref of chartRefs) {
|
|
131
143
|
if (!chartData.has(ref.chartPartPath)) {
|
|
132
144
|
const chartXml = pkg.getPart(ref.chartPartPath);
|
|
@@ -139,7 +151,8 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
139
151
|
widthPt: ref.widthPt,
|
|
140
152
|
heightPt: ref.heightPt,
|
|
141
153
|
xPt: ref.xPt,
|
|
142
|
-
yPt: ref.yPt
|
|
154
|
+
yPt: ref.yPt,
|
|
155
|
+
...ref.screenOnly ? { screenOnly: true } : {}
|
|
143
156
|
});
|
|
144
157
|
}
|
|
145
158
|
for (const pic of pictures) {
|
|
@@ -151,14 +164,15 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
151
164
|
widthPt: pic.widthPt,
|
|
152
165
|
heightPt: pic.heightPt,
|
|
153
166
|
xPt: pic.xPt,
|
|
154
|
-
yPt: pic.yPt
|
|
167
|
+
yPt: pic.yPt,
|
|
168
|
+
...pic.screenOnly ? { screenOnly: true } : {}
|
|
155
169
|
});
|
|
156
170
|
}
|
|
157
171
|
if (bytesInclude(drawing.data, ":sp>") || bytesInclude(drawing.data, ":sp ")) {
|
|
158
|
-
const parsed = parseSheetShapes(drawing.data, worksheet, resolveColor, themeLineWidths, themeFillStyles, themeEffectStyles);
|
|
172
|
+
const parsed = parseSheetShapes(drawing.data, worksheet, resolveColor, themeLineWidths, themeFillStyles, themeEffectStyles, screenOnlyShapes, colUnit);
|
|
159
173
|
if (parsed.length > 0) shapes = parsed;
|
|
160
174
|
}
|
|
161
|
-
const frames = parseDiagramFrames(drawing.data, worksheet);
|
|
175
|
+
const frames = parseDiagramFrames(drawing.data, worksheet, colUnit);
|
|
162
176
|
if (frames.length > 0) {
|
|
163
177
|
const dsp = pkg.getPartRelationships(drawing.path).filter((r) => r.type.endsWith("/diagramDrawing"));
|
|
164
178
|
const fromDiagrams = [];
|
|
@@ -181,7 +195,7 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
181
195
|
const part = rel ? pkg.resolveRelatedPart(resolved.path, rel) : void 0;
|
|
182
196
|
const full = part ? parseTablePartFull(part.data) : void 0;
|
|
183
197
|
if (!full) continue;
|
|
184
|
-
resolvedTables.push(resolveTableStyle(full.table, palette));
|
|
198
|
+
resolvedTables.push(withTableStyle(resolveTableStyle(full.table, palette), styles, themePalette));
|
|
185
199
|
if (full.id !== void 0) tableIndex.set(full.id, {
|
|
186
200
|
cells: worksheet.cells,
|
|
187
201
|
ref: full.table.ref,
|
|
@@ -266,7 +280,8 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
266
280
|
...props
|
|
267
281
|
};
|
|
268
282
|
};
|
|
269
|
-
const legacyVml = readLegacyVml(pkg, resolved.path, wsRels, worksheet);
|
|
283
|
+
const legacyVml = readLegacyVml(pkg, resolved.path, wsRels, worksheet, colUnit);
|
|
284
|
+
if (comments && legacyVml.notes.length > 0) comments = withShownNotes(comments, legacyVml.notes, worksheet, colUnit);
|
|
270
285
|
let formControls;
|
|
271
286
|
if (worksheet.formControls && worksheet.formControls.length > 0) {
|
|
272
287
|
const resolvedControls = [];
|
|
@@ -275,7 +290,7 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
275
290
|
if (fc.shapeId !== void 0 && legacyVml.nonPrinting.has(fc.shapeId)) continue;
|
|
276
291
|
const rel = wsRels.find((r) => r.id === fc.relId);
|
|
277
292
|
const part = rel ? pkg.resolveRelatedPart(resolved.path, rel) : void 0;
|
|
278
|
-
const box = fc.shapeId !== void 0 ? legacyVml.boxes.get(fc.shapeId) : void 0;
|
|
293
|
+
const box = fc.shapeId !== void 0 ? legacyVml.anchoredBoxes.get(fc.shapeId) ?? legacyVml.boxes.get(fc.shapeId) : void 0;
|
|
279
294
|
if (part && ACTIVEX_PART.test(part.path)) {
|
|
280
295
|
resolvedAx.push({
|
|
281
296
|
...activeXState(part),
|
|
@@ -320,6 +335,7 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
320
335
|
...charts.length > 0 ? { charts } : {},
|
|
321
336
|
...images.length > 0 ? { images } : {},
|
|
322
337
|
...shapes ? { shapes } : {},
|
|
338
|
+
...shapes && screenOnlyShapes.size > 0 ? { screenOnlyShapes: new Set(shapes.flatMap((shape, i) => screenOnlyShapes.has(shape) ? [i] : [])) } : {},
|
|
323
339
|
...hyperlinks ? { hyperlinks } : {},
|
|
324
340
|
...comments ? { comments } : {},
|
|
325
341
|
...formControls ? { formControls } : {},
|
|
@@ -393,6 +409,11 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
393
409
|
* them, and a reference naming a sheet this workbook does not have resolves to
|
|
394
410
|
* nothing rather than to zeros.
|
|
395
411
|
*
|
|
412
|
+
* A reference reads no more cells than the series' share of the chart's points
|
|
413
|
+
* ({@link pointsPerSeries}), and finds each in an index of its sheet. The range
|
|
414
|
+
* is the file's to name and unbounded — `B2:B99999999999` — and every cell of
|
|
415
|
+
* it was searched for through the whole sheet.
|
|
416
|
+
*
|
|
396
417
|
* @param chart The parsed chart.
|
|
397
418
|
* @param sheets Every sheet in the workbook, by tab order.
|
|
398
419
|
* @param styles The style table (for a referenced cell's number format).
|
|
@@ -401,13 +422,27 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
401
422
|
* @returns The chart, unchanged when nothing needed resolving.
|
|
402
423
|
*/
|
|
403
424
|
function withWorkbookData(chart, sheets, styles, sharedStrings, date1904) {
|
|
425
|
+
const most = pointsPerSeries(chart.series.length);
|
|
426
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
427
|
+
const cellAt = (grid, row, column) => {
|
|
428
|
+
let index = indexes.get(grid);
|
|
429
|
+
if (!index) {
|
|
430
|
+
index = /* @__PURE__ */ new Map();
|
|
431
|
+
for (const cell of grid.cells) {
|
|
432
|
+
const key = `${String(cell.row)}:${String(cell.column)}`;
|
|
433
|
+
if (!index.has(key)) index.set(key, cell);
|
|
434
|
+
}
|
|
435
|
+
indexes.set(grid, index);
|
|
436
|
+
}
|
|
437
|
+
return index.get(`${String(row)}:${String(column)}`);
|
|
438
|
+
};
|
|
404
439
|
const cellsOf = (ref) => {
|
|
405
440
|
if (ref === void 0) return void 0;
|
|
406
441
|
const area = resolveChartRef(ref, sheets);
|
|
407
442
|
if (!area) return void 0;
|
|
408
443
|
const out = [];
|
|
409
|
-
for (let row = area.startRow; row <= area.endRow; row++) for (let col = area.startColumn; col <= area.endColumn; col++) {
|
|
410
|
-
const cell = area.grid
|
|
444
|
+
for (let row = area.startRow; row <= area.endRow && out.length < most; row++) for (let col = area.startColumn; col <= area.endColumn && out.length < most; col++) {
|
|
445
|
+
const cell = cellAt(area.grid, row, col);
|
|
411
446
|
out.push(cell ? resolveCellText(cell, sharedStrings, styles, date1904) : "");
|
|
412
447
|
}
|
|
413
448
|
return out;
|
|
@@ -488,10 +523,12 @@ function withPrinterPageSetup(worksheet, pkg, sheetPath, wsRels) {
|
|
|
488
523
|
* through the activeX part. What is left is the Forms-toolbar kind, whose
|
|
489
524
|
* caption and checked state exist nowhere else in the package.
|
|
490
525
|
*/
|
|
491
|
-
function readLegacyVml(pkg, sheetPath, wsRels, worksheet) {
|
|
526
|
+
function readLegacyVml(pkg, sheetPath, wsRels, worksheet, colUnitTwips) {
|
|
492
527
|
const empty = {
|
|
493
528
|
controls: [],
|
|
529
|
+
notes: [],
|
|
494
530
|
boxes: /* @__PURE__ */ new Map(),
|
|
531
|
+
anchoredBoxes: /* @__PURE__ */ new Map(),
|
|
495
532
|
nonPrinting: /* @__PURE__ */ new Set()
|
|
496
533
|
};
|
|
497
534
|
const relId = worksheet.legacyDrawingRelId;
|
|
@@ -501,9 +538,25 @@ function readLegacyVml(pkg, sheetPath, wsRels, worksheet) {
|
|
|
501
538
|
if (!part) return empty;
|
|
502
539
|
const activeXShapeIds = new Set((worksheet.formControls ?? []).map((fc) => fc.shapeId).filter((id) => id !== void 0));
|
|
503
540
|
const drawing = parseVmlDrawing(part.data);
|
|
541
|
+
const colWidthPt = makeColWidthPt(worksheet, colUnitTwips);
|
|
542
|
+
const rowHeightPt = makeRowHeightPt(worksheet);
|
|
543
|
+
const anchoredBoxes = /* @__PURE__ */ new Map();
|
|
544
|
+
for (const [id, anchor] of drawing.anchors) {
|
|
545
|
+
const box = anchoredBox(anchor, colWidthPt, rowHeightPt);
|
|
546
|
+
if (box) anchoredBoxes.set(id, box);
|
|
547
|
+
}
|
|
548
|
+
const colOnce = memoTrack(colWidthPt);
|
|
549
|
+
const rowOnce = memoTrack(rowHeightPt);
|
|
550
|
+
const onGrid = (box) => anchoredBox(pixelAnchor(box, colOnce, rowOnce), colOnce, rowOnce);
|
|
551
|
+
for (const [id, box] of drawing.boxes) {
|
|
552
|
+
if (anchoredBoxes.has(id)) continue;
|
|
553
|
+
const placed = onGrid(box);
|
|
554
|
+
if (placed) anchoredBoxes.set(id, placed);
|
|
555
|
+
}
|
|
504
556
|
const out = [];
|
|
505
557
|
for (const shape of drawing.controls) {
|
|
506
558
|
if (shape.shapeId !== void 0 && activeXShapeIds.has(shape.shapeId)) continue;
|
|
559
|
+
const box = (shape.anchor && anchoredBox(shape.anchor, colWidthPt, rowHeightPt)) ?? (shape.box && onGrid(shape.box)) ?? shape.box;
|
|
507
560
|
out.push({
|
|
508
561
|
objectType: shape.objectType,
|
|
509
562
|
...shape.caption ? {
|
|
@@ -511,18 +564,154 @@ function readLegacyVml(pkg, sheetPath, wsRels, worksheet) {
|
|
|
511
564
|
caption: shape.caption
|
|
512
565
|
} : {},
|
|
513
566
|
...shape.checked ? { checked: true } : {},
|
|
514
|
-
...
|
|
567
|
+
...box ? { box } : {},
|
|
515
568
|
...shape.fontSizePt !== void 0 ? { fontSizePt: shape.fontSizePt } : {}
|
|
516
569
|
});
|
|
517
570
|
}
|
|
518
571
|
return {
|
|
519
572
|
controls: out,
|
|
573
|
+
notes: drawing.notes,
|
|
520
574
|
boxes: drawing.boxes,
|
|
575
|
+
anchoredBoxes,
|
|
521
576
|
nonPrinting: drawing.nonPrinting
|
|
522
577
|
};
|
|
523
578
|
}
|
|
579
|
+
/**
|
|
580
|
+
* A legacy VML shape's box by the cells its `<x:Anchor>` names — on the grid
|
|
581
|
+
* we draw, whatever measure of the columns the producer wrote its `style` in.
|
|
582
|
+
*
|
|
583
|
+
* @param anchor The anchor: cells and pixels into them.
|
|
584
|
+
* @param colWidthPt The sheet's column widths.
|
|
585
|
+
* @param rowHeightPt The sheet's row heights.
|
|
586
|
+
* @returns The box, or undefined for an anchor that names no box on the sheet.
|
|
587
|
+
*/
|
|
588
|
+
function anchoredBox(anchor, colWidthPt, rowHeightPt) {
|
|
589
|
+
if (anchor[0] < 0 || anchor[2] < 0) return void 0;
|
|
590
|
+
const x0 = trackPt(anchor[0], anchor[1], colWidthPt);
|
|
591
|
+
const x1 = trackPt(anchor[4], anchor[5], colWidthPt);
|
|
592
|
+
const y0 = trackPt(anchor[2], anchor[3], rowHeightPt);
|
|
593
|
+
const y1 = trackPt(anchor[6], anchor[7], rowHeightPt);
|
|
594
|
+
return x1 > x0 && y1 > y0 ? {
|
|
595
|
+
xPt: x0,
|
|
596
|
+
yPt: y0,
|
|
597
|
+
widthPt: x1 - x0,
|
|
598
|
+
heightPt: y1 - y0
|
|
599
|
+
} : void 0;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* The cells a box placed by points alone stands on, as a `<x:Anchor>` would
|
|
603
|
+
* name them — counted the way Excel counts its own sheet when it writes such a
|
|
604
|
+
* box: columns in whole pixels, which ours are, and rows in whole pixels too,
|
|
605
|
+
* a row's points truncated (20.1pt is 26px). 45540_form_Footer.xlsx says so
|
|
606
|
+
* itself: a check box anchored at row 7 + 9px stands at `margin-top:184.5pt`,
|
|
607
|
+
* and its seven rows above come to the 237px that leaves only truncated.
|
|
608
|
+
* Taken as points on our grid, whose rows keep their fractions, a box placed
|
|
609
|
+
* that way stood the more rows above its cells the further down it was.
|
|
610
|
+
*
|
|
611
|
+
* @param box The box, in the producer's points.
|
|
612
|
+
* @param colWidthPt The sheet's column widths.
|
|
613
|
+
* @param rowHeightPt The sheet's row heights.
|
|
614
|
+
* @returns The anchor: cells, 0-based, and pixels into them.
|
|
615
|
+
*/
|
|
616
|
+
function pixelAnchor(box, colWidthPt, rowHeightPt) {
|
|
617
|
+
const colPx = (i) => Math.round(colWidthPt(i) / PT_PER_PX);
|
|
618
|
+
const rowPx = (i) => Math.trunc(rowHeightPt(i) / PT_PER_PX + 1e-6);
|
|
619
|
+
const locate = (pt, track, limit) => {
|
|
620
|
+
let i = 0;
|
|
621
|
+
let rest = pt / PT_PER_PX;
|
|
622
|
+
while (i < limit && rest >= track(i)) {
|
|
623
|
+
rest -= track(i);
|
|
624
|
+
i++;
|
|
625
|
+
}
|
|
626
|
+
return [i, rest];
|
|
627
|
+
};
|
|
628
|
+
const [c0, dx0] = locate(box.xPt, colPx, MAX_COLUMNS);
|
|
629
|
+
const [r0, dy0] = locate(box.yPt, rowPx, MAX_ROWS);
|
|
630
|
+
const [c1, dx1] = locate(box.xPt + box.widthPt, colPx, MAX_COLUMNS);
|
|
631
|
+
const [r1, dy1] = locate(box.yPt + box.heightPt, rowPx, MAX_ROWS);
|
|
632
|
+
return [
|
|
633
|
+
c0,
|
|
634
|
+
dx0,
|
|
635
|
+
r0,
|
|
636
|
+
dy0,
|
|
637
|
+
c1,
|
|
638
|
+
dx1,
|
|
639
|
+
r1,
|
|
640
|
+
dy1
|
|
641
|
+
];
|
|
642
|
+
}
|
|
643
|
+
/** A track accessor that answers each index once. */
|
|
644
|
+
function memoTrack(track) {
|
|
645
|
+
const seen = /* @__PURE__ */ new Map();
|
|
646
|
+
return (i) => {
|
|
647
|
+
let v = seen.get(i);
|
|
648
|
+
if (v === void 0) seen.set(i, v = track(i));
|
|
649
|
+
return v;
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
/** SpreadsheetML's grid: 16 384 columns, 1 048 576 rows. */
|
|
653
|
+
var MAX_COLUMNS = 16384;
|
|
654
|
+
var MAX_ROWS = 1048576;
|
|
655
|
+
/** Where `offsetPx` pixels into track `index` stands, in points from the first track. */
|
|
656
|
+
function trackPt(index, offsetPx, track) {
|
|
657
|
+
let total = 0;
|
|
658
|
+
for (let i = 0; i < index; i++) total += track(i);
|
|
659
|
+
return total + offsetPx * PT_PER_PX;
|
|
660
|
+
}
|
|
661
|
+
var PT_PER_PX = .75;
|
|
662
|
+
/**
|
|
663
|
+
* §18.7 + the legacy VML drawing — a comment's box, where its shape SHOWS it.
|
|
664
|
+
* The comments part holds what a note says; the VML shape says whether it is
|
|
665
|
+
* shown and where, and the two meet at the cell (`<x:Row>`/`<x:Column>`
|
|
666
|
+
* against the comment's `ref`).
|
|
667
|
+
*
|
|
668
|
+
* The box is placed by its `<x:Anchor>` — cells plus pixels — so it lands on
|
|
669
|
+
* the grid we draw, whatever widths the producer measured with; the shape's
|
|
670
|
+
* `style` is the fallback for an anchor that is missing or unusable
|
|
671
|
+
* (LibreOffice writes negative columns on a sheet that reads from the right).
|
|
672
|
+
*
|
|
673
|
+
* @param comments The sheet's comments, legacy and threaded.
|
|
674
|
+
* @param notes The note shapes of the sheet's legacy VML drawing.
|
|
675
|
+
* @param worksheet The sheet, for its column widths, row heights and merges.
|
|
676
|
+
* @returns The comments, a shown one carrying its box.
|
|
677
|
+
*/
|
|
678
|
+
function withShownNotes(comments, notes, worksheet, colUnitTwips) {
|
|
679
|
+
const shown = /* @__PURE__ */ new Map();
|
|
680
|
+
for (const n of notes) if (n.visible) shown.set(`${n.row}:${n.column}`, n);
|
|
681
|
+
if (shown.size === 0) return [...comments];
|
|
682
|
+
const colWidthPt = makeColWidthPt(worksheet, colUnitTwips);
|
|
683
|
+
const rowHeightPt = makeRowHeightPt(worksheet);
|
|
684
|
+
const along = trackPt;
|
|
685
|
+
return comments.map((c) => {
|
|
686
|
+
if (c.threaded) return c;
|
|
687
|
+
let cell;
|
|
688
|
+
try {
|
|
689
|
+
cell = parseCellRef(c.ref);
|
|
690
|
+
} catch {
|
|
691
|
+
return c;
|
|
692
|
+
}
|
|
693
|
+
const note = shown.get(`${cell.row}:${cell.column}`);
|
|
694
|
+
if (!note) return c;
|
|
695
|
+
let box = note.anchor ? anchoredBox(note.anchor, colWidthPt, rowHeightPt) : void 0;
|
|
696
|
+
if (!box && note.box && note.box.xPt >= 0 && note.box.yPt >= 0) box = note.box;
|
|
697
|
+
if (!box) return c;
|
|
698
|
+
const merge = worksheet.merges.find((m) => m.startRow === cell.row && m.startColumn === cell.column);
|
|
699
|
+
return {
|
|
700
|
+
...c,
|
|
701
|
+
shown: {
|
|
702
|
+
...box,
|
|
703
|
+
cornerXPt: along((merge?.endColumn ?? cell.column) + 1, 0, colWidthPt),
|
|
704
|
+
cornerYPt: along(cell.row, 0, rowHeightPt),
|
|
705
|
+
fillHex: note.fillHex,
|
|
706
|
+
lineHex: note.lineHex,
|
|
707
|
+
shadow: note.shadow,
|
|
708
|
+
...note.textAlign ? { textAlign: note.textAlign } : {}
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
});
|
|
712
|
+
}
|
|
524
713
|
function buildThemePalette(pkg, workbookRels) {
|
|
525
|
-
const palette = new Map(
|
|
714
|
+
const palette = new Map(OFFICE_2023_THEME_PALETTE);
|
|
526
715
|
for (const rel of workbookRels) {
|
|
527
716
|
if (!isOoxmlRel(rel.type, "theme")) continue;
|
|
528
717
|
const resolved = pkg.resolveRelatedPart(WORKBOOK_PART, rel);
|
|
@@ -574,6 +763,17 @@ function resolveTableStyle(t, palette) {
|
|
|
574
763
|
headerTextHex: "FFFFFF"
|
|
575
764
|
};
|
|
576
765
|
}
|
|
766
|
+
function withTableStyle(t, styles, theme) {
|
|
767
|
+
if (t.styleName === void 0) return t;
|
|
768
|
+
const style = resolveTableStyleFormat(t.styleName, styles, {
|
|
769
|
+
...theme ? { theme } : {},
|
|
770
|
+
indexed: INDEXED_COLORS
|
|
771
|
+
});
|
|
772
|
+
return style ? {
|
|
773
|
+
...t,
|
|
774
|
+
style
|
|
775
|
+
} : t;
|
|
776
|
+
}
|
|
577
777
|
function resolvePivotStyle(p, palette) {
|
|
578
778
|
const m = p.styleName ? /PivotStyle(Light|Medium|Dark)(\d+)/i.exec(p.styleName) : null;
|
|
579
779
|
if (!m) return p;
|
|
@@ -629,9 +829,24 @@ function resolveTableSlicerItems(cache, tableIndex, styles, sharedStrings, date1
|
|
|
629
829
|
}
|
|
630
830
|
return out;
|
|
631
831
|
}
|
|
832
|
+
function slicerStyleNumber(name) {
|
|
833
|
+
const prefix = /SlicerStyle/gi;
|
|
834
|
+
const isLetter = (i) => /[A-Za-z]/.test(name[i] ?? "");
|
|
835
|
+
const isDigit = (i) => /\d/.test(name[i] ?? "");
|
|
836
|
+
for (let found = prefix.exec(name); found; found = prefix.exec(name)) {
|
|
837
|
+
let end = prefix.lastIndex;
|
|
838
|
+
while (isLetter(end)) end++;
|
|
839
|
+
if (isDigit(end)) {
|
|
840
|
+
let digits = end;
|
|
841
|
+
while (isDigit(digits)) digits++;
|
|
842
|
+
return name.slice(end, digits);
|
|
843
|
+
}
|
|
844
|
+
prefix.lastIndex = end;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
632
847
|
function resolveSlicerStyle(styleName, palette) {
|
|
633
|
-
const
|
|
634
|
-
const column =
|
|
848
|
+
const number = styleName ? slicerStyleNumber(styleName) : void 0;
|
|
849
|
+
const column = number !== void 0 ? (Number(number) - 1) % 7 : 1;
|
|
635
850
|
const base = column === 0 ? "7F7F7F" : palette.get(`accent${column}`) ?? "4472C4";
|
|
636
851
|
return {
|
|
637
852
|
headerHex: base,
|
|
@@ -213,22 +213,23 @@ function worksheetXml(grid, tableRelIds = [], drawingRelId) {
|
|
|
213
213
|
return `<row r="${r + 1}"${heightAttrs}>${cells.map(cellXml).join("")}</row>`;
|
|
214
214
|
}).join("");
|
|
215
215
|
const mergesXml = grid.merges.length > 0 ? `<mergeCells count="${grid.merges.length}">${grid.merges.map((m) => `<mergeCell ref="${cellRef(m.startRow, m.startColumn)}:${cellRef(m.endRow, m.endColumn)}"/>`).join("")}</mergeCells>` : "";
|
|
216
|
-
return XML_DECL + `<worksheet xmlns="${MAIN_NS}" xmlns:r="${R_NS}">` + (grid.fitToPage ? "<sheetPr><pageSetUpPr fitToPage=\"1\"/></sheetPr>" : "") + dimension + sheetViewsXml(grid.pane) + colsXml + `<sheetData>${rowsXml}</sheetData>` + mergesXml + conditionalFormattingXml(grid.conditionalFormats) + dataValidationsXml(grid.dataValidations) + printOptionsXml(grid.printOptions) + pageMarginsXml(grid.pageMargins) + pageSetupXml(grid.pageSetup) + breaksXml("rowBreaks", grid.rowBreaks) + breaksXml("colBreaks", grid.colBreaks) + (drawingRelId ? `<drawing r:id="${drawingRelId}"/>` : "") + (tableRelIds.length > 0 ? `<tableParts count="${tableRelIds.length}">${tableRelIds.map((id) => `<tablePart r:id="${id}"/>`).join("")}</tableParts>` : "") + sparklineExtXml(grid.sparklines) + "</worksheet>";
|
|
216
|
+
return XML_DECL + `<worksheet xmlns="${MAIN_NS}" xmlns:r="${R_NS}">` + (grid.fitToPage ? "<sheetPr><pageSetUpPr fitToPage=\"1\"/></sheetPr>" : "") + dimension + sheetViewsXml(grid.pane, grid.showGridLines, grid.rightToLeft) + colsXml + `<sheetData>${rowsXml}</sheetData>` + mergesXml + conditionalFormattingXml(grid.conditionalFormats) + dataValidationsXml(grid.dataValidations) + printOptionsXml(grid.printOptions) + pageMarginsXml(grid.pageMargins) + pageSetupXml(grid.pageSetup) + breaksXml("rowBreaks", grid.rowBreaks) + breaksXml("colBreaks", grid.colBreaks) + (drawingRelId ? `<drawing r:id="${drawingRelId}"/>` : "") + (tableRelIds.length > 0 ? `<tableParts count="${tableRelIds.length}">${tableRelIds.map((id) => `<tablePart r:id="${id}"/>`).join("")}</tableParts>` : "") + sparklineExtXml(grid.sparklines) + "</worksheet>";
|
|
217
217
|
}
|
|
218
|
-
function sheetViewsXml(pane) {
|
|
219
|
-
|
|
218
|
+
function sheetViewsXml(pane, showGridLines, rightToLeft) {
|
|
219
|
+
const grid = (showGridLines === false ? " showGridLines=\"0\"" : "") + (rightToLeft ? " rightToLeft=\"1\"" : "");
|
|
220
|
+
if (!pane || pane.frozenRows <= 0 && pane.frozenCols <= 0) return grid ? `<sheetViews><sheetView${grid} workbookViewId="0"/></sheetViews>` : "";
|
|
220
221
|
const { frozenRows, frozenCols } = pane;
|
|
221
222
|
const topLeftCell = cellRef(frozenRows, frozenCols);
|
|
222
223
|
const activePane = frozenRows > 0 && frozenCols > 0 ? "bottomRight" : frozenRows > 0 ? "bottomLeft" : "topRight";
|
|
223
|
-
return `<sheetViews><sheetView workbookViewId="0"><pane${(frozenCols > 0 ? ` xSplit="${frozenCols}"` : "") + (frozenRows > 0 ? ` ySplit="${frozenRows}"` : "") + ` topLeftCell="${topLeftCell}" activePane="${activePane}" state="frozen"`}/></sheetView></sheetViews>`;
|
|
224
|
+
return `<sheetViews><sheetView${grid} workbookViewId="0"><pane${(frozenCols > 0 ? ` xSplit="${frozenCols}"` : "") + (frozenRows > 0 ? ` ySplit="${frozenRows}"` : "") + ` topLeftCell="${topLeftCell}" activePane="${activePane}" state="frozen"`}/></sheetView></sheetViews>`;
|
|
224
225
|
}
|
|
225
226
|
function tableXml(t, id) {
|
|
226
227
|
const ref = rangeRef(t.ref);
|
|
227
228
|
const name = t.name ?? `Table${id}`;
|
|
228
229
|
const ncols = t.ref.endColumn - t.ref.startColumn + 1;
|
|
229
|
-
const columns = Array.from({ length: ncols }, (_, c) => `<tableColumn id="${c + 1}" name="Column${c + 1}"/>`).join("");
|
|
230
|
+
const columns = Array.from({ length: ncols }, (_, c) => `<tableColumn id="${c + 1}" name="${escapeAttr(t.columns?.[c] ?? `Column${c + 1}`)}"/>`).join("");
|
|
230
231
|
const styleInfo = t.styleName ? `<tableStyleInfo name="${escapeAttr(t.styleName)}" showFirstColumn="${t.showFirstColumn ? 1 : 0}" showLastColumn="${t.showLastColumn ? 1 : 0}" showRowStripes="${t.showRowStripes ? 1 : 0}" showColumnStripes="${t.showColumnStripes ? 1 : 0}"/>` : "";
|
|
231
|
-
return XML_DECL + `<table xmlns="${MAIN_NS}" id="${id}" name="${escapeAttr(name)}" displayName="${escapeAttr(name)}" ref="${ref}"${t.headerRowCount !== 1 ? ` headerRowCount="${t.headerRowCount}"` : ""}
|
|
232
|
+
return XML_DECL + `<table xmlns="${MAIN_NS}" id="${id}" name="${escapeAttr(name)}" displayName="${escapeAttr(name)}" ref="${ref}"${t.headerRowCount !== 1 ? ` headerRowCount="${t.headerRowCount}"` : ""}${t.totalsRowCount ? ` totalsRowCount="${t.totalsRowCount}"` : " totalsRowShown=\"0\""}>` + (t.autoFilter ? `<autoFilter ref="${ref}"/>` : "") + `<tableColumns count="${ncols}">${columns}</tableColumns>` + styleInfo + "</table>";
|
|
232
233
|
}
|
|
233
234
|
function conditionalFormattingXml(cfs) {
|
|
234
235
|
if (!cfs || cfs.length === 0) return "";
|
|
@@ -346,7 +347,7 @@ function edgeXml(name, edge) {
|
|
|
346
347
|
function cellXfXml(xf) {
|
|
347
348
|
const apply = applyAttr("applyNumberFormat", xf.applyNumberFormat) + applyAttr("applyFont", xf.applyFont) + applyAttr("applyFill", xf.applyFill) + applyAttr("applyBorder", xf.applyBorder) + applyAttr("applyAlignment", xf.applyAlignment);
|
|
348
349
|
const a = xf.alignment;
|
|
349
|
-
const alignment = a ? `<alignment${a.horizontal ? ` horizontal="${a.horizontal}"` : ""}${a.vertical ? ` vertical="${a.vertical}"` : ""}${a.wrapText ? " wrapText=\"1\"" : ""}${a.textRotation !== void 0 ? ` textRotation="${a.textRotation}"` : ""}${a.indent !== void 0 ? ` indent="${a.indent}"` : ""}${a.shrinkToFit ? " shrinkToFit=\"1\"" : ""}/>` : "";
|
|
350
|
+
const alignment = a ? `<alignment${a.horizontal ? ` horizontal="${a.horizontal}"` : ""}${a.vertical ? ` vertical="${a.vertical}"` : ""}${a.wrapText ? " wrapText=\"1\"" : ""}${a.textRotation !== void 0 ? ` textRotation="${a.textRotation}"` : ""}${a.indent !== void 0 ? ` indent="${a.indent}"` : ""}${a.shrinkToFit ? " shrinkToFit=\"1\"" : ""}${a.readingOrder ? ` readingOrder="${a.readingOrder === "rtl" ? 2 : 1}"` : ""}/>` : "";
|
|
350
351
|
return `<xf numFmtId="${xf.numFmtId}" fontId="${xf.fontId}" fillId="${xf.fillId}" borderId="${xf.borderId}"${apply}>` + alignment + "</xf>";
|
|
351
352
|
}
|
|
352
353
|
function applyAttr(name, value) {
|