reamkit 1.15.4 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/core/bidi/segments.js +1 -2
- package/dist/esm/core/converter/facade.d.ts +5 -0
- package/dist/esm/core/converter/project.js +5 -1
- package/dist/esm/core/converter/ream.d.ts +6 -0
- package/dist/esm/core/converter/ream.js +34 -8
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +659 -7
- package/dist/esm/core/drawingml/chart-geometry.d.ts +34 -10
- package/dist/esm/core/drawingml/chart-geometry.js +424 -92
- package/dist/esm/core/drawingml/chart-parser.js +301 -11
- package/dist/esm/core/drawingml/colors.d.ts +7 -7
- package/dist/esm/core/drawingml/colors.js +84 -18
- package/dist/esm/core/drawingml/preset-geometry.js +240 -6
- package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
- package/dist/esm/core/drawingml/shape-render.js +116 -3
- package/dist/esm/core/drawingml/sparkline-geometry.js +6 -4
- package/dist/esm/core/drawingml/theme-parser.d.ts +51 -0
- package/dist/esm/core/drawingml/theme-parser.js +92 -1
- package/dist/esm/core/font/measure.d.ts +5 -0
- package/dist/esm/core/font/measure.js +21 -1
- package/dist/esm/core/font/ttf-subset.js +26 -1
- package/dist/esm/core/images.d.ts +2 -2
- package/dist/esm/core/images.js +353 -43
- package/dist/esm/core/indexed-colors.d.ts +11 -0
- package/dist/esm/core/indexed-colors.js +81 -0
- package/dist/esm/core/ir/flow.d.ts +23 -1
- package/dist/esm/core/ir/sheet.d.ts +61 -0
- package/dist/esm/{excel → core}/number-format.d.ts +37 -0
- package/dist/esm/core/number-format.js +800 -0
- package/dist/esm/core/numbering/apply.d.ts +5 -3
- package/dist/esm/core/numbering/apply.js +42 -11
- package/dist/esm/core/numbering/index.js +2 -0
- package/dist/esm/core/numbering/state.d.ts +13 -1
- package/dist/esm/core/numbering/state.js +256 -15
- package/dist/esm/core/opc/alternate-content.d.ts +13 -0
- package/dist/esm/core/opc/alternate-content.js +72 -0
- package/dist/esm/core/opc/core-properties.js +1 -0
- package/dist/esm/core/opc/package.d.ts +14 -1
- package/dist/esm/core/opc/package.js +43 -4
- package/dist/esm/core/opc/relationships.js +1 -0
- package/dist/esm/core/opc/xml-entities.d.ts +12 -0
- package/dist/esm/core/opc/xml-entities.js +91 -0
- package/dist/esm/core/po-helpers.js +16 -1
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +137 -0
- package/dist/esm/core/style-cascade/resolver.js +66 -11
- package/dist/esm/core/style-cascade/table.js +35 -11
- package/dist/esm/core/style-cascade/types.d.ts +42 -1
- package/dist/esm/core/style-cascade/types.js +4 -0
- package/dist/esm/core/vector.d.ts +30 -0
- package/dist/esm/excel/activex-parser.js +1 -0
- package/dist/esm/excel/column-bands.d.ts +26 -1
- package/dist/esm/excel/column-bands.js +156 -20
- package/dist/esm/excel/comments-parser.js +5 -3
- package/dist/esm/excel/conditional-format.d.ts +25 -2
- package/dist/esm/excel/conditional-format.js +63 -19
- package/dist/esm/excel/escaped-text.d.ts +9 -0
- package/dist/esm/excel/escaped-text.js +20 -0
- package/dist/esm/excel/form-control-parser.js +1 -0
- package/dist/esm/excel/formula/dates.js +1 -1
- package/dist/esm/excel/header-footer.d.ts +9 -1
- package/dist/esm/excel/header-footer.js +162 -14
- package/dist/esm/excel/index.d.ts +1 -1
- package/dist/esm/excel/index.js +2 -2
- package/dist/esm/excel/pivot-table-parser.js +1 -0
- package/dist/esm/excel/print-model.d.ts +75 -0
- package/dist/esm/excel/print-model.js +899 -77
- package/dist/esm/excel/printer-settings.d.ts +16 -0
- package/dist/esm/excel/printer-settings.js +36 -0
- package/dist/esm/excel/rich-value.d.ts +13 -0
- package/dist/esm/excel/rich-value.js +120 -0
- package/dist/esm/excel/shared-strings-parser.js +11 -7
- package/dist/esm/excel/sheet-drawing.d.ts +11 -0
- package/dist/esm/excel/sheet-drawing.js +26 -3
- package/dist/esm/excel/sheet-shape-parser.d.ts +53 -1
- package/dist/esm/excel/sheet-shape-parser.js +461 -32
- package/dist/esm/excel/sheet-to-flow.d.ts +23 -2
- package/dist/esm/excel/sheet-to-flow.js +553 -36
- package/dist/esm/excel/slicer-parser.js +1 -0
- package/dist/esm/excel/styles-parser.d.ts +30 -2
- package/dist/esm/excel/styles-parser.js +177 -40
- package/dist/esm/excel/table-parser.js +1 -0
- package/dist/esm/excel/vml-drawing.d.ts +68 -0
- package/dist/esm/excel/vml-drawing.js +158 -0
- package/dist/esm/excel/workbook-parser.d.ts +5 -0
- package/dist/esm/excel/workbook-parser.js +5 -1
- package/dist/esm/excel/worksheet-parser.d.ts +2 -1
- package/dist/esm/excel/worksheet-parser.js +150 -61
- package/dist/esm/excel/xlsx-reader.js +242 -11
- package/dist/esm/excel/xlsx-to-pdf.js +12 -1
- package/dist/esm/html/html-writer.js +29 -6
- package/dist/esm/layout/page-doc.d.ts +87 -1
- package/dist/esm/layout/styled-layout.d.ts +46 -2
- package/dist/esm/layout/styled-layout.js +2345 -274
- package/dist/esm/pdf/cid-font.js +20 -9
- package/dist/esm/pdf/objects.d.ts +13 -0
- package/dist/esm/pdf/objects.js +18 -1
- package/dist/esm/pdf/shading.js +76 -6
- package/dist/esm/pdf/styled-page-emitter.js +355 -49
- package/dist/esm/pdf/text-page-renderer.js +1 -0
- package/dist/esm/pdf/vector-graphics.d.ts +31 -2
- package/dist/esm/pdf/vector-graphics.js +103 -3
- package/dist/esm/pptx/pptx-reader.js +2 -0
- package/dist/esm/pptx/slide-parser.d.ts +21 -4
- package/dist/esm/pptx/slide-parser.js +98 -24
- package/dist/esm/svg/svg-writer.js +23 -4
- package/dist/esm/word/document-parser.d.ts +96 -7
- package/dist/esm/word/document-parser.js +538 -116
- package/dist/esm/word/docx-reader.js +135 -43
- package/dist/esm/word/docx-writer.js +6 -1
- package/dist/esm/word/drawing-parser.d.ts +86 -5
- package/dist/esm/word/drawing-parser.js +1590 -54
- package/dist/esm/word/index.d.ts +4 -4
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +108 -21
- package/dist/esm/word/paragraph-properties.d.ts +11 -1
- package/dist/esm/word/paragraph-properties.js +219 -10
- package/dist/esm/word/run-properties.js +45 -1
- package/dist/esm/word/settings-parser.d.ts +24 -0
- package/dist/esm/word/settings-parser.js +32 -5
- package/dist/esm/word/shading.d.ts +11 -0
- package/dist/esm/word/shading.js +64 -0
- package/dist/esm/word/styles-parser.js +9 -2
- package/dist/esm/word/table-parser.d.ts +9 -1
- package/dist/esm/word/table-parser.js +182 -30
- package/package.json +7 -3
- package/dist/esm/excel/number-format.js +0 -476
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import { pt } from "../core/ir/units.js";
|
|
2
2
|
import { EMPTY_STYLE_SHEET, resolveBodyStyles } from "../core/style-cascade/resolver.js";
|
|
3
3
|
import "../core/style-cascade/index.js";
|
|
4
|
-
import { resolvePrintArea, resolvePrintTitleRows, sectionFromWorksheet, slicerTable, worksheetToBody } from "./print-model.js";
|
|
4
|
+
import { cellPaintsVisibly, printableHeightPt, printableWidthPt, resolvePrintArea, resolvePrintTitleRows, sectionFromWorksheet, slicerTable, worksheetToBody } from "./print-model.js";
|
|
5
5
|
import { buildHeaderFooterContent } from "./header-footer.js";
|
|
6
6
|
//#region src/excel/sheet-to-flow.ts
|
|
7
7
|
var HEADER_REL = "_xlsxHeaderDefault";
|
|
8
8
|
var FOOTER_REL = "_xlsxFooterDefault";
|
|
9
|
+
var PAGE_BREAK_PARAGRAPH = {
|
|
10
|
+
properties: {
|
|
11
|
+
pageBreakBefore: true,
|
|
12
|
+
spacingLine: pt(0),
|
|
13
|
+
spacingLineRule: "exact"
|
|
14
|
+
},
|
|
15
|
+
runs: []
|
|
16
|
+
};
|
|
9
17
|
/**
|
|
10
18
|
* Project a {@link SheetDoc} into a {@link FlowDoc} (E-SHEET SA2): each grid sheet
|
|
11
19
|
* becomes flow blocks (a table + chart/picture/shape/slicer frames, then comment
|
|
12
|
-
* / control listings), with sheets after the first starting on a new page.
|
|
13
|
-
*
|
|
20
|
+
* / control listings), with sheets after the first starting on a new page. Each
|
|
21
|
+
* sheet gets its own section — its page geometry and its own header/footer.
|
|
14
22
|
*
|
|
15
23
|
* @param sheet The SpreadsheetML IR tree.
|
|
16
24
|
* @param options Projection knobs (the W9 reference date).
|
|
@@ -23,64 +31,111 @@ function projectSheetDoc(sheet, options = {}) {
|
|
|
23
31
|
let firstSheetSection;
|
|
24
32
|
const headersFooters = /* @__PURE__ */ new Map();
|
|
25
33
|
const sheetGrids = new Map(sheet.sheets.map((s) => [s.name, s.grid]));
|
|
34
|
+
let printed = 0;
|
|
35
|
+
let printableSheets = sheet.sheets.filter((s) => !s.hidden).length;
|
|
36
|
+
const visible = sheet.sheets.filter((s) => !s.hidden);
|
|
37
|
+
const fallbackSheet = visible.some((s) => sheetPrintsAnything(s, sheet.styles)) ? void 0 : visible.find((s) => hasHeaderOrFooter(s)) ?? visible[0];
|
|
26
38
|
for (let sheetIdx = 0; sheetIdx < sheet.sheets.length; sheetIdx++) {
|
|
27
39
|
const ws = sheet.sheets[sheetIdx];
|
|
28
|
-
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
});
|
|
40
|
+
if (ws.hidden) continue;
|
|
41
|
+
if (!sheetPrintsAnything(ws, sheet.styles) && ws !== fallbackSheet) {
|
|
42
|
+
printableSheets--;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const scaleSink = { value: 1 };
|
|
46
|
+
const bandSink = { lefts: [0] };
|
|
47
|
+
const drawingExtentPt = drawingReachPt(ws);
|
|
38
48
|
const printArea = resolvePrintArea(sheet.definedNames, sheetIdx);
|
|
39
49
|
const titleRows = resolvePrintTitleRows(sheet.definedNames, sheetIdx);
|
|
40
|
-
const
|
|
41
|
-
body.push(...worksheetToBody(ws.grid, sheet.sharedStrings, sheet.styles, sheet.date1904, {
|
|
50
|
+
const gridBody = worksheetToBody(ws.grid, sheet.sharedStrings, sheet.styles, sheet.date1904, {
|
|
42
51
|
...printArea ? { printArea } : {},
|
|
43
52
|
...titleRows ? { titleRows } : {},
|
|
44
|
-
gridLines,
|
|
53
|
+
gridLines: ws.grid.printOptions?.gridLines === true,
|
|
45
54
|
sheetGrids,
|
|
46
55
|
sheetName: ws.name,
|
|
47
56
|
definedNames: sheet.definedNames,
|
|
48
57
|
...ws.hyperlinks ? { hyperlinks: ws.hyperlinks } : {},
|
|
49
58
|
...sheet.sharedStringRuns ? { sharedStringRuns: sheet.sharedStringRuns } : {},
|
|
50
59
|
...options.now ? { now: options.now } : {},
|
|
51
|
-
...options.
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
...options.digitWidthPt !== void 0 ? { digitWidthPt: options.digitWidthPt } : {},
|
|
61
|
+
...sheet.styles.fonts[0]?.sizePt !== void 0 ? { defaultFontPt: sheet.styles.fonts[0].sizePt } : {},
|
|
62
|
+
...options.losses ? { losses: options.losses } : {},
|
|
63
|
+
scaleSink,
|
|
64
|
+
bandSink,
|
|
65
|
+
...drawingExtentPt ? { drawingExtentPt } : {}
|
|
66
|
+
});
|
|
67
|
+
const sheetSection = withHeaderFooter(sectionFromWorksheet(ws.grid), ws, headersFooters, scaleSink.value, sheet.styles.fonts[0]?.sizePt, printed, options.fileName, sheet.themePalette, options.now);
|
|
68
|
+
if (printed === 0) firstSheetSection = sheetSection;
|
|
69
|
+
sheetSections.push(sheetSection);
|
|
70
|
+
if (printed > 0) body.push({
|
|
71
|
+
kind: "paragraph",
|
|
72
|
+
paragraph: PAGE_BREAK_PARAGRAPH
|
|
73
|
+
});
|
|
74
|
+
const drawings = [];
|
|
75
|
+
for (const ref of ws.charts ?? []) drawings.push({
|
|
54
76
|
kind: "chart",
|
|
55
77
|
chart: {
|
|
78
|
+
...anchorFloat(ref.xPt, ref.yPt, scaleSink.value),
|
|
56
79
|
chartRelId: ref.chartPartPath,
|
|
57
|
-
width: pt(ref.widthPt),
|
|
58
|
-
height: pt(ref.heightPt),
|
|
80
|
+
width: pt(ref.widthPt * scaleSink.value),
|
|
81
|
+
height: pt(ref.heightPt * scaleSink.value),
|
|
59
82
|
paragraphProperties: {}
|
|
60
83
|
}
|
|
61
84
|
});
|
|
62
|
-
for (const img of ws.images ?? [])
|
|
85
|
+
for (const img of ws.images ?? []) drawings.push({
|
|
63
86
|
kind: "image",
|
|
64
87
|
image: {
|
|
88
|
+
...anchorFloat(img.xPt, img.yPt, scaleSink.value),
|
|
65
89
|
resource: img.resourceId,
|
|
66
|
-
width: pt(img.widthPt),
|
|
67
|
-
height: pt(img.heightPt),
|
|
90
|
+
width: pt(img.widthPt * scaleSink.value),
|
|
91
|
+
height: pt(img.heightPt * scaleSink.value),
|
|
68
92
|
paragraphProperties: {}
|
|
69
93
|
}
|
|
70
94
|
});
|
|
71
|
-
for (const shape of ws.shapes ?? [])
|
|
95
|
+
for (const shape of ws.shapes ?? []) drawings.push({
|
|
72
96
|
kind: "shape",
|
|
73
|
-
shape
|
|
97
|
+
shape: centreShape(scaleShape(shape, scaleSink.value), ws.grid, drawingExtentPt, scaleSink.value)
|
|
74
98
|
});
|
|
99
|
+
const controlBlocks = controlShapeBlocks(ws.formControls, ws.activeXControls);
|
|
100
|
+
const drawingBands = gridBody.length === 0 ? bandDrawings(controlBlocks, printableHeightPt(ws.grid), scaleSink.value, DOWN).flatMap((row) => bandDrawings(row, printableWidthPt(ws.grid), scaleSink.value)) : [controlBlocks];
|
|
101
|
+
for (let band = 0; band < drawingBands.length; band++) {
|
|
102
|
+
if (band > 0) drawings.push({
|
|
103
|
+
kind: "paragraph",
|
|
104
|
+
paragraph: PAGE_BREAK_PARAGRAPH
|
|
105
|
+
});
|
|
106
|
+
for (const shape of drawingBands[band]) drawings.push({
|
|
107
|
+
kind: "shape",
|
|
108
|
+
shape: centreShape(scaleShape(shape, scaleSink.value), ws.grid, drawingExtentPt, scaleSink.value)
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
body.push(...withDrawingsByBand(drawings, gridBody, bandSink.lefts));
|
|
75
112
|
for (const slicer of ws.slicers ?? []) body.push({
|
|
76
113
|
kind: "table",
|
|
77
114
|
table: slicerTable(slicer)
|
|
78
115
|
});
|
|
79
|
-
|
|
116
|
+
const printComments = ws.grid.pageSetup?.cellComments === "atEnd" || ws.grid.pageSetup?.cellComments === "asDisplayed";
|
|
117
|
+
if (ws.comments && ws.comments.length > 0) if (printComments) body.push(...commentBlocks(ws.comments));
|
|
118
|
+
else options.losses?.push({
|
|
119
|
+
severity: "dropped",
|
|
120
|
+
feature: "comments",
|
|
121
|
+
detail: `${ws.comments.length} cell note(s) not printed — <pageSetup cellComments> is "${ws.grid.pageSetup?.cellComments ?? "none"}"`,
|
|
122
|
+
where: `sheet "${ws.name}"`
|
|
123
|
+
});
|
|
80
124
|
if (ws.formControls && ws.formControls.length > 0) body.push(...formControlBlocks(ws.formControls));
|
|
81
125
|
if (ws.activeXControls && ws.activeXControls.length > 0) body.push(...activeXBlocks(ws.activeXControls));
|
|
82
126
|
sheetEnds.push(body.length);
|
|
127
|
+
printed++;
|
|
83
128
|
}
|
|
129
|
+
if (sheet.embeddedObjects) options.losses?.push({
|
|
130
|
+
severity: "dropped",
|
|
131
|
+
feature: "shapes",
|
|
132
|
+
detail: `${String(sheet.embeddedObjects)} embedded object(s) not rendered — an OLE embedding draws as an icon from a metafile preview`
|
|
133
|
+
});
|
|
134
|
+
if (sheet.metafilePictures) options.losses?.push({
|
|
135
|
+
severity: "dropped",
|
|
136
|
+
feature: "images",
|
|
137
|
+
detail: `${String(sheet.metafilePictures)} picture(s) not rendered — a WMF/EMF/PICT metafile is replayed, not embedded; the anchor keeps its space`
|
|
138
|
+
});
|
|
84
139
|
const sections = sheetSections.length > 1 ? sheetSections.map((properties, i) => ({
|
|
85
140
|
properties,
|
|
86
141
|
endIndex: sheetEnds[i]
|
|
@@ -127,7 +182,364 @@ function commentBlocks(comments) {
|
|
|
127
182
|
}
|
|
128
183
|
return out;
|
|
129
184
|
}
|
|
185
|
+
var RADIO_DIAMETER_PT = 8.4;
|
|
186
|
+
var RADIO_RING_PT = .6;
|
|
187
|
+
var RADIO_DOT_INSET_PT = 1.2;
|
|
188
|
+
var CHECKBOX_SIDE_PT = 8.4;
|
|
189
|
+
var CAPTION_GUTTER_PT = 11.5;
|
|
190
|
+
var CONTROL_LINE_PT = .75;
|
|
191
|
+
var GROUP_BOX_GREY = "808080";
|
|
192
|
+
var DEFAULT_FORM_CONTROL_PT = 8;
|
|
193
|
+
var DEFAULT_ACTIVEX_CONTROL_PT = 10;
|
|
194
|
+
function formControlGlyph(objectType) {
|
|
195
|
+
switch ((objectType ?? "").toLowerCase()) {
|
|
196
|
+
case "radio": return "radio";
|
|
197
|
+
case "checkbox": return "checkbox";
|
|
198
|
+
case "gbox": return "group";
|
|
199
|
+
case "button":
|
|
200
|
+
case "buttons": return "button";
|
|
201
|
+
case "label": return "label";
|
|
202
|
+
default: return "frame";
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function activeXGlyph(type) {
|
|
206
|
+
switch (type) {
|
|
207
|
+
case "option": return "radio";
|
|
208
|
+
case "checkbox": return "checkbox";
|
|
209
|
+
case "button":
|
|
210
|
+
case "toggle": return "button";
|
|
211
|
+
case "label": return "label";
|
|
212
|
+
default: return "frame";
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/** A floating shape at `box`, sized and positioned in sheet points. */
|
|
216
|
+
function controlShape(box, dx, dy, widthPt, heightPt, rest) {
|
|
217
|
+
return {
|
|
218
|
+
float: {
|
|
219
|
+
wrap: "none",
|
|
220
|
+
posH: {
|
|
221
|
+
relativeFrom: "margin",
|
|
222
|
+
offsetPt: pt(box.xPt + dx)
|
|
223
|
+
},
|
|
224
|
+
posV: {
|
|
225
|
+
relativeFrom: "margin",
|
|
226
|
+
offsetPt: pt(box.yPt + dy)
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
width: pt(widthPt),
|
|
230
|
+
height: pt(heightPt),
|
|
231
|
+
...rest,
|
|
232
|
+
paragraphProperties: {}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* A control drawn where the document puts it (E-SHEET W8/W10), as the widget it
|
|
237
|
+
* is: an option button's ring and dot, a check box, a group box's frame, a
|
|
238
|
+
* push button's outline — each with its caption beside or inside it.
|
|
239
|
+
*
|
|
240
|
+
* Listing the captions after the grid instead was a stand-in for having no
|
|
241
|
+
* geometry to place them with. It read as a paragraph of ASCII where
|
|
242
|
+
* tdf111980_radioButtons.xlsx has eleven widgets spread across the sheet, the
|
|
243
|
+
* furthest of them 18cm from where we drew it.
|
|
244
|
+
*/
|
|
245
|
+
function controlShapes(box, glyph, caption, checked, fontSizePt) {
|
|
246
|
+
const out = [];
|
|
247
|
+
const noFill = { kind: "none" };
|
|
248
|
+
const rect = {
|
|
249
|
+
kind: "preset",
|
|
250
|
+
preset: "rect"
|
|
251
|
+
};
|
|
252
|
+
const ellipse = {
|
|
253
|
+
kind: "preset",
|
|
254
|
+
preset: "ellipse"
|
|
255
|
+
};
|
|
256
|
+
const grey = {
|
|
257
|
+
colorHex: GROUP_BOX_GREY,
|
|
258
|
+
width: pt(CONTROL_LINE_PT)
|
|
259
|
+
};
|
|
260
|
+
const black = {
|
|
261
|
+
colorHex: "000000",
|
|
262
|
+
width: pt(CONTROL_LINE_PT)
|
|
263
|
+
};
|
|
264
|
+
if (glyph === "radio" || glyph === "checkbox") {
|
|
265
|
+
const side = glyph === "radio" ? RADIO_DIAMETER_PT : CHECKBOX_SIDE_PT;
|
|
266
|
+
const top = Math.max(0, (box.heightPt - side) / 2);
|
|
267
|
+
out.push(controlShape(box, 0, top, side, side, {
|
|
268
|
+
geometry: glyph === "radio" ? ellipse : rect,
|
|
269
|
+
fill: {
|
|
270
|
+
kind: "solid",
|
|
271
|
+
colorHex: "FFFFFF"
|
|
272
|
+
},
|
|
273
|
+
line: {
|
|
274
|
+
colorHex: "000000",
|
|
275
|
+
width: pt(RADIO_RING_PT)
|
|
276
|
+
}
|
|
277
|
+
}));
|
|
278
|
+
if (checked) {
|
|
279
|
+
const mark = side - 2 * RADIO_DOT_INSET_PT;
|
|
280
|
+
if (glyph === "radio") out.push(controlShape(box, RADIO_DOT_INSET_PT, top + RADIO_DOT_INSET_PT, mark, mark, {
|
|
281
|
+
geometry: ellipse,
|
|
282
|
+
fill: {
|
|
283
|
+
kind: "solid",
|
|
284
|
+
colorHex: "000000"
|
|
285
|
+
}
|
|
286
|
+
}));
|
|
287
|
+
else for (const flipV of [false, true]) out.push(controlShape(box, RADIO_DOT_INSET_PT, top + RADIO_DOT_INSET_PT, mark, mark, {
|
|
288
|
+
geometry: {
|
|
289
|
+
kind: "preset",
|
|
290
|
+
preset: "line"
|
|
291
|
+
},
|
|
292
|
+
fill: noFill,
|
|
293
|
+
line: {
|
|
294
|
+
colorHex: "000000",
|
|
295
|
+
width: pt(RADIO_RING_PT)
|
|
296
|
+
},
|
|
297
|
+
...flipV ? { transform: { flipV: true } } : {}
|
|
298
|
+
}));
|
|
299
|
+
}
|
|
300
|
+
} else if (glyph !== "label") out.push(controlShape(box, 0, 0, box.widthPt, box.heightPt, {
|
|
301
|
+
geometry: rect,
|
|
302
|
+
fill: noFill,
|
|
303
|
+
line: glyph === "group" ? grey : black
|
|
304
|
+
}));
|
|
305
|
+
if (caption !== void 0 && caption.length > 0) {
|
|
306
|
+
const inset = glyph === "radio" || glyph === "checkbox" ? CAPTION_GUTTER_PT : 3;
|
|
307
|
+
const runs = [{
|
|
308
|
+
text: caption,
|
|
309
|
+
properties: { fontSizePt: pt(fontSizePt) }
|
|
310
|
+
}];
|
|
311
|
+
out.push(controlShape(box, 0, 0, box.widthPt, box.heightPt, {
|
|
312
|
+
geometry: rect,
|
|
313
|
+
fill: noFill,
|
|
314
|
+
text: {
|
|
315
|
+
content: [{
|
|
316
|
+
kind: "paragraph",
|
|
317
|
+
paragraph: {
|
|
318
|
+
properties: glyph === "button" ? { alignment: "center" } : {},
|
|
319
|
+
runs
|
|
320
|
+
}
|
|
321
|
+
}],
|
|
322
|
+
insetLeft: pt(inset),
|
|
323
|
+
insetTop: pt(1),
|
|
324
|
+
insetRight: pt(1),
|
|
325
|
+
insetBottom: pt(1),
|
|
326
|
+
anchor: glyph === "group" ? "t" : "ctr"
|
|
327
|
+
}
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
return out;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Split floating drawings into page-wide bands, left to right — the "down, then
|
|
334
|
+
* over" order a wide sheet prints in (§18.3.1.63 `pageOrder`), applied to the
|
|
335
|
+
* drawing layer when there is no grid whose column bands it could follow.
|
|
336
|
+
*
|
|
337
|
+
* Each band is shifted back to the page's left margin, so band 2 starts where
|
|
338
|
+
* the printable width ran out. A drawing straddling the boundary belongs to the
|
|
339
|
+
* band its left edge is in, which is where the reference draws it too — the
|
|
340
|
+
* part past the edge is clipped on that page and continues on the next.
|
|
341
|
+
*/
|
|
342
|
+
/**
|
|
343
|
+
* Whether a sheet has anything to put on a page.
|
|
344
|
+
*
|
|
345
|
+
* A cell that carries a value or inline text, any drawing, control or slicer,
|
|
346
|
+
* or a printed note. A tab nobody touched has none of those, and Excel and
|
|
347
|
+
* LibreOffice both leave it out of the print — a header or footer does not
|
|
348
|
+
* rescue it.
|
|
349
|
+
*
|
|
350
|
+
* @param ws The sheet.
|
|
351
|
+
* @returns True when the sheet would print something.
|
|
352
|
+
*/
|
|
353
|
+
/**
|
|
354
|
+
* Whether a sheet carries a header or footer with anything in it.
|
|
355
|
+
*
|
|
356
|
+
* @param ws The sheet.
|
|
357
|
+
* @returns True when either band has a non-empty format string.
|
|
358
|
+
*/
|
|
359
|
+
function hasHeaderOrFooter(ws) {
|
|
360
|
+
const hf = ws.grid.headerFooter;
|
|
361
|
+
return Boolean(hf && ((hf.oddHeader?.length ?? 0) > 0 || (hf.oddFooter?.length ?? 0) > 0));
|
|
362
|
+
}
|
|
363
|
+
function sheetPrintsAnything(ws, styles) {
|
|
364
|
+
if (ws.grid.cells.some((c) => c.rawValue !== "" || c.inlineText !== void 0)) return true;
|
|
365
|
+
if (ws.grid.cells.some((c) => cellPaintsVisibly(c, styles))) return true;
|
|
366
|
+
if ((ws.charts?.length ?? 0) > 0) return true;
|
|
367
|
+
if ((ws.images?.length ?? 0) > 0) return true;
|
|
368
|
+
if ((ws.shapes?.length ?? 0) > 0) return true;
|
|
369
|
+
if ((ws.slicers?.length ?? 0) > 0) return true;
|
|
370
|
+
if ((ws.comments?.length ?? 0) > 0) return true;
|
|
371
|
+
if ((ws.formControls?.length ?? 0) > 0) return true;
|
|
372
|
+
if ((ws.activeXControls?.length ?? 0) > 0) return true;
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Put each drawing beside the column band it is anchored in.
|
|
377
|
+
*
|
|
378
|
+
* A wide sheet's grid prints as one table per band, each on its own page, and a
|
|
379
|
+
* float lands on whatever page the layout has reached when it meets the block.
|
|
380
|
+
* Emitted ahead of the whole grid, a drawing anchored in the second band was
|
|
381
|
+
* printed on the FIRST page at an offset a page and a half wide — off the paper
|
|
382
|
+
* entirely. shape-macro-ext-ref.xlsx anchors its chart and its macro button at
|
|
383
|
+
* x=838pt and x=891pt of a 480pt page and lost both.
|
|
384
|
+
*
|
|
385
|
+
* Each drawing goes in front of its band's table with its horizontal anchor
|
|
386
|
+
* measured from that band's left edge instead of the sheet's.
|
|
387
|
+
*
|
|
388
|
+
* @param drawings The sheet's floats, in the order they were projected.
|
|
389
|
+
* @param gridBody The grid's body elements — one table per band.
|
|
390
|
+
* @param lefts Each band's left edge in points (from the projection's sink).
|
|
391
|
+
* @returns The two merged; drawings first when the sheet does not band.
|
|
392
|
+
*/
|
|
393
|
+
function withDrawingsByBand(drawings, gridBody, lefts) {
|
|
394
|
+
const tables = gridBody.filter((el) => el.kind === "table").length;
|
|
395
|
+
if (drawings.length === 0 || lefts.length < 2 || tables !== lefts.length) return [...drawings, ...gridBody];
|
|
396
|
+
const bandOf = (x) => {
|
|
397
|
+
let band = 0;
|
|
398
|
+
while (band + 1 < lefts.length && x >= lefts[band + 1]) band++;
|
|
399
|
+
return band;
|
|
400
|
+
};
|
|
401
|
+
const byBand = lefts.map(() => []);
|
|
402
|
+
for (const el of drawings) {
|
|
403
|
+
const x = floatLeftPt(el);
|
|
404
|
+
const band = x === void 0 ? 0 : bandOf(x);
|
|
405
|
+
byBand[band].push(x === void 0 ? el : shiftFloatLeft(el, lefts[band]));
|
|
406
|
+
}
|
|
407
|
+
const out = [];
|
|
408
|
+
let seen = 0;
|
|
409
|
+
for (const el of gridBody) {
|
|
410
|
+
out.push(el);
|
|
411
|
+
if (el.kind === "table") out.push(...byBand[seen++]);
|
|
412
|
+
}
|
|
413
|
+
return out;
|
|
414
|
+
}
|
|
415
|
+
/** A float's horizontal anchor, for the block kinds a sheet anchors. */
|
|
416
|
+
function floatLeftPt(el) {
|
|
417
|
+
return (el.kind === "chart" ? el.chart.float : el.kind === "image" ? el.image.float : el.kind === "shape" ? el.shape.float : void 0)?.posH?.offsetPt;
|
|
418
|
+
}
|
|
419
|
+
/** The same block with its horizontal anchor measured from `by` points later. */
|
|
420
|
+
function shiftFloatLeft(el, by) {
|
|
421
|
+
if (by === 0) return el;
|
|
422
|
+
const moved = (block) => ({
|
|
423
|
+
...block,
|
|
424
|
+
float: {
|
|
425
|
+
...block.float,
|
|
426
|
+
posH: {
|
|
427
|
+
...block.float.posH,
|
|
428
|
+
offsetPt: pt((block.float.posH.offsetPt ?? 0) - by)
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
if (el.kind === "chart") return {
|
|
433
|
+
...el,
|
|
434
|
+
chart: moved(el.chart)
|
|
435
|
+
};
|
|
436
|
+
if (el.kind === "image") return {
|
|
437
|
+
...el,
|
|
438
|
+
image: moved(el.image)
|
|
439
|
+
};
|
|
440
|
+
if (el.kind === "shape") return {
|
|
441
|
+
...el,
|
|
442
|
+
shape: moved(el.shape)
|
|
443
|
+
};
|
|
444
|
+
return el;
|
|
445
|
+
}
|
|
446
|
+
var ACROSS = {
|
|
447
|
+
anchorOf: (s) => s.float?.posH?.offsetPt,
|
|
448
|
+
sizeOf: (s) => s.width,
|
|
449
|
+
shifted: (s, by) => ({
|
|
450
|
+
...s,
|
|
451
|
+
float: {
|
|
452
|
+
...s.float,
|
|
453
|
+
posH: {
|
|
454
|
+
...s.float.posH,
|
|
455
|
+
offsetPt: pt((s.float.posH.offsetPt ?? 0) - by)
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
})
|
|
459
|
+
};
|
|
460
|
+
var DOWN = {
|
|
461
|
+
anchorOf: (s) => s.float?.posV?.offsetPt,
|
|
462
|
+
sizeOf: (s) => s.height,
|
|
463
|
+
shifted: (s, by) => ({
|
|
464
|
+
...s,
|
|
465
|
+
float: {
|
|
466
|
+
...s.float,
|
|
467
|
+
posV: {
|
|
468
|
+
...s.float.posV,
|
|
469
|
+
offsetPt: pt((s.float.posV.offsetPt ?? 0) - by)
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
})
|
|
473
|
+
};
|
|
474
|
+
function bandDrawings(shapes, printable, scale, axis = ACROSS) {
|
|
475
|
+
if (shapes.length === 0 || !(printable > 0)) return [shapes];
|
|
476
|
+
const rightOf = (s) => (axis.anchorOf(s) ?? 0) * scale + axis.sizeOf(s);
|
|
477
|
+
const extent = Math.max(0, ...shapes.map(rightOf));
|
|
478
|
+
const bandCount = Math.ceil(extent / printable);
|
|
479
|
+
if (bandCount <= 1) return [shapes];
|
|
480
|
+
const bands = Array.from({ length: bandCount }, () => []);
|
|
481
|
+
for (const shape of shapes) {
|
|
482
|
+
const anchor = axis.anchorOf(shape);
|
|
483
|
+
const left = (anchor ?? 0) * scale;
|
|
484
|
+
const right = left + axis.sizeOf(shape);
|
|
485
|
+
const first = Math.max(0, Math.min(bandCount - 1, Math.floor(left / printable)));
|
|
486
|
+
const last = Math.max(first, Math.min(bandCount - 1, Math.ceil(right / printable) - 1));
|
|
487
|
+
for (let band = first; band <= last; band++) {
|
|
488
|
+
if (!shape.float || anchor === void 0) {
|
|
489
|
+
bands[band].push(shape);
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
const { text: _text, ...frame } = shape;
|
|
493
|
+
if (band !== first && !frame.line && frame.fill.kind === "none") continue;
|
|
494
|
+
bands[band].push(axis.shifted(band === first ? shape : frame, band * printable / scale));
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return bands.filter((b) => b.length > 0);
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* §20.5.2.35 — the float a drawing's anchor asks for: pinned at the point the
|
|
501
|
+
* anchor names, measured from the page margin, wrapping nothing.
|
|
502
|
+
*
|
|
503
|
+
* A chart or a picture placed in the FLOW instead lands at the left margin,
|
|
504
|
+
* below every block before it, and on whatever page that turns out to be:
|
|
505
|
+
* simple-monthly-budget.xlsx anchors its chart beside the summary on page one
|
|
506
|
+
* and we printed it alone on page two, a third of the way in from the left.
|
|
507
|
+
* Shapes have floated at their anchors since W2; these two never did.
|
|
508
|
+
*
|
|
509
|
+
* No anchor (an `absoluteAnchor`, or a reader that gave none) ⇒ no float, and
|
|
510
|
+
* the block keeps the flow placement it has always had.
|
|
511
|
+
*/
|
|
512
|
+
function anchorFloat(xPt, yPt, scale) {
|
|
513
|
+
if (xPt === void 0 || yPt === void 0) return {};
|
|
514
|
+
return { float: {
|
|
515
|
+
wrap: "none",
|
|
516
|
+
posH: {
|
|
517
|
+
relativeFrom: "margin",
|
|
518
|
+
offsetPt: pt(xPt * scale)
|
|
519
|
+
},
|
|
520
|
+
posV: {
|
|
521
|
+
relativeFrom: "margin",
|
|
522
|
+
offsetPt: pt(yPt * scale)
|
|
523
|
+
}
|
|
524
|
+
} };
|
|
525
|
+
}
|
|
526
|
+
/** Every control that carries geometry, as the shapes that draw it. */
|
|
527
|
+
function controlShapeBlocks(formControls, activeXControls) {
|
|
528
|
+
const out = [];
|
|
529
|
+
for (const c of formControls ?? []) {
|
|
530
|
+
if (!c.box) continue;
|
|
531
|
+
out.push(...controlShapes(c.box, formControlGlyph(c.objectType), c.caption, c.checked === true, c.fontSizePt ?? DEFAULT_FORM_CONTROL_PT));
|
|
532
|
+
}
|
|
533
|
+
for (const c of activeXControls ?? []) {
|
|
534
|
+
if (!c.box) continue;
|
|
535
|
+
const on = c.value === "1" || c.value?.toLowerCase() === "true";
|
|
536
|
+
out.push(...controlShapes(c.box, activeXGlyph(c.type), c.caption, on, DEFAULT_ACTIVEX_CONTROL_PT));
|
|
537
|
+
}
|
|
538
|
+
return out;
|
|
539
|
+
}
|
|
130
540
|
function formControlBlocks(controls) {
|
|
541
|
+
const listed = controls.filter((c) => c.box === void 0);
|
|
542
|
+
if (listed.length === 0) return [];
|
|
131
543
|
const out = [{
|
|
132
544
|
kind: "paragraph",
|
|
133
545
|
paragraph: {
|
|
@@ -138,7 +550,7 @@ function formControlBlocks(controls) {
|
|
|
138
550
|
}]
|
|
139
551
|
}
|
|
140
552
|
}];
|
|
141
|
-
for (const c of
|
|
553
|
+
for (const c of listed) out.push({
|
|
142
554
|
kind: "paragraph",
|
|
143
555
|
paragraph: {
|
|
144
556
|
properties: {},
|
|
@@ -164,6 +576,8 @@ function formControlLabel(c) {
|
|
|
164
576
|
}
|
|
165
577
|
}
|
|
166
578
|
function activeXBlocks(controls) {
|
|
579
|
+
const listed = controls.filter((c) => c.box === void 0);
|
|
580
|
+
if (listed.length === 0) return [];
|
|
167
581
|
const out = [{
|
|
168
582
|
kind: "paragraph",
|
|
169
583
|
paragraph: {
|
|
@@ -174,7 +588,7 @@ function activeXBlocks(controls) {
|
|
|
174
588
|
}]
|
|
175
589
|
}
|
|
176
590
|
}];
|
|
177
|
-
for (const c of
|
|
591
|
+
for (const c of listed) out.push({
|
|
178
592
|
kind: "paragraph",
|
|
179
593
|
paragraph: {
|
|
180
594
|
properties: {},
|
|
@@ -203,28 +617,131 @@ function activeXLabel(c) {
|
|
|
203
617
|
default: return label;
|
|
204
618
|
}
|
|
205
619
|
}
|
|
206
|
-
|
|
620
|
+
/**
|
|
621
|
+
* How far the sheet's drawings reach from its origin, or undefined when it has
|
|
622
|
+
* none. Fit-to-page has to fit them as well as the cells: a drawing anchored
|
|
623
|
+
* past the last value is still printed, and on a sheet whose values sit in a
|
|
624
|
+
* handful of cells it is the drawing that decides the page.
|
|
625
|
+
*/
|
|
626
|
+
function drawingReachPt(ws) {
|
|
627
|
+
let widthPt = 0;
|
|
628
|
+
let heightPt = 0;
|
|
629
|
+
for (const shape of ws.shapes ?? []) {
|
|
630
|
+
widthPt = Math.max(widthPt, (shape.float?.posH?.offsetPt ?? 0) + shape.width);
|
|
631
|
+
heightPt = Math.max(heightPt, (shape.float?.posV?.offsetPt ?? 0) + shape.height);
|
|
632
|
+
}
|
|
633
|
+
for (const c of ws.charts ?? []) {
|
|
634
|
+
widthPt = Math.max(widthPt, (c.xPt ?? 0) + c.widthPt);
|
|
635
|
+
heightPt = Math.max(heightPt, (c.yPt ?? 0) + c.heightPt);
|
|
636
|
+
}
|
|
637
|
+
for (const p of ws.images ?? []) {
|
|
638
|
+
widthPt = Math.max(widthPt, (p.xPt ?? 0) + p.widthPt);
|
|
639
|
+
heightPt = Math.max(heightPt, (p.yPt ?? 0) + p.heightPt);
|
|
640
|
+
}
|
|
641
|
+
return widthPt > 0 || heightPt > 0 ? {
|
|
642
|
+
widthPt,
|
|
643
|
+
heightPt
|
|
644
|
+
} : void 0;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* `<printOptions horizontalCentered/verticalCentered>` centres what is PRINTED,
|
|
648
|
+
* and a drawing is printed. We centred the table only, which leaves a drawing
|
|
649
|
+
* at its raw offset — and on a sheet whose cells are all empty there is no
|
|
650
|
+
* table to centre at all: bnc762542.xlsx asks for both axes and its callout sat
|
|
651
|
+
* some 280pt left of where the reference puts it, matching the file's own
|
|
652
|
+
* numbers exactly but ignoring the request that moves them.
|
|
653
|
+
*/
|
|
654
|
+
function centreShape(shape, worksheet, extent, scale) {
|
|
655
|
+
const options = worksheet.printOptions;
|
|
656
|
+
if (!extent || !options?.horizontalCentered && !options?.verticalCentered) return shape;
|
|
657
|
+
const section = sectionFromWorksheet(worksheet);
|
|
658
|
+
const size = section.pageSize;
|
|
659
|
+
const margins = section.margins;
|
|
660
|
+
if (!size || !margins) return shape;
|
|
661
|
+
const dx = options.horizontalCentered ? (size.width - margins.left - margins.right - extent.widthPt * scale) / 2 : 0;
|
|
662
|
+
const dy = options.verticalCentered ? (size.height - margins.top - margins.bottom - extent.heightPt * scale) / 2 : 0;
|
|
663
|
+
if (dx <= 0 && dy <= 0) return shape;
|
|
664
|
+
const posH = shape.float?.posH;
|
|
665
|
+
const posV = shape.float?.posV;
|
|
666
|
+
if (!shape.float) return shape;
|
|
667
|
+
return {
|
|
668
|
+
...shape,
|
|
669
|
+
float: {
|
|
670
|
+
...shape.float,
|
|
671
|
+
...posH && dx > 0 ? { posH: {
|
|
672
|
+
...posH,
|
|
673
|
+
offsetPt: pt((posH.offsetPt ?? 0) + dx)
|
|
674
|
+
} } : {},
|
|
675
|
+
...posV && dy > 0 ? { posV: {
|
|
676
|
+
...posV,
|
|
677
|
+
offsetPt: pt((posV.offsetPt ?? 0) + dy)
|
|
678
|
+
} } : {}
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* A drawing at the sheet's print scale: its box and the point it floats at
|
|
684
|
+
* shrink together, exactly as the grid beneath them does. Returns the shape
|
|
685
|
+
* untouched at 1.0 so an unscaled sheet stays byte-identical.
|
|
686
|
+
*/
|
|
687
|
+
function scaleShape(shape, scale) {
|
|
688
|
+
if (!(scale > 0) || scale >= .999) return shape;
|
|
689
|
+
const offset = (o) => o?.offsetPt === void 0 ? void 0 : o.offsetPt * scale;
|
|
690
|
+
const posH = shape.float?.posH;
|
|
691
|
+
const posV = shape.float?.posV;
|
|
692
|
+
return {
|
|
693
|
+
...shape,
|
|
694
|
+
width: pt(shape.width * scale),
|
|
695
|
+
height: pt(shape.height * scale),
|
|
696
|
+
...shape.float ? { float: {
|
|
697
|
+
...shape.float,
|
|
698
|
+
...posH ? { posH: {
|
|
699
|
+
...posH,
|
|
700
|
+
...withOffset(offset(posH))
|
|
701
|
+
} } : {},
|
|
702
|
+
...posV ? { posV: {
|
|
703
|
+
...posV,
|
|
704
|
+
...withOffset(offset(posV))
|
|
705
|
+
} } : {}
|
|
706
|
+
} } : {}
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
function withOffset(value) {
|
|
710
|
+
return value === void 0 ? {} : { offsetPt: pt(value) };
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* The sheet's header/footer bands, registered under ids of this sheet's own.
|
|
714
|
+
*
|
|
715
|
+
* The map is document-level and the ids used to be fixed, so a second sheet
|
|
716
|
+
* overwrote the first's bands and every section pointed at the last one — in
|
|
717
|
+
* practice only the first sheet's header survived, because only its section
|
|
718
|
+
* carried the references. formats.xlsx puts the sheet name and page number on
|
|
719
|
+
* all five of its pages and we printed them on one.
|
|
720
|
+
*/
|
|
721
|
+
function withHeaderFooter(section, ws, headersFooters, scale, basePt, sheetIdx, fileName, themePalette, now) {
|
|
722
|
+
const headerRel = `${HEADER_REL}${sheetIdx}`;
|
|
723
|
+
const footerRel = `${FOOTER_REL}${sheetIdx}`;
|
|
207
724
|
const hf = ws.grid.headerFooter;
|
|
208
725
|
if (!hf || !hf.oddHeader && !hf.oddFooter) return section;
|
|
209
726
|
const headers = [];
|
|
210
727
|
const footers = [];
|
|
211
728
|
if (hf.oddHeader) {
|
|
212
|
-
const content = buildHeaderFooterContent(hf.oddHeader, ws.name);
|
|
729
|
+
const content = buildHeaderFooterContent(hf.oddHeader, ws.name, scale, basePt, fileName, themePalette, now);
|
|
213
730
|
if (content.length > 0) {
|
|
214
|
-
headersFooters.set(
|
|
731
|
+
headersFooters.set(headerRel, resolveBodyStyles(content, EMPTY_STYLE_SHEET));
|
|
215
732
|
headers.push({
|
|
216
733
|
type: "default",
|
|
217
|
-
relationshipId:
|
|
734
|
+
relationshipId: headerRel
|
|
218
735
|
});
|
|
219
736
|
}
|
|
220
737
|
}
|
|
221
738
|
if (hf.oddFooter) {
|
|
222
|
-
const content = buildHeaderFooterContent(hf.oddFooter, ws.name);
|
|
739
|
+
const content = buildHeaderFooterContent(hf.oddFooter, ws.name, scale, basePt, fileName, themePalette, now);
|
|
223
740
|
if (content.length > 0) {
|
|
224
|
-
headersFooters.set(
|
|
741
|
+
headersFooters.set(footerRel, resolveBodyStyles(content, EMPTY_STYLE_SHEET));
|
|
225
742
|
footers.push({
|
|
226
743
|
type: "default",
|
|
227
|
-
relationshipId:
|
|
744
|
+
relationshipId: footerRel
|
|
228
745
|
});
|
|
229
746
|
}
|
|
230
747
|
}
|