@coding01/docsjs 0.1.3 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -21
- package/README.zh-CN.md +74 -20
- package/dist/{chunk-PRPDJOB7.js → chunk-632UOG2B.js} +448 -102
- package/dist/chunk-632UOG2B.js.map +1 -0
- package/dist/index.cjs +452 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +449 -102
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +12 -3
- package/dist/react.js.map +1 -1
- package/dist/types-VvdwVF0_.d.cts +44 -0
- package/dist/types-VvdwVF0_.d.ts +44 -0
- package/dist/vue.cjs +438 -100
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.cts +1 -1
- package/dist/vue.d.ts +1 -1
- package/dist/vue.js +1 -1
- package/package.json +3 -1
- package/dist/chunk-PRPDJOB7.js.map +0 -1
- package/dist/types-DF14w1ol.d.cts +0 -20
- package/dist/types-DF14w1ol.d.ts +0 -20
package/dist/react.cjs
CHANGED
|
@@ -56,6 +56,21 @@ function buildHtmlSnapshot(rawHtml) {
|
|
|
56
56
|
|
|
57
57
|
// src/lib/docxHtml.ts
|
|
58
58
|
var import_jszip = __toESM(require("jszip"), 1);
|
|
59
|
+
function createEmptyFeatureCounts() {
|
|
60
|
+
return {
|
|
61
|
+
hyperlinkCount: 0,
|
|
62
|
+
anchorImageCount: 0,
|
|
63
|
+
chartCount: 0,
|
|
64
|
+
smartArtCount: 0,
|
|
65
|
+
ommlCount: 0,
|
|
66
|
+
tableCount: 0,
|
|
67
|
+
footnoteRefCount: 0,
|
|
68
|
+
endnoteRefCount: 0,
|
|
69
|
+
commentRefCount: 0,
|
|
70
|
+
revisionCount: 0,
|
|
71
|
+
pageBreakCount: 0
|
|
72
|
+
};
|
|
73
|
+
}
|
|
59
74
|
function escapeHtml(text) {
|
|
60
75
|
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
61
76
|
}
|
|
@@ -79,6 +94,9 @@ function getAttr(node, name) {
|
|
|
79
94
|
function emuToPx(emu) {
|
|
80
95
|
return emu * 96 / 914400;
|
|
81
96
|
}
|
|
97
|
+
function twipToPx(twip) {
|
|
98
|
+
return twip * 96 / 1440;
|
|
99
|
+
}
|
|
82
100
|
function parseDrawingSizePx(drawing) {
|
|
83
101
|
const extentNode = queryAllByLocalName(drawing, "extent").find((node) => {
|
|
84
102
|
const parent = node.parentElement;
|
|
@@ -107,9 +125,7 @@ function imageDimensionAttributes(sizePx) {
|
|
|
107
125
|
}
|
|
108
126
|
return attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
109
127
|
}
|
|
110
|
-
function parseAnchorPositionPx(
|
|
111
|
-
const anchor = directChildrenByLocalName(drawing, "anchor")[0] ?? null;
|
|
112
|
-
if (!anchor) return { leftPx: null, topPx: null };
|
|
128
|
+
function parseAnchorPositionPx(anchor) {
|
|
113
129
|
let leftPx = null;
|
|
114
130
|
let topPx = null;
|
|
115
131
|
const positionH = directChildrenByLocalName(anchor, "positionH")[0] ?? null;
|
|
@@ -124,34 +140,80 @@ function parseAnchorPositionPx(drawing) {
|
|
|
124
140
|
if (Number.isFinite(top)) topPx = emuToPx(top);
|
|
125
141
|
return { leftPx, topPx };
|
|
126
142
|
}
|
|
127
|
-
function parseAnchorWrapMode(
|
|
128
|
-
const anchor = directChildrenByLocalName(drawing, "anchor")[0] ?? null;
|
|
129
|
-
if (!anchor) return null;
|
|
143
|
+
function parseAnchorWrapMode(anchor) {
|
|
130
144
|
if (directChildrenByLocalName(anchor, "wrapSquare")[0]) return "square";
|
|
131
145
|
if (directChildrenByLocalName(anchor, "wrapTight")[0]) return "tight";
|
|
132
146
|
if (directChildrenByLocalName(anchor, "wrapTopAndBottom")[0]) return "topAndBottom";
|
|
133
147
|
if (directChildrenByLocalName(anchor, "wrapNone")[0]) return "none";
|
|
134
148
|
return null;
|
|
135
149
|
}
|
|
136
|
-
function
|
|
137
|
-
|
|
150
|
+
function parseAnchorMeta(drawing) {
|
|
151
|
+
const anchor = directChildrenByLocalName(drawing, "anchor")[0] ?? null;
|
|
152
|
+
if (!anchor) return null;
|
|
153
|
+
const positionH = directChildrenByLocalName(anchor, "positionH")[0] ?? null;
|
|
154
|
+
const positionV = directChildrenByLocalName(anchor, "positionV")[0] ?? null;
|
|
155
|
+
const relativeFromH = getAttr(positionH, "relativeFrom");
|
|
156
|
+
const relativeFromV = getAttr(positionV, "relativeFrom");
|
|
157
|
+
const parseDistPx = (name) => {
|
|
158
|
+
const raw = getAttr(anchor, name);
|
|
159
|
+
const emu = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
160
|
+
return Number.isFinite(emu) && emu >= 0 ? emuToPx(emu) : null;
|
|
161
|
+
};
|
|
162
|
+
const rawHeight = getAttr(anchor, "relativeHeight");
|
|
163
|
+
const parsedHeight = rawHeight ? Number.parseInt(rawHeight, 10) : Number.NaN;
|
|
164
|
+
const boolAttr = (name, fallback) => {
|
|
165
|
+
const raw = (getAttr(anchor, name) ?? "").toLowerCase();
|
|
166
|
+
if (raw === "1" || raw === "true" || raw === "on") return true;
|
|
167
|
+
if (raw === "0" || raw === "false" || raw === "off") return false;
|
|
168
|
+
return fallback;
|
|
169
|
+
};
|
|
170
|
+
return {
|
|
171
|
+
position: parseAnchorPositionPx(anchor),
|
|
172
|
+
wrapMode: parseAnchorWrapMode(anchor),
|
|
173
|
+
distTPx: parseDistPx("distT"),
|
|
174
|
+
distBPx: parseDistPx("distB"),
|
|
175
|
+
distLPx: parseDistPx("distL"),
|
|
176
|
+
distRPx: parseDistPx("distR"),
|
|
177
|
+
relativeFromH,
|
|
178
|
+
relativeFromV,
|
|
179
|
+
behindDoc: boolAttr("behindDoc", false),
|
|
180
|
+
allowOverlap: boolAttr("allowOverlap", true),
|
|
181
|
+
layoutInCell: boolAttr("layoutInCell", true),
|
|
182
|
+
relativeHeight: Number.isFinite(parsedHeight) ? parsedHeight : null
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function mergeImageStyle(baseAttrs, anchorMeta) {
|
|
186
|
+
if (!anchorMeta) return baseAttrs;
|
|
187
|
+
const { position, wrapMode } = anchorMeta;
|
|
188
|
+
if (position.leftPx === null && position.topPx === null) return baseAttrs;
|
|
138
189
|
const styleParts = [
|
|
139
190
|
"position:absolute",
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
191
|
+
position.leftPx !== null ? `left:${position.leftPx.toFixed(2)}px` : "",
|
|
192
|
+
position.topPx !== null ? `top:${position.topPx.toFixed(2)}px` : "",
|
|
193
|
+
`z-index:${anchorMeta.behindDoc ? 0 : anchorMeta.relativeHeight ?? 3}`,
|
|
194
|
+
anchorMeta.distTPx !== null ? `margin-top:${anchorMeta.distTPx.toFixed(2)}px` : "",
|
|
195
|
+
anchorMeta.distBPx !== null ? `margin-bottom:${anchorMeta.distBPx.toFixed(2)}px` : "",
|
|
196
|
+
anchorMeta.distLPx !== null ? `margin-left:${anchorMeta.distLPx.toFixed(2)}px` : "",
|
|
197
|
+
anchorMeta.distRPx !== null ? `margin-right:${anchorMeta.distRPx.toFixed(2)}px` : ""
|
|
143
198
|
].filter((x) => x.length > 0);
|
|
144
199
|
if (wrapMode === "topAndBottom") {
|
|
145
|
-
styleParts.push("display:block");
|
|
146
|
-
}
|
|
200
|
+
styleParts.push("display:block", "clear:both");
|
|
201
|
+
}
|
|
202
|
+
const anchorAttrs = [
|
|
203
|
+
`data-word-anchor="1"`,
|
|
204
|
+
wrapMode ? `data-word-wrap="${wrapMode}"` : "",
|
|
205
|
+
anchorMeta.relativeFromH ? `data-word-anchor-relh="${escapeHtml(anchorMeta.relativeFromH)}"` : "",
|
|
206
|
+
anchorMeta.relativeFromV ? `data-word-anchor-relv="${escapeHtml(anchorMeta.relativeFromV)}"` : "",
|
|
207
|
+
anchorMeta.behindDoc ? `data-word-anchor-behind="1"` : `data-word-anchor-behind="0"`,
|
|
208
|
+
anchorMeta.allowOverlap ? `data-word-anchor-overlap="1"` : `data-word-anchor-overlap="0"`,
|
|
209
|
+
anchorMeta.layoutInCell ? `data-word-anchor-layout-cell="1"` : `data-word-anchor-layout-cell="0"`
|
|
210
|
+
].filter((x) => x.length > 0).join(" ");
|
|
147
211
|
if (!baseAttrs.includes("style=")) {
|
|
148
|
-
|
|
149
|
-
return `${baseAttrs} style="${styleParts.join(";")}" data-word-anchor="1"${wrapAttr}`;
|
|
212
|
+
return `${baseAttrs} style="${styleParts.join(";")}" ${anchorAttrs}`;
|
|
150
213
|
}
|
|
151
214
|
return baseAttrs.replace(/style="([^"]*)"/, (_m, styleText) => {
|
|
152
215
|
const merged = [styleText, ...styleParts].filter((x) => x.length > 0).join(";");
|
|
153
|
-
|
|
154
|
-
return `style="${merged}" data-word-anchor="1"${wrapAttr}`;
|
|
216
|
+
return `style="${merged}" ${anchorAttrs}`;
|
|
155
217
|
});
|
|
156
218
|
}
|
|
157
219
|
function parseDocRelsMap(relsXmlText) {
|
|
@@ -177,11 +239,29 @@ function extToMime(ext) {
|
|
|
177
239
|
if (lower === "svg") return "image/svg+xml";
|
|
178
240
|
return "application/octet-stream";
|
|
179
241
|
}
|
|
242
|
+
function normalizeWordPath(relTarget) {
|
|
243
|
+
const normalized = relTarget.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
244
|
+
if (normalized.startsWith("word/")) return normalized;
|
|
245
|
+
if (normalized.startsWith("../")) return `word/${normalized.replace(/^(\.\.\/)+/, "")}`;
|
|
246
|
+
return `word/${normalized}`;
|
|
247
|
+
}
|
|
248
|
+
function resolveHyperlinkHref(relMap, rid, anchor) {
|
|
249
|
+
if (anchor && anchor.trim()) return `#${encodeURIComponent(anchor.trim())}`;
|
|
250
|
+
if (!rid) return null;
|
|
251
|
+
const relTarget = relMap[rid];
|
|
252
|
+
if (!relTarget) return null;
|
|
253
|
+
const trimmed = relTarget.trim();
|
|
254
|
+
if (!trimmed) return null;
|
|
255
|
+
const lower = trimmed.toLowerCase();
|
|
256
|
+
if (lower.startsWith("http://") || lower.startsWith("https://") || lower.startsWith("mailto:") || lower.startsWith("tel:")) {
|
|
257
|
+
return trimmed;
|
|
258
|
+
}
|
|
259
|
+
return trimmed.startsWith("#") ? trimmed : `#${encodeURIComponent(trimmed)}`;
|
|
260
|
+
}
|
|
180
261
|
async function imageRidToDataUrl(zip, relMap, rid) {
|
|
181
262
|
const relTarget = relMap[rid];
|
|
182
263
|
if (!relTarget) return null;
|
|
183
|
-
const
|
|
184
|
-
const path = normalized.startsWith("word/") ? normalized : `word/${normalized}`;
|
|
264
|
+
const path = normalizeWordPath(relTarget);
|
|
185
265
|
const file = zip.file(path);
|
|
186
266
|
if (!file) return null;
|
|
187
267
|
const base64 = await file.async("base64");
|
|
@@ -189,6 +269,55 @@ async function imageRidToDataUrl(zip, relMap, rid) {
|
|
|
189
269
|
const mime = extToMime(ext);
|
|
190
270
|
return `data:${mime};base64,${base64}`;
|
|
191
271
|
}
|
|
272
|
+
async function readXmlByRid(zip, relMap, rid) {
|
|
273
|
+
const relTarget = relMap[rid];
|
|
274
|
+
if (!relTarget) return null;
|
|
275
|
+
const path = normalizeWordPath(relTarget);
|
|
276
|
+
const file = zip.file(path);
|
|
277
|
+
return file ? file.async("string") : null;
|
|
278
|
+
}
|
|
279
|
+
function parseChartType(chartDoc) {
|
|
280
|
+
const known = ["barChart", "lineChart", "pieChart", "areaChart", "scatterChart", "radarChart", "doughnutChart"];
|
|
281
|
+
for (const type of known) {
|
|
282
|
+
if (queryByLocalName(chartDoc, type)) return type.replace(/Chart$/, "");
|
|
283
|
+
}
|
|
284
|
+
return "unknown";
|
|
285
|
+
}
|
|
286
|
+
function parseChartSummary(chartXmlText) {
|
|
287
|
+
const chartDoc = parseXml(chartXmlText);
|
|
288
|
+
const title = queryAllByLocalName(chartDoc, "t").map((n) => (n.textContent ?? "").trim()).find((v) => v.length > 0) ?? "Chart";
|
|
289
|
+
const seriesCount = queryAllByLocalName(chartDoc, "ser").length;
|
|
290
|
+
const pointCount = queryAllByLocalName(chartDoc, "pt").length;
|
|
291
|
+
const type = parseChartType(chartDoc);
|
|
292
|
+
return { title, type, seriesCount, pointCount };
|
|
293
|
+
}
|
|
294
|
+
function extractSmartArtText(diagramXmlText) {
|
|
295
|
+
const diagramDoc = parseXml(diagramXmlText);
|
|
296
|
+
return queryAllByLocalName(diagramDoc, "t").map((n) => (n.textContent ?? "").trim()).filter((v) => v.length > 0).slice(0, 12);
|
|
297
|
+
}
|
|
298
|
+
function ommlNodeToText(node) {
|
|
299
|
+
if (node.localName === "t") return node.textContent ?? "";
|
|
300
|
+
if (node.localName === "f") {
|
|
301
|
+
const num = queryByLocalName(node, "num");
|
|
302
|
+
const den = queryByLocalName(node, "den");
|
|
303
|
+
return `(${num ? ommlNodeToText(num) : "?"})/(${den ? ommlNodeToText(den) : "?"})`;
|
|
304
|
+
}
|
|
305
|
+
if (node.localName === "sSup") {
|
|
306
|
+
const e = queryByLocalName(node, "e");
|
|
307
|
+
const sup = queryByLocalName(node, "sup");
|
|
308
|
+
return `${e ? ommlNodeToText(e) : ""}^(${sup ? ommlNodeToText(sup) : ""})`;
|
|
309
|
+
}
|
|
310
|
+
if (node.localName === "sSub") {
|
|
311
|
+
const e = queryByLocalName(node, "e");
|
|
312
|
+
const sub = queryByLocalName(node, "sub");
|
|
313
|
+
return `${e ? ommlNodeToText(e) : ""}_(${sub ? ommlNodeToText(sub) : ""})`;
|
|
314
|
+
}
|
|
315
|
+
if (node.localName === "rad") {
|
|
316
|
+
const e = queryByLocalName(node, "e");
|
|
317
|
+
return `sqrt(${e ? ommlNodeToText(e) : ""})`;
|
|
318
|
+
}
|
|
319
|
+
return Array.from(node.children).map((child) => ommlNodeToText(child)).join("");
|
|
320
|
+
}
|
|
192
321
|
function runStyleToCss(rPr) {
|
|
193
322
|
if (!rPr) return "";
|
|
194
323
|
const declarations = [];
|
|
@@ -303,48 +432,73 @@ function renderEndnotesSection(usedIds, endnotesMap) {
|
|
|
303
432
|
const items = uniq.map((id) => `<li id="word-endnote-${id}" data-word-endnote-id="${id}">${endnotesMap[id]}</li>`).join("");
|
|
304
433
|
return `<section data-word-endnotes="1"><hr/><ol>${items}</ol></section>`;
|
|
305
434
|
}
|
|
306
|
-
async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotesMap, usedFootnoteIds, endnotesMap, usedEndnoteIds, commentsMap, usedCommentIds) {
|
|
435
|
+
async function paragraphToHtml(zip, relMap, context, paragraph, paragraphIndex, footnotesMap, usedFootnoteIds, endnotesMap, usedEndnoteIds, commentsMap, usedCommentIds) {
|
|
307
436
|
const tag = paragraphTag(paragraph);
|
|
308
437
|
const alignStyle = paragraphAlignStyle(paragraph);
|
|
309
438
|
const dataAttr = paragraphDataAttr(paragraphIndex);
|
|
310
|
-
const
|
|
311
|
-
if (
|
|
439
|
+
const hasRenderableNode = queryAllByLocalName(paragraph, "r").length > 0 || queryAllByLocalName(paragraph, "oMath").length > 0 || queryAllByLocalName(paragraph, "oMathPara").length > 0;
|
|
440
|
+
if (!hasRenderableNode) {
|
|
312
441
|
return `<${tag}${dataAttr}${alignStyle ? ` style="${alignStyle}"` : ""}><br/></${tag}>`;
|
|
313
442
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
443
|
+
function parseRevisionMeta(node, type) {
|
|
444
|
+
return {
|
|
445
|
+
type,
|
|
446
|
+
id: getAttr(node, "w:id") ?? getAttr(node, "id"),
|
|
447
|
+
author: getAttr(node, "w:author") ?? getAttr(node, "author"),
|
|
448
|
+
date: getAttr(node, "w:date") ?? getAttr(node, "date")
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
function inferRevisionMeta(run, fallback) {
|
|
452
|
+
if (fallback) return fallback;
|
|
453
|
+
let cursor = run;
|
|
454
|
+
while (cursor) {
|
|
455
|
+
if (cursor.localName === "ins") return parseRevisionMeta(cursor, "ins");
|
|
456
|
+
if (cursor.localName === "del") return parseRevisionMeta(cursor, "del");
|
|
457
|
+
if (cursor.localName === "p") break;
|
|
458
|
+
cursor = cursor.parentElement;
|
|
459
|
+
}
|
|
460
|
+
return null;
|
|
318
461
|
}
|
|
319
|
-
|
|
462
|
+
function revisionMetaAttrs(meta) {
|
|
463
|
+
const attrs = [`data-word-revision="${meta.type}"`];
|
|
464
|
+
if (meta.id) attrs.push(`data-word-revision-id="${escapeHtml(meta.id)}"`);
|
|
465
|
+
if (meta.author) attrs.push(`data-word-revision-author="${escapeHtml(meta.author)}"`);
|
|
466
|
+
if (meta.date) attrs.push(`data-word-revision-date="${escapeHtml(meta.date)}"`);
|
|
467
|
+
return attrs.join(" ");
|
|
468
|
+
}
|
|
469
|
+
async function runToHtml(run, revisionFallback) {
|
|
470
|
+
const result = [];
|
|
320
471
|
const rPr = queryByLocalName(run, "rPr");
|
|
321
472
|
const css = runStyleToCss(rPr);
|
|
322
473
|
const footnoteRef = queryByLocalName(run, "footnoteReference");
|
|
323
474
|
const footnoteId = getAttr(footnoteRef, "w:id") ?? getAttr(footnoteRef, "id");
|
|
324
475
|
if (footnoteId && footnotesMap[footnoteId]) {
|
|
476
|
+
context.features.footnoteRefCount += 1;
|
|
325
477
|
usedFootnoteIds.push(footnoteId);
|
|
326
|
-
|
|
478
|
+
result.push(
|
|
327
479
|
`<sup data-word-footnote-ref="${footnoteId}"><a href="#word-footnote-${footnoteId}">[${footnoteId}]</a></sup>`
|
|
328
480
|
);
|
|
329
|
-
|
|
481
|
+
return result;
|
|
330
482
|
}
|
|
331
483
|
const endnoteRef = queryByLocalName(run, "endnoteReference");
|
|
332
484
|
const endnoteId = getAttr(endnoteRef, "w:id") ?? getAttr(endnoteRef, "id");
|
|
333
485
|
if (endnoteId && endnotesMap[endnoteId]) {
|
|
486
|
+
context.features.endnoteRefCount += 1;
|
|
334
487
|
usedEndnoteIds.push(endnoteId);
|
|
335
|
-
|
|
488
|
+
result.push(
|
|
336
489
|
`<sup data-word-endnote-ref="${endnoteId}"><a href="#word-endnote-${endnoteId}">[${endnoteId}]</a></sup>`
|
|
337
490
|
);
|
|
338
|
-
|
|
491
|
+
return result;
|
|
339
492
|
}
|
|
340
493
|
const commentRef = queryByLocalName(run, "commentReference");
|
|
341
494
|
const commentId = getAttr(commentRef, "w:id") ?? getAttr(commentRef, "id");
|
|
342
495
|
if (commentId && commentsMap[commentId]) {
|
|
496
|
+
context.features.commentRefCount += 1;
|
|
343
497
|
usedCommentIds.push(commentId);
|
|
344
|
-
|
|
498
|
+
result.push(
|
|
345
499
|
`<sup data-word-comment-ref="${commentId}"><a href="#word-comment-${commentId}">[c${commentId}]</a></sup>`
|
|
346
500
|
);
|
|
347
|
-
|
|
501
|
+
return result;
|
|
348
502
|
}
|
|
349
503
|
const drawing = queryByLocalName(run, "drawing");
|
|
350
504
|
if (drawing) {
|
|
@@ -355,13 +509,38 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
|
|
|
355
509
|
if (src) {
|
|
356
510
|
const imageSize = parseDrawingSizePx(drawing);
|
|
357
511
|
const dimensionAttrs = imageDimensionAttributes(imageSize);
|
|
358
|
-
const
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
512
|
+
const anchorMeta = parseAnchorMeta(drawing);
|
|
513
|
+
const attrs = mergeImageStyle(dimensionAttrs, anchorMeta);
|
|
514
|
+
if (anchorMeta) context.features.anchorImageCount += 1;
|
|
515
|
+
result.push(`<img src="${src}" alt="word-image"${attrs}/>`);
|
|
516
|
+
return result;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
const chartRef = queryByLocalName(drawing, "chart");
|
|
520
|
+
const chartRid = getAttr(chartRef, "r:id") ?? getAttr(chartRef, "id");
|
|
521
|
+
if (chartRid) {
|
|
522
|
+
const chartXmlText = await readXmlByRid(zip, relMap, chartRid);
|
|
523
|
+
if (chartXmlText) {
|
|
524
|
+
const summary = parseChartSummary(chartXmlText);
|
|
525
|
+
context.features.chartCount += 1;
|
|
526
|
+
result.push(
|
|
527
|
+
`<figure data-word-chart="1" data-word-chart-type="${summary.type}" data-word-chart-series="${summary.seriesCount}" data-word-chart-points="${summary.pointCount}"><figcaption>${escapeHtml(summary.title)}</figcaption><div>Chart(${escapeHtml(summary.type)}): series=${summary.seriesCount}, points=${summary.pointCount}</div></figure>`
|
|
528
|
+
);
|
|
529
|
+
return result;
|
|
363
530
|
}
|
|
364
531
|
}
|
|
532
|
+
const smartArtRef = queryByLocalName(drawing, "relIds");
|
|
533
|
+
const smartArtRid = getAttr(smartArtRef, "r:dm") ?? getAttr(smartArtRef, "dm");
|
|
534
|
+
if (smartArtRid) {
|
|
535
|
+
const diagramXmlText = await readXmlByRid(zip, relMap, smartArtRid);
|
|
536
|
+
const textItems = diagramXmlText ? extractSmartArtText(diagramXmlText) : [];
|
|
537
|
+
context.features.smartArtCount += 1;
|
|
538
|
+
const preview = textItems.length > 0 ? `: ${escapeHtml(textItems.join(" / "))}` : "";
|
|
539
|
+
result.push(
|
|
540
|
+
`<figure data-word-smartart="1" data-word-smartart-items="${textItems.length}"><figcaption>SmartArt fallback${preview}</figcaption></figure>`
|
|
541
|
+
);
|
|
542
|
+
return result;
|
|
543
|
+
}
|
|
365
544
|
}
|
|
366
545
|
const texts = queryAllByLocalName(run, "t").map((t) => t.textContent ?? "").join("");
|
|
367
546
|
const delTexts = queryAllByLocalName(run, "delText").map((t) => t.textContent ?? "").join("");
|
|
@@ -372,40 +551,86 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
|
|
|
372
551
|
}).length;
|
|
373
552
|
const lineBreakCount = Math.max(0, brNodes.length - pageBreakCount);
|
|
374
553
|
const runText2 = `${escapeHtml(texts || delTexts)}${"<br/>".repeat(lineBreakCount)}`;
|
|
375
|
-
if (
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
554
|
+
if (runText2) {
|
|
555
|
+
const revisionMeta = inferRevisionMeta(run, revisionFallback);
|
|
556
|
+
if (css) {
|
|
557
|
+
const span = `<span style="${css}">${runText2}</span>`;
|
|
558
|
+
if (revisionMeta) {
|
|
559
|
+
context.features.revisionCount += 1;
|
|
560
|
+
const tagName = revisionMeta.type === "ins" ? "ins" : "del";
|
|
561
|
+
result.push(`<${tagName} ${revisionMetaAttrs(revisionMeta)}>${span}</${tagName}>`);
|
|
562
|
+
} else {
|
|
563
|
+
result.push(span);
|
|
564
|
+
}
|
|
565
|
+
} else if (revisionMeta) {
|
|
566
|
+
context.features.revisionCount += 1;
|
|
567
|
+
const tagName = revisionMeta.type === "ins" ? "ins" : "del";
|
|
568
|
+
result.push(`<${tagName} ${revisionMetaAttrs(revisionMeta)}>${runText2}</${tagName}>`);
|
|
569
|
+
} else {
|
|
570
|
+
result.push(runText2);
|
|
386
571
|
}
|
|
387
|
-
if (cursor.localName === "p") break;
|
|
388
|
-
cursor = cursor.parentElement;
|
|
389
572
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
573
|
+
for (let i = 0; i < pageBreakCount; i += 1) {
|
|
574
|
+
context.features.pageBreakCount += 1;
|
|
575
|
+
result.push(`<span data-word-page-break="1" style="display:block;break-before:page"></span>`);
|
|
576
|
+
}
|
|
577
|
+
return result;
|
|
578
|
+
}
|
|
579
|
+
async function nodeToHtml(node, revisionFallback) {
|
|
580
|
+
if (node.localName === "commentRangeStart") {
|
|
581
|
+
const id = getAttr(node, "w:id") ?? getAttr(node, "id");
|
|
582
|
+
return id ? [`<span data-word-comment-range-start="${id}"></span>`] : [];
|
|
583
|
+
}
|
|
584
|
+
if (node.localName === "commentRangeEnd") {
|
|
585
|
+
const id = getAttr(node, "w:id") ?? getAttr(node, "id");
|
|
586
|
+
return id ? [`<span data-word-comment-range-end="${id}"></span>`] : [];
|
|
587
|
+
}
|
|
588
|
+
if (node.localName === "r") {
|
|
589
|
+
return runToHtml(node, revisionFallback);
|
|
590
|
+
}
|
|
591
|
+
if (node.localName === "hyperlink") {
|
|
592
|
+
const rid = getAttr(node, "r:id") ?? getAttr(node, "id");
|
|
593
|
+
const anchor = getAttr(node, "w:anchor") ?? getAttr(node, "anchor");
|
|
594
|
+
const href = resolveHyperlinkHref(relMap, rid, anchor);
|
|
595
|
+
const nested2 = [];
|
|
596
|
+
for (const child of Array.from(node.children)) {
|
|
597
|
+
nested2.push(...await nodeToHtml(child, revisionFallback));
|
|
397
598
|
}
|
|
398
|
-
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
599
|
+
const content2 = nested2.join("") || escapeHtml(node.textContent ?? "");
|
|
600
|
+
if (!href) return content2 ? [content2] : [];
|
|
601
|
+
context.features.hyperlinkCount += 1;
|
|
602
|
+
return [
|
|
603
|
+
`<a data-word-hyperlink="1" href="${escapeHtml(href)}" rel="noreferrer noopener" target="_blank">${content2}</a>`
|
|
604
|
+
];
|
|
605
|
+
}
|
|
606
|
+
if (node.localName === "oMath" || node.localName === "oMathPara") {
|
|
607
|
+
const linear = ommlNodeToText(node).trim();
|
|
608
|
+
if (!linear) return [];
|
|
609
|
+
context.features.ommlCount += 1;
|
|
610
|
+
return [`<span data-word-omml="1">${escapeHtml(linear)}</span>`];
|
|
611
|
+
}
|
|
612
|
+
if (node.localName === "ins" || node.localName === "del") {
|
|
613
|
+
const scopedMeta = parseRevisionMeta(node, node.localName === "ins" ? "ins" : "del");
|
|
614
|
+
const nested2 = [];
|
|
615
|
+
for (const child of Array.from(node.children)) {
|
|
616
|
+
nested2.push(...await nodeToHtml(child, scopedMeta));
|
|
404
617
|
}
|
|
618
|
+
return nested2;
|
|
405
619
|
}
|
|
406
|
-
|
|
407
|
-
|
|
620
|
+
const nested = [];
|
|
621
|
+
for (const child of Array.from(node.children)) {
|
|
622
|
+
nested.push(...await nodeToHtml(child, revisionFallback));
|
|
408
623
|
}
|
|
624
|
+
return nested;
|
|
625
|
+
}
|
|
626
|
+
const parts = [];
|
|
627
|
+
const renderedPageBreakCount = queryAllByLocalName(paragraph, "lastRenderedPageBreak").length;
|
|
628
|
+
for (let i = 0; i < renderedPageBreakCount; i += 1) {
|
|
629
|
+
context.features.pageBreakCount += 1;
|
|
630
|
+
parts.push(`<span data-word-page-break="1" style="display:block;break-before:page"></span>`);
|
|
631
|
+
}
|
|
632
|
+
for (const child of Array.from(paragraph.children)) {
|
|
633
|
+
parts.push(...await nodeToHtml(child, null));
|
|
409
634
|
}
|
|
410
635
|
const content = parts.join("") || "<br/>";
|
|
411
636
|
return `<${tag}${dataAttr}${alignStyle ? ` style="${alignStyle}"` : ""}>${content}</${tag}>`;
|
|
@@ -435,7 +660,102 @@ function parseTcVMerge(tc) {
|
|
|
435
660
|
const rawVal = (getAttr(vMerge, "w:val") ?? getAttr(vMerge, "val") ?? "continue").toLowerCase();
|
|
436
661
|
return rawVal === "restart" ? "restart" : "continue";
|
|
437
662
|
}
|
|
438
|
-
function
|
|
663
|
+
function parseTblGridWidthsPx(table) {
|
|
664
|
+
const grid = directChildrenByLocalName(table, "tblGrid")[0] ?? null;
|
|
665
|
+
if (!grid) return [];
|
|
666
|
+
return directChildrenByLocalName(grid, "gridCol").map((col) => {
|
|
667
|
+
const raw = getAttr(col, "w:w") ?? getAttr(col, "w");
|
|
668
|
+
const twip = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
669
|
+
return Number.isFinite(twip) && twip > 0 ? twipToPx(twip) : 0;
|
|
670
|
+
}).filter((px) => px > 0);
|
|
671
|
+
}
|
|
672
|
+
function borderSizeToPx(size) {
|
|
673
|
+
return size / 6;
|
|
674
|
+
}
|
|
675
|
+
function parseBorderCss(borderNode) {
|
|
676
|
+
if (!borderNode) return null;
|
|
677
|
+
const val = (getAttr(borderNode, "w:val") ?? getAttr(borderNode, "val") ?? "").toLowerCase();
|
|
678
|
+
if (!val || val === "nil" || val === "none") return "none";
|
|
679
|
+
const color = (getAttr(borderNode, "w:color") ?? getAttr(borderNode, "color") ?? "222222").replace(/^#/, "");
|
|
680
|
+
const rawSize = getAttr(borderNode, "w:sz") ?? getAttr(borderNode, "sz");
|
|
681
|
+
const size = rawSize ? Number.parseInt(rawSize, 10) : Number.NaN;
|
|
682
|
+
const px = Number.isFinite(size) && size > 0 ? borderSizeToPx(size) : 1;
|
|
683
|
+
const style = val === "single" ? "solid" : val;
|
|
684
|
+
return `${px.toFixed(2)}px ${style} #${color}`;
|
|
685
|
+
}
|
|
686
|
+
function parseTableStyleProfile(table) {
|
|
687
|
+
const tblPr = directChildrenByLocalName(table, "tblPr")[0] ?? null;
|
|
688
|
+
const tblBorders = tblPr ? directChildrenByLocalName(tblPr, "tblBorders")[0] ?? null : null;
|
|
689
|
+
const layout = tblPr ? directChildrenByLocalName(tblPr, "tblLayout")[0] ?? null : null;
|
|
690
|
+
const spacing = tblPr ? directChildrenByLocalName(tblPr, "tblCellSpacing")[0] ?? null : null;
|
|
691
|
+
const spacingType = (getAttr(spacing, "w:type") ?? getAttr(spacing, "type") ?? "dxa").toLowerCase();
|
|
692
|
+
const spacingRaw = getAttr(spacing, "w:w") ?? getAttr(spacing, "w");
|
|
693
|
+
const spacingVal = spacingRaw ? Number.parseFloat(spacingRaw) : Number.NaN;
|
|
694
|
+
const borderSpacingPx = spacingType === "dxa" && Number.isFinite(spacingVal) && spacingVal > 0 ? twipToPx(spacingVal) : 0;
|
|
695
|
+
const borderCollapse = borderSpacingPx > 0 ? "separate" : "collapse";
|
|
696
|
+
const tableLayout = (getAttr(layout, "w:type") ?? getAttr(layout, "type") ?? "").toLowerCase() === "autofit" ? "auto" : "fixed";
|
|
697
|
+
const top = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "top")[0] ?? null : null);
|
|
698
|
+
const bottom = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "bottom")[0] ?? null : null);
|
|
699
|
+
const left = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "left")[0] ?? null : null);
|
|
700
|
+
const right = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "right")[0] ?? null : null);
|
|
701
|
+
const insideH = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "insideH")[0] ?? null : null);
|
|
702
|
+
const insideV = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "insideV")[0] ?? null : null);
|
|
703
|
+
const borderCss = top ?? right ?? bottom ?? left ?? "1px solid #222";
|
|
704
|
+
return {
|
|
705
|
+
tableLayout,
|
|
706
|
+
borderCollapse,
|
|
707
|
+
borderSpacingPx,
|
|
708
|
+
borderCss,
|
|
709
|
+
insideHCss: insideH,
|
|
710
|
+
insideVCss: insideV
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
function parseTableWidthStyle(table, gridWidthsPx) {
|
|
714
|
+
const tblPr = directChildrenByLocalName(table, "tblPr")[0] ?? null;
|
|
715
|
+
const tblW = tblPr ? directChildrenByLocalName(tblPr, "tblW")[0] ?? null : null;
|
|
716
|
+
const type = (getAttr(tblW, "w:type") ?? getAttr(tblW, "type") ?? "").toLowerCase();
|
|
717
|
+
const rawVal = getAttr(tblW, "w:w") ?? getAttr(tblW, "w");
|
|
718
|
+
const numericVal = rawVal ? Number.parseFloat(rawVal) : Number.NaN;
|
|
719
|
+
if (type === "dxa" && Number.isFinite(numericVal) && numericVal > 0) {
|
|
720
|
+
return `width:${twipToPx(numericVal).toFixed(2)}px`;
|
|
721
|
+
}
|
|
722
|
+
if (type === "pct" && Number.isFinite(numericVal) && numericVal > 0) {
|
|
723
|
+
return `width:${(numericVal / 50).toFixed(2)}%`;
|
|
724
|
+
}
|
|
725
|
+
const gridTotal = gridWidthsPx.reduce((sum, item) => sum + item, 0);
|
|
726
|
+
if (gridTotal > 0) return `width:${gridTotal.toFixed(2)}px;max-width:100%`;
|
|
727
|
+
return "width:100%";
|
|
728
|
+
}
|
|
729
|
+
function parseCellWidthStyle(cell, colCursor, colSpan, gridWidthsPx) {
|
|
730
|
+
const tcPr = directChildrenByLocalName(cell, "tcPr")[0] ?? null;
|
|
731
|
+
const tcW = tcPr ? directChildrenByLocalName(tcPr, "tcW")[0] ?? null : null;
|
|
732
|
+
const type = (getAttr(tcW, "w:type") ?? getAttr(tcW, "type") ?? "").toLowerCase();
|
|
733
|
+
const rawVal = getAttr(tcW, "w:w") ?? getAttr(tcW, "w");
|
|
734
|
+
const numericVal = rawVal ? Number.parseFloat(rawVal) : Number.NaN;
|
|
735
|
+
if (type === "dxa" && Number.isFinite(numericVal) && numericVal > 0) {
|
|
736
|
+
return `width:${twipToPx(numericVal).toFixed(2)}px`;
|
|
737
|
+
}
|
|
738
|
+
if (type === "pct" && Number.isFinite(numericVal) && numericVal > 0) {
|
|
739
|
+
return `width:${(numericVal / 50).toFixed(2)}%`;
|
|
740
|
+
}
|
|
741
|
+
const width = gridWidthsPx.slice(colCursor, colCursor + colSpan).reduce((sum, item) => sum + item, 0);
|
|
742
|
+
if (width > 0) return `width:${width.toFixed(2)}px`;
|
|
743
|
+
return "";
|
|
744
|
+
}
|
|
745
|
+
function parseCellBorderStyle(cell, tableStyle) {
|
|
746
|
+
const tcPr = directChildrenByLocalName(cell, "tcPr")[0] ?? null;
|
|
747
|
+
const tcBorders = tcPr ? directChildrenByLocalName(tcPr, "tcBorders")[0] ?? null : null;
|
|
748
|
+
if (!tcBorders) {
|
|
749
|
+
const fallback = tableStyle.insideHCss ?? tableStyle.insideVCss ?? tableStyle.borderCss;
|
|
750
|
+
return `border:${fallback}`;
|
|
751
|
+
}
|
|
752
|
+
const top = parseBorderCss(directChildrenByLocalName(tcBorders, "top")[0] ?? null) ?? tableStyle.insideHCss ?? tableStyle.borderCss;
|
|
753
|
+
const right = parseBorderCss(directChildrenByLocalName(tcBorders, "right")[0] ?? null) ?? tableStyle.insideVCss ?? tableStyle.borderCss;
|
|
754
|
+
const bottom = parseBorderCss(directChildrenByLocalName(tcBorders, "bottom")[0] ?? null) ?? tableStyle.insideHCss ?? tableStyle.borderCss;
|
|
755
|
+
const left = parseBorderCss(directChildrenByLocalName(tcBorders, "left")[0] ?? null) ?? tableStyle.insideVCss ?? tableStyle.borderCss;
|
|
756
|
+
return `border-top:${top};border-right:${right};border-bottom:${bottom};border-left:${left}`;
|
|
757
|
+
}
|
|
758
|
+
function tableCellHtml(cell, paragraphIndexMap, context) {
|
|
439
759
|
const blocks = [];
|
|
440
760
|
for (const child of Array.from(cell.children)) {
|
|
441
761
|
if (child.localName === "tcPr") continue;
|
|
@@ -445,7 +765,7 @@ function tableCellHtml(cell, paragraphIndexMap) {
|
|
|
445
765
|
continue;
|
|
446
766
|
}
|
|
447
767
|
if (child.localName === "tbl") {
|
|
448
|
-
blocks.push(tableToHtml(child, paragraphIndexMap));
|
|
768
|
+
blocks.push(tableToHtml(child, paragraphIndexMap, context));
|
|
449
769
|
continue;
|
|
450
770
|
}
|
|
451
771
|
}
|
|
@@ -453,8 +773,11 @@ function tableCellHtml(cell, paragraphIndexMap) {
|
|
|
453
773
|
const text = queryAllByLocalName(cell, "t").map((t) => t.textContent ?? "").join("").trim();
|
|
454
774
|
return escapeHtml(text) || "<br/>";
|
|
455
775
|
}
|
|
456
|
-
function tableToHtml(table, paragraphIndexMap) {
|
|
776
|
+
function tableToHtml(table, paragraphIndexMap, context) {
|
|
777
|
+
context.features.tableCount += 1;
|
|
457
778
|
const rows = directChildrenByLocalName(table, "tr");
|
|
779
|
+
const gridWidthsPx = parseTblGridWidthsPx(table);
|
|
780
|
+
const tableStyle = parseTableStyleProfile(table);
|
|
458
781
|
const activeByCol = /* @__PURE__ */ new Map();
|
|
459
782
|
const allOrigins = [];
|
|
460
783
|
let nextOriginId = 1;
|
|
@@ -479,8 +802,10 @@ function tableToHtml(table, paragraphIndexMap) {
|
|
|
479
802
|
while (activeByCol.has(colCursor)) {
|
|
480
803
|
colCursor += 1;
|
|
481
804
|
}
|
|
482
|
-
const html = tableCellHtml(cell, paragraphIndexMap);
|
|
805
|
+
const html = tableCellHtml(cell, paragraphIndexMap, context);
|
|
483
806
|
const attrs = [];
|
|
807
|
+
const widthStyle = parseCellWidthStyle(cell, colCursor, colSpan, gridWidthsPx);
|
|
808
|
+
const borderStyle = parseCellBorderStyle(cell, tableStyle);
|
|
484
809
|
if (vMerge === "restart") {
|
|
485
810
|
const origin = {
|
|
486
811
|
id: `m${nextOriginId}`,
|
|
@@ -498,7 +823,7 @@ function tableToHtml(table, paragraphIndexMap) {
|
|
|
498
823
|
}
|
|
499
824
|
if (colSpan > 1) attrs.push(`colspan="${colSpan}"`);
|
|
500
825
|
emittedCells.push(
|
|
501
|
-
`<td${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""} style="
|
|
826
|
+
`<td${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""} style="${borderStyle};vertical-align:top;${widthStyle}">${html}</td>`
|
|
502
827
|
);
|
|
503
828
|
colCursor += colSpan;
|
|
504
829
|
}
|
|
@@ -517,9 +842,13 @@ function tableToHtml(table, paragraphIndexMap) {
|
|
|
517
842
|
const replacement = origin.rowSpan > 1 ? `rowspan="${origin.rowSpan}"` : "";
|
|
518
843
|
merged = merged.replace(marker, replacement).replace(/\s{2,}/g, " ");
|
|
519
844
|
}
|
|
520
|
-
|
|
845
|
+
const tableWidthStyle = parseTableWidthStyle(table, gridWidthsPx);
|
|
846
|
+
const spacing = tableStyle.borderSpacingPx > 0 ? `border-spacing:${tableStyle.borderSpacingPx.toFixed(2)}px;` : "";
|
|
847
|
+
return `<table style="border-collapse:${tableStyle.borderCollapse};${spacing}table-layout:${tableStyle.tableLayout};${tableWidthStyle};border:${tableStyle.borderCss};">${merged}</table>`;
|
|
521
848
|
}
|
|
522
|
-
async function
|
|
849
|
+
async function parseDocxToHtmlSnapshotWithReport(file) {
|
|
850
|
+
const startedAt = Date.now();
|
|
851
|
+
const context = { features: createEmptyFeatureCounts() };
|
|
523
852
|
const maybeArrayBuffer = file.arrayBuffer;
|
|
524
853
|
const buffer = maybeArrayBuffer ? await maybeArrayBuffer.call(file) : await new Response(file).arrayBuffer();
|
|
525
854
|
const zip = await import_jszip.default.loadAsync(buffer);
|
|
@@ -556,6 +885,7 @@ async function parseDocxToHtmlSnapshot(file) {
|
|
|
556
885
|
await paragraphToHtml(
|
|
557
886
|
zip,
|
|
558
887
|
relMap,
|
|
888
|
+
context,
|
|
559
889
|
child,
|
|
560
890
|
paragraphIndex,
|
|
561
891
|
footnotesMap,
|
|
@@ -569,14 +899,20 @@ async function parseDocxToHtmlSnapshot(file) {
|
|
|
569
899
|
continue;
|
|
570
900
|
}
|
|
571
901
|
if (child.localName === "tbl") {
|
|
572
|
-
blockHtml.push(tableToHtml(child, paragraphIndexMap));
|
|
902
|
+
blockHtml.push(tableToHtml(child, paragraphIndexMap, context));
|
|
573
903
|
continue;
|
|
574
904
|
}
|
|
575
905
|
}
|
|
576
906
|
blockHtml.push(renderFootnotesSection(usedFootnoteIds, footnotesMap));
|
|
577
907
|
blockHtml.push(renderEndnotesSection(usedEndnoteIds, endnotesMap));
|
|
578
908
|
blockHtml.push(renderCommentsSection(usedCommentIds, commentsMap));
|
|
579
|
-
return
|
|
909
|
+
return {
|
|
910
|
+
htmlSnapshot: buildHtmlSnapshot(blockHtml.join("\n")),
|
|
911
|
+
report: {
|
|
912
|
+
elapsedMs: Date.now() - startedAt,
|
|
913
|
+
features: context.features
|
|
914
|
+
}
|
|
915
|
+
};
|
|
580
916
|
}
|
|
581
917
|
|
|
582
918
|
// src/lib/pastePipeline.ts
|
|
@@ -807,7 +1143,7 @@ function createFallbackWordStyleProfile(sourceFileName = "snapshot") {
|
|
|
807
1143
|
paragraphProfiles: []
|
|
808
1144
|
};
|
|
809
1145
|
}
|
|
810
|
-
function
|
|
1146
|
+
function twipToPx2(twip) {
|
|
811
1147
|
return twip / 15;
|
|
812
1148
|
}
|
|
813
1149
|
function getAttr2(node, attr) {
|
|
@@ -851,10 +1187,10 @@ function parsePageGeometry(documentXml) {
|
|
|
851
1187
|
const top = getTwipAttr(pgMar, "w:top") ?? getTwipAttr(pgMar, "top") ?? null;
|
|
852
1188
|
const bottom = getTwipAttr(pgMar, "w:bottom") ?? getTwipAttr(pgMar, "bottom") ?? null;
|
|
853
1189
|
return {
|
|
854
|
-
contentWidthPx: pageW === null ? null :
|
|
855
|
-
pageHeightPx: pageH === null ? null :
|
|
856
|
-
marginTopPx: top === null ? null :
|
|
857
|
-
marginBottomPx: bottom === null ? null :
|
|
1190
|
+
contentWidthPx: pageW === null ? null : twipToPx2(pageW - left - right),
|
|
1191
|
+
pageHeightPx: pageH === null ? null : twipToPx2(pageH),
|
|
1192
|
+
marginTopPx: top === null ? null : twipToPx2(top),
|
|
1193
|
+
marginBottomPx: bottom === null ? null : twipToPx2(bottom)
|
|
858
1194
|
};
|
|
859
1195
|
}
|
|
860
1196
|
function parseHeadingAlignFromDocument(documentXml) {
|
|
@@ -1027,15 +1363,15 @@ function parseParagraphProfiles(documentXml, numberingMap) {
|
|
|
1027
1363
|
text,
|
|
1028
1364
|
isEmpty: text.length === 0,
|
|
1029
1365
|
align: parseParagraphAlign(paragraph),
|
|
1030
|
-
beforePx: before === null ? null :
|
|
1031
|
-
afterPx: after === null ? null :
|
|
1366
|
+
beforePx: before === null ? null : twipToPx2(before),
|
|
1367
|
+
afterPx: after === null ? null : twipToPx2(after),
|
|
1032
1368
|
lineHeightRatio: line === null || lineHeightRule !== "auto" ? null : line / 240,
|
|
1033
|
-
lineHeightPx: line === null || lineHeightRule === "auto" ? null :
|
|
1369
|
+
lineHeightPx: line === null || lineHeightRule === "auto" ? null : twipToPx2(line),
|
|
1034
1370
|
lineHeightRule,
|
|
1035
|
-
indentLeftPx: left === null ? null :
|
|
1036
|
-
indentRightPx: right === null ? null :
|
|
1037
|
-
firstLinePx: firstLine === null ? null :
|
|
1038
|
-
hangingPx: hanging === null ? null :
|
|
1371
|
+
indentLeftPx: left === null ? null : twipToPx2(left),
|
|
1372
|
+
indentRightPx: right === null ? null : twipToPx2(right),
|
|
1373
|
+
firstLinePx: firstLine === null ? null : twipToPx2(firstLine),
|
|
1374
|
+
hangingPx: hanging === null ? null : twipToPx2(hanging),
|
|
1039
1375
|
listNumId,
|
|
1040
1376
|
listLevel,
|
|
1041
1377
|
listFormat: listSpec?.numFmt ?? null,
|
|
@@ -1070,19 +1406,19 @@ function parseTableDefaults(stylesXml) {
|
|
|
1070
1406
|
return {
|
|
1071
1407
|
topPx: (() => {
|
|
1072
1408
|
const v = getTwipAttr(top, "w:w") ?? getTwipAttr(top, "w") ?? null;
|
|
1073
|
-
return v === null ? null :
|
|
1409
|
+
return v === null ? null : twipToPx2(v);
|
|
1074
1410
|
})(),
|
|
1075
1411
|
leftPx: (() => {
|
|
1076
1412
|
const v = getTwipAttr(left, "w:w") ?? getTwipAttr(left, "w") ?? null;
|
|
1077
|
-
return v === null ? null :
|
|
1413
|
+
return v === null ? null : twipToPx2(v);
|
|
1078
1414
|
})(),
|
|
1079
1415
|
bottomPx: (() => {
|
|
1080
1416
|
const v = getTwipAttr(bottom, "w:w") ?? getTwipAttr(bottom, "w") ?? null;
|
|
1081
|
-
return v === null ? null :
|
|
1417
|
+
return v === null ? null : twipToPx2(v);
|
|
1082
1418
|
})(),
|
|
1083
1419
|
rightPx: (() => {
|
|
1084
1420
|
const v = getTwipAttr(right, "w:w") ?? getTwipAttr(right, "w") ?? null;
|
|
1085
|
-
return v === null ? null :
|
|
1421
|
+
return v === null ? null : twipToPx2(v);
|
|
1086
1422
|
})()
|
|
1087
1423
|
};
|
|
1088
1424
|
}
|
|
@@ -1180,9 +1516,9 @@ function parseDefaults(stylesXml) {
|
|
|
1180
1516
|
const rawLineRule = (getAttr2(spacing, "w:lineRule") ?? getAttr2(spacing, "lineRule") ?? "auto").toLowerCase();
|
|
1181
1517
|
const bodyLineHeightRule = rawLineRule === "exact" ? "exact" : rawLineRule === "atleast" ? "atLeast" : "auto";
|
|
1182
1518
|
const bodyLineHeightRatio = line === null || bodyLineHeightRule !== "auto" ? null : line / 240;
|
|
1183
|
-
const bodyLineHeightPx = line === null || bodyLineHeightRule === "auto" ? null :
|
|
1519
|
+
const bodyLineHeightPx = line === null || bodyLineHeightRule === "auto" ? null : twipToPx2(line);
|
|
1184
1520
|
const after = getTwipAttr(spacing, "w:after") ?? getTwipAttr(spacing, "after") ?? null;
|
|
1185
|
-
const paragraphAfterPx = after === null ? null :
|
|
1521
|
+
const paragraphAfterPx = after === null ? null : twipToPx2(after);
|
|
1186
1522
|
return { bodyFontPx, bodyLineHeightRatio, bodyLineHeightPx, bodyLineHeightRule, paragraphAfterPx };
|
|
1187
1523
|
}
|
|
1188
1524
|
function parseHeading1Style(stylesXml) {
|
|
@@ -1707,7 +2043,7 @@ function applyWordRenderModel({ doc, styleProfile, showFormattingMarks }) {
|
|
|
1707
2043
|
}
|
|
1708
2044
|
|
|
1709
2045
|
// src/core/DocsWordElement.ts
|
|
1710
|
-
var VERSION = "0.1.
|
|
2046
|
+
var VERSION = "0.1.5";
|
|
1711
2047
|
var MESSAGES = {
|
|
1712
2048
|
zh: {
|
|
1713
2049
|
readClipboard: "\u4ECE\u7CFB\u7EDF\u526A\u8D34\u677F\u8BFB\u53D6",
|
|
@@ -1850,15 +2186,15 @@ var DocsWordElement = class extends HTMLElement {
|
|
|
1850
2186
|
}
|
|
1851
2187
|
async applyDocx(file) {
|
|
1852
2188
|
try {
|
|
1853
|
-
const [
|
|
1854
|
-
|
|
2189
|
+
const [parseResult, profile] = await Promise.all([
|
|
2190
|
+
parseDocxToHtmlSnapshotWithReport(file),
|
|
1855
2191
|
parseDocxStyleProfile(file)
|
|
1856
2192
|
]);
|
|
1857
2193
|
this.styleProfile = profile;
|
|
1858
|
-
this.htmlSnapshot =
|
|
2194
|
+
this.htmlSnapshot = parseResult.htmlSnapshot;
|
|
1859
2195
|
this.renderSnapshot();
|
|
1860
2196
|
this.setHint(MESSAGES[this.locale].loadedWord(profile.sourceFileName));
|
|
1861
|
-
this.emitChange("upload", profile.sourceFileName);
|
|
2197
|
+
this.emitChange("upload", profile.sourceFileName, parseResult.report);
|
|
1862
2198
|
} catch (error) {
|
|
1863
2199
|
this.emitError(error instanceof Error ? error.message : MESSAGES[this.locale].parseFailed);
|
|
1864
2200
|
}
|
|
@@ -1918,8 +2254,10 @@ var DocsWordElement = class extends HTMLElement {
|
|
|
1918
2254
|
renderSnapshot() {
|
|
1919
2255
|
this.frame.srcdoc = this.htmlSnapshot;
|
|
1920
2256
|
}
|
|
1921
|
-
emitChange(source, fileName) {
|
|
1922
|
-
this.dispatchEvent(
|
|
2257
|
+
emitChange(source, fileName, parseReport) {
|
|
2258
|
+
this.dispatchEvent(
|
|
2259
|
+
new CustomEvent("docsjs-change", { detail: { htmlSnapshot: this.htmlSnapshot, source, fileName, parseReport } })
|
|
2260
|
+
);
|
|
1923
2261
|
}
|
|
1924
2262
|
emitError(message) {
|
|
1925
2263
|
this.dispatchEvent(new CustomEvent("docsjs-error", { detail: { message } }));
|
|
@@ -1955,7 +2293,13 @@ function defineDocsWordElement() {
|
|
|
1955
2293
|
|
|
1956
2294
|
// src/react/WordFidelityEditorReact.tsx
|
|
1957
2295
|
defineDocsWordElement();
|
|
1958
|
-
function WordFidelityEditorReact({
|
|
2296
|
+
function WordFidelityEditorReact({
|
|
2297
|
+
lang,
|
|
2298
|
+
onChange,
|
|
2299
|
+
onError,
|
|
2300
|
+
onReady,
|
|
2301
|
+
editorRef
|
|
2302
|
+
}) {
|
|
1959
2303
|
const ref = (0, import_react.useRef)(null);
|
|
1960
2304
|
(0, import_react.useEffect)(() => {
|
|
1961
2305
|
const node = ref.current;
|
|
@@ -1983,7 +2327,10 @@ function WordFidelityEditorReact({ lang, onChange, onError, onReady, editorRef }
|
|
|
1983
2327
|
editorRef?.(null);
|
|
1984
2328
|
};
|
|
1985
2329
|
}, [editorRef, onChange, onError, onReady]);
|
|
1986
|
-
return import_react.default.createElement("docs-word-editor", {
|
|
2330
|
+
return import_react.default.createElement("docs-word-editor", {
|
|
2331
|
+
ref,
|
|
2332
|
+
lang
|
|
2333
|
+
});
|
|
1987
2334
|
}
|
|
1988
2335
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1989
2336
|
0 && (module.exports = {
|