@coding01/docsjs 0.1.3 → 0.1.5
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 +32 -5
- package/README.zh-CN.md +30 -5
- package/dist/{chunk-PRPDJOB7.js → chunk-IBVWD4UO.js} +359 -87
- package/dist/chunk-IBVWD4UO.js.map +1 -0
- package/dist/index.cjs +362 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +358 -86
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +1 -1
- package/dist/vue.cjs +358 -86
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +1 -1
- package/package.json +2 -1
- package/dist/chunk-PRPDJOB7.js.map +0 -1
|
@@ -40,6 +40,9 @@ function getAttr(node, name) {
|
|
|
40
40
|
function emuToPx(emu) {
|
|
41
41
|
return emu * 96 / 914400;
|
|
42
42
|
}
|
|
43
|
+
function twipToPx(twip) {
|
|
44
|
+
return twip * 96 / 1440;
|
|
45
|
+
}
|
|
43
46
|
function parseDrawingSizePx(drawing) {
|
|
44
47
|
const extentNode = queryAllByLocalName(drawing, "extent").find((node) => {
|
|
45
48
|
const parent = node.parentElement;
|
|
@@ -68,9 +71,7 @@ function imageDimensionAttributes(sizePx) {
|
|
|
68
71
|
}
|
|
69
72
|
return attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
70
73
|
}
|
|
71
|
-
function parseAnchorPositionPx(
|
|
72
|
-
const anchor = directChildrenByLocalName(drawing, "anchor")[0] ?? null;
|
|
73
|
-
if (!anchor) return { leftPx: null, topPx: null };
|
|
74
|
+
function parseAnchorPositionPx(anchor) {
|
|
74
75
|
let leftPx = null;
|
|
75
76
|
let topPx = null;
|
|
76
77
|
const positionH = directChildrenByLocalName(anchor, "positionH")[0] ?? null;
|
|
@@ -85,34 +86,80 @@ function parseAnchorPositionPx(drawing) {
|
|
|
85
86
|
if (Number.isFinite(top)) topPx = emuToPx(top);
|
|
86
87
|
return { leftPx, topPx };
|
|
87
88
|
}
|
|
88
|
-
function parseAnchorWrapMode(
|
|
89
|
-
const anchor = directChildrenByLocalName(drawing, "anchor")[0] ?? null;
|
|
90
|
-
if (!anchor) return null;
|
|
89
|
+
function parseAnchorWrapMode(anchor) {
|
|
91
90
|
if (directChildrenByLocalName(anchor, "wrapSquare")[0]) return "square";
|
|
92
91
|
if (directChildrenByLocalName(anchor, "wrapTight")[0]) return "tight";
|
|
93
92
|
if (directChildrenByLocalName(anchor, "wrapTopAndBottom")[0]) return "topAndBottom";
|
|
94
93
|
if (directChildrenByLocalName(anchor, "wrapNone")[0]) return "none";
|
|
95
94
|
return null;
|
|
96
95
|
}
|
|
97
|
-
function
|
|
98
|
-
|
|
96
|
+
function parseAnchorMeta(drawing) {
|
|
97
|
+
const anchor = directChildrenByLocalName(drawing, "anchor")[0] ?? null;
|
|
98
|
+
if (!anchor) return null;
|
|
99
|
+
const positionH = directChildrenByLocalName(anchor, "positionH")[0] ?? null;
|
|
100
|
+
const positionV = directChildrenByLocalName(anchor, "positionV")[0] ?? null;
|
|
101
|
+
const relativeFromH = getAttr(positionH, "relativeFrom");
|
|
102
|
+
const relativeFromV = getAttr(positionV, "relativeFrom");
|
|
103
|
+
const parseDistPx = (name) => {
|
|
104
|
+
const raw = getAttr(anchor, name);
|
|
105
|
+
const emu = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
106
|
+
return Number.isFinite(emu) && emu >= 0 ? emuToPx(emu) : null;
|
|
107
|
+
};
|
|
108
|
+
const rawHeight = getAttr(anchor, "relativeHeight");
|
|
109
|
+
const parsedHeight = rawHeight ? Number.parseInt(rawHeight, 10) : Number.NaN;
|
|
110
|
+
const boolAttr = (name, fallback) => {
|
|
111
|
+
const raw = (getAttr(anchor, name) ?? "").toLowerCase();
|
|
112
|
+
if (raw === "1" || raw === "true" || raw === "on") return true;
|
|
113
|
+
if (raw === "0" || raw === "false" || raw === "off") return false;
|
|
114
|
+
return fallback;
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
position: parseAnchorPositionPx(anchor),
|
|
118
|
+
wrapMode: parseAnchorWrapMode(anchor),
|
|
119
|
+
distTPx: parseDistPx("distT"),
|
|
120
|
+
distBPx: parseDistPx("distB"),
|
|
121
|
+
distLPx: parseDistPx("distL"),
|
|
122
|
+
distRPx: parseDistPx("distR"),
|
|
123
|
+
relativeFromH,
|
|
124
|
+
relativeFromV,
|
|
125
|
+
behindDoc: boolAttr("behindDoc", false),
|
|
126
|
+
allowOverlap: boolAttr("allowOverlap", true),
|
|
127
|
+
layoutInCell: boolAttr("layoutInCell", true),
|
|
128
|
+
relativeHeight: Number.isFinite(parsedHeight) ? parsedHeight : null
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function mergeImageStyle(baseAttrs, anchorMeta) {
|
|
132
|
+
if (!anchorMeta) return baseAttrs;
|
|
133
|
+
const { position, wrapMode } = anchorMeta;
|
|
134
|
+
if (position.leftPx === null && position.topPx === null) return baseAttrs;
|
|
99
135
|
const styleParts = [
|
|
100
136
|
"position:absolute",
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
137
|
+
position.leftPx !== null ? `left:${position.leftPx.toFixed(2)}px` : "",
|
|
138
|
+
position.topPx !== null ? `top:${position.topPx.toFixed(2)}px` : "",
|
|
139
|
+
`z-index:${anchorMeta.behindDoc ? 0 : anchorMeta.relativeHeight ?? 3}`,
|
|
140
|
+
anchorMeta.distTPx !== null ? `margin-top:${anchorMeta.distTPx.toFixed(2)}px` : "",
|
|
141
|
+
anchorMeta.distBPx !== null ? `margin-bottom:${anchorMeta.distBPx.toFixed(2)}px` : "",
|
|
142
|
+
anchorMeta.distLPx !== null ? `margin-left:${anchorMeta.distLPx.toFixed(2)}px` : "",
|
|
143
|
+
anchorMeta.distRPx !== null ? `margin-right:${anchorMeta.distRPx.toFixed(2)}px` : ""
|
|
104
144
|
].filter((x) => x.length > 0);
|
|
105
145
|
if (wrapMode === "topAndBottom") {
|
|
106
|
-
styleParts.push("display:block");
|
|
107
|
-
}
|
|
146
|
+
styleParts.push("display:block", "clear:both");
|
|
147
|
+
}
|
|
148
|
+
const anchorAttrs = [
|
|
149
|
+
`data-word-anchor="1"`,
|
|
150
|
+
wrapMode ? `data-word-wrap="${wrapMode}"` : "",
|
|
151
|
+
anchorMeta.relativeFromH ? `data-word-anchor-relh="${escapeHtml(anchorMeta.relativeFromH)}"` : "",
|
|
152
|
+
anchorMeta.relativeFromV ? `data-word-anchor-relv="${escapeHtml(anchorMeta.relativeFromV)}"` : "",
|
|
153
|
+
anchorMeta.behindDoc ? `data-word-anchor-behind="1"` : `data-word-anchor-behind="0"`,
|
|
154
|
+
anchorMeta.allowOverlap ? `data-word-anchor-overlap="1"` : `data-word-anchor-overlap="0"`,
|
|
155
|
+
anchorMeta.layoutInCell ? `data-word-anchor-layout-cell="1"` : `data-word-anchor-layout-cell="0"`
|
|
156
|
+
].filter((x) => x.length > 0).join(" ");
|
|
108
157
|
if (!baseAttrs.includes("style=")) {
|
|
109
|
-
|
|
110
|
-
return `${baseAttrs} style="${styleParts.join(";")}" data-word-anchor="1"${wrapAttr}`;
|
|
158
|
+
return `${baseAttrs} style="${styleParts.join(";")}" ${anchorAttrs}`;
|
|
111
159
|
}
|
|
112
160
|
return baseAttrs.replace(/style="([^"]*)"/, (_m, styleText) => {
|
|
113
161
|
const merged = [styleText, ...styleParts].filter((x) => x.length > 0).join(";");
|
|
114
|
-
|
|
115
|
-
return `style="${merged}" data-word-anchor="1"${wrapAttr}`;
|
|
162
|
+
return `style="${merged}" ${anchorAttrs}`;
|
|
116
163
|
});
|
|
117
164
|
}
|
|
118
165
|
function parseDocRelsMap(relsXmlText) {
|
|
@@ -138,11 +185,16 @@ function extToMime(ext) {
|
|
|
138
185
|
if (lower === "svg") return "image/svg+xml";
|
|
139
186
|
return "application/octet-stream";
|
|
140
187
|
}
|
|
188
|
+
function normalizeWordPath(relTarget) {
|
|
189
|
+
const normalized = relTarget.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
190
|
+
if (normalized.startsWith("word/")) return normalized;
|
|
191
|
+
if (normalized.startsWith("../")) return `word/${normalized.replace(/^(\.\.\/)+/, "")}`;
|
|
192
|
+
return `word/${normalized}`;
|
|
193
|
+
}
|
|
141
194
|
async function imageRidToDataUrl(zip, relMap, rid) {
|
|
142
195
|
const relTarget = relMap[rid];
|
|
143
196
|
if (!relTarget) return null;
|
|
144
|
-
const
|
|
145
|
-
const path = normalized.startsWith("word/") ? normalized : `word/${normalized}`;
|
|
197
|
+
const path = normalizeWordPath(relTarget);
|
|
146
198
|
const file = zip.file(path);
|
|
147
199
|
if (!file) return null;
|
|
148
200
|
const base64 = await file.async("base64");
|
|
@@ -150,6 +202,55 @@ async function imageRidToDataUrl(zip, relMap, rid) {
|
|
|
150
202
|
const mime = extToMime(ext);
|
|
151
203
|
return `data:${mime};base64,${base64}`;
|
|
152
204
|
}
|
|
205
|
+
async function readXmlByRid(zip, relMap, rid) {
|
|
206
|
+
const relTarget = relMap[rid];
|
|
207
|
+
if (!relTarget) return null;
|
|
208
|
+
const path = normalizeWordPath(relTarget);
|
|
209
|
+
const file = zip.file(path);
|
|
210
|
+
return file ? file.async("string") : null;
|
|
211
|
+
}
|
|
212
|
+
function parseChartType(chartDoc) {
|
|
213
|
+
const known = ["barChart", "lineChart", "pieChart", "areaChart", "scatterChart", "radarChart", "doughnutChart"];
|
|
214
|
+
for (const type of known) {
|
|
215
|
+
if (queryByLocalName(chartDoc, type)) return type.replace(/Chart$/, "");
|
|
216
|
+
}
|
|
217
|
+
return "unknown";
|
|
218
|
+
}
|
|
219
|
+
function parseChartSummary(chartXmlText) {
|
|
220
|
+
const chartDoc = parseXml(chartXmlText);
|
|
221
|
+
const title = queryAllByLocalName(chartDoc, "t").map((n) => (n.textContent ?? "").trim()).find((v) => v.length > 0) ?? "Chart";
|
|
222
|
+
const seriesCount = queryAllByLocalName(chartDoc, "ser").length;
|
|
223
|
+
const pointCount = queryAllByLocalName(chartDoc, "pt").length;
|
|
224
|
+
const type = parseChartType(chartDoc);
|
|
225
|
+
return { title, type, seriesCount, pointCount };
|
|
226
|
+
}
|
|
227
|
+
function extractSmartArtText(diagramXmlText) {
|
|
228
|
+
const diagramDoc = parseXml(diagramXmlText);
|
|
229
|
+
return queryAllByLocalName(diagramDoc, "t").map((n) => (n.textContent ?? "").trim()).filter((v) => v.length > 0).slice(0, 12);
|
|
230
|
+
}
|
|
231
|
+
function ommlNodeToText(node) {
|
|
232
|
+
if (node.localName === "t") return node.textContent ?? "";
|
|
233
|
+
if (node.localName === "f") {
|
|
234
|
+
const num = queryByLocalName(node, "num");
|
|
235
|
+
const den = queryByLocalName(node, "den");
|
|
236
|
+
return `(${num ? ommlNodeToText(num) : "?"})/(${den ? ommlNodeToText(den) : "?"})`;
|
|
237
|
+
}
|
|
238
|
+
if (node.localName === "sSup") {
|
|
239
|
+
const e = queryByLocalName(node, "e");
|
|
240
|
+
const sup = queryByLocalName(node, "sup");
|
|
241
|
+
return `${e ? ommlNodeToText(e) : ""}^(${sup ? ommlNodeToText(sup) : ""})`;
|
|
242
|
+
}
|
|
243
|
+
if (node.localName === "sSub") {
|
|
244
|
+
const e = queryByLocalName(node, "e");
|
|
245
|
+
const sub = queryByLocalName(node, "sub");
|
|
246
|
+
return `${e ? ommlNodeToText(e) : ""}_(${sub ? ommlNodeToText(sub) : ""})`;
|
|
247
|
+
}
|
|
248
|
+
if (node.localName === "rad") {
|
|
249
|
+
const e = queryByLocalName(node, "e");
|
|
250
|
+
return `sqrt(${e ? ommlNodeToText(e) : ""})`;
|
|
251
|
+
}
|
|
252
|
+
return Array.from(node.children).map((child) => ommlNodeToText(child)).join("");
|
|
253
|
+
}
|
|
153
254
|
function runStyleToCss(rPr) {
|
|
154
255
|
if (!rPr) return "";
|
|
155
256
|
const declarations = [];
|
|
@@ -268,44 +369,66 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
|
|
|
268
369
|
const tag = paragraphTag(paragraph);
|
|
269
370
|
const alignStyle = paragraphAlignStyle(paragraph);
|
|
270
371
|
const dataAttr = paragraphDataAttr(paragraphIndex);
|
|
271
|
-
const
|
|
272
|
-
if (
|
|
372
|
+
const hasRenderableNode = queryAllByLocalName(paragraph, "r").length > 0 || queryAllByLocalName(paragraph, "oMath").length > 0 || queryAllByLocalName(paragraph, "oMathPara").length > 0;
|
|
373
|
+
if (!hasRenderableNode) {
|
|
273
374
|
return `<${tag}${dataAttr}${alignStyle ? ` style="${alignStyle}"` : ""}><br/></${tag}>`;
|
|
274
375
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
376
|
+
function parseRevisionMeta(node, type) {
|
|
377
|
+
return {
|
|
378
|
+
type,
|
|
379
|
+
id: getAttr(node, "w:id") ?? getAttr(node, "id"),
|
|
380
|
+
author: getAttr(node, "w:author") ?? getAttr(node, "author"),
|
|
381
|
+
date: getAttr(node, "w:date") ?? getAttr(node, "date")
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function inferRevisionMeta(run, fallback) {
|
|
385
|
+
if (fallback) return fallback;
|
|
386
|
+
let cursor = run;
|
|
387
|
+
while (cursor) {
|
|
388
|
+
if (cursor.localName === "ins") return parseRevisionMeta(cursor, "ins");
|
|
389
|
+
if (cursor.localName === "del") return parseRevisionMeta(cursor, "del");
|
|
390
|
+
if (cursor.localName === "p") break;
|
|
391
|
+
cursor = cursor.parentElement;
|
|
392
|
+
}
|
|
393
|
+
return null;
|
|
279
394
|
}
|
|
280
|
-
|
|
395
|
+
function revisionMetaAttrs(meta) {
|
|
396
|
+
const attrs = [`data-word-revision="${meta.type}"`];
|
|
397
|
+
if (meta.id) attrs.push(`data-word-revision-id="${escapeHtml(meta.id)}"`);
|
|
398
|
+
if (meta.author) attrs.push(`data-word-revision-author="${escapeHtml(meta.author)}"`);
|
|
399
|
+
if (meta.date) attrs.push(`data-word-revision-date="${escapeHtml(meta.date)}"`);
|
|
400
|
+
return attrs.join(" ");
|
|
401
|
+
}
|
|
402
|
+
async function runToHtml(run, revisionFallback) {
|
|
403
|
+
const result = [];
|
|
281
404
|
const rPr = queryByLocalName(run, "rPr");
|
|
282
405
|
const css = runStyleToCss(rPr);
|
|
283
406
|
const footnoteRef = queryByLocalName(run, "footnoteReference");
|
|
284
407
|
const footnoteId = getAttr(footnoteRef, "w:id") ?? getAttr(footnoteRef, "id");
|
|
285
408
|
if (footnoteId && footnotesMap[footnoteId]) {
|
|
286
409
|
usedFootnoteIds.push(footnoteId);
|
|
287
|
-
|
|
410
|
+
result.push(
|
|
288
411
|
`<sup data-word-footnote-ref="${footnoteId}"><a href="#word-footnote-${footnoteId}">[${footnoteId}]</a></sup>`
|
|
289
412
|
);
|
|
290
|
-
|
|
413
|
+
return result;
|
|
291
414
|
}
|
|
292
415
|
const endnoteRef = queryByLocalName(run, "endnoteReference");
|
|
293
416
|
const endnoteId = getAttr(endnoteRef, "w:id") ?? getAttr(endnoteRef, "id");
|
|
294
417
|
if (endnoteId && endnotesMap[endnoteId]) {
|
|
295
418
|
usedEndnoteIds.push(endnoteId);
|
|
296
|
-
|
|
419
|
+
result.push(
|
|
297
420
|
`<sup data-word-endnote-ref="${endnoteId}"><a href="#word-endnote-${endnoteId}">[${endnoteId}]</a></sup>`
|
|
298
421
|
);
|
|
299
|
-
|
|
422
|
+
return result;
|
|
300
423
|
}
|
|
301
424
|
const commentRef = queryByLocalName(run, "commentReference");
|
|
302
425
|
const commentId = getAttr(commentRef, "w:id") ?? getAttr(commentRef, "id");
|
|
303
426
|
if (commentId && commentsMap[commentId]) {
|
|
304
427
|
usedCommentIds.push(commentId);
|
|
305
|
-
|
|
428
|
+
result.push(
|
|
306
429
|
`<sup data-word-comment-ref="${commentId}"><a href="#word-comment-${commentId}">[c${commentId}]</a></sup>`
|
|
307
430
|
);
|
|
308
|
-
|
|
431
|
+
return result;
|
|
309
432
|
}
|
|
310
433
|
const drawing = queryByLocalName(run, "drawing");
|
|
311
434
|
if (drawing) {
|
|
@@ -316,13 +439,35 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
|
|
|
316
439
|
if (src) {
|
|
317
440
|
const imageSize = parseDrawingSizePx(drawing);
|
|
318
441
|
const dimensionAttrs = imageDimensionAttributes(imageSize);
|
|
319
|
-
const
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
continue;
|
|
442
|
+
const anchorMeta = parseAnchorMeta(drawing);
|
|
443
|
+
const attrs = mergeImageStyle(dimensionAttrs, anchorMeta);
|
|
444
|
+
result.push(`<img src="${src}" alt="word-image"${attrs}/>`);
|
|
445
|
+
return result;
|
|
324
446
|
}
|
|
325
447
|
}
|
|
448
|
+
const chartRef = queryByLocalName(drawing, "chart");
|
|
449
|
+
const chartRid = getAttr(chartRef, "r:id") ?? getAttr(chartRef, "id");
|
|
450
|
+
if (chartRid) {
|
|
451
|
+
const chartXmlText = await readXmlByRid(zip, relMap, chartRid);
|
|
452
|
+
if (chartXmlText) {
|
|
453
|
+
const summary = parseChartSummary(chartXmlText);
|
|
454
|
+
result.push(
|
|
455
|
+
`<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>`
|
|
456
|
+
);
|
|
457
|
+
return result;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
const smartArtRef = queryByLocalName(drawing, "relIds");
|
|
461
|
+
const smartArtRid = getAttr(smartArtRef, "r:dm") ?? getAttr(smartArtRef, "dm");
|
|
462
|
+
if (smartArtRid) {
|
|
463
|
+
const diagramXmlText = await readXmlByRid(zip, relMap, smartArtRid);
|
|
464
|
+
const textItems = diagramXmlText ? extractSmartArtText(diagramXmlText) : [];
|
|
465
|
+
const preview = textItems.length > 0 ? `: ${escapeHtml(textItems.join(" / "))}` : "";
|
|
466
|
+
result.push(
|
|
467
|
+
`<figure data-word-smartart="1" data-word-smartart-items="${textItems.length}"><figcaption>SmartArt fallback${preview}</figcaption></figure>`
|
|
468
|
+
);
|
|
469
|
+
return result;
|
|
470
|
+
}
|
|
326
471
|
}
|
|
327
472
|
const texts = queryAllByLocalName(run, "t").map((t) => t.textContent ?? "").join("");
|
|
328
473
|
const delTexts = queryAllByLocalName(run, "delText").map((t) => t.textContent ?? "").join("");
|
|
@@ -333,40 +478,66 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
|
|
|
333
478
|
}).length;
|
|
334
479
|
const lineBreakCount = Math.max(0, brNodes.length - pageBreakCount);
|
|
335
480
|
const runText2 = `${escapeHtml(texts || delTexts)}${"<br/>".repeat(lineBreakCount)}`;
|
|
336
|
-
if (
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
cursor = cursor.parentElement;
|
|
350
|
-
}
|
|
351
|
-
if (css) {
|
|
352
|
-
const span = `<span style="${css}">${runText2}</span>`;
|
|
353
|
-
if (revisionType) {
|
|
354
|
-
const tag2 = revisionType === "ins" ? "ins" : "del";
|
|
355
|
-
parts.push(`<${tag2} data-word-revision="${revisionType}">${span}</${tag2}>`);
|
|
356
|
-
} else {
|
|
357
|
-
parts.push(span);
|
|
358
|
-
}
|
|
359
|
-
} else {
|
|
360
|
-
if (revisionType) {
|
|
361
|
-
const tag2 = revisionType === "ins" ? "ins" : "del";
|
|
362
|
-
parts.push(`<${tag2} data-word-revision="${revisionType}">${runText2}</${tag2}>`);
|
|
481
|
+
if (runText2) {
|
|
482
|
+
const revisionMeta = inferRevisionMeta(run, revisionFallback);
|
|
483
|
+
if (css) {
|
|
484
|
+
const span = `<span style="${css}">${runText2}</span>`;
|
|
485
|
+
if (revisionMeta) {
|
|
486
|
+
const tagName = revisionMeta.type === "ins" ? "ins" : "del";
|
|
487
|
+
result.push(`<${tagName} ${revisionMetaAttrs(revisionMeta)}>${span}</${tagName}>`);
|
|
488
|
+
} else {
|
|
489
|
+
result.push(span);
|
|
490
|
+
}
|
|
491
|
+
} else if (revisionMeta) {
|
|
492
|
+
const tagName = revisionMeta.type === "ins" ? "ins" : "del";
|
|
493
|
+
result.push(`<${tagName} ${revisionMetaAttrs(revisionMeta)}>${runText2}</${tagName}>`);
|
|
363
494
|
} else {
|
|
364
|
-
|
|
495
|
+
result.push(runText2);
|
|
365
496
|
}
|
|
366
497
|
}
|
|
367
498
|
for (let i = 0; i < pageBreakCount; i += 1) {
|
|
368
|
-
|
|
499
|
+
result.push(`<span data-word-page-break="1" style="display:block;break-before:page"></span>`);
|
|
500
|
+
}
|
|
501
|
+
return result;
|
|
502
|
+
}
|
|
503
|
+
async function nodeToHtml(node, revisionFallback) {
|
|
504
|
+
if (node.localName === "commentRangeStart") {
|
|
505
|
+
const id = getAttr(node, "w:id") ?? getAttr(node, "id");
|
|
506
|
+
return id ? [`<span data-word-comment-range-start="${id}"></span>`] : [];
|
|
507
|
+
}
|
|
508
|
+
if (node.localName === "commentRangeEnd") {
|
|
509
|
+
const id = getAttr(node, "w:id") ?? getAttr(node, "id");
|
|
510
|
+
return id ? [`<span data-word-comment-range-end="${id}"></span>`] : [];
|
|
511
|
+
}
|
|
512
|
+
if (node.localName === "r") {
|
|
513
|
+
return runToHtml(node, revisionFallback);
|
|
369
514
|
}
|
|
515
|
+
if (node.localName === "oMath" || node.localName === "oMathPara") {
|
|
516
|
+
const linear = ommlNodeToText(node).trim();
|
|
517
|
+
if (!linear) return [];
|
|
518
|
+
return [`<span data-word-omml="1">${escapeHtml(linear)}</span>`];
|
|
519
|
+
}
|
|
520
|
+
if (node.localName === "ins" || node.localName === "del") {
|
|
521
|
+
const scopedMeta = parseRevisionMeta(node, node.localName === "ins" ? "ins" : "del");
|
|
522
|
+
const nested2 = [];
|
|
523
|
+
for (const child of Array.from(node.children)) {
|
|
524
|
+
nested2.push(...await nodeToHtml(child, scopedMeta));
|
|
525
|
+
}
|
|
526
|
+
return nested2;
|
|
527
|
+
}
|
|
528
|
+
const nested = [];
|
|
529
|
+
for (const child of Array.from(node.children)) {
|
|
530
|
+
nested.push(...await nodeToHtml(child, revisionFallback));
|
|
531
|
+
}
|
|
532
|
+
return nested;
|
|
533
|
+
}
|
|
534
|
+
const parts = [];
|
|
535
|
+
const renderedPageBreakCount = queryAllByLocalName(paragraph, "lastRenderedPageBreak").length;
|
|
536
|
+
for (let i = 0; i < renderedPageBreakCount; i += 1) {
|
|
537
|
+
parts.push(`<span data-word-page-break="1" style="display:block;break-before:page"></span>`);
|
|
538
|
+
}
|
|
539
|
+
for (const child of Array.from(paragraph.children)) {
|
|
540
|
+
parts.push(...await nodeToHtml(child, null));
|
|
370
541
|
}
|
|
371
542
|
const content = parts.join("") || "<br/>";
|
|
372
543
|
return `<${tag}${dataAttr}${alignStyle ? ` style="${alignStyle}"` : ""}>${content}</${tag}>`;
|
|
@@ -396,6 +567,101 @@ function parseTcVMerge(tc) {
|
|
|
396
567
|
const rawVal = (getAttr(vMerge, "w:val") ?? getAttr(vMerge, "val") ?? "continue").toLowerCase();
|
|
397
568
|
return rawVal === "restart" ? "restart" : "continue";
|
|
398
569
|
}
|
|
570
|
+
function parseTblGridWidthsPx(table) {
|
|
571
|
+
const grid = directChildrenByLocalName(table, "tblGrid")[0] ?? null;
|
|
572
|
+
if (!grid) return [];
|
|
573
|
+
return directChildrenByLocalName(grid, "gridCol").map((col) => {
|
|
574
|
+
const raw = getAttr(col, "w:w") ?? getAttr(col, "w");
|
|
575
|
+
const twip = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
576
|
+
return Number.isFinite(twip) && twip > 0 ? twipToPx(twip) : 0;
|
|
577
|
+
}).filter((px) => px > 0);
|
|
578
|
+
}
|
|
579
|
+
function borderSizeToPx(size) {
|
|
580
|
+
return size / 6;
|
|
581
|
+
}
|
|
582
|
+
function parseBorderCss(borderNode) {
|
|
583
|
+
if (!borderNode) return null;
|
|
584
|
+
const val = (getAttr(borderNode, "w:val") ?? getAttr(borderNode, "val") ?? "").toLowerCase();
|
|
585
|
+
if (!val || val === "nil" || val === "none") return "none";
|
|
586
|
+
const color = (getAttr(borderNode, "w:color") ?? getAttr(borderNode, "color") ?? "222222").replace(/^#/, "");
|
|
587
|
+
const rawSize = getAttr(borderNode, "w:sz") ?? getAttr(borderNode, "sz");
|
|
588
|
+
const size = rawSize ? Number.parseInt(rawSize, 10) : Number.NaN;
|
|
589
|
+
const px = Number.isFinite(size) && size > 0 ? borderSizeToPx(size) : 1;
|
|
590
|
+
const style = val === "single" ? "solid" : val;
|
|
591
|
+
return `${px.toFixed(2)}px ${style} #${color}`;
|
|
592
|
+
}
|
|
593
|
+
function parseTableStyleProfile(table) {
|
|
594
|
+
const tblPr = directChildrenByLocalName(table, "tblPr")[0] ?? null;
|
|
595
|
+
const tblBorders = tblPr ? directChildrenByLocalName(tblPr, "tblBorders")[0] ?? null : null;
|
|
596
|
+
const layout = tblPr ? directChildrenByLocalName(tblPr, "tblLayout")[0] ?? null : null;
|
|
597
|
+
const spacing = tblPr ? directChildrenByLocalName(tblPr, "tblCellSpacing")[0] ?? null : null;
|
|
598
|
+
const spacingType = (getAttr(spacing, "w:type") ?? getAttr(spacing, "type") ?? "dxa").toLowerCase();
|
|
599
|
+
const spacingRaw = getAttr(spacing, "w:w") ?? getAttr(spacing, "w");
|
|
600
|
+
const spacingVal = spacingRaw ? Number.parseFloat(spacingRaw) : Number.NaN;
|
|
601
|
+
const borderSpacingPx = spacingType === "dxa" && Number.isFinite(spacingVal) && spacingVal > 0 ? twipToPx(spacingVal) : 0;
|
|
602
|
+
const borderCollapse = borderSpacingPx > 0 ? "separate" : "collapse";
|
|
603
|
+
const tableLayout = (getAttr(layout, "w:type") ?? getAttr(layout, "type") ?? "").toLowerCase() === "autofit" ? "auto" : "fixed";
|
|
604
|
+
const top = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "top")[0] ?? null : null);
|
|
605
|
+
const bottom = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "bottom")[0] ?? null : null);
|
|
606
|
+
const left = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "left")[0] ?? null : null);
|
|
607
|
+
const right = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "right")[0] ?? null : null);
|
|
608
|
+
const insideH = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "insideH")[0] ?? null : null);
|
|
609
|
+
const insideV = parseBorderCss(tblBorders ? directChildrenByLocalName(tblBorders, "insideV")[0] ?? null : null);
|
|
610
|
+
const borderCss = top ?? right ?? bottom ?? left ?? "1px solid #222";
|
|
611
|
+
return {
|
|
612
|
+
tableLayout,
|
|
613
|
+
borderCollapse,
|
|
614
|
+
borderSpacingPx,
|
|
615
|
+
borderCss,
|
|
616
|
+
insideHCss: insideH,
|
|
617
|
+
insideVCss: insideV
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
function parseTableWidthStyle(table, gridWidthsPx) {
|
|
621
|
+
const tblPr = directChildrenByLocalName(table, "tblPr")[0] ?? null;
|
|
622
|
+
const tblW = tblPr ? directChildrenByLocalName(tblPr, "tblW")[0] ?? null : null;
|
|
623
|
+
const type = (getAttr(tblW, "w:type") ?? getAttr(tblW, "type") ?? "").toLowerCase();
|
|
624
|
+
const rawVal = getAttr(tblW, "w:w") ?? getAttr(tblW, "w");
|
|
625
|
+
const numericVal = rawVal ? Number.parseFloat(rawVal) : Number.NaN;
|
|
626
|
+
if (type === "dxa" && Number.isFinite(numericVal) && numericVal > 0) {
|
|
627
|
+
return `width:${twipToPx(numericVal).toFixed(2)}px`;
|
|
628
|
+
}
|
|
629
|
+
if (type === "pct" && Number.isFinite(numericVal) && numericVal > 0) {
|
|
630
|
+
return `width:${(numericVal / 50).toFixed(2)}%`;
|
|
631
|
+
}
|
|
632
|
+
const gridTotal = gridWidthsPx.reduce((sum, item) => sum + item, 0);
|
|
633
|
+
if (gridTotal > 0) return `width:${gridTotal.toFixed(2)}px;max-width:100%`;
|
|
634
|
+
return "width:100%";
|
|
635
|
+
}
|
|
636
|
+
function parseCellWidthStyle(cell, colCursor, colSpan, gridWidthsPx) {
|
|
637
|
+
const tcPr = directChildrenByLocalName(cell, "tcPr")[0] ?? null;
|
|
638
|
+
const tcW = tcPr ? directChildrenByLocalName(tcPr, "tcW")[0] ?? null : null;
|
|
639
|
+
const type = (getAttr(tcW, "w:type") ?? getAttr(tcW, "type") ?? "").toLowerCase();
|
|
640
|
+
const rawVal = getAttr(tcW, "w:w") ?? getAttr(tcW, "w");
|
|
641
|
+
const numericVal = rawVal ? Number.parseFloat(rawVal) : Number.NaN;
|
|
642
|
+
if (type === "dxa" && Number.isFinite(numericVal) && numericVal > 0) {
|
|
643
|
+
return `width:${twipToPx(numericVal).toFixed(2)}px`;
|
|
644
|
+
}
|
|
645
|
+
if (type === "pct" && Number.isFinite(numericVal) && numericVal > 0) {
|
|
646
|
+
return `width:${(numericVal / 50).toFixed(2)}%`;
|
|
647
|
+
}
|
|
648
|
+
const width = gridWidthsPx.slice(colCursor, colCursor + colSpan).reduce((sum, item) => sum + item, 0);
|
|
649
|
+
if (width > 0) return `width:${width.toFixed(2)}px`;
|
|
650
|
+
return "";
|
|
651
|
+
}
|
|
652
|
+
function parseCellBorderStyle(cell, tableStyle) {
|
|
653
|
+
const tcPr = directChildrenByLocalName(cell, "tcPr")[0] ?? null;
|
|
654
|
+
const tcBorders = tcPr ? directChildrenByLocalName(tcPr, "tcBorders")[0] ?? null : null;
|
|
655
|
+
if (!tcBorders) {
|
|
656
|
+
const fallback = tableStyle.insideHCss ?? tableStyle.insideVCss ?? tableStyle.borderCss;
|
|
657
|
+
return `border:${fallback}`;
|
|
658
|
+
}
|
|
659
|
+
const top = parseBorderCss(directChildrenByLocalName(tcBorders, "top")[0] ?? null) ?? tableStyle.insideHCss ?? tableStyle.borderCss;
|
|
660
|
+
const right = parseBorderCss(directChildrenByLocalName(tcBorders, "right")[0] ?? null) ?? tableStyle.insideVCss ?? tableStyle.borderCss;
|
|
661
|
+
const bottom = parseBorderCss(directChildrenByLocalName(tcBorders, "bottom")[0] ?? null) ?? tableStyle.insideHCss ?? tableStyle.borderCss;
|
|
662
|
+
const left = parseBorderCss(directChildrenByLocalName(tcBorders, "left")[0] ?? null) ?? tableStyle.insideVCss ?? tableStyle.borderCss;
|
|
663
|
+
return `border-top:${top};border-right:${right};border-bottom:${bottom};border-left:${left}`;
|
|
664
|
+
}
|
|
399
665
|
function tableCellHtml(cell, paragraphIndexMap) {
|
|
400
666
|
const blocks = [];
|
|
401
667
|
for (const child of Array.from(cell.children)) {
|
|
@@ -416,6 +682,8 @@ function tableCellHtml(cell, paragraphIndexMap) {
|
|
|
416
682
|
}
|
|
417
683
|
function tableToHtml(table, paragraphIndexMap) {
|
|
418
684
|
const rows = directChildrenByLocalName(table, "tr");
|
|
685
|
+
const gridWidthsPx = parseTblGridWidthsPx(table);
|
|
686
|
+
const tableStyle = parseTableStyleProfile(table);
|
|
419
687
|
const activeByCol = /* @__PURE__ */ new Map();
|
|
420
688
|
const allOrigins = [];
|
|
421
689
|
let nextOriginId = 1;
|
|
@@ -442,6 +710,8 @@ function tableToHtml(table, paragraphIndexMap) {
|
|
|
442
710
|
}
|
|
443
711
|
const html = tableCellHtml(cell, paragraphIndexMap);
|
|
444
712
|
const attrs = [];
|
|
713
|
+
const widthStyle = parseCellWidthStyle(cell, colCursor, colSpan, gridWidthsPx);
|
|
714
|
+
const borderStyle = parseCellBorderStyle(cell, tableStyle);
|
|
445
715
|
if (vMerge === "restart") {
|
|
446
716
|
const origin = {
|
|
447
717
|
id: `m${nextOriginId}`,
|
|
@@ -459,7 +729,7 @@ function tableToHtml(table, paragraphIndexMap) {
|
|
|
459
729
|
}
|
|
460
730
|
if (colSpan > 1) attrs.push(`colspan="${colSpan}"`);
|
|
461
731
|
emittedCells.push(
|
|
462
|
-
`<td${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""} style="
|
|
732
|
+
`<td${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""} style="${borderStyle};vertical-align:top;${widthStyle}">${html}</td>`
|
|
463
733
|
);
|
|
464
734
|
colCursor += colSpan;
|
|
465
735
|
}
|
|
@@ -478,7 +748,9 @@ function tableToHtml(table, paragraphIndexMap) {
|
|
|
478
748
|
const replacement = origin.rowSpan > 1 ? `rowspan="${origin.rowSpan}"` : "";
|
|
479
749
|
merged = merged.replace(marker, replacement).replace(/\s{2,}/g, " ");
|
|
480
750
|
}
|
|
481
|
-
|
|
751
|
+
const tableWidthStyle = parseTableWidthStyle(table, gridWidthsPx);
|
|
752
|
+
const spacing = tableStyle.borderSpacingPx > 0 ? `border-spacing:${tableStyle.borderSpacingPx.toFixed(2)}px;` : "";
|
|
753
|
+
return `<table style="border-collapse:${tableStyle.borderCollapse};${spacing}table-layout:${tableStyle.tableLayout};${tableWidthStyle};border:${tableStyle.borderCss};">${merged}</table>`;
|
|
482
754
|
}
|
|
483
755
|
async function parseDocxToHtmlSnapshot(file) {
|
|
484
756
|
const maybeArrayBuffer = file.arrayBuffer;
|
|
@@ -768,7 +1040,7 @@ function createFallbackWordStyleProfile(sourceFileName = "snapshot") {
|
|
|
768
1040
|
paragraphProfiles: []
|
|
769
1041
|
};
|
|
770
1042
|
}
|
|
771
|
-
function
|
|
1043
|
+
function twipToPx2(twip) {
|
|
772
1044
|
return twip / 15;
|
|
773
1045
|
}
|
|
774
1046
|
function getAttr2(node, attr) {
|
|
@@ -812,10 +1084,10 @@ function parsePageGeometry(documentXml) {
|
|
|
812
1084
|
const top = getTwipAttr(pgMar, "w:top") ?? getTwipAttr(pgMar, "top") ?? null;
|
|
813
1085
|
const bottom = getTwipAttr(pgMar, "w:bottom") ?? getTwipAttr(pgMar, "bottom") ?? null;
|
|
814
1086
|
return {
|
|
815
|
-
contentWidthPx: pageW === null ? null :
|
|
816
|
-
pageHeightPx: pageH === null ? null :
|
|
817
|
-
marginTopPx: top === null ? null :
|
|
818
|
-
marginBottomPx: bottom === null ? null :
|
|
1087
|
+
contentWidthPx: pageW === null ? null : twipToPx2(pageW - left - right),
|
|
1088
|
+
pageHeightPx: pageH === null ? null : twipToPx2(pageH),
|
|
1089
|
+
marginTopPx: top === null ? null : twipToPx2(top),
|
|
1090
|
+
marginBottomPx: bottom === null ? null : twipToPx2(bottom)
|
|
819
1091
|
};
|
|
820
1092
|
}
|
|
821
1093
|
function parseHeadingAlignFromDocument(documentXml) {
|
|
@@ -988,15 +1260,15 @@ function parseParagraphProfiles(documentXml, numberingMap) {
|
|
|
988
1260
|
text,
|
|
989
1261
|
isEmpty: text.length === 0,
|
|
990
1262
|
align: parseParagraphAlign(paragraph),
|
|
991
|
-
beforePx: before === null ? null :
|
|
992
|
-
afterPx: after === null ? null :
|
|
1263
|
+
beforePx: before === null ? null : twipToPx2(before),
|
|
1264
|
+
afterPx: after === null ? null : twipToPx2(after),
|
|
993
1265
|
lineHeightRatio: line === null || lineHeightRule !== "auto" ? null : line / 240,
|
|
994
|
-
lineHeightPx: line === null || lineHeightRule === "auto" ? null :
|
|
1266
|
+
lineHeightPx: line === null || lineHeightRule === "auto" ? null : twipToPx2(line),
|
|
995
1267
|
lineHeightRule,
|
|
996
|
-
indentLeftPx: left === null ? null :
|
|
997
|
-
indentRightPx: right === null ? null :
|
|
998
|
-
firstLinePx: firstLine === null ? null :
|
|
999
|
-
hangingPx: hanging === null ? null :
|
|
1268
|
+
indentLeftPx: left === null ? null : twipToPx2(left),
|
|
1269
|
+
indentRightPx: right === null ? null : twipToPx2(right),
|
|
1270
|
+
firstLinePx: firstLine === null ? null : twipToPx2(firstLine),
|
|
1271
|
+
hangingPx: hanging === null ? null : twipToPx2(hanging),
|
|
1000
1272
|
listNumId,
|
|
1001
1273
|
listLevel,
|
|
1002
1274
|
listFormat: listSpec?.numFmt ?? null,
|
|
@@ -1031,19 +1303,19 @@ function parseTableDefaults(stylesXml) {
|
|
|
1031
1303
|
return {
|
|
1032
1304
|
topPx: (() => {
|
|
1033
1305
|
const v = getTwipAttr(top, "w:w") ?? getTwipAttr(top, "w") ?? null;
|
|
1034
|
-
return v === null ? null :
|
|
1306
|
+
return v === null ? null : twipToPx2(v);
|
|
1035
1307
|
})(),
|
|
1036
1308
|
leftPx: (() => {
|
|
1037
1309
|
const v = getTwipAttr(left, "w:w") ?? getTwipAttr(left, "w") ?? null;
|
|
1038
|
-
return v === null ? null :
|
|
1310
|
+
return v === null ? null : twipToPx2(v);
|
|
1039
1311
|
})(),
|
|
1040
1312
|
bottomPx: (() => {
|
|
1041
1313
|
const v = getTwipAttr(bottom, "w:w") ?? getTwipAttr(bottom, "w") ?? null;
|
|
1042
|
-
return v === null ? null :
|
|
1314
|
+
return v === null ? null : twipToPx2(v);
|
|
1043
1315
|
})(),
|
|
1044
1316
|
rightPx: (() => {
|
|
1045
1317
|
const v = getTwipAttr(right, "w:w") ?? getTwipAttr(right, "w") ?? null;
|
|
1046
|
-
return v === null ? null :
|
|
1318
|
+
return v === null ? null : twipToPx2(v);
|
|
1047
1319
|
})()
|
|
1048
1320
|
};
|
|
1049
1321
|
}
|
|
@@ -1141,9 +1413,9 @@ function parseDefaults(stylesXml) {
|
|
|
1141
1413
|
const rawLineRule = (getAttr2(spacing, "w:lineRule") ?? getAttr2(spacing, "lineRule") ?? "auto").toLowerCase();
|
|
1142
1414
|
const bodyLineHeightRule = rawLineRule === "exact" ? "exact" : rawLineRule === "atleast" ? "atLeast" : "auto";
|
|
1143
1415
|
const bodyLineHeightRatio = line === null || bodyLineHeightRule !== "auto" ? null : line / 240;
|
|
1144
|
-
const bodyLineHeightPx = line === null || bodyLineHeightRule === "auto" ? null :
|
|
1416
|
+
const bodyLineHeightPx = line === null || bodyLineHeightRule === "auto" ? null : twipToPx2(line);
|
|
1145
1417
|
const after = getTwipAttr(spacing, "w:after") ?? getTwipAttr(spacing, "after") ?? null;
|
|
1146
|
-
const paragraphAfterPx = after === null ? null :
|
|
1418
|
+
const paragraphAfterPx = after === null ? null : twipToPx2(after);
|
|
1147
1419
|
return { bodyFontPx, bodyLineHeightRatio, bodyLineHeightPx, bodyLineHeightRule, paragraphAfterPx };
|
|
1148
1420
|
}
|
|
1149
1421
|
function parseHeading1Style(stylesXml) {
|
|
@@ -1918,4 +2190,4 @@ export {
|
|
|
1918
2190
|
DocsWordElement,
|
|
1919
2191
|
defineDocsWordElement
|
|
1920
2192
|
};
|
|
1921
|
-
//# sourceMappingURL=chunk-
|
|
2193
|
+
//# sourceMappingURL=chunk-IBVWD4UO.js.map
|