reamkit 1.11.0 → 1.12.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 +23 -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/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 +16 -0
- 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.js +28 -6
- package/dist/esm/excel/xlsx-reader.js +33 -2
- package/dist/esm/html/html-writer.js +52 -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 +111 -5
- 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
|
}
|
|
@@ -756,6 +857,7 @@ function collectImageResources(body, headersFooters, options) {
|
|
|
756
857
|
for (const hf of headersFooters.values()) visit(hf);
|
|
757
858
|
for (const note of options.footnotes?.values() ?? []) visit(note);
|
|
758
859
|
for (const note of options.endnotes?.values() ?? []) visit(note);
|
|
860
|
+
for (const comment of options.comments?.values() ?? []) visit(comment.content);
|
|
759
861
|
const flattenAlpha = options.pdfA ? parsePdfAProfile(options.pdfA).part === 1 : false;
|
|
760
862
|
let counter = 0;
|
|
761
863
|
for (const resourceId of seen) {
|
|
@@ -916,6 +1018,7 @@ function collectFontResources(body, headersFooters, options) {
|
|
|
916
1018
|
for (const hf of headersFooters.values()) visit(hf);
|
|
917
1019
|
for (const note of options.footnotes?.values() ?? []) visit(note);
|
|
918
1020
|
for (const note of options.endnotes?.values() ?? []) visit(note);
|
|
1021
|
+
for (const comment of options.comments?.values() ?? []) visit(comment.content);
|
|
919
1022
|
if (used.size === 0) {
|
|
920
1023
|
const regular = options.registry.resolveByStyle(false, false);
|
|
921
1024
|
used.set(regular.variant, {
|
|
@@ -1086,6 +1189,7 @@ function tokenizePlansLtr(plans) {
|
|
|
1086
1189
|
});
|
|
1087
1190
|
continue;
|
|
1088
1191
|
}
|
|
1192
|
+
const highlight = (plan.run.commentRangeRefs?.length ?? 0) > 0;
|
|
1089
1193
|
for (const t of tokenizeText(plan.run.text)) tokens.push({
|
|
1090
1194
|
kind: "text",
|
|
1091
1195
|
text: t.text,
|
|
@@ -1094,6 +1198,7 @@ function tokenizePlansLtr(plans) {
|
|
|
1094
1198
|
...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
|
|
1095
1199
|
...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
|
|
1096
1200
|
...plan.run.listMarker ? { listMarker: true } : {},
|
|
1201
|
+
...highlight ? { highlight: true } : {},
|
|
1097
1202
|
resolvedRun: plan.resolvedRun,
|
|
1098
1203
|
font: plan.font,
|
|
1099
1204
|
fontSizePt: plan.fontSizePt,
|
|
@@ -1148,6 +1253,7 @@ function tokenizePlansBidi(plans, realLevels) {
|
|
|
1148
1253
|
...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
|
|
1149
1254
|
...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
|
|
1150
1255
|
...plan.run.listMarker ? { listMarker: true } : {},
|
|
1256
|
+
...(plan.run.commentRangeRefs?.length ?? 0) > 0 ? { highlight: true } : {},
|
|
1151
1257
|
resolvedRun: plan.resolvedRun,
|
|
1152
1258
|
font: plan.font,
|
|
1153
1259
|
fontSizePt: plan.fontSizePt,
|
|
@@ -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>;
|