reamkit 1.11.0 → 1.13.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/converter/facade.js +1 -1
- package/dist/esm/core/converter/project.js +1 -0
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +24 -0
- package/dist/esm/core/ir/features.d.ts +1 -0
- package/dist/esm/core/ir/features.js +1 -0
- package/dist/esm/core/ir/flow.d.ts +3 -1
- package/dist/esm/core/ir/sheet.d.ts +14 -0
- package/dist/esm/core/po-helpers.d.ts +2 -0
- package/dist/esm/core/po-helpers.js +14 -1
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +34 -0
- package/dist/esm/excel/index.d.ts +1 -1
- package/dist/esm/excel/pivot-table-parser.d.ts +2 -0
- package/dist/esm/excel/pivot-table-parser.js +68 -0
- package/dist/esm/excel/print-model.d.ts +5 -2
- package/dist/esm/excel/print-model.js +123 -9
- package/dist/esm/excel/sheet-to-flow.js +5 -1
- package/dist/esm/excel/slicer-parser.d.ts +15 -0
- package/dist/esm/excel/slicer-parser.js +76 -0
- package/dist/esm/excel/table-parser.d.ts +10 -0
- package/dist/esm/excel/table-parser.js +36 -4
- package/dist/esm/excel/worksheet-parser.js +56 -0
- package/dist/esm/excel/xlsx-reader.js +129 -5
- package/dist/esm/excel/xlsx-writer.js +9 -1
- package/dist/esm/html/html-writer.js +56 -2
- package/dist/esm/layout/page-doc.d.ts +1 -0
- package/dist/esm/layout/styled-layout.d.ts +8 -1
- package/dist/esm/layout/styled-layout.js +154 -6
- package/dist/esm/pdf/styled-page-emitter.js +38 -0
- package/dist/esm/pptx/pptx-reader.d.ts +2 -0
- package/dist/esm/pptx/pptx-reader.js +30 -3
- package/dist/esm/pptx/slide-parser.d.ts +8 -2
- package/dist/esm/pptx/slide-parser.js +80 -12
- package/dist/esm/word/document-parser.d.ts +17 -2
- package/dist/esm/word/document-parser.js +178 -18
- package/dist/esm/word/docx-reader.js +54 -4
- package/dist/esm/word/docx-writer.js +84 -1
- package/dist/esm/word/drawing-parser.d.ts +7 -0
- package/dist/esm/word/drawing-parser.js +13 -0
- package/dist/esm/word/index.d.ts +2 -1
- package/package.json +1 -1
|
@@ -44,9 +44,10 @@ function isOutOfFlowFloat(f) {
|
|
|
44
44
|
return f !== void 0 && f.wrap !== "topAndBottom";
|
|
45
45
|
}
|
|
46
46
|
var FOOTNOTE_RULE_WIDTH = 144;
|
|
47
|
-
function assignNoteNumbers(body) {
|
|
47
|
+
function assignNoteNumbers(body, commentIds) {
|
|
48
48
|
const footnotes = /* @__PURE__ */ new Map();
|
|
49
49
|
const endnotes = /* @__PURE__ */ new Map();
|
|
50
|
+
const comments = /* @__PURE__ */ new Map();
|
|
50
51
|
const paragraphFootnotes = /* @__PURE__ */ new Set();
|
|
51
52
|
const numberRun = (run, n) => ({
|
|
52
53
|
...run,
|
|
@@ -56,8 +57,17 @@ function assignNoteNumbers(body) {
|
|
|
56
57
|
verticalAlign: "superscript"
|
|
57
58
|
}
|
|
58
59
|
});
|
|
60
|
+
const commentMarkerRun = (run, n) => ({
|
|
61
|
+
...run,
|
|
62
|
+
text: `[${n}]`,
|
|
63
|
+
...run.commentRef !== void 0 && commentIds?.has(run.commentRef) ? { anchor: `comment-${n}` } : {},
|
|
64
|
+
properties: {
|
|
65
|
+
...run.properties,
|
|
66
|
+
verticalAlign: "superscript"
|
|
67
|
+
}
|
|
68
|
+
});
|
|
59
69
|
const mapParagraph = (paragraph) => {
|
|
60
|
-
if (!paragraph.runs.some((r) => r.footnoteRef !== void 0 || r.endnoteRef !== void 0)) return paragraph;
|
|
70
|
+
if (!paragraph.runs.some((r) => r.footnoteRef !== void 0 || r.endnoteRef !== void 0 || r.commentRef !== void 0)) return paragraph;
|
|
61
71
|
return {
|
|
62
72
|
...paragraph,
|
|
63
73
|
runs: paragraph.runs.map((run) => {
|
|
@@ -77,6 +87,14 @@ function assignNoteNumbers(body) {
|
|
|
77
87
|
}
|
|
78
88
|
return numberRun(run, n);
|
|
79
89
|
}
|
|
90
|
+
if (run.commentRef !== void 0) {
|
|
91
|
+
let n = comments.get(run.commentRef);
|
|
92
|
+
if (n === void 0) {
|
|
93
|
+
n = comments.size + 1;
|
|
94
|
+
comments.set(run.commentRef, n);
|
|
95
|
+
}
|
|
96
|
+
return commentMarkerRun(run, n);
|
|
97
|
+
}
|
|
80
98
|
return run;
|
|
81
99
|
})
|
|
82
100
|
};
|
|
@@ -117,7 +135,7 @@ function assignNoteNumbers(body) {
|
|
|
117
135
|
return el;
|
|
118
136
|
};
|
|
119
137
|
const hasRefs = (els) => els.some((el) => {
|
|
120
|
-
if (el.kind === "paragraph") return el.paragraph.runs.some((r) => r.footnoteRef !== void 0 || r.endnoteRef !== void 0);
|
|
138
|
+
if (el.kind === "paragraph") return el.paragraph.runs.some((r) => r.footnoteRef !== void 0 || r.endnoteRef !== void 0 || r.commentRef !== void 0);
|
|
121
139
|
if (el.kind === "table") return el.table.rows.some((row) => row.cells.some((c) => hasRefs(c.content)));
|
|
122
140
|
if (el.kind === "shape" && el.shape.text) return hasRefs(el.shape.text.content);
|
|
123
141
|
return false;
|
|
@@ -126,12 +144,14 @@ function assignNoteNumbers(body) {
|
|
|
126
144
|
body,
|
|
127
145
|
footnotes,
|
|
128
146
|
endnotes,
|
|
147
|
+
comments,
|
|
129
148
|
deferredFootnotes: []
|
|
130
149
|
};
|
|
131
150
|
return {
|
|
132
151
|
body: body.map((el) => mapElement(el, true)),
|
|
133
152
|
footnotes,
|
|
134
153
|
endnotes,
|
|
154
|
+
comments,
|
|
135
155
|
deferredFootnotes: [...footnotes.keys()].filter((id) => !paragraphFootnotes.has(id))
|
|
136
156
|
};
|
|
137
157
|
}
|
|
@@ -169,9 +189,62 @@ function substituteNoteNumber(content, n) {
|
|
|
169
189
|
}
|
|
170
190
|
}, ...out.slice(1)];
|
|
171
191
|
}
|
|
192
|
+
function flattenCommentText(content) {
|
|
193
|
+
const lines = [];
|
|
194
|
+
const visit = (els) => {
|
|
195
|
+
for (const el of els) if (el.kind === "paragraph") lines.push(el.paragraph.runs.map((r) => r.text).join(""));
|
|
196
|
+
else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
|
|
197
|
+
};
|
|
198
|
+
visit(content);
|
|
199
|
+
return lines.join("\n").trim();
|
|
200
|
+
}
|
|
201
|
+
function buildCommentNotes(numbers, comments) {
|
|
202
|
+
const out = /* @__PURE__ */ new Map();
|
|
203
|
+
for (const [id, n] of numbers) {
|
|
204
|
+
const c = comments.get(id);
|
|
205
|
+
if (!c) continue;
|
|
206
|
+
out.set(`comment-${n}`, {
|
|
207
|
+
...c.author !== void 0 ? { author: c.author } : {},
|
|
208
|
+
contents: flattenCommentText(c.content)
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return out;
|
|
212
|
+
}
|
|
213
|
+
function commentTailBlocks(comment, n, opts) {
|
|
214
|
+
const who = [comment.author, comment.date].filter((s) => s !== void 0 && s.length > 0).join(", ");
|
|
215
|
+
const inReplyTo = opts?.parentN !== void 0 ? ` (in reply to [${opts.parentN}])` : "";
|
|
216
|
+
const resolved = opts?.done ? " (resolved)" : "";
|
|
217
|
+
const labelRun = {
|
|
218
|
+
text: who ? `[${n}] ${who}${inReplyTo}${resolved}: ` : `[${n}]${inReplyTo}${resolved} `,
|
|
219
|
+
properties: {}
|
|
220
|
+
};
|
|
221
|
+
const bm = `comment-${n}`;
|
|
222
|
+
const indent = opts?.depth && opts.depth > 0 ? { indentLeft: pt(18 * opts.depth) } : {};
|
|
223
|
+
const first = comment.content[0];
|
|
224
|
+
if (first && first.kind === "paragraph") return [{
|
|
225
|
+
kind: "paragraph",
|
|
226
|
+
paragraph: {
|
|
227
|
+
...first.paragraph,
|
|
228
|
+
properties: {
|
|
229
|
+
...first.paragraph.properties,
|
|
230
|
+
...indent
|
|
231
|
+
},
|
|
232
|
+
runs: [labelRun, ...first.paragraph.runs],
|
|
233
|
+
bookmarks: [bm, ...first.paragraph.bookmarks ?? []]
|
|
234
|
+
}
|
|
235
|
+
}, ...comment.content.slice(1)];
|
|
236
|
+
return [{
|
|
237
|
+
kind: "paragraph",
|
|
238
|
+
paragraph: {
|
|
239
|
+
properties: { ...indent },
|
|
240
|
+
runs: [labelRun],
|
|
241
|
+
bookmarks: [bm]
|
|
242
|
+
}
|
|
243
|
+
}, ...comment.content];
|
|
244
|
+
}
|
|
172
245
|
function layoutStyledDocument(body, options) {
|
|
173
246
|
const sectionList = resolveSectionList(body, options);
|
|
174
|
-
const noteAssigned = assignNoteNumbers(applyNumbering(body, options.numbering));
|
|
247
|
+
const noteAssigned = assignNoteNumbers(applyNumbering(body, options.numbering), options.comments ? new Set(options.comments.keys()) : void 0);
|
|
175
248
|
const numberedBody = noteAssigned.body;
|
|
176
249
|
const numberedHeadersFooters = applyNumberingToHeadersFooters(options.headersFooters, options.numbering);
|
|
177
250
|
const pdfaProfile = options.pdfA ? parsePdfAProfile(options.pdfA) : void 0;
|
|
@@ -229,8 +302,35 @@ function layoutStyledDocument(body, options) {
|
|
|
229
302
|
});
|
|
230
303
|
}
|
|
231
304
|
for (const note of tailNotes.sort((a, b) => a.n - b.n)) for (const el of substituteNoteNumber(note.content, note.n)) blocks.push(layoutBodyElement(el, options, fontResources, imageResources, lastCtx.contentWidth, lastCtx.pageContentHeight));
|
|
305
|
+
const commentNums = noteAssigned.comments;
|
|
306
|
+
const threadDepth = (id) => {
|
|
307
|
+
let depth = 0;
|
|
308
|
+
const seen = new Set([id]);
|
|
309
|
+
let cur = options.comments?.get(id)?.parentId;
|
|
310
|
+
while (cur !== void 0 && commentNums.has(cur) && !seen.has(cur)) {
|
|
311
|
+
depth++;
|
|
312
|
+
seen.add(cur);
|
|
313
|
+
cur = options.comments?.get(cur)?.parentId;
|
|
314
|
+
}
|
|
315
|
+
return depth;
|
|
316
|
+
};
|
|
317
|
+
const commentTail = [...commentNums].map(([id, n]) => ({
|
|
318
|
+
id,
|
|
319
|
+
comment: options.comments?.get(id),
|
|
320
|
+
n
|
|
321
|
+
})).filter((e) => e.comment !== void 0).sort((a, b) => a.n - b.n);
|
|
322
|
+
for (const { id, comment, n } of commentTail) {
|
|
323
|
+
const parentId = comment.parentId;
|
|
324
|
+
const parentN = parentId !== void 0 && commentNums.has(parentId) ? commentNums.get(parentId) : void 0;
|
|
325
|
+
for (const el of commentTailBlocks(comment, n, {
|
|
326
|
+
...parentN !== void 0 ? { parentN } : {},
|
|
327
|
+
depth: threadDepth(id),
|
|
328
|
+
...comment.done ? { done: true } : {}
|
|
329
|
+
})) blocks.push(layoutBodyElement(el, options, fontResources, imageResources, lastCtx.contentWidth, lastCtx.pageContentHeight));
|
|
330
|
+
}
|
|
232
331
|
}
|
|
233
332
|
const bookmarks = /* @__PURE__ */ new Map();
|
|
333
|
+
const commentNotes = options.commentAnnotations && options.comments ? buildCommentNotes(noteAssigned.comments, options.comments) : void 0;
|
|
234
334
|
const reflowParagraph = (paragraph, width, widths) => layoutParagraphBlock(paragraph, options, fontResources, imageResources, width, widths);
|
|
235
335
|
return {
|
|
236
336
|
pages: paginateSections(blocks, sectionCtxs, structBuilder, options.language ?? "en-US", notePlan, bookmarks, reflowParagraph),
|
|
@@ -242,7 +342,8 @@ function layoutStyledDocument(body, options) {
|
|
|
242
342
|
sectionCtxs,
|
|
243
343
|
pdfaProfile,
|
|
244
344
|
tagged,
|
|
245
|
-
bookmarks
|
|
345
|
+
bookmarks,
|
|
346
|
+
...commentNotes ? { commentNotes } : {}
|
|
246
347
|
}
|
|
247
348
|
};
|
|
248
349
|
}
|
|
@@ -567,6 +668,24 @@ function rectAtPath(x, y, w, h) {
|
|
|
567
668
|
var CF_ICON_SIZE_PT = 9;
|
|
568
669
|
var CF_ICON_GUTTER_PT = 12;
|
|
569
670
|
var CF_ICON_EMPTY_HEX = "BFBFBF";
|
|
671
|
+
var DROPDOWN_BUTTON_PT = 11;
|
|
672
|
+
var DROPDOWN_GUTTER_PT = 13;
|
|
673
|
+
var DROPDOWN_FILL_HEX = "F0F0F0";
|
|
674
|
+
var DROPDOWN_BORDER_HEX = "B0B0B0";
|
|
675
|
+
var DROPDOWN_ARROW_HEX = "595959";
|
|
676
|
+
function buildDropdownPrims(s) {
|
|
677
|
+
return [{
|
|
678
|
+
paths: [rectAtPath(0, 0, s, s)],
|
|
679
|
+
fillColorHex: DROPDOWN_FILL_HEX,
|
|
680
|
+
stroke: {
|
|
681
|
+
colorHex: DROPDOWN_BORDER_HEX,
|
|
682
|
+
widthPt: .5
|
|
683
|
+
}
|
|
684
|
+
}, {
|
|
685
|
+
paths: [trianglePath([s / 2, s * .34], [s * .26, s * .64], [s * .74, s * .64])],
|
|
686
|
+
fillColorHex: DROPDOWN_ARROW_HEX
|
|
687
|
+
}];
|
|
688
|
+
}
|
|
570
689
|
function buildCellIconShape(icon, s) {
|
|
571
690
|
const color = icon.colorHex;
|
|
572
691
|
switch (icon.shape) {
|
|
@@ -756,6 +875,7 @@ function collectImageResources(body, headersFooters, options) {
|
|
|
756
875
|
for (const hf of headersFooters.values()) visit(hf);
|
|
757
876
|
for (const note of options.footnotes?.values() ?? []) visit(note);
|
|
758
877
|
for (const note of options.endnotes?.values() ?? []) visit(note);
|
|
878
|
+
for (const comment of options.comments?.values() ?? []) visit(comment.content);
|
|
759
879
|
const flattenAlpha = options.pdfA ? parsePdfAProfile(options.pdfA).part === 1 : false;
|
|
760
880
|
let counter = 0;
|
|
761
881
|
for (const resourceId of seen) {
|
|
@@ -916,6 +1036,7 @@ function collectFontResources(body, headersFooters, options) {
|
|
|
916
1036
|
for (const hf of headersFooters.values()) visit(hf);
|
|
917
1037
|
for (const note of options.footnotes?.values() ?? []) visit(note);
|
|
918
1038
|
for (const note of options.endnotes?.values() ?? []) visit(note);
|
|
1039
|
+
for (const comment of options.comments?.values() ?? []) visit(comment.content);
|
|
919
1040
|
if (used.size === 0) {
|
|
920
1041
|
const regular = options.registry.resolveByStyle(false, false);
|
|
921
1042
|
used.set(regular.variant, {
|
|
@@ -1086,6 +1207,7 @@ function tokenizePlansLtr(plans) {
|
|
|
1086
1207
|
});
|
|
1087
1208
|
continue;
|
|
1088
1209
|
}
|
|
1210
|
+
const highlight = (plan.run.commentRangeRefs?.length ?? 0) > 0;
|
|
1089
1211
|
for (const t of tokenizeText(plan.run.text)) tokens.push({
|
|
1090
1212
|
kind: "text",
|
|
1091
1213
|
text: t.text,
|
|
@@ -1094,6 +1216,7 @@ function tokenizePlansLtr(plans) {
|
|
|
1094
1216
|
...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
|
|
1095
1217
|
...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
|
|
1096
1218
|
...plan.run.listMarker ? { listMarker: true } : {},
|
|
1219
|
+
...highlight ? { highlight: true } : {},
|
|
1097
1220
|
resolvedRun: plan.resolvedRun,
|
|
1098
1221
|
font: plan.font,
|
|
1099
1222
|
fontSizePt: plan.fontSizePt,
|
|
@@ -1148,6 +1271,7 @@ function tokenizePlansBidi(plans, realLevels) {
|
|
|
1148
1271
|
...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
|
|
1149
1272
|
...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
|
|
1150
1273
|
...plan.run.listMarker ? { listMarker: true } : {},
|
|
1274
|
+
...(plan.run.commentRangeRefs?.length ?? 0) > 0 ? { highlight: true } : {},
|
|
1151
1275
|
resolvedRun: plan.resolvedRun,
|
|
1152
1276
|
font: plan.font,
|
|
1153
1277
|
fontSizePt: plan.fontSizePt,
|
|
@@ -1565,8 +1689,9 @@ function layoutTableCell(cell, tableProps, widthPt, options, fontResources, imag
|
|
|
1565
1689
|
const padTopPt = cellMar?.top ?? tableMar?.top ?? 0;
|
|
1566
1690
|
const padBottomPt = cellMar?.bottom ?? tableMar?.bottom ?? 0;
|
|
1567
1691
|
const padLeftBase = cellMar?.left ?? tableMar?.left ?? DEFAULT_CELL_PADDING_TWIPS * TWIP_TO_PT;
|
|
1568
|
-
const
|
|
1692
|
+
const padRightBase = cellMar?.right ?? tableMar?.right ?? DEFAULT_CELL_PADDING_TWIPS * TWIP_TO_PT;
|
|
1569
1693
|
const padLeftPt = padLeftBase + (cell.properties.icon ? CF_ICON_GUTTER_PT : 0);
|
|
1694
|
+
const padRightPt = padRightBase + (cell.properties.dropdown ? DROPDOWN_GUTTER_PT : 0);
|
|
1570
1695
|
const innerWidth = Math.max(1, widthPt - padLeftPt - padRightPt);
|
|
1571
1696
|
const lines = [];
|
|
1572
1697
|
const nestedTables = [];
|
|
@@ -1599,6 +1724,7 @@ function layoutTableCell(cell, tableProps, widthPt, options, fontResources, imag
|
|
|
1599
1724
|
...cell.properties.dataBar ? { dataBar: cell.properties.dataBar } : {},
|
|
1600
1725
|
...cell.properties.icon ? { icon: cell.properties.icon } : {},
|
|
1601
1726
|
...cell.properties.sparkline ? { sparkline: cell.properties.sparkline } : {},
|
|
1727
|
+
...cell.properties.dropdown ? { dropdown: true } : {},
|
|
1602
1728
|
lines,
|
|
1603
1729
|
...nestedTables.length > 0 ? { nestedTables } : {},
|
|
1604
1730
|
contentHeightPt,
|
|
@@ -2256,6 +2382,28 @@ function emitRowChunk(out, row, marginLeft, cursorY, pageHeight, colCount, cellS
|
|
|
2256
2382
|
});
|
|
2257
2383
|
}
|
|
2258
2384
|
}
|
|
2385
|
+
if (cell.dropdown && cell.mergeRole !== "middle" && cell.mergeRole !== "end") {
|
|
2386
|
+
const btn = Math.min(DROPDOWN_BUTTON_PT, Math.max(0, row.heightPt - 2));
|
|
2387
|
+
if (btn > 1) {
|
|
2388
|
+
const btnTransform = flipTransform([
|
|
2389
|
+
1,
|
|
2390
|
+
0,
|
|
2391
|
+
0,
|
|
2392
|
+
1,
|
|
2393
|
+
cellX + cell.widthPt - btn - 1.5,
|
|
2394
|
+
rowBottom + (row.heightPt - btn) / 2
|
|
2395
|
+
], pageHeight);
|
|
2396
|
+
for (const prim of buildDropdownPrims(btn)) out.push({
|
|
2397
|
+
type: "shape",
|
|
2398
|
+
shape: {
|
|
2399
|
+
paths: prim.paths,
|
|
2400
|
+
...prim.fillColorHex ? { fillColorHex: prim.fillColorHex } : {},
|
|
2401
|
+
...prim.stroke ? { stroke: prim.stroke } : {},
|
|
2402
|
+
transform: btnTransform
|
|
2403
|
+
}
|
|
2404
|
+
});
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2259
2407
|
if (cell.sparkline && cell.sparkline.values.length > 0 && cell.mergeRole !== "middle" && cell.mergeRole !== "end") {
|
|
2260
2408
|
const inset = 1.5;
|
|
2261
2409
|
const sw = cell.widthPt - 2 * inset;
|
|
@@ -33,6 +33,7 @@ async function emitStyledPdfEncrypted(laid, options, doc, encrypt) {
|
|
|
33
33
|
function assembleStyledPdf(laid, options, doc) {
|
|
34
34
|
const { pages: renderedPages } = laid;
|
|
35
35
|
const { structBuilder, sectionCtxs, pdfaProfile, tagged } = laid.pdf;
|
|
36
|
+
const commentNotes = !pdfaProfile && !structBuilder ? laid.pdf.commentNotes : void 0;
|
|
36
37
|
const docInfo = options.pdfUA && !options.info?.title ? {
|
|
37
38
|
...options.info,
|
|
38
39
|
title: "Untitled document"
|
|
@@ -158,6 +159,24 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
158
159
|
annotParentCount++;
|
|
159
160
|
}
|
|
160
161
|
annots.push(ref(annotRef.id));
|
|
162
|
+
const note = l.anchor !== void 0 ? commentNotes?.get(l.anchor) : void 0;
|
|
163
|
+
if (note) {
|
|
164
|
+
const textAnnot = doc.add(dict({
|
|
165
|
+
Type: name("Annot"),
|
|
166
|
+
Subtype: name("Text"),
|
|
167
|
+
Name: name("Comment"),
|
|
168
|
+
Rect: [
|
|
169
|
+
l.rect[0],
|
|
170
|
+
l.rect[1],
|
|
171
|
+
l.rect[2],
|
|
172
|
+
l.rect[3]
|
|
173
|
+
],
|
|
174
|
+
F: 28,
|
|
175
|
+
Contents: note.contents,
|
|
176
|
+
...note.author !== void 0 ? { T: note.author } : {}
|
|
177
|
+
}));
|
|
178
|
+
annots.push(ref(textAnnot.id));
|
|
179
|
+
}
|
|
161
180
|
}
|
|
162
181
|
if (annots.length > 0) {
|
|
163
182
|
pageEntries["Annots"] = annots;
|
|
@@ -624,6 +643,25 @@ function emitPageContent(page, tagging, gradientNames) {
|
|
|
624
643
|
const text = tok.bidiLevel % 2 === 1 ? reverseByCodePoint(tok.text) : tok.text;
|
|
625
644
|
return tok.font.measure.encodeTextAsCidHex(text);
|
|
626
645
|
};
|
|
646
|
+
if (line.tokens.some((t) => t.kind === "text" && t.highlight === true)) {
|
|
647
|
+
if (inBT) {
|
|
648
|
+
out.push("ET");
|
|
649
|
+
inBT = false;
|
|
650
|
+
}
|
|
651
|
+
const hlAscent = Math.max(lineFs, line.mathAscentPt ?? 0);
|
|
652
|
+
const hlDescent = Math.max(lineFs * .2, line.mathDescentPt ?? 0);
|
|
653
|
+
const [hr, hg, hb] = hexToRgb01("fff3a3");
|
|
654
|
+
out.push("q");
|
|
655
|
+
out.push(`${formatNumber(hr)} ${formatNumber(hg)} ${formatNumber(hb)} rg`);
|
|
656
|
+
let hx = originX;
|
|
657
|
+
for (const tok of line.tokens) {
|
|
658
|
+
const w = tok.widthPt + (tok.kind === "text" && tok.isSpace ? extraPerSpace : 0);
|
|
659
|
+
if (tok.kind === "text" && tok.highlight === true) out.push(`${formatNumber(hx)} ${formatNumber(baselineY - hlDescent)} ${formatNumber(w)} ${formatNumber(hlAscent + hlDescent)} re`);
|
|
660
|
+
hx += w;
|
|
661
|
+
}
|
|
662
|
+
out.push("f");
|
|
663
|
+
out.push("Q");
|
|
664
|
+
}
|
|
627
665
|
if (extraPerSpace > 0 || hasImageToken || hasMathToken || hasRtl) {
|
|
628
666
|
const order = hasRtl ? lineVisualOrder(line) : line.tokens.map((_, i) => i);
|
|
629
667
|
let x = originX;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { DocumentReader, ReadResult } from '../core/ir/adapters.js';
|
|
2
2
|
import { FlowDoc } from '../core/ir/flow.js';
|
|
3
|
+
import { PoNode } from '../core/po-helpers.js';
|
|
3
4
|
export declare function readPptx(bytes: Uint8Array): ReadResult<FlowDoc>;
|
|
5
|
+
export declare function parseXml(data: Uint8Array): Array<PoNode>;
|
|
4
6
|
export declare const pptxReader: DocumentReader<FlowDoc>;
|
|
@@ -3,8 +3,8 @@ import { ResourceStore } from "../core/ir/resources.js";
|
|
|
3
3
|
import { FEATURES } from "../core/ir/features.js";
|
|
4
4
|
import { EMPTY_STYLE_SHEET, resolveBodyStyles } from "../core/style-cascade/resolver.js";
|
|
5
5
|
import "../core/style-cascade/index.js";
|
|
6
|
+
import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs } from "../core/po-helpers.js";
|
|
6
7
|
import { bytesInclude } from "../core/bytes.js";
|
|
7
|
-
import { poAttr, poChildren, poIntAttr, poIs } from "../core/po-helpers.js";
|
|
8
8
|
import { DEFAULT_THEME_PALETTE, defaultColorResolver, makeColorResolver } from "../core/drawingml/colors.js";
|
|
9
9
|
import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
|
|
10
10
|
import { parseTheme } from "../core/drawingml/theme-parser.js";
|
|
@@ -81,7 +81,12 @@ function readPptx(bytes) {
|
|
|
81
81
|
colors: styles.colors,
|
|
82
82
|
resolveImage: makeSlideImageResolver(pkg, part.path, resources),
|
|
83
83
|
resolveChart: makeSlideChartResolver(pkg, part.path, charts, styles.colors),
|
|
84
|
-
resolveHyperlink: makeHyperlinkResolver(pkg, part.path)
|
|
84
|
+
resolveHyperlink: makeHyperlinkResolver(pkg, part.path),
|
|
85
|
+
resolveDiagram: makeSlideDiagramResolver(pkg, part.path),
|
|
86
|
+
onLoss: (loss) => losses.push(loss.where ? loss : {
|
|
87
|
+
...loss,
|
|
88
|
+
where: `slide ${i + 1}`
|
|
89
|
+
})
|
|
85
90
|
};
|
|
86
91
|
body.push(...parseSlide(part.data, ctx, styles.background, pageW, pageH));
|
|
87
92
|
}
|
|
@@ -167,6 +172,28 @@ function makeSlideChartResolver(pkg, slidePath, charts, colors) {
|
|
|
167
172
|
return key;
|
|
168
173
|
};
|
|
169
174
|
}
|
|
175
|
+
function makeSlideDiagramResolver(pkg, slidePath) {
|
|
176
|
+
const cache = /* @__PURE__ */ new Map();
|
|
177
|
+
return (relId) => {
|
|
178
|
+
if (cache.has(relId)) return cache.get(relId);
|
|
179
|
+
let spTree;
|
|
180
|
+
const dataRel = pkg.getPartRelationships(slidePath).find((r) => r.id === relId);
|
|
181
|
+
const data = dataRel ? pkg.resolveRelatedPart(slidePath, dataRel) : void 0;
|
|
182
|
+
if (data) {
|
|
183
|
+
const drawRel = pkg.getPartRelationships(data.path).find((r) => r.type.endsWith("/diagramDrawing"));
|
|
184
|
+
const draw = drawRel ? pkg.resolveRelatedPart(data.path, drawRel) : void 0;
|
|
185
|
+
if (draw) for (const root of parseXml(draw.data)) {
|
|
186
|
+
const found = poFindDescendant(root, "dsp:spTree");
|
|
187
|
+
if (found) {
|
|
188
|
+
spTree = found;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
cache.set(relId, spTree);
|
|
194
|
+
return spTree;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
170
197
|
function slideStylesFor(pkg, slidePath, cache) {
|
|
171
198
|
const layoutRel = pkg.getPartRelationships(slidePath).find((r) => r.type.endsWith("/slideLayout"));
|
|
172
199
|
const layout = layoutRel ? pkg.resolveRelatedPart(slidePath, layoutRel) : void 0;
|
|
@@ -210,4 +237,4 @@ var pptxReader = {
|
|
|
210
237
|
read: (bytes) => readPptx(bytes)
|
|
211
238
|
};
|
|
212
239
|
//#endregion
|
|
213
|
-
export { pptxReader };
|
|
240
|
+
export { parseXml, pptxReader };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BodyElement, ShapeFill } from '../core/document-model/index.js';
|
|
1
|
+
import { BodyElement, FloatAnchor, ShapeBlock, ShapeFill } from '../core/document-model/index.js';
|
|
2
2
|
import { ColorResolver } from '../core/drawingml/colors.js';
|
|
3
|
-
import { Pt, ResourceId } from '../core/ir/index.js';
|
|
3
|
+
import { Loss, Pt, ResourceId } from '../core/ir/index.js';
|
|
4
4
|
import { PoNode } from '../core/po-helpers.js';
|
|
5
5
|
import { PlaceholderCascade } from './placeholder-cascade.js';
|
|
6
6
|
import { ShapeBoxEmu } from './sp-helpers.js';
|
|
@@ -10,9 +10,15 @@ export interface SlideContext {
|
|
|
10
10
|
readonly resolveChart?: (relId: string) => string | undefined;
|
|
11
11
|
readonly colors?: ColorResolver;
|
|
12
12
|
readonly resolveHyperlink?: (relId: string) => string | undefined;
|
|
13
|
+
readonly resolveDiagram?: (relId: string) => PoNode | undefined;
|
|
14
|
+
readonly onLoss?: (loss: Loss) => void;
|
|
13
15
|
}
|
|
16
|
+
type LinkResolver = ((relId: string) => string | undefined) | undefined;
|
|
14
17
|
type GroupTransform = (box: ShapeBoxEmu) => ShapeBoxEmu;
|
|
15
18
|
export declare function parseSlideShapes(container: PoNode, ctx?: SlideContext, transform?: GroupTransform): Array<BodyElement>;
|
|
19
|
+
export declare function diagramTransform(spTree: PoNode, frame: ShapeBoxEmu): GroupTransform;
|
|
20
|
+
export declare function noDiagramOverrideLoss(where?: string): Loss;
|
|
21
|
+
export declare function parseDiagramDrawing(spTree: PoNode, transform: GroupTransform, makeFloat: (box: ShapeBoxEmu) => FloatAnchor, colors: ColorResolver, resolveLink: LinkResolver): Array<ShapeBlock>;
|
|
16
22
|
export declare function parseBackgroundFill(bg: PoNode, colors: ColorResolver): ShapeFill | undefined;
|
|
17
23
|
export declare function backdropElement(fill: ShapeFill, widthPt: Pt, heightPt: Pt): BodyElement;
|
|
18
24
|
export {};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { emuToPt } from "../core/ir/units.js";
|
|
2
|
+
import { FEATURES } from "../core/ir/features.js";
|
|
2
3
|
import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs, poText } from "../core/po-helpers.js";
|
|
3
4
|
import { defaultColorResolver, resolveColorNode } from "../core/drawingml/colors.js";
|
|
4
|
-
import { parseCustGeom, parseFill, parseLine, parsePrstGeom } from "../word/drawing-parser.js";
|
|
5
5
|
import { boxFromXfrm, parsePh, parseXfrmBox, rPrToRunProps } from "./sp-helpers.js";
|
|
6
|
+
import { parseCustGeom, parseFill, parseLine, parsePrstGeom } from "../word/drawing-parser.js";
|
|
6
7
|
//#region src/pptx/slide-parser.ts
|
|
7
8
|
var CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
|
|
8
9
|
var TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
|
|
10
|
+
var DIAGRAM_URI = "http://schemas.openxmlformats.org/drawingml/2006/diagram";
|
|
9
11
|
var ALGN_TO_ALIGNMENT = {
|
|
10
12
|
l: "left",
|
|
11
13
|
ctr: "center",
|
|
@@ -33,10 +35,8 @@ function parseSlideShapes(container, ctx = {}, transform = IDENTITY_TRANSFORM) {
|
|
|
33
35
|
kind: "image",
|
|
34
36
|
image
|
|
35
37
|
});
|
|
36
|
-
} else if (poIs(child, "p:graphicFrame"))
|
|
37
|
-
|
|
38
|
-
if (el) out.push(el);
|
|
39
|
-
} else if (poIs(child, "p:grpSp")) out.push(...parseSlideShapes(child, ctx, composeGroupTransform(child, transform)));
|
|
38
|
+
} else if (poIs(child, "p:graphicFrame")) out.push(...parseGraphicFrame(child, ctx, transform));
|
|
39
|
+
else if (poIs(child, "p:grpSp")) out.push(...parseSlideShapes(child, ctx, composeGroupTransform(child, transform)));
|
|
40
40
|
return out;
|
|
41
41
|
}
|
|
42
42
|
function composeGroupTransform(grpSp, parent) {
|
|
@@ -106,7 +106,7 @@ function parseSp(sp, ctx, transform) {
|
|
|
106
106
|
}
|
|
107
107
|
function parseGraphicFrame(gf, ctx, transform) {
|
|
108
108
|
const own = boxFromXfrm(poChildren(gf).find((c) => poIs(c, "p:xfrm")));
|
|
109
|
-
if (!own) return
|
|
109
|
+
if (!own) return [];
|
|
110
110
|
const box = transform(own);
|
|
111
111
|
const graphicData = poFindDescendant(gf, "a:graphicData");
|
|
112
112
|
const uri = graphicData ? poAttr(graphicData, "uri") : void 0;
|
|
@@ -114,8 +114,8 @@ function parseGraphicFrame(gf, ctx, transform) {
|
|
|
114
114
|
const cChart = poFindDescendant(gf, "c:chart");
|
|
115
115
|
const relId = cChart ? poAttr(cChart, "id") : void 0;
|
|
116
116
|
const key = relId !== void 0 ? ctx.resolveChart?.(relId) : void 0;
|
|
117
|
-
if (key === void 0) return
|
|
118
|
-
return {
|
|
117
|
+
if (key === void 0) return [];
|
|
118
|
+
return [{
|
|
119
119
|
kind: "chart",
|
|
120
120
|
chart: {
|
|
121
121
|
float: floatAt(box),
|
|
@@ -124,15 +124,83 @@ function parseGraphicFrame(gf, ctx, transform) {
|
|
|
124
124
|
height: emuToPt(box.cy),
|
|
125
125
|
paragraphProperties: {}
|
|
126
126
|
}
|
|
127
|
-
};
|
|
127
|
+
}];
|
|
128
128
|
}
|
|
129
129
|
if (uri === TABLE_URI) {
|
|
130
130
|
const tbl = poFindDescendant(gf, "a:tbl");
|
|
131
|
-
return tbl ? {
|
|
131
|
+
return tbl ? [{
|
|
132
132
|
kind: "table",
|
|
133
133
|
table: parseTable(tbl, ctx.colors ?? defaultColorResolver)
|
|
134
|
-
} :
|
|
134
|
+
}] : [];
|
|
135
135
|
}
|
|
136
|
+
if (uri === DIAGRAM_URI) {
|
|
137
|
+
const relIds = poFindDescendant(gf, "dgm:relIds");
|
|
138
|
+
const dmRelId = relIds ? poAttr(relIds, "dm") : void 0;
|
|
139
|
+
const spTree = dmRelId !== void 0 ? ctx.resolveDiagram?.(dmRelId) : void 0;
|
|
140
|
+
if (!spTree) {
|
|
141
|
+
if (dmRelId !== void 0) ctx.onLoss?.(noDiagramOverrideLoss());
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
return parseDiagramDrawing(spTree, diagramTransform(spTree, box), floatAt, ctx.colors ?? defaultColorResolver, ctx.resolveHyperlink).map((shape) => ({
|
|
145
|
+
kind: "shape",
|
|
146
|
+
shape
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
function diagramTransform(spTree, frame) {
|
|
152
|
+
const grpSpPr = poChildren(spTree).find((c) => poIs(c, "dsp:grpSpPr"));
|
|
153
|
+
const xfrm = grpSpPr ? poChildren(grpSpPr).find((c) => poIs(c, "a:xfrm")) : void 0;
|
|
154
|
+
const chOff = xfrm ? poChildren(xfrm).find((c) => poIs(c, "a:chOff")) : void 0;
|
|
155
|
+
const chExt = xfrm ? poChildren(xfrm).find((c) => poIs(c, "a:chExt")) : void 0;
|
|
156
|
+
const chExtCx = chExt ? poIntAttr(chExt, "cx") : void 0;
|
|
157
|
+
const chExtCy = chExt ? poIntAttr(chExt, "cy") : void 0;
|
|
158
|
+
const chOffX = (chOff ? poIntAttr(chOff, "x") : void 0) ?? 0;
|
|
159
|
+
const chOffY = (chOff ? poIntAttr(chOff, "y") : void 0) ?? 0;
|
|
160
|
+
const sx = chExtCx && chExtCx > 0 ? frame.cx / chExtCx : 1;
|
|
161
|
+
const sy = chExtCy && chExtCy > 0 ? frame.cy / chExtCy : 1;
|
|
162
|
+
return (b) => ({
|
|
163
|
+
x: frame.x + (b.x - chOffX) * sx,
|
|
164
|
+
y: frame.y + (b.y - chOffY) * sy,
|
|
165
|
+
cx: b.cx * sx,
|
|
166
|
+
cy: b.cy * sy
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function noDiagramOverrideLoss(where) {
|
|
170
|
+
return {
|
|
171
|
+
severity: "dropped",
|
|
172
|
+
feature: FEATURES.smartArt,
|
|
173
|
+
detail: "SmartArt diagram has no pre-rendered drawing override; its layout is not reconstructed",
|
|
174
|
+
...where ? { where } : {}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function parseDiagramDrawing(spTree, transform, makeFloat, colors, resolveLink) {
|
|
178
|
+
const out = [];
|
|
179
|
+
for (const sp of poChildren(spTree)) {
|
|
180
|
+
if (!poIs(sp, "dsp:sp")) continue;
|
|
181
|
+
const spPr = poChildren(sp).find((c) => poIs(c, "dsp:spPr"));
|
|
182
|
+
const own = parseXfrmBox(spPr);
|
|
183
|
+
if (!own) continue;
|
|
184
|
+
const box = transform(own);
|
|
185
|
+
const txBody = poChildren(sp).find((c) => poIs(c, "dsp:txBody"));
|
|
186
|
+
const text = txBody ? parseTxBody(txBody, void 0, void 0, colors, resolveLink) : void 0;
|
|
187
|
+
const geometry = parseGeometry(spPr);
|
|
188
|
+
const fill = spPr ? parseFill(spPr, colors) : { kind: "none" };
|
|
189
|
+
const line = spPr ? parseLine(spPr, colors) : void 0;
|
|
190
|
+
const visibleLine = line !== void 0 && line.fill !== "none";
|
|
191
|
+
if (!text && fill.kind === "none" && !visibleLine) continue;
|
|
192
|
+
out.push({
|
|
193
|
+
float: makeFloat(box),
|
|
194
|
+
width: emuToPt(box.cx),
|
|
195
|
+
height: emuToPt(box.cy),
|
|
196
|
+
geometry,
|
|
197
|
+
fill,
|
|
198
|
+
...line ? { line } : {},
|
|
199
|
+
...text ? { text } : {},
|
|
200
|
+
paragraphProperties: {}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return out;
|
|
136
204
|
}
|
|
137
205
|
function parseBackgroundFill(bg, colors) {
|
|
138
206
|
const bgPr = poChildren(bg).find((c) => poIs(c, "p:bgPr"));
|
|
@@ -356,4 +424,4 @@ function cellFillHex(tcPr, colors) {
|
|
|
356
424
|
}
|
|
357
425
|
}
|
|
358
426
|
//#endregion
|
|
359
|
-
export { backdropElement, parseBackgroundFill, parseSlideShapes };
|
|
427
|
+
export { backdropElement, diagramTransform, noDiagramOverrideLoss, parseBackgroundFill, parseDiagramDrawing, parseSlideShapes };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BodyElement, Section, SectionProperties } from '../core/document-model/index.js';
|
|
1
|
+
import { BodyElement, Comment, Section, SectionProperties } from '../core/document-model/index.js';
|
|
2
2
|
import { ColorResolver } from '../core/drawingml/colors.js';
|
|
3
|
-
import { ResourceId } from '../core/ir/index.js';
|
|
3
|
+
import { Loss, ResourceId } from '../core/ir/index.js';
|
|
4
4
|
import { PoNode } from '../core/po-helpers.js';
|
|
5
5
|
export type ImageResolver = (relId: string) => ResourceId | undefined;
|
|
6
6
|
export type HyperlinkResolver = (relId: string) => string | undefined;
|
|
@@ -8,6 +8,9 @@ export interface ParseContext {
|
|
|
8
8
|
readonly resolveColor: ColorResolver;
|
|
9
9
|
readonly resolveImage?: ImageResolver;
|
|
10
10
|
readonly resolveHyperlink?: HyperlinkResolver;
|
|
11
|
+
readonly resolveDiagram?: (relId: string) => PoNode | undefined;
|
|
12
|
+
readonly onLoss?: (loss: Loss) => void;
|
|
13
|
+
readonly openCommentRanges?: Set<string>;
|
|
11
14
|
}
|
|
12
15
|
export declare const DEFAULT_PARSE_CONTEXT: ParseContext;
|
|
13
16
|
export declare function parseDocument(documentXml: Uint8Array, ctx?: ParseContext): Array<BodyElement>;
|
|
@@ -17,3 +20,15 @@ export declare function parseSections(documentXml: Uint8Array): Array<Section>;
|
|
|
17
20
|
export declare function parseHeaderFooter(xml: Uint8Array, ctx?: ParseContext): Array<BodyElement>;
|
|
18
21
|
export declare function parseBodyElements(children: ReadonlyArray<PoNode>, ctx?: ParseContext): Array<BodyElement>;
|
|
19
22
|
export declare function parseNotes(notesXml: Uint8Array, rootTag: 'w:footnotes' | 'w:endnotes', noteTag: 'w:footnote' | 'w:endnote', ctx?: ParseContext): Map<string, Array<BodyElement>>;
|
|
23
|
+
export declare function parseComments(commentsXml: Uint8Array, ctx?: ParseContext): Map<string, Comment>;
|
|
24
|
+
/** A commentsExtended entry, keyed by the comment's last-paragraph w14:paraId. */
|
|
25
|
+
export interface CommentExtension {
|
|
26
|
+
/** The parent comment's paraId — present when this comment is a reply. */
|
|
27
|
+
readonly paraIdParent?: string;
|
|
28
|
+
/** w15:done — the thread is resolved. */
|
|
29
|
+
readonly done: boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare function parseCommentsExtended(xml: Uint8Array): Map<string, CommentExtension>;
|
|
32
|
+
export declare function parseCommentThreads(commentsXml: Uint8Array, commentsExtendedXml: Uint8Array | undefined, ctx?: ParseContext): Map<string, Comment>;
|
|
33
|
+
export declare function parsePeople(xml: Uint8Array): Map<string, string>;
|
|
34
|
+
export declare function applyAuthorIds(comments: Map<string, Comment>, people: Map<string, string>): Map<string, Comment>;
|