@courtifyai/docx-render 1.0.0 → 1.0.1
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/index.es.js +2915 -0
- package/dist/index.umd.js +27 -0
- package/dist/style.css +1 -0
- package/package.json +5 -1
- package/debug-comments.cjs +0 -19
- package/index.html +0 -312
- package/src/comments/comments-parser.ts +0 -159
- package/src/comments/index.ts +0 -6
- package/src/font-table/font-loader.ts +0 -379
- package/src/font-table/font-parser.ts +0 -258
- package/src/font-table/index.ts +0 -22
- package/src/index.ts +0 -137
- package/src/parser/document-parser.ts +0 -1606
- package/src/parser/index.ts +0 -3
- package/src/parser/xml-parser.ts +0 -152
- package/src/renderer/document-renderer.ts +0 -2163
- package/src/renderer/index.ts +0 -1
- package/src/styles/index.css +0 -692
- package/src/theme/index.ts +0 -8
- package/src/theme/theme-parser.ts +0 -172
- package/src/theme/theme-utils.ts +0 -148
- package/src/types/index.ts +0 -847
- package/tsconfig.json +0 -27
- package/vite.config.ts +0 -26
package/dist/index.es.js
ADDED
|
@@ -0,0 +1,2915 @@
|
|
|
1
|
+
var z = Object.defineProperty;
|
|
2
|
+
var O = (o, e, t) => e in o ? z(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
|
|
3
|
+
var g = (o, e, t) => O(o, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
import G from "jszip";
|
|
5
|
+
var m = /* @__PURE__ */ ((o) => (o.Document = "document", o.Paragraph = "paragraph", o.Run = "run", o.Text = "text", o.Break = "break", o.Table = "table", o.TableRow = "tableRow", o.TableCell = "tableCell", o.Hyperlink = "hyperlink", o.Drawing = "drawing", o.Image = "image", o.BookmarkStart = "bookmarkStart", o.BookmarkEnd = "bookmarkEnd", o.Comment = "comment", o.CommentRangeStart = "commentRangeStart", o.CommentRangeEnd = "commentRangeEnd", o.CommentReference = "commentReference", o.Section = "section", o.Header = "header", o.Footer = "footer", o.Tab = "tab", o.Symbol = "symbol", o.SimpleField = "simpleField", o.ComplexField = "complexField", o.FieldInstruction = "fieldInstruction", o.Footnote = "footnote", o.Endnote = "endnote", o.FootnoteReference = "footnoteReference", o.EndnoteReference = "endnoteReference", o))(m || {});
|
|
6
|
+
const U = {
|
|
7
|
+
W: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
|
8
|
+
W14: "http://schemas.microsoft.com/office/word/2010/wordml",
|
|
9
|
+
W15: "http://schemas.microsoft.com/office/word/2012/wordml",
|
|
10
|
+
R: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
11
|
+
A: "http://schemas.openxmlformats.org/drawingml/2006/main",
|
|
12
|
+
WP: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
|
|
13
|
+
PIC: "http://schemas.openxmlformats.org/drawingml/2006/picture"
|
|
14
|
+
}, C = {
|
|
15
|
+
DOCUMENT: "word/document.xml",
|
|
16
|
+
COMMENTS: "word/comments.xml",
|
|
17
|
+
COMMENTS_EXTENDED: "word/commentsExtended.xml",
|
|
18
|
+
STYLES: "word/styles.xml",
|
|
19
|
+
NUMBERING: "word/numbering.xml",
|
|
20
|
+
THEME: "word/theme/theme1.xml",
|
|
21
|
+
FOOTNOTES: "word/footnotes.xml",
|
|
22
|
+
ENDNOTES: "word/endnotes.xml",
|
|
23
|
+
FONT_TABLE: "word/fontTable.xml",
|
|
24
|
+
FONT_TABLE_RELS: "word/_rels/fontTable.xml.rels",
|
|
25
|
+
RELS: "word/_rels/document.xml.rels",
|
|
26
|
+
CONTENT_TYPES: "[Content_Types].xml",
|
|
27
|
+
HEADER_PREFIX: "word/header",
|
|
28
|
+
FOOTER_PREFIX: "word/footer"
|
|
29
|
+
}, F = {
|
|
30
|
+
IMAGE: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
31
|
+
HEADER: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
|
|
32
|
+
FOOTER: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
|
|
33
|
+
FONT: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/font"
|
|
34
|
+
};
|
|
35
|
+
class _ {
|
|
36
|
+
/**
|
|
37
|
+
* 获取元素的所有子元素
|
|
38
|
+
*/
|
|
39
|
+
elements(e, t) {
|
|
40
|
+
const n = [];
|
|
41
|
+
for (let r = 0; r < e.childNodes.length; r++) {
|
|
42
|
+
const i = e.childNodes[r];
|
|
43
|
+
i.nodeType === Node.ELEMENT_NODE && (!t || i.localName === t) && n.push(i);
|
|
44
|
+
}
|
|
45
|
+
return n;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 获取第一个匹配的子元素
|
|
49
|
+
*/
|
|
50
|
+
element(e, t) {
|
|
51
|
+
for (let n = 0; n < e.childNodes.length; n++) {
|
|
52
|
+
const r = e.childNodes[n];
|
|
53
|
+
if (r.nodeType === Node.ELEMENT_NODE && r.localName === t)
|
|
54
|
+
return r;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 获取元素属性值
|
|
60
|
+
*/
|
|
61
|
+
attr(e, t) {
|
|
62
|
+
if (!e) return;
|
|
63
|
+
for (const r of Object.values(U)) {
|
|
64
|
+
const i = e.getAttributeNS(r, t);
|
|
65
|
+
if (i) return i;
|
|
66
|
+
}
|
|
67
|
+
const n = e.getAttribute(`w:${t}`);
|
|
68
|
+
return n || e.getAttribute(t) || void 0;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 获取布尔属性
|
|
72
|
+
*/
|
|
73
|
+
boolAttr(e, t, n = !1) {
|
|
74
|
+
if (!e) return n;
|
|
75
|
+
const r = this.attr(e, t);
|
|
76
|
+
return r === void 0 ? n : r === "1" || r === "true" || r === "on";
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 获取整数属性
|
|
80
|
+
*/
|
|
81
|
+
intAttr(e, t) {
|
|
82
|
+
if (!e) return;
|
|
83
|
+
const n = this.attr(e, t);
|
|
84
|
+
if (n)
|
|
85
|
+
return parseInt(n, 10);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 获取长度属性并转换单位
|
|
89
|
+
*/
|
|
90
|
+
lengthAttr(e, t, n = T.Dxa) {
|
|
91
|
+
if (!e) return;
|
|
92
|
+
const r = this.attr(e, t);
|
|
93
|
+
return this.convertLength(r, n);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 转换长度单位
|
|
97
|
+
*/
|
|
98
|
+
convertLength(e, t = T.Dxa) {
|
|
99
|
+
return e ? /[a-z%]+$/i.test(e) ? e : `${(parseFloat(e) * t.mul).toFixed(2)}${t.unit}` : void 0;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 获取元素的文本内容
|
|
103
|
+
*/
|
|
104
|
+
textContent(e) {
|
|
105
|
+
return e && e.textContent || "";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const T = {
|
|
109
|
+
/** 1/20 点 (twip) */
|
|
110
|
+
Dxa: { mul: 0.05, unit: "pt" },
|
|
111
|
+
/** EMU (English Metric Unit) */
|
|
112
|
+
Emu: { mul: 1 / 12700, unit: "pt" },
|
|
113
|
+
/** 半点 */
|
|
114
|
+
FontSize: { mul: 0.5, unit: "pt" },
|
|
115
|
+
/** 1/8 点 */
|
|
116
|
+
Border: { mul: 0.125, unit: "pt" }
|
|
117
|
+
};
|
|
118
|
+
function w(o) {
|
|
119
|
+
o.charCodeAt(0) === 65279 && (o = o.substring(1)), o = o.replace(/<\?xml[^?]*\?>/g, "");
|
|
120
|
+
const t = new DOMParser().parseFromString(o, "application/xml"), n = t.getElementsByTagName("parsererror")[0];
|
|
121
|
+
if (n)
|
|
122
|
+
throw new Error(`XML 解析错误: ${n.textContent}`);
|
|
123
|
+
return t;
|
|
124
|
+
}
|
|
125
|
+
const s = new _();
|
|
126
|
+
function j(o) {
|
|
127
|
+
const e = {
|
|
128
|
+
colorScheme: { name: "", colors: {} },
|
|
129
|
+
fontScheme: { name: "", majorFont: {}, minorFont: {} }
|
|
130
|
+
}, t = $(o, "themeElements");
|
|
131
|
+
if (!t) return e;
|
|
132
|
+
for (const n of R(t)) {
|
|
133
|
+
const r = n.localName;
|
|
134
|
+
r === "clrScheme" ? e.colorScheme = V(n) : r === "fontScheme" && (e.fontScheme = X(n));
|
|
135
|
+
}
|
|
136
|
+
return e;
|
|
137
|
+
}
|
|
138
|
+
function V(o) {
|
|
139
|
+
const e = {
|
|
140
|
+
name: o.getAttribute("name") || "",
|
|
141
|
+
colors: {}
|
|
142
|
+
};
|
|
143
|
+
for (const t of R(o)) {
|
|
144
|
+
const n = t.localName, r = W(t);
|
|
145
|
+
r && (e.colors[n] = r);
|
|
146
|
+
}
|
|
147
|
+
return e;
|
|
148
|
+
}
|
|
149
|
+
function W(o) {
|
|
150
|
+
const e = $(o, "srgbClr");
|
|
151
|
+
if (e) {
|
|
152
|
+
const n = e.getAttribute("val");
|
|
153
|
+
return n ? `#${n}` : null;
|
|
154
|
+
}
|
|
155
|
+
const t = $(o, "sysClr");
|
|
156
|
+
if (t) {
|
|
157
|
+
const n = t.getAttribute("lastClr");
|
|
158
|
+
return n ? `#${n}` : null;
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
function X(o) {
|
|
163
|
+
const e = {
|
|
164
|
+
name: o.getAttribute("name") || "",
|
|
165
|
+
majorFont: {},
|
|
166
|
+
minorFont: {}
|
|
167
|
+
};
|
|
168
|
+
for (const t of R(o)) {
|
|
169
|
+
const n = t.localName;
|
|
170
|
+
n === "majorFont" ? e.majorFont = I(t) : n === "minorFont" && (e.minorFont = I(t));
|
|
171
|
+
}
|
|
172
|
+
return e;
|
|
173
|
+
}
|
|
174
|
+
function I(o) {
|
|
175
|
+
const e = {};
|
|
176
|
+
for (const t of R(o)) {
|
|
177
|
+
const n = t.localName, r = t.getAttribute("typeface");
|
|
178
|
+
r && (n === "latin" ? e.latin = r : n === "ea" ? e.ea = r : n === "cs" && (e.cs = r));
|
|
179
|
+
}
|
|
180
|
+
return e;
|
|
181
|
+
}
|
|
182
|
+
function $(o, e) {
|
|
183
|
+
for (let t = 0; t < o.childNodes.length; t++) {
|
|
184
|
+
const n = o.childNodes[t];
|
|
185
|
+
if (n.nodeType === Node.ELEMENT_NODE) {
|
|
186
|
+
const r = n;
|
|
187
|
+
if (r.localName === e)
|
|
188
|
+
return r;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
function R(o) {
|
|
194
|
+
const e = [];
|
|
195
|
+
for (let t = 0; t < o.childNodes.length; t++) {
|
|
196
|
+
const n = o.childNodes[t];
|
|
197
|
+
n.nodeType === Node.ELEMENT_NODE && e.push(n);
|
|
198
|
+
}
|
|
199
|
+
return e;
|
|
200
|
+
}
|
|
201
|
+
const q = {
|
|
202
|
+
// 标准映射
|
|
203
|
+
dark1: "dk1",
|
|
204
|
+
dark2: "dk2",
|
|
205
|
+
light1: "lt1",
|
|
206
|
+
light2: "lt2",
|
|
207
|
+
accent1: "accent1",
|
|
208
|
+
accent2: "accent2",
|
|
209
|
+
accent3: "accent3",
|
|
210
|
+
accent4: "accent4",
|
|
211
|
+
accent5: "accent5",
|
|
212
|
+
accent6: "accent6",
|
|
213
|
+
hyperlink: "hlink",
|
|
214
|
+
followedHyperlink: "folHlink",
|
|
215
|
+
// 直接映射(XML 中的原始名称)
|
|
216
|
+
dk1: "dk1",
|
|
217
|
+
dk2: "dk2",
|
|
218
|
+
lt1: "lt1",
|
|
219
|
+
lt2: "lt2",
|
|
220
|
+
hlink: "hlink",
|
|
221
|
+
folHlink: "folHlink",
|
|
222
|
+
// 文本颜色别名
|
|
223
|
+
text1: "dk1",
|
|
224
|
+
text2: "dk2",
|
|
225
|
+
background1: "lt1",
|
|
226
|
+
background2: "lt2"
|
|
227
|
+
};
|
|
228
|
+
function Y(o, e) {
|
|
229
|
+
var i;
|
|
230
|
+
if (!((i = o == null ? void 0 : o.colorScheme) != null && i.colors)) return;
|
|
231
|
+
const t = e.themeColor, n = q[t] || t, r = o.colorScheme.colors[n];
|
|
232
|
+
if (r)
|
|
233
|
+
return e.themeTint !== void 0 || e.themeShade !== void 0 ? K(r, e.themeTint, e.themeShade) : r;
|
|
234
|
+
}
|
|
235
|
+
function K(o, e, t) {
|
|
236
|
+
const n = o.replace("#", ""), r = parseInt(n.substr(0, 2), 16), i = parseInt(n.substr(2, 2), 16), a = parseInt(n.substr(4, 2), 16);
|
|
237
|
+
let c = r, l = i, d = a;
|
|
238
|
+
if (e !== void 0 && e > 0) {
|
|
239
|
+
const h = e / 255;
|
|
240
|
+
c = Math.round(r + (255 - r) * h), l = Math.round(i + (255 - i) * h), d = Math.round(a + (255 - a) * h);
|
|
241
|
+
}
|
|
242
|
+
if (t !== void 0 && t > 0) {
|
|
243
|
+
const h = 1 - t / 255;
|
|
244
|
+
c = Math.round(c * h), l = Math.round(l * h), d = Math.round(d * h);
|
|
245
|
+
}
|
|
246
|
+
return c = Math.max(0, Math.min(255, c)), l = Math.max(0, Math.min(255, l)), d = Math.max(0, Math.min(255, d)), `#${N(c)}${N(l)}${N(d)}`;
|
|
247
|
+
}
|
|
248
|
+
function N(o) {
|
|
249
|
+
const e = o.toString(16);
|
|
250
|
+
return e.length === 1 ? "0" + e : e;
|
|
251
|
+
}
|
|
252
|
+
function Te(o, e, t = "latin") {
|
|
253
|
+
return o != null && o.fontScheme ? (e === "major" ? o.fontScheme.majorFont : o.fontScheme.minorFont)[t] : void 0;
|
|
254
|
+
}
|
|
255
|
+
const Z = {
|
|
256
|
+
embedRegular: "regular",
|
|
257
|
+
embedBold: "bold",
|
|
258
|
+
embedItalic: "italic",
|
|
259
|
+
embedBoldItalic: "boldItalic"
|
|
260
|
+
};
|
|
261
|
+
function J(o) {
|
|
262
|
+
const t = w(o).documentElement, n = Q(t), r = new Map(n.map((a) => [a.name, a])), i = re(n);
|
|
263
|
+
return {
|
|
264
|
+
fonts: n,
|
|
265
|
+
fontMap: r,
|
|
266
|
+
substitutionMap: i
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function Q(o) {
|
|
270
|
+
return s.elements(o, "font").map((e) => ee(e));
|
|
271
|
+
}
|
|
272
|
+
function ee(o) {
|
|
273
|
+
const e = {
|
|
274
|
+
name: s.attr(o, "name") || "",
|
|
275
|
+
embedFontRefs: []
|
|
276
|
+
};
|
|
277
|
+
for (const t of s.elements(o))
|
|
278
|
+
switch (t.localName) {
|
|
279
|
+
case "family":
|
|
280
|
+
e.family = s.attr(t, "val");
|
|
281
|
+
break;
|
|
282
|
+
case "altName":
|
|
283
|
+
e.altName = s.attr(t, "val");
|
|
284
|
+
break;
|
|
285
|
+
case "charset":
|
|
286
|
+
e.charset = s.attr(t, "val");
|
|
287
|
+
break;
|
|
288
|
+
case "panose1":
|
|
289
|
+
e.panose1 = s.attr(t, "val");
|
|
290
|
+
break;
|
|
291
|
+
case "sig":
|
|
292
|
+
e.sig = te(t);
|
|
293
|
+
break;
|
|
294
|
+
case "embedRegular":
|
|
295
|
+
case "embedBold":
|
|
296
|
+
case "embedItalic":
|
|
297
|
+
case "embedBoldItalic":
|
|
298
|
+
const n = ne(t);
|
|
299
|
+
n && e.embedFontRefs.push(n);
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
return e;
|
|
303
|
+
}
|
|
304
|
+
function te(o) {
|
|
305
|
+
return {
|
|
306
|
+
usb0: s.attr(o, "usb0"),
|
|
307
|
+
usb1: s.attr(o, "usb1"),
|
|
308
|
+
usb2: s.attr(o, "usb2"),
|
|
309
|
+
usb3: s.attr(o, "usb3"),
|
|
310
|
+
csb0: s.attr(o, "csb0"),
|
|
311
|
+
csb1: s.attr(o, "csb1")
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
function ne(o) {
|
|
315
|
+
const e = s.attr(o, "id");
|
|
316
|
+
if (!e) return null;
|
|
317
|
+
const t = Z[o.localName];
|
|
318
|
+
return t ? {
|
|
319
|
+
id: e,
|
|
320
|
+
key: s.attr(o, "fontKey"),
|
|
321
|
+
subsetted: s.boolAttr(o, "subsetted"),
|
|
322
|
+
type: t
|
|
323
|
+
} : null;
|
|
324
|
+
}
|
|
325
|
+
function re(o) {
|
|
326
|
+
const e = /* @__PURE__ */ new Map();
|
|
327
|
+
for (const t of o)
|
|
328
|
+
t.altName && e.set(t.name, t.altName);
|
|
329
|
+
return e;
|
|
330
|
+
}
|
|
331
|
+
function Pe(o, e) {
|
|
332
|
+
return o.substitutionMap.get(e) || e;
|
|
333
|
+
}
|
|
334
|
+
function Fe(o, e) {
|
|
335
|
+
return o.fontMap.get(e);
|
|
336
|
+
}
|
|
337
|
+
function Re(o, e) {
|
|
338
|
+
const t = o.fontMap.get(e);
|
|
339
|
+
return t ? t.embedFontRefs.length > 0 : !1;
|
|
340
|
+
}
|
|
341
|
+
function Ne(o, e, t) {
|
|
342
|
+
const n = o.fontMap.get(e);
|
|
343
|
+
return n ? t ? n.embedFontRefs.filter((r) => r.type === t) : n.embedFontRefs : [];
|
|
344
|
+
}
|
|
345
|
+
function $e(o, e) {
|
|
346
|
+
const t = [], n = o.fontMap.get(e);
|
|
347
|
+
if (t.push(B(e)), n != null && n.altName && t.push(B(n.altName)), n != null && n.family) {
|
|
348
|
+
const r = se(n.family);
|
|
349
|
+
r && t.push(r);
|
|
350
|
+
}
|
|
351
|
+
return t.join(", ");
|
|
352
|
+
}
|
|
353
|
+
function B(o) {
|
|
354
|
+
return /[\s,'"()]/.test(o) ? `"${o.replace(/"/g, '\\"')}"` : o;
|
|
355
|
+
}
|
|
356
|
+
function se(o) {
|
|
357
|
+
switch (o.toLowerCase()) {
|
|
358
|
+
case "roman":
|
|
359
|
+
return "serif";
|
|
360
|
+
case "swiss":
|
|
361
|
+
return "sans-serif";
|
|
362
|
+
case "modern":
|
|
363
|
+
return "monospace";
|
|
364
|
+
case "script":
|
|
365
|
+
return "cursive";
|
|
366
|
+
case "decorative":
|
|
367
|
+
return "fantasy";
|
|
368
|
+
default:
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const L = {
|
|
373
|
+
injectStyles: !0,
|
|
374
|
+
timeout: 1e4
|
|
375
|
+
};
|
|
376
|
+
async function oe(o, e, t, n = {}) {
|
|
377
|
+
const r = { ...L, ...n }, i = [];
|
|
378
|
+
for (const a of e.fonts)
|
|
379
|
+
if (a.embedFontRefs.length !== 0)
|
|
380
|
+
for (const c of a.embedFontRefs)
|
|
381
|
+
try {
|
|
382
|
+
const l = await ie(
|
|
383
|
+
o,
|
|
384
|
+
a,
|
|
385
|
+
c,
|
|
386
|
+
t,
|
|
387
|
+
r.timeout || L.timeout
|
|
388
|
+
);
|
|
389
|
+
l && i.push(l);
|
|
390
|
+
} catch (l) {
|
|
391
|
+
console.warn(`加载嵌入字体失败: ${a.name} (${c.type})`, l);
|
|
392
|
+
}
|
|
393
|
+
return r.injectStyles && i.length > 0 && de(i, r.styleContainer), i;
|
|
394
|
+
}
|
|
395
|
+
async function ie(o, e, t, n, r) {
|
|
396
|
+
const i = n.find((b) => b.id === t.id);
|
|
397
|
+
if (!i)
|
|
398
|
+
return console.warn(`找不到嵌入字体关系: ${t.id}`), null;
|
|
399
|
+
const a = `word/${i.target}`, c = o.file(a);
|
|
400
|
+
if (!c)
|
|
401
|
+
return console.warn(`找不到嵌入字体文件: ${a}`), null;
|
|
402
|
+
const l = await Promise.race([
|
|
403
|
+
c.async("arraybuffer"),
|
|
404
|
+
new Promise(
|
|
405
|
+
(b, y) => setTimeout(() => y(new Error("字体加载超时")), r)
|
|
406
|
+
)
|
|
407
|
+
]);
|
|
408
|
+
let d = l;
|
|
409
|
+
t.key && (d = ae(l, t.key));
|
|
410
|
+
const h = ce(new Uint8Array(d)), p = le(h), u = new Blob([d], { type: p }), f = await he(u);
|
|
411
|
+
return {
|
|
412
|
+
fontName: e.name,
|
|
413
|
+
type: t.type,
|
|
414
|
+
dataUrl: f,
|
|
415
|
+
format: h
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
function ae(o, e) {
|
|
419
|
+
const t = e.replace(/[{}-]/g, "");
|
|
420
|
+
if (t.length !== 32)
|
|
421
|
+
return console.warn("无效的字体密钥格式:", e), o;
|
|
422
|
+
const n = new Uint8Array(16);
|
|
423
|
+
for (let c = 0; c < 4; c++)
|
|
424
|
+
n[3 - c] = parseInt(t.substr(c * 2, 2), 16);
|
|
425
|
+
for (let c = 0; c < 2; c++)
|
|
426
|
+
n[5 - c] = parseInt(t.substr(8 + c * 2, 2), 16);
|
|
427
|
+
for (let c = 0; c < 2; c++)
|
|
428
|
+
n[7 - c] = parseInt(t.substr(12 + c * 2, 2), 16);
|
|
429
|
+
for (let c = 0; c < 8; c++)
|
|
430
|
+
n[8 + c] = parseInt(t.substr(16 + c * 2, 2), 16);
|
|
431
|
+
const r = new Uint8Array(o), i = new Uint8Array(r.length), a = Math.min(32, r.length);
|
|
432
|
+
for (let c = 0; c < a; c++)
|
|
433
|
+
i[c] = r[c] ^ n[c % 16];
|
|
434
|
+
for (let c = a; c < r.length; c++)
|
|
435
|
+
i[c] = r[c];
|
|
436
|
+
return i.buffer;
|
|
437
|
+
}
|
|
438
|
+
function ce(o) {
|
|
439
|
+
return o.length < 4 ? "truetype" : o[0] === 79 && o[1] === 84 && o[2] === 84 && o[3] === 79 ? "opentype" : o[0] === 0 && o[1] === 1 && o[2] === 0 && o[3] === 0 || o[0] === 116 && o[1] === 114 && o[2] === 117 && o[3] === 101 ? "truetype" : o[0] === 0 && o[1] === 0 && o[2] === 1 ? "embedded-opentype" : "truetype";
|
|
440
|
+
}
|
|
441
|
+
function le(o) {
|
|
442
|
+
switch (o) {
|
|
443
|
+
case "opentype":
|
|
444
|
+
return "font/otf";
|
|
445
|
+
case "truetype":
|
|
446
|
+
return "font/ttf";
|
|
447
|
+
case "embedded-opentype":
|
|
448
|
+
return "application/vnd.ms-fontobject";
|
|
449
|
+
default:
|
|
450
|
+
return "font/ttf";
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
function he(o) {
|
|
454
|
+
return new Promise((e, t) => {
|
|
455
|
+
const n = new FileReader();
|
|
456
|
+
n.onloadend = () => e(n.result), n.onerror = t, n.readAsDataURL(o);
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
function de(o, e) {
|
|
460
|
+
const t = document.createElement("style");
|
|
461
|
+
t.setAttribute("data-docx-fonts", "true");
|
|
462
|
+
const n = o.map((a) => me(a)).join(`
|
|
463
|
+
`);
|
|
464
|
+
t.textContent = n;
|
|
465
|
+
const r = e || document.head, i = r.querySelector("style[data-docx-fonts]");
|
|
466
|
+
i && i.remove(), r.appendChild(t);
|
|
467
|
+
}
|
|
468
|
+
function me(o) {
|
|
469
|
+
const e = ue(o.type), t = fe(o.type), n = pe(o.format);
|
|
470
|
+
return `@font-face {
|
|
471
|
+
font-family: "${ge(o.fontName)}";
|
|
472
|
+
src: url("${o.dataUrl}") format("${n}");
|
|
473
|
+
font-weight: ${e};
|
|
474
|
+
font-style: ${t};
|
|
475
|
+
font-display: swap;
|
|
476
|
+
}`;
|
|
477
|
+
}
|
|
478
|
+
function ue(o) {
|
|
479
|
+
switch (o) {
|
|
480
|
+
case "bold":
|
|
481
|
+
case "boldItalic":
|
|
482
|
+
return "700";
|
|
483
|
+
default:
|
|
484
|
+
return "400";
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
function fe(o) {
|
|
488
|
+
switch (o) {
|
|
489
|
+
case "italic":
|
|
490
|
+
case "boldItalic":
|
|
491
|
+
return "italic";
|
|
492
|
+
default:
|
|
493
|
+
return "normal";
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function pe(o) {
|
|
497
|
+
switch (o) {
|
|
498
|
+
case "opentype":
|
|
499
|
+
return "opentype";
|
|
500
|
+
case "truetype":
|
|
501
|
+
return "truetype";
|
|
502
|
+
case "embedded-opentype":
|
|
503
|
+
return "embedded-opentype";
|
|
504
|
+
default:
|
|
505
|
+
return "truetype";
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
function ge(o) {
|
|
509
|
+
return o.replace(/"/g, '\\"');
|
|
510
|
+
}
|
|
511
|
+
function Ae(o) {
|
|
512
|
+
const t = (o || document.head).querySelector("style[data-docx-fonts]");
|
|
513
|
+
t && t.remove();
|
|
514
|
+
}
|
|
515
|
+
function be(o) {
|
|
516
|
+
const n = new DOMParser().parseFromString(o, "application/xml").documentElement, r = [], i = n.getElementsByTagName("Relationship");
|
|
517
|
+
for (let a = 0; a < i.length; a++) {
|
|
518
|
+
const c = i[a], l = c.getAttribute("Type") || "";
|
|
519
|
+
l === F.FONT && r.push({
|
|
520
|
+
id: c.getAttribute("Id") || "",
|
|
521
|
+
type: l,
|
|
522
|
+
target: c.getAttribute("Target") || "",
|
|
523
|
+
targetMode: c.getAttribute("TargetMode") || void 0
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
return r;
|
|
527
|
+
}
|
|
528
|
+
const D = "http://schemas.microsoft.com/office/word/2012/wordml";
|
|
529
|
+
function ye(o) {
|
|
530
|
+
const e = /* @__PURE__ */ new Map();
|
|
531
|
+
if (!o)
|
|
532
|
+
return e;
|
|
533
|
+
try {
|
|
534
|
+
const n = w(o).documentElement, r = n.getElementsByTagNameNS(D, "commentEx"), i = r.length > 0 ? Array.from(r) : Array.from(n.getElementsByTagName("commentEx"));
|
|
535
|
+
for (const a of i) {
|
|
536
|
+
const c = A(a, "paraId");
|
|
537
|
+
if (!c) continue;
|
|
538
|
+
const l = {
|
|
539
|
+
paraId: c,
|
|
540
|
+
paraIdParent: A(a, "paraIdParent"),
|
|
541
|
+
done: Ce(a, "done")
|
|
542
|
+
};
|
|
543
|
+
e.set(c, l);
|
|
544
|
+
}
|
|
545
|
+
console.log("[DEBUG] parseCommentsExtended: found", e.size, "extended comments");
|
|
546
|
+
} catch (t) {
|
|
547
|
+
console.warn("解析 commentsExtended.xml 失败:", t);
|
|
548
|
+
}
|
|
549
|
+
return e;
|
|
550
|
+
}
|
|
551
|
+
function Ee(o, e) {
|
|
552
|
+
const t = /* @__PURE__ */ new Map();
|
|
553
|
+
for (const r of o)
|
|
554
|
+
r.paraId && t.set(r.paraId, r);
|
|
555
|
+
for (const r of o)
|
|
556
|
+
r.replies = [];
|
|
557
|
+
for (const [r, i] of e) {
|
|
558
|
+
const a = t.get(r);
|
|
559
|
+
if (a && (a.done = i.done, i.paraIdParent)) {
|
|
560
|
+
const c = t.get(i.paraIdParent);
|
|
561
|
+
c && (a.parentId = c.id, c.replies.push(a));
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
const n = o.filter((r) => !r.parentId);
|
|
565
|
+
return n.sort((r, i) => {
|
|
566
|
+
const a = new Date(r.date).getTime(), c = new Date(i.date).getTime();
|
|
567
|
+
return a - c;
|
|
568
|
+
}), H(n), console.log(
|
|
569
|
+
"[DEBUG] buildCommentTree: root comments:",
|
|
570
|
+
n.length,
|
|
571
|
+
"total comments:",
|
|
572
|
+
o.length
|
|
573
|
+
), n;
|
|
574
|
+
}
|
|
575
|
+
function H(o) {
|
|
576
|
+
for (const e of o)
|
|
577
|
+
e.replies && e.replies.length > 0 && (e.replies.sort((t, n) => {
|
|
578
|
+
const r = new Date(t.date).getTime(), i = new Date(n.date).getTime();
|
|
579
|
+
return r - i;
|
|
580
|
+
}), H(e.replies));
|
|
581
|
+
}
|
|
582
|
+
function A(o, e) {
|
|
583
|
+
let t = o.getAttributeNS(D, e);
|
|
584
|
+
return t || (t = o.getAttribute(e), t) ? t : (t = o.getAttribute(`w15:${e}`), t || void 0);
|
|
585
|
+
}
|
|
586
|
+
function Ce(o, e) {
|
|
587
|
+
const t = A(o, e);
|
|
588
|
+
return t ? t === "1" || t === "true" : !1;
|
|
589
|
+
}
|
|
590
|
+
class we {
|
|
591
|
+
constructor() {
|
|
592
|
+
g(this, "zip", null);
|
|
593
|
+
g(this, "relationships", []);
|
|
594
|
+
g(this, "images", /* @__PURE__ */ new Map());
|
|
595
|
+
g(this, "theme");
|
|
596
|
+
g(this, "fontTable");
|
|
597
|
+
g(this, "embeddedFonts", []);
|
|
598
|
+
g(this, "bookmarks", /* @__PURE__ */ new Map());
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* 解析 DOCX 文件
|
|
602
|
+
*/
|
|
603
|
+
async parse(e) {
|
|
604
|
+
const t = e instanceof ArrayBuffer ? e : await e.arrayBuffer();
|
|
605
|
+
this.zip = await G.loadAsync(t), this.bookmarks = /* @__PURE__ */ new Map(), await this.parseRelationships(), await this.loadImages();
|
|
606
|
+
const n = await this.parseStyles(), r = new Map(n.map((k) => [k.id, k])), i = await this.parseComments(), a = new Map(i.map((k) => [k.id, k])), c = await this.parseCommentsExtended(), l = Ee(i, c), { numberings: d, abstractNumberings: h, numberingMap: p } = await this.parseNumberings();
|
|
607
|
+
this.theme = await this.parseTheme();
|
|
608
|
+
const u = await this.parseHeadersFooters("header"), f = await this.parseHeadersFooters("footer"), b = await this.parseFootnotes(), y = await this.parseEndnotes();
|
|
609
|
+
return this.fontTable = await this.parseFontTable(), this.embeddedFonts = await this.loadEmbeddedFonts(), {
|
|
610
|
+
body: await this.parseDocument(),
|
|
611
|
+
comments: i,
|
|
612
|
+
commentMap: a,
|
|
613
|
+
rootComments: l,
|
|
614
|
+
commentsExtendedMap: c,
|
|
615
|
+
styles: n,
|
|
616
|
+
styleMap: r,
|
|
617
|
+
numberings: d,
|
|
618
|
+
numberingMap: p,
|
|
619
|
+
abstractNumberings: h,
|
|
620
|
+
images: this.images,
|
|
621
|
+
relationships: this.relationships,
|
|
622
|
+
headers: u,
|
|
623
|
+
footers: f,
|
|
624
|
+
theme: this.theme,
|
|
625
|
+
footnotes: b,
|
|
626
|
+
endnotes: y,
|
|
627
|
+
fontTable: this.fontTable,
|
|
628
|
+
embeddedFonts: this.embeddedFonts,
|
|
629
|
+
bookmarks: this.bookmarks
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* 获取 ZIP 实例
|
|
634
|
+
*/
|
|
635
|
+
getZip() {
|
|
636
|
+
return this.zip;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* 解析关系文件
|
|
640
|
+
*/
|
|
641
|
+
async parseRelationships() {
|
|
642
|
+
var r, i;
|
|
643
|
+
const e = await ((i = (r = this.zip) == null ? void 0 : r.file(C.RELS)) == null ? void 0 : i.async("string"));
|
|
644
|
+
if (!e) return;
|
|
645
|
+
const n = w(e).documentElement;
|
|
646
|
+
this.relationships = s.elements(n, "Relationship").map((a) => ({
|
|
647
|
+
id: s.attr(a, "Id") || "",
|
|
648
|
+
type: s.attr(a, "Type") || "",
|
|
649
|
+
target: s.attr(a, "Target") || "",
|
|
650
|
+
targetMode: s.attr(a, "TargetMode")
|
|
651
|
+
}));
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* 加载图片资源
|
|
655
|
+
*/
|
|
656
|
+
async loadImages() {
|
|
657
|
+
var e;
|
|
658
|
+
for (const t of this.relationships)
|
|
659
|
+
if (t.type === F.IMAGE) {
|
|
660
|
+
const n = `word/${t.target}`, r = (e = this.zip) == null ? void 0 : e.file(n);
|
|
661
|
+
if (r) {
|
|
662
|
+
const i = await r.async("blob"), a = await this.blobToBase64(i);
|
|
663
|
+
this.images.set(t.id, a);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Blob 转 Base64
|
|
669
|
+
*/
|
|
670
|
+
blobToBase64(e) {
|
|
671
|
+
return new Promise((t, n) => {
|
|
672
|
+
const r = new FileReader();
|
|
673
|
+
r.onloadend = () => t(r.result), r.onerror = n, r.readAsDataURL(e);
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* 解析样式
|
|
678
|
+
*/
|
|
679
|
+
async parseStyles() {
|
|
680
|
+
var i, a;
|
|
681
|
+
const e = await ((a = (i = this.zip) == null ? void 0 : i.file(C.STYLES)) == null ? void 0 : a.async("string"));
|
|
682
|
+
if (!e) return [];
|
|
683
|
+
const t = w(e), n = [], r = t.getElementsByTagNameNS(
|
|
684
|
+
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
|
685
|
+
"style"
|
|
686
|
+
);
|
|
687
|
+
for (let c = 0; c < r.length; c++) {
|
|
688
|
+
const l = r[c], d = s.element(l, "name"), h = s.element(l, "basedOn"), p = {
|
|
689
|
+
id: s.attr(l, "styleId") || "",
|
|
690
|
+
name: d ? s.attr(d, "val") : void 0,
|
|
691
|
+
type: s.attr(l, "type") || "paragraph",
|
|
692
|
+
basedOn: h ? s.attr(h, "val") : void 0
|
|
693
|
+
}, u = s.element(l, "pPr");
|
|
694
|
+
u && (p.paragraphProps = this.parseParagraphProperties(u));
|
|
695
|
+
const f = s.element(l, "rPr");
|
|
696
|
+
f && (p.runProps = this.parseRunProperties(f)), n.push(p);
|
|
697
|
+
}
|
|
698
|
+
return n;
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* 解析主题(word/theme/theme1.xml)
|
|
702
|
+
*/
|
|
703
|
+
async parseTheme() {
|
|
704
|
+
var t, n;
|
|
705
|
+
const e = await ((n = (t = this.zip) == null ? void 0 : t.file(C.THEME)) == null ? void 0 : n.async("string"));
|
|
706
|
+
if (e)
|
|
707
|
+
try {
|
|
708
|
+
const r = w(e);
|
|
709
|
+
return j(r.documentElement);
|
|
710
|
+
} catch (r) {
|
|
711
|
+
console.warn("主题解析失败:", r);
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* 解析字体表(word/fontTable.xml)
|
|
717
|
+
*/
|
|
718
|
+
async parseFontTable() {
|
|
719
|
+
var t, n;
|
|
720
|
+
const e = await ((n = (t = this.zip) == null ? void 0 : t.file(C.FONT_TABLE)) == null ? void 0 : n.async("string"));
|
|
721
|
+
if (e)
|
|
722
|
+
try {
|
|
723
|
+
return J(e);
|
|
724
|
+
} catch (r) {
|
|
725
|
+
console.warn("字体表解析失败:", r);
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* 加载嵌入字体
|
|
731
|
+
*/
|
|
732
|
+
async loadEmbeddedFonts() {
|
|
733
|
+
var t;
|
|
734
|
+
if (!this.fontTable || !this.zip) return [];
|
|
735
|
+
if (!this.fontTable.fonts.some((n) => n.embedFontRefs.length > 0)) return [];
|
|
736
|
+
try {
|
|
737
|
+
const n = await ((t = this.zip.file(C.FONT_TABLE_RELS)) == null ? void 0 : t.async("string"));
|
|
738
|
+
if (!n)
|
|
739
|
+
return console.warn("找不到字体表关系文件"), [];
|
|
740
|
+
const r = be(n);
|
|
741
|
+
return await oe(this.zip, this.fontTable, r, {
|
|
742
|
+
injectStyles: !0
|
|
743
|
+
});
|
|
744
|
+
} catch (n) {
|
|
745
|
+
return console.warn("嵌入字体加载失败:", n), [];
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* 解析脚注(word/footnotes.xml)
|
|
750
|
+
*/
|
|
751
|
+
async parseFootnotes() {
|
|
752
|
+
var t, n;
|
|
753
|
+
const e = await ((n = (t = this.zip) == null ? void 0 : t.file(C.FOOTNOTES)) == null ? void 0 : n.async("string"));
|
|
754
|
+
if (!e) return /* @__PURE__ */ new Map();
|
|
755
|
+
try {
|
|
756
|
+
const r = w(e);
|
|
757
|
+
return this.parseNotes(r.documentElement, "footnote", m.Footnote);
|
|
758
|
+
} catch (r) {
|
|
759
|
+
return console.warn("脚注解析失败:", r), /* @__PURE__ */ new Map();
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* 解析尾注(word/endnotes.xml)
|
|
764
|
+
*/
|
|
765
|
+
async parseEndnotes() {
|
|
766
|
+
var t, n;
|
|
767
|
+
const e = await ((n = (t = this.zip) == null ? void 0 : t.file(C.ENDNOTES)) == null ? void 0 : n.async("string"));
|
|
768
|
+
if (!e) return /* @__PURE__ */ new Map();
|
|
769
|
+
try {
|
|
770
|
+
const r = w(e);
|
|
771
|
+
return this.parseNotes(r.documentElement, "endnote", m.Endnote);
|
|
772
|
+
} catch (r) {
|
|
773
|
+
return console.warn("尾注解析失败:", r), /* @__PURE__ */ new Map();
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* 解析注释(脚注/尾注通用)
|
|
778
|
+
*/
|
|
779
|
+
parseNotes(e, t, n) {
|
|
780
|
+
const r = /* @__PURE__ */ new Map(), i = e.getElementsByTagNameNS(
|
|
781
|
+
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
|
782
|
+
t
|
|
783
|
+
);
|
|
784
|
+
for (let a = 0; a < i.length; a++) {
|
|
785
|
+
const c = i[a], l = s.attr(c, "id") || "", d = s.attr(c, "type");
|
|
786
|
+
if (d === "separator" || d === "continuationSeparator")
|
|
787
|
+
continue;
|
|
788
|
+
const h = {
|
|
789
|
+
type: n,
|
|
790
|
+
id: l,
|
|
791
|
+
noteType: d,
|
|
792
|
+
children: this.parseChildren(c)
|
|
793
|
+
};
|
|
794
|
+
r.set(l, h);
|
|
795
|
+
}
|
|
796
|
+
return r;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* 解析编号(word/numbering.xml)
|
|
800
|
+
*/
|
|
801
|
+
async parseNumberings() {
|
|
802
|
+
var l, d;
|
|
803
|
+
const e = await ((d = (l = this.zip) == null ? void 0 : l.file(C.NUMBERING)) == null ? void 0 : d.async("string"));
|
|
804
|
+
if (!e)
|
|
805
|
+
return {
|
|
806
|
+
numberings: [],
|
|
807
|
+
abstractNumberings: [],
|
|
808
|
+
numberingMap: /* @__PURE__ */ new Map()
|
|
809
|
+
};
|
|
810
|
+
const n = w(e).documentElement, r = [], i = /* @__PURE__ */ new Map();
|
|
811
|
+
for (const h of s.elements(n))
|
|
812
|
+
switch (h.localName) {
|
|
813
|
+
case "abstractNum":
|
|
814
|
+
r.push(this.parseAbstractNumbering(h));
|
|
815
|
+
break;
|
|
816
|
+
case "num":
|
|
817
|
+
const p = s.attr(h, "numId") || "", u = s.element(h, "abstractNumId");
|
|
818
|
+
if (u) {
|
|
819
|
+
const f = s.attr(u, "val") || "";
|
|
820
|
+
i.set(p, f);
|
|
821
|
+
}
|
|
822
|
+
break;
|
|
823
|
+
}
|
|
824
|
+
const a = [], c = /* @__PURE__ */ new Map();
|
|
825
|
+
for (const [h, p] of i) {
|
|
826
|
+
const u = r.find((f) => f.id === p);
|
|
827
|
+
if (u) {
|
|
828
|
+
const f = {
|
|
829
|
+
id: h,
|
|
830
|
+
abstractNumId: p,
|
|
831
|
+
levels: u.levels.map((b) => ({ ...b }))
|
|
832
|
+
};
|
|
833
|
+
a.push(f), c.set(h, f);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return { numberings: a, abstractNumberings: r, numberingMap: c };
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* 解析抽象编号定义
|
|
840
|
+
*/
|
|
841
|
+
parseAbstractNumbering(e) {
|
|
842
|
+
const t = {
|
|
843
|
+
id: s.attr(e, "abstractNumId") || "",
|
|
844
|
+
levels: []
|
|
845
|
+
};
|
|
846
|
+
for (const n of s.elements(e))
|
|
847
|
+
switch (n.localName) {
|
|
848
|
+
case "name":
|
|
849
|
+
t.name = s.attr(n, "val");
|
|
850
|
+
break;
|
|
851
|
+
case "multiLevelType":
|
|
852
|
+
t.multiLevelType = s.attr(n, "val");
|
|
853
|
+
break;
|
|
854
|
+
case "numStyleLink":
|
|
855
|
+
t.numberingStyleLink = s.attr(n, "val");
|
|
856
|
+
break;
|
|
857
|
+
case "styleLink":
|
|
858
|
+
t.styleLink = s.attr(n, "val");
|
|
859
|
+
break;
|
|
860
|
+
case "lvl":
|
|
861
|
+
t.levels.push(this.parseNumberingLevel(n));
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
return t;
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* 解析编号级别
|
|
868
|
+
*/
|
|
869
|
+
parseNumberingLevel(e) {
|
|
870
|
+
const t = {
|
|
871
|
+
level: s.intAttr(e, "ilvl") ?? 0,
|
|
872
|
+
format: "decimal",
|
|
873
|
+
text: "",
|
|
874
|
+
start: 1,
|
|
875
|
+
suffix: "tab"
|
|
876
|
+
};
|
|
877
|
+
for (const n of s.elements(e))
|
|
878
|
+
switch (n.localName) {
|
|
879
|
+
case "start":
|
|
880
|
+
t.start = s.intAttr(n, "val") ?? 1;
|
|
881
|
+
break;
|
|
882
|
+
case "numFmt":
|
|
883
|
+
t.format = s.attr(n, "val") || "decimal";
|
|
884
|
+
break;
|
|
885
|
+
case "lvlText":
|
|
886
|
+
t.text = s.attr(n, "val") || "";
|
|
887
|
+
break;
|
|
888
|
+
case "suff":
|
|
889
|
+
t.suffix = s.attr(n, "val") || "tab";
|
|
890
|
+
break;
|
|
891
|
+
case "pStyle":
|
|
892
|
+
t.pStyleName = s.attr(n, "val");
|
|
893
|
+
break;
|
|
894
|
+
case "pPr":
|
|
895
|
+
t.paragraphProps = this.parseParagraphProperties(n);
|
|
896
|
+
break;
|
|
897
|
+
case "rPr":
|
|
898
|
+
t.runProps = this.parseRunProperties(n);
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
return t;
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* 解析评论
|
|
905
|
+
*/
|
|
906
|
+
async parseComments() {
|
|
907
|
+
var a, c, l;
|
|
908
|
+
const e = await ((c = (a = this.zip) == null ? void 0 : a.file(C.COMMENTS)) == null ? void 0 : c.async("string"));
|
|
909
|
+
if (!e) return [];
|
|
910
|
+
const t = w(e), n = [], r = t.getElementsByTagNameNS(
|
|
911
|
+
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
|
912
|
+
"comment"
|
|
913
|
+
), i = "http://schemas.microsoft.com/office/word/2010/wordml";
|
|
914
|
+
for (let d = 0; d < r.length; d++) {
|
|
915
|
+
const h = r[d], p = ((l = h.textContent) == null ? void 0 : l.trim()) || "";
|
|
916
|
+
let u = h.getAttributeNS(i, "paraId");
|
|
917
|
+
u || (u = h.getAttribute("w14:paraId") || null);
|
|
918
|
+
const f = {
|
|
919
|
+
type: m.Comment,
|
|
920
|
+
id: s.attr(h, "id") || "",
|
|
921
|
+
author: s.attr(h, "author") || "未知",
|
|
922
|
+
date: s.attr(h, "date") || (/* @__PURE__ */ new Date()).toISOString(),
|
|
923
|
+
initials: s.attr(h, "initials"),
|
|
924
|
+
children: this.parseChildren(h),
|
|
925
|
+
rawText: p,
|
|
926
|
+
paraId: u || void 0
|
|
927
|
+
};
|
|
928
|
+
n.push(f);
|
|
929
|
+
}
|
|
930
|
+
return console.log("[DEBUG] parseComments: found", n.length, "comments"), n;
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* 解析扩展评论(word/commentsExtended.xml)
|
|
934
|
+
* 包含评论的父子关系信息
|
|
935
|
+
*/
|
|
936
|
+
async parseCommentsExtended() {
|
|
937
|
+
var t, n;
|
|
938
|
+
const e = await ((n = (t = this.zip) == null ? void 0 : t.file(C.COMMENTS_EXTENDED)) == null ? void 0 : n.async("string"));
|
|
939
|
+
return e ? (console.log("[DEBUG] commentsExtended.xml found, length:", e.length), ye(e)) : (console.log("[DEBUG] commentsExtended.xml not found"), /* @__PURE__ */ new Map());
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* 解析文档主体
|
|
943
|
+
*/
|
|
944
|
+
async parseDocument() {
|
|
945
|
+
var d, h;
|
|
946
|
+
const e = await ((h = (d = this.zip) == null ? void 0 : d.file(C.DOCUMENT)) == null ? void 0 : h.async("string"));
|
|
947
|
+
if (!e)
|
|
948
|
+
return { type: m.Document, children: [] };
|
|
949
|
+
const t = w(e), n = t.getElementsByTagNameNS(
|
|
950
|
+
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
|
951
|
+
"body"
|
|
952
|
+
)[0];
|
|
953
|
+
if (!n)
|
|
954
|
+
return { type: m.Document, children: [] };
|
|
955
|
+
const r = s.element(n, "sectPr"), i = r ? this.parseSectionProperties(r) : void 0, a = t.getElementsByTagNameNS(
|
|
956
|
+
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
|
957
|
+
"document"
|
|
958
|
+
)[0], c = a ? s.element(a, "background") : null, l = c ? this.parseBackground(c) : void 0;
|
|
959
|
+
return {
|
|
960
|
+
type: m.Document,
|
|
961
|
+
children: this.parseChildren(n),
|
|
962
|
+
sectionProps: i,
|
|
963
|
+
background: l
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* 解析页眉页脚
|
|
968
|
+
*/
|
|
969
|
+
async parseHeadersFooters(e) {
|
|
970
|
+
var r, i;
|
|
971
|
+
const t = /* @__PURE__ */ new Map(), n = e === "header" ? F.HEADER : F.FOOTER;
|
|
972
|
+
for (const a of this.relationships)
|
|
973
|
+
if (a.type === n) {
|
|
974
|
+
const c = `word/${a.target}`, l = await ((i = (r = this.zip) == null ? void 0 : r.file(c)) == null ? void 0 : i.async("string"));
|
|
975
|
+
if (l) {
|
|
976
|
+
const h = w(l).getElementsByTagNameNS(
|
|
977
|
+
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
|
978
|
+
e === "header" ? "hdr" : "ftr"
|
|
979
|
+
)[0];
|
|
980
|
+
if (h) {
|
|
981
|
+
const p = {
|
|
982
|
+
type: e === "header" ? m.Header : m.Footer,
|
|
983
|
+
children: this.parseChildren(h)
|
|
984
|
+
};
|
|
985
|
+
t.set(a.id, p);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
return t;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* 解析背景
|
|
993
|
+
*/
|
|
994
|
+
parseBackground(e) {
|
|
995
|
+
const t = {}, n = s.attr(e, "color");
|
|
996
|
+
return n && n !== "auto" && (t["background-color"] = `#${n}`), t;
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* 解析 Section 属性
|
|
1000
|
+
*/
|
|
1001
|
+
parseSectionProperties(e) {
|
|
1002
|
+
const t = {};
|
|
1003
|
+
for (const n of s.elements(e))
|
|
1004
|
+
switch (n.localName) {
|
|
1005
|
+
case "pgSz":
|
|
1006
|
+
t.pageSize = this.parsePageSize(n);
|
|
1007
|
+
break;
|
|
1008
|
+
case "pgMar":
|
|
1009
|
+
t.pageMargins = this.parsePageMargins(n);
|
|
1010
|
+
break;
|
|
1011
|
+
case "type":
|
|
1012
|
+
t.type = s.attr(n, "val") || "nextPage";
|
|
1013
|
+
break;
|
|
1014
|
+
case "cols":
|
|
1015
|
+
t.columns = this.parseColumns(n);
|
|
1016
|
+
break;
|
|
1017
|
+
case "pgBorders":
|
|
1018
|
+
t.pageBorders = this.parseBorders(n);
|
|
1019
|
+
break;
|
|
1020
|
+
case "pgNumType":
|
|
1021
|
+
t.pageNumber = {
|
|
1022
|
+
start: s.intAttr(n, "start"),
|
|
1023
|
+
format: s.attr(n, "fmt"),
|
|
1024
|
+
chapSep: s.attr(n, "chapSep"),
|
|
1025
|
+
chapStyle: s.attr(n, "chapStyle")
|
|
1026
|
+
};
|
|
1027
|
+
break;
|
|
1028
|
+
case "headerReference":
|
|
1029
|
+
t.headerRefs || (t.headerRefs = []), t.headerRefs.push({
|
|
1030
|
+
id: s.attr(n, "id") || "",
|
|
1031
|
+
type: s.attr(n, "type") || "default"
|
|
1032
|
+
});
|
|
1033
|
+
break;
|
|
1034
|
+
case "footerReference":
|
|
1035
|
+
t.footerRefs || (t.footerRefs = []), t.footerRefs.push({
|
|
1036
|
+
id: s.attr(n, "id") || "",
|
|
1037
|
+
type: s.attr(n, "type") || "default"
|
|
1038
|
+
});
|
|
1039
|
+
break;
|
|
1040
|
+
case "titlePg":
|
|
1041
|
+
t.titlePage = s.boolAttr(n, "val") !== !1;
|
|
1042
|
+
break;
|
|
1043
|
+
}
|
|
1044
|
+
return t;
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* 解析页面尺寸
|
|
1048
|
+
*/
|
|
1049
|
+
parsePageSize(e) {
|
|
1050
|
+
return {
|
|
1051
|
+
width: s.lengthAttr(e, "w"),
|
|
1052
|
+
height: s.lengthAttr(e, "h"),
|
|
1053
|
+
orientation: s.attr(e, "orient")
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
/**
|
|
1057
|
+
* 解析页边距
|
|
1058
|
+
*/
|
|
1059
|
+
parsePageMargins(e) {
|
|
1060
|
+
return {
|
|
1061
|
+
top: s.lengthAttr(e, "top"),
|
|
1062
|
+
right: s.lengthAttr(e, "right"),
|
|
1063
|
+
bottom: s.lengthAttr(e, "bottom"),
|
|
1064
|
+
left: s.lengthAttr(e, "left"),
|
|
1065
|
+
header: s.lengthAttr(e, "header"),
|
|
1066
|
+
footer: s.lengthAttr(e, "footer"),
|
|
1067
|
+
gutter: s.lengthAttr(e, "gutter")
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* 解析分栏
|
|
1072
|
+
*/
|
|
1073
|
+
parseColumns(e) {
|
|
1074
|
+
const t = {
|
|
1075
|
+
numberOfColumns: s.intAttr(e, "num"),
|
|
1076
|
+
space: s.lengthAttr(e, "space"),
|
|
1077
|
+
separator: s.boolAttr(e, "sep"),
|
|
1078
|
+
equalWidth: s.boolAttr(e, "equalWidth") !== !1,
|
|
1079
|
+
columns: []
|
|
1080
|
+
};
|
|
1081
|
+
for (const n of s.elements(e, "col"))
|
|
1082
|
+
t.columns.push({
|
|
1083
|
+
width: s.lengthAttr(n, "w"),
|
|
1084
|
+
space: s.lengthAttr(n, "space")
|
|
1085
|
+
});
|
|
1086
|
+
return t;
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* 解析边框
|
|
1090
|
+
*/
|
|
1091
|
+
parseBorders(e) {
|
|
1092
|
+
const t = {};
|
|
1093
|
+
for (const n of s.elements(e)) {
|
|
1094
|
+
const r = this.parseBorder(n);
|
|
1095
|
+
switch (n.localName) {
|
|
1096
|
+
case "top":
|
|
1097
|
+
t.top = r;
|
|
1098
|
+
break;
|
|
1099
|
+
case "bottom":
|
|
1100
|
+
t.bottom = r;
|
|
1101
|
+
break;
|
|
1102
|
+
case "left":
|
|
1103
|
+
case "start":
|
|
1104
|
+
t.left = r;
|
|
1105
|
+
break;
|
|
1106
|
+
case "right":
|
|
1107
|
+
case "end":
|
|
1108
|
+
t.right = r;
|
|
1109
|
+
break;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return t;
|
|
1113
|
+
}
|
|
1114
|
+
/**
|
|
1115
|
+
* 解析单个边框
|
|
1116
|
+
*/
|
|
1117
|
+
parseBorder(e) {
|
|
1118
|
+
const t = s.attr(e, "color");
|
|
1119
|
+
return {
|
|
1120
|
+
style: s.attr(e, "val"),
|
|
1121
|
+
width: s.lengthAttr(e, "sz", T.Border),
|
|
1122
|
+
color: t && t !== "auto" ? `#${t}` : void 0
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* 解析子元素
|
|
1127
|
+
*/
|
|
1128
|
+
parseChildren(e, t = !1) {
|
|
1129
|
+
const n = [];
|
|
1130
|
+
for (const r of s.elements(e)) {
|
|
1131
|
+
const i = this.parseElement(r);
|
|
1132
|
+
i && n.push(i);
|
|
1133
|
+
}
|
|
1134
|
+
return t && n.length === 0 && console.log(
|
|
1135
|
+
"[DEBUG] parseChildren: no children parsed from",
|
|
1136
|
+
e.localName,
|
|
1137
|
+
"childNodes:",
|
|
1138
|
+
e.childNodes.length,
|
|
1139
|
+
"elements:",
|
|
1140
|
+
s.elements(e).map((r) => r.localName)
|
|
1141
|
+
), n;
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* 解析单个元素
|
|
1145
|
+
*/
|
|
1146
|
+
parseElement(e) {
|
|
1147
|
+
var n;
|
|
1148
|
+
const t = e.localName;
|
|
1149
|
+
switch (t) {
|
|
1150
|
+
case "p":
|
|
1151
|
+
return this.parseParagraph(e);
|
|
1152
|
+
case "r":
|
|
1153
|
+
return this.parseRun(e);
|
|
1154
|
+
case "t":
|
|
1155
|
+
return this.parseText(e);
|
|
1156
|
+
case "br":
|
|
1157
|
+
return this.parseBreak(e);
|
|
1158
|
+
case "tab":
|
|
1159
|
+
return this.parseTab();
|
|
1160
|
+
case "sym":
|
|
1161
|
+
return this.parseSymbol(e);
|
|
1162
|
+
case "lastRenderedPageBreak":
|
|
1163
|
+
return { type: m.Break, breakType: "lastRenderedPageBreak" };
|
|
1164
|
+
case "fldSimple":
|
|
1165
|
+
return this.parseSimpleField(e);
|
|
1166
|
+
case "fldChar":
|
|
1167
|
+
return this.parseComplexField(e);
|
|
1168
|
+
case "instrText":
|
|
1169
|
+
return this.parseFieldInstruction(e);
|
|
1170
|
+
case "tbl":
|
|
1171
|
+
return this.parseTable(e);
|
|
1172
|
+
case "tr":
|
|
1173
|
+
return this.parseTableRow(e);
|
|
1174
|
+
case "tc":
|
|
1175
|
+
return this.parseTableCell(e);
|
|
1176
|
+
case "hyperlink":
|
|
1177
|
+
return this.parseHyperlink(e);
|
|
1178
|
+
case "drawing":
|
|
1179
|
+
return this.parseDrawing(e);
|
|
1180
|
+
case "commentRangeStart":
|
|
1181
|
+
return this.parseCommentRangeStart(e);
|
|
1182
|
+
case "commentRangeEnd":
|
|
1183
|
+
return this.parseCommentRangeEnd(e);
|
|
1184
|
+
case "commentReference":
|
|
1185
|
+
return this.parseCommentReference(e);
|
|
1186
|
+
case "footnoteReference":
|
|
1187
|
+
return this.parseFootnoteReference(e);
|
|
1188
|
+
case "endnoteReference":
|
|
1189
|
+
return this.parseEndnoteReference(e);
|
|
1190
|
+
case "bookmarkStart":
|
|
1191
|
+
return this.parseBookmarkStart(e);
|
|
1192
|
+
case "bookmarkEnd":
|
|
1193
|
+
return this.parseBookmarkEnd(e);
|
|
1194
|
+
default:
|
|
1195
|
+
console.log("[DEBUG] parseElement default branch for:", t);
|
|
1196
|
+
const r = this.parseChildren(e);
|
|
1197
|
+
if (r.length > 0)
|
|
1198
|
+
return console.log("[DEBUG] -> found children:", r.length), r.length === 1 ? r[0] : {
|
|
1199
|
+
type: m.Run,
|
|
1200
|
+
children: r
|
|
1201
|
+
};
|
|
1202
|
+
const i = (n = e.textContent) == null ? void 0 : n.trim();
|
|
1203
|
+
return i ? (console.log("[DEBUG] -> using textContent:", i.substring(0, 50)), {
|
|
1204
|
+
type: m.Text,
|
|
1205
|
+
text: i
|
|
1206
|
+
}) : null;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* 解析段落
|
|
1211
|
+
*/
|
|
1212
|
+
parseParagraph(e) {
|
|
1213
|
+
const t = s.element(e, "pPr");
|
|
1214
|
+
return {
|
|
1215
|
+
type: m.Paragraph,
|
|
1216
|
+
props: t ? this.parseParagraphProperties(t) : void 0,
|
|
1217
|
+
children: this.parseChildren(e).filter((n) => n.type !== m.Paragraph)
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* 解析段落属性
|
|
1222
|
+
*/
|
|
1223
|
+
parseParagraphProperties(e) {
|
|
1224
|
+
const t = {}, n = s.element(e, "pStyle");
|
|
1225
|
+
n && (t.styleId = s.attr(n, "val"));
|
|
1226
|
+
const r = s.element(e, "jc");
|
|
1227
|
+
if (r) {
|
|
1228
|
+
const p = s.attr(r, "val");
|
|
1229
|
+
(p === "left" || p === "center" || p === "right" || p === "both") && (t.justification = p);
|
|
1230
|
+
}
|
|
1231
|
+
const i = s.element(e, "ind");
|
|
1232
|
+
i && (t.indentation = {
|
|
1233
|
+
left: s.lengthAttr(i, "left"),
|
|
1234
|
+
right: s.lengthAttr(i, "right"),
|
|
1235
|
+
firstLine: s.lengthAttr(i, "firstLine"),
|
|
1236
|
+
hanging: s.lengthAttr(i, "hanging")
|
|
1237
|
+
});
|
|
1238
|
+
const a = s.element(e, "spacing");
|
|
1239
|
+
a && (t.spacing = {
|
|
1240
|
+
before: s.lengthAttr(a, "before"),
|
|
1241
|
+
after: s.lengthAttr(a, "after"),
|
|
1242
|
+
// line 保存原始数值(twip),由渲染器根据 lineRule 计算
|
|
1243
|
+
line: s.intAttr(a, "line"),
|
|
1244
|
+
lineRule: s.attr(a, "lineRule")
|
|
1245
|
+
});
|
|
1246
|
+
const c = s.element(e, "pageBreakBefore");
|
|
1247
|
+
c && (t.pageBreakBefore = s.boolAttr(c, "val") !== !1);
|
|
1248
|
+
const l = s.element(e, "pBdr");
|
|
1249
|
+
l && (t.borders = this.parseBorders(l));
|
|
1250
|
+
const d = s.element(e, "sectPr");
|
|
1251
|
+
d && (t.sectionProps = this.parseSectionProperties(d));
|
|
1252
|
+
const h = s.element(e, "numPr");
|
|
1253
|
+
return h && (t.numbering = this.parseParagraphNumbering(h)), t;
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* 解析段落编号引用
|
|
1257
|
+
*/
|
|
1258
|
+
parseParagraphNumbering(e) {
|
|
1259
|
+
const t = {
|
|
1260
|
+
id: "",
|
|
1261
|
+
level: 0
|
|
1262
|
+
};
|
|
1263
|
+
for (const n of s.elements(e))
|
|
1264
|
+
switch (n.localName) {
|
|
1265
|
+
case "numId":
|
|
1266
|
+
t.id = s.attr(n, "val") || "";
|
|
1267
|
+
break;
|
|
1268
|
+
case "ilvl":
|
|
1269
|
+
t.level = s.intAttr(n, "val") ?? 0;
|
|
1270
|
+
break;
|
|
1271
|
+
}
|
|
1272
|
+
if (t.id)
|
|
1273
|
+
return t;
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* 解析 Run
|
|
1277
|
+
*/
|
|
1278
|
+
parseRun(e) {
|
|
1279
|
+
const t = s.element(e, "rPr");
|
|
1280
|
+
return {
|
|
1281
|
+
type: m.Run,
|
|
1282
|
+
props: t ? this.parseRunProperties(t) : void 0,
|
|
1283
|
+
children: this.parseChildren(e)
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
/**
|
|
1287
|
+
* 解析 Run 属性
|
|
1288
|
+
*/
|
|
1289
|
+
parseRunProperties(e) {
|
|
1290
|
+
var b, y, v, k;
|
|
1291
|
+
const t = {}, n = s.element(e, "rStyle");
|
|
1292
|
+
n && (t.styleId = s.attr(n, "val"));
|
|
1293
|
+
const r = s.element(e, "b");
|
|
1294
|
+
r && (t.bold = s.attr(r, "val") !== "0");
|
|
1295
|
+
const i = s.element(e, "i");
|
|
1296
|
+
i && (t.italic = s.attr(i, "val") !== "0");
|
|
1297
|
+
const a = s.element(e, "u");
|
|
1298
|
+
a && (t.underline = s.attr(a, "val") || "single");
|
|
1299
|
+
const c = s.element(e, "strike");
|
|
1300
|
+
c && (t.strike = s.attr(c, "val") !== "0");
|
|
1301
|
+
const l = s.element(e, "dstrike");
|
|
1302
|
+
l && (t.dstrike = s.attr(l, "val") !== "0");
|
|
1303
|
+
const d = s.element(e, "vertAlign");
|
|
1304
|
+
if (d) {
|
|
1305
|
+
const E = s.attr(d, "val");
|
|
1306
|
+
(E === "superscript" || E === "subscript") && (t.vertAlign = E);
|
|
1307
|
+
}
|
|
1308
|
+
const h = s.element(e, "color");
|
|
1309
|
+
if (h) {
|
|
1310
|
+
const E = s.attr(h, "val"), P = s.attr(h, "themeColor");
|
|
1311
|
+
if (P) {
|
|
1312
|
+
const S = s.attr(h, "themeTint"), x = s.attr(h, "themeShade");
|
|
1313
|
+
if (t.themeColor = {
|
|
1314
|
+
themeColor: P,
|
|
1315
|
+
themeTint: S ? parseInt(S, 16) : void 0,
|
|
1316
|
+
themeShade: x ? parseInt(x, 16) : void 0
|
|
1317
|
+
}, this.theme) {
|
|
1318
|
+
const M = Y(this.theme, t.themeColor);
|
|
1319
|
+
M && (t.color = M);
|
|
1320
|
+
}
|
|
1321
|
+
} else E && E !== "auto" && (t.color = `#${E}`);
|
|
1322
|
+
}
|
|
1323
|
+
const p = s.element(e, "sz");
|
|
1324
|
+
p && (t.fontSize = s.lengthAttr(p, "val", T.FontSize));
|
|
1325
|
+
const u = s.element(e, "rFonts");
|
|
1326
|
+
if (u) {
|
|
1327
|
+
const E = s.attr(u, "asciiTheme"), P = s.attr(u, "eastAsiaTheme");
|
|
1328
|
+
if (E || P) {
|
|
1329
|
+
const S = E || P || "";
|
|
1330
|
+
if (S.startsWith("major")) {
|
|
1331
|
+
if (t.themeFontFamily = "major", (y = (b = this.theme) == null ? void 0 : b.fontScheme) != null && y.majorFont) {
|
|
1332
|
+
const x = S.includes("EastAsia") ? this.theme.fontScheme.majorFont.ea : this.theme.fontScheme.majorFont.latin;
|
|
1333
|
+
x && (t.fontFamily = x);
|
|
1334
|
+
}
|
|
1335
|
+
} else if (S.startsWith("minor") && (t.themeFontFamily = "minor", (k = (v = this.theme) == null ? void 0 : v.fontScheme) != null && k.minorFont)) {
|
|
1336
|
+
const x = S.includes("EastAsia") ? this.theme.fontScheme.minorFont.ea : this.theme.fontScheme.minorFont.latin;
|
|
1337
|
+
x && (t.fontFamily = x);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
t.fontFamily || (t.fontFamily = s.attr(u, "ascii") || s.attr(u, "eastAsia") || s.attr(u, "hAnsi"));
|
|
1341
|
+
}
|
|
1342
|
+
const f = s.element(e, "highlight");
|
|
1343
|
+
return f && (t.highlight = s.attr(f, "val")), t;
|
|
1344
|
+
}
|
|
1345
|
+
/**
|
|
1346
|
+
* 解析文本
|
|
1347
|
+
*/
|
|
1348
|
+
parseText(e) {
|
|
1349
|
+
return {
|
|
1350
|
+
type: m.Text,
|
|
1351
|
+
text: e.textContent || ""
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
/**
|
|
1355
|
+
* 解析换行
|
|
1356
|
+
*/
|
|
1357
|
+
parseBreak(e) {
|
|
1358
|
+
const t = s.attr(e, "type");
|
|
1359
|
+
return {
|
|
1360
|
+
type: m.Break,
|
|
1361
|
+
breakType: t || "textWrapping"
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
/**
|
|
1365
|
+
* 解析 Tab
|
|
1366
|
+
*/
|
|
1367
|
+
parseTab() {
|
|
1368
|
+
return {
|
|
1369
|
+
type: m.Tab
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* 解析符号字符 - <w:sym w:font="Symbol" w:char="F0B7"/>
|
|
1374
|
+
* Symbol 字体中的特殊字符,如箭头、符号等
|
|
1375
|
+
*/
|
|
1376
|
+
parseSymbol(e) {
|
|
1377
|
+
const t = s.attr(e, "font"), n = s.attr(e, "char");
|
|
1378
|
+
let r;
|
|
1379
|
+
if (n) {
|
|
1380
|
+
const i = parseInt(n, 16);
|
|
1381
|
+
isNaN(i) || (r = String.fromCharCode(i));
|
|
1382
|
+
}
|
|
1383
|
+
return {
|
|
1384
|
+
type: m.Symbol,
|
|
1385
|
+
font: t,
|
|
1386
|
+
char: r
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* 解析简单域 - <w:fldSimple w:instr="PAGE">...</w:fldSimple>
|
|
1391
|
+
*/
|
|
1392
|
+
parseSimpleField(e) {
|
|
1393
|
+
return {
|
|
1394
|
+
type: m.SimpleField,
|
|
1395
|
+
instruction: s.attr(e, "instr") || "",
|
|
1396
|
+
children: this.parseChildren(e)
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* 解析复杂域字符 - <w:fldChar w:fldCharType="begin"/>
|
|
1401
|
+
*/
|
|
1402
|
+
parseComplexField(e) {
|
|
1403
|
+
return {
|
|
1404
|
+
type: m.ComplexField,
|
|
1405
|
+
charType: s.attr(e, "fldCharType") || ""
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
/**
|
|
1409
|
+
* 解析域指令 - <w:instrText>PAGE</w:instrText>
|
|
1410
|
+
*/
|
|
1411
|
+
parseFieldInstruction(e) {
|
|
1412
|
+
return {
|
|
1413
|
+
type: m.FieldInstruction,
|
|
1414
|
+
text: e.textContent || ""
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
/**
|
|
1418
|
+
* 解析表格
|
|
1419
|
+
*/
|
|
1420
|
+
parseTable(e) {
|
|
1421
|
+
const t = {
|
|
1422
|
+
type: m.Table,
|
|
1423
|
+
children: []
|
|
1424
|
+
};
|
|
1425
|
+
for (const n of s.elements(e))
|
|
1426
|
+
switch (n.localName) {
|
|
1427
|
+
case "tr":
|
|
1428
|
+
t.children.push(this.parseTableRow(n));
|
|
1429
|
+
break;
|
|
1430
|
+
case "tblGrid":
|
|
1431
|
+
t.columns = this.parseTableGrid(n);
|
|
1432
|
+
break;
|
|
1433
|
+
case "tblPr":
|
|
1434
|
+
t.props = this.parseTableProperties(n);
|
|
1435
|
+
break;
|
|
1436
|
+
}
|
|
1437
|
+
return t;
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* 解析表格列宽度
|
|
1441
|
+
*/
|
|
1442
|
+
parseTableGrid(e) {
|
|
1443
|
+
const t = [];
|
|
1444
|
+
for (const n of s.elements(e))
|
|
1445
|
+
n.localName === "gridCol" && t.push({
|
|
1446
|
+
width: s.lengthAttr(n, "w")
|
|
1447
|
+
});
|
|
1448
|
+
return t;
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* 解析表格属性
|
|
1452
|
+
*/
|
|
1453
|
+
parseTableProperties(e) {
|
|
1454
|
+
const t = {};
|
|
1455
|
+
for (const n of s.elements(e))
|
|
1456
|
+
switch (n.localName) {
|
|
1457
|
+
case "tblW":
|
|
1458
|
+
t.width = s.lengthAttr(n, "w");
|
|
1459
|
+
const r = s.attr(n, "type");
|
|
1460
|
+
(r === "auto" || r === "dxa" || r === "pct") && (t.widthType = r);
|
|
1461
|
+
break;
|
|
1462
|
+
case "jc":
|
|
1463
|
+
t.justification = s.attr(n, "val");
|
|
1464
|
+
break;
|
|
1465
|
+
case "tblBorders":
|
|
1466
|
+
t.borders = this.parseTableBorders(n);
|
|
1467
|
+
break;
|
|
1468
|
+
case "tblCellSpacing":
|
|
1469
|
+
t.cellSpacing = s.lengthAttr(n, "w");
|
|
1470
|
+
break;
|
|
1471
|
+
case "tblCellMar":
|
|
1472
|
+
t.cellMargin = {
|
|
1473
|
+
top: s.lengthAttr(s.element(n, "top"), "w"),
|
|
1474
|
+
bottom: s.lengthAttr(s.element(n, "bottom"), "w"),
|
|
1475
|
+
left: s.lengthAttr(s.element(n, "left"), "w") || s.lengthAttr(s.element(n, "start"), "w"),
|
|
1476
|
+
right: s.lengthAttr(s.element(n, "right"), "w") || s.lengthAttr(s.element(n, "end"), "w")
|
|
1477
|
+
};
|
|
1478
|
+
break;
|
|
1479
|
+
}
|
|
1480
|
+
return t;
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* 解析表格边框(包含内部边框 insideH/insideV)
|
|
1484
|
+
*/
|
|
1485
|
+
parseTableBorders(e) {
|
|
1486
|
+
const t = {};
|
|
1487
|
+
for (const n of s.elements(e)) {
|
|
1488
|
+
const r = this.parseBorder(n);
|
|
1489
|
+
switch (n.localName) {
|
|
1490
|
+
case "top":
|
|
1491
|
+
t.top = r;
|
|
1492
|
+
break;
|
|
1493
|
+
case "bottom":
|
|
1494
|
+
t.bottom = r;
|
|
1495
|
+
break;
|
|
1496
|
+
case "left":
|
|
1497
|
+
case "start":
|
|
1498
|
+
t.left = r;
|
|
1499
|
+
break;
|
|
1500
|
+
case "right":
|
|
1501
|
+
case "end":
|
|
1502
|
+
t.right = r;
|
|
1503
|
+
break;
|
|
1504
|
+
case "insideH":
|
|
1505
|
+
t.insideH = r;
|
|
1506
|
+
break;
|
|
1507
|
+
case "insideV":
|
|
1508
|
+
t.insideV = r;
|
|
1509
|
+
break;
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
return t;
|
|
1513
|
+
}
|
|
1514
|
+
/**
|
|
1515
|
+
* 解析表格行
|
|
1516
|
+
*/
|
|
1517
|
+
parseTableRow(e) {
|
|
1518
|
+
return {
|
|
1519
|
+
type: m.TableRow,
|
|
1520
|
+
children: s.elements(e).filter((t) => t.localName === "tc").map((t) => this.parseTableCell(t))
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* 解析表格单元格
|
|
1525
|
+
*/
|
|
1526
|
+
parseTableCell(e) {
|
|
1527
|
+
const t = {
|
|
1528
|
+
type: m.TableCell,
|
|
1529
|
+
children: []
|
|
1530
|
+
};
|
|
1531
|
+
for (const n of s.elements(e))
|
|
1532
|
+
if (n.localName === "tcPr")
|
|
1533
|
+
t.props = this.parseTableCellProperties(n);
|
|
1534
|
+
else {
|
|
1535
|
+
const r = this.parseElement(n);
|
|
1536
|
+
r && t.children.push(r);
|
|
1537
|
+
}
|
|
1538
|
+
return t;
|
|
1539
|
+
}
|
|
1540
|
+
/**
|
|
1541
|
+
* 解析表格单元格属性
|
|
1542
|
+
*/
|
|
1543
|
+
parseTableCellProperties(e) {
|
|
1544
|
+
const t = {};
|
|
1545
|
+
for (const n of s.elements(e))
|
|
1546
|
+
switch (n.localName) {
|
|
1547
|
+
case "tcW":
|
|
1548
|
+
t.width = s.lengthAttr(n, "w");
|
|
1549
|
+
break;
|
|
1550
|
+
case "gridSpan":
|
|
1551
|
+
t.gridSpan = s.intAttr(n, "val");
|
|
1552
|
+
break;
|
|
1553
|
+
case "vMerge":
|
|
1554
|
+
const r = s.attr(n, "val");
|
|
1555
|
+
t.verticalMerge = r === "restart" ? "restart" : "continue";
|
|
1556
|
+
break;
|
|
1557
|
+
case "vAlign":
|
|
1558
|
+
t.verticalAlign = s.attr(n, "val");
|
|
1559
|
+
break;
|
|
1560
|
+
case "shd":
|
|
1561
|
+
const i = s.attr(n, "fill");
|
|
1562
|
+
i && i !== "auto" && (t.shading = `#${i}`);
|
|
1563
|
+
break;
|
|
1564
|
+
case "tcBorders":
|
|
1565
|
+
t.borders = this.parseBorders(n);
|
|
1566
|
+
break;
|
|
1567
|
+
}
|
|
1568
|
+
return t;
|
|
1569
|
+
}
|
|
1570
|
+
/**
|
|
1571
|
+
* 解析超链接
|
|
1572
|
+
*/
|
|
1573
|
+
parseHyperlink(e) {
|
|
1574
|
+
const t = s.attr(e, "id");
|
|
1575
|
+
let n;
|
|
1576
|
+
if (t) {
|
|
1577
|
+
const r = this.relationships.find((i) => i.id === t);
|
|
1578
|
+
r && (n = r.target);
|
|
1579
|
+
}
|
|
1580
|
+
return {
|
|
1581
|
+
type: m.Hyperlink,
|
|
1582
|
+
href: n,
|
|
1583
|
+
anchor: s.attr(e, "anchor"),
|
|
1584
|
+
children: this.parseChildren(e)
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* 解析绘图(图片等)
|
|
1589
|
+
*/
|
|
1590
|
+
parseDrawing(e) {
|
|
1591
|
+
const t = [], n = e.getElementsByTagNameNS(
|
|
1592
|
+
"http://schemas.openxmlformats.org/drawingml/2006/main",
|
|
1593
|
+
"blip"
|
|
1594
|
+
);
|
|
1595
|
+
for (let r = 0; r < n.length; r++) {
|
|
1596
|
+
const a = n[r].getAttributeNS(
|
|
1597
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
1598
|
+
"embed"
|
|
1599
|
+
);
|
|
1600
|
+
if (a && this.images.has(a)) {
|
|
1601
|
+
const c = e.getElementsByTagNameNS(
|
|
1602
|
+
"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
|
|
1603
|
+
"extent"
|
|
1604
|
+
)[0];
|
|
1605
|
+
let l, d;
|
|
1606
|
+
if (c) {
|
|
1607
|
+
const h = c.getAttribute("cx"), p = c.getAttribute("cy");
|
|
1608
|
+
h && (l = s.convertLength(h, T.Emu)), p && (d = s.convertLength(p, T.Emu));
|
|
1609
|
+
}
|
|
1610
|
+
t.push({
|
|
1611
|
+
type: m.Image,
|
|
1612
|
+
src: this.images.get(a),
|
|
1613
|
+
width: l,
|
|
1614
|
+
height: d
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
return {
|
|
1619
|
+
type: m.Drawing,
|
|
1620
|
+
children: t
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* 解析评论范围开始
|
|
1625
|
+
*/
|
|
1626
|
+
parseCommentRangeStart(e) {
|
|
1627
|
+
return {
|
|
1628
|
+
type: m.CommentRangeStart,
|
|
1629
|
+
id: s.attr(e, "id") || ""
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* 解析评论范围结束
|
|
1634
|
+
*/
|
|
1635
|
+
parseCommentRangeEnd(e) {
|
|
1636
|
+
return {
|
|
1637
|
+
type: m.CommentRangeEnd,
|
|
1638
|
+
id: s.attr(e, "id") || ""
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* 解析评论引用
|
|
1643
|
+
*/
|
|
1644
|
+
parseCommentReference(e) {
|
|
1645
|
+
return {
|
|
1646
|
+
type: m.CommentReference,
|
|
1647
|
+
id: s.attr(e, "id") || ""
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1650
|
+
/**
|
|
1651
|
+
* 解析脚注引用
|
|
1652
|
+
*/
|
|
1653
|
+
parseFootnoteReference(e) {
|
|
1654
|
+
return {
|
|
1655
|
+
type: m.FootnoteReference,
|
|
1656
|
+
id: s.attr(e, "id") || ""
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
/**
|
|
1660
|
+
* 解析尾注引用
|
|
1661
|
+
*/
|
|
1662
|
+
parseEndnoteReference(e) {
|
|
1663
|
+
return {
|
|
1664
|
+
type: m.EndnoteReference,
|
|
1665
|
+
id: s.attr(e, "id") || ""
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* 解析书签开始
|
|
1670
|
+
* <w:bookmarkStart w:id="0" w:name="bookmark1"/>
|
|
1671
|
+
*/
|
|
1672
|
+
parseBookmarkStart(e) {
|
|
1673
|
+
const t = {
|
|
1674
|
+
type: m.BookmarkStart,
|
|
1675
|
+
id: s.attr(e, "id") || "",
|
|
1676
|
+
name: s.attr(e, "name") || "",
|
|
1677
|
+
colFirst: s.intAttr(e, "colFirst"),
|
|
1678
|
+
colLast: s.intAttr(e, "colLast")
|
|
1679
|
+
};
|
|
1680
|
+
return t.name && !t.name.startsWith("_") && this.bookmarks.set(t.name, t), t;
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* 解析书签结束
|
|
1684
|
+
* <w:bookmarkEnd w:id="0"/>
|
|
1685
|
+
*/
|
|
1686
|
+
parseBookmarkEnd(e) {
|
|
1687
|
+
return {
|
|
1688
|
+
type: m.BookmarkEnd,
|
|
1689
|
+
id: s.attr(e, "id") || ""
|
|
1690
|
+
};
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
class ke {
|
|
1694
|
+
// 尾注编号计数器
|
|
1695
|
+
constructor(e) {
|
|
1696
|
+
g(this, "document", null);
|
|
1697
|
+
g(this, "container");
|
|
1698
|
+
g(this, "options");
|
|
1699
|
+
g(this, "classPrefix");
|
|
1700
|
+
// 评论相关状态
|
|
1701
|
+
g(this, "commentRanges", /* @__PURE__ */ new Map());
|
|
1702
|
+
g(this, "activeCommentId", null);
|
|
1703
|
+
g(this, "svgLayer", null);
|
|
1704
|
+
g(this, "currentCommentIds", /* @__PURE__ */ new Set());
|
|
1705
|
+
// 当前正在渲染的评论范围
|
|
1706
|
+
g(this, "commentStartInParagraph", /* @__PURE__ */ new Set());
|
|
1707
|
+
// 在当前段落开始的评论
|
|
1708
|
+
// 页码相关状态
|
|
1709
|
+
g(this, "currentPageNumber", 1);
|
|
1710
|
+
g(this, "totalPages", 1);
|
|
1711
|
+
g(this, "inComplexField", !1);
|
|
1712
|
+
// 是否在复杂域中
|
|
1713
|
+
g(this, "currentFieldInstruction", "");
|
|
1714
|
+
// 当前域指令
|
|
1715
|
+
g(this, "skipFieldContent", !1);
|
|
1716
|
+
// 是否跳过域的静态内容(separate 后)
|
|
1717
|
+
// 编号/列表相关状态
|
|
1718
|
+
// 编号计数器:key 格式为 "numId-level",value 为当前计数
|
|
1719
|
+
g(this, "numberingCounters", /* @__PURE__ */ new Map());
|
|
1720
|
+
// 脚注/尾注相关状态
|
|
1721
|
+
g(this, "currentFootnoteIds", []);
|
|
1722
|
+
// 当前页面引用的脚注 ID
|
|
1723
|
+
g(this, "currentEndnoteIds", []);
|
|
1724
|
+
// 文档中引用的尾注 ID
|
|
1725
|
+
g(this, "footnoteCounter", 0);
|
|
1726
|
+
// 脚注编号计数器
|
|
1727
|
+
g(this, "endnoteCounter", 0);
|
|
1728
|
+
// 表格垂直合并状态
|
|
1729
|
+
g(this, "tableVerticalMerges", []);
|
|
1730
|
+
g(this, "currentVerticalMerge", /* @__PURE__ */ new Map());
|
|
1731
|
+
g(this, "currentCellCol", 0);
|
|
1732
|
+
// 表格边框状态(用于 insideH/insideV 内部边框)
|
|
1733
|
+
g(this, "currentTableBorders");
|
|
1734
|
+
g(this, "tableBordersStack", []);
|
|
1735
|
+
g(this, "currentTableRowIndex", 0);
|
|
1736
|
+
g(this, "currentTableRowCount", 0);
|
|
1737
|
+
g(this, "currentTableColCount", 0);
|
|
1738
|
+
const t = typeof e.container == "string" ? document.querySelector(e.container) : e.container;
|
|
1739
|
+
if (!t)
|
|
1740
|
+
throw new Error("容器元素不存在");
|
|
1741
|
+
this.container = t, this.classPrefix = e.classNamePrefix || "docx", this.options = {
|
|
1742
|
+
container: this.container,
|
|
1743
|
+
renderComments: e.renderComments ?? !0,
|
|
1744
|
+
enableCommentEdit: e.enableCommentEdit ?? !0,
|
|
1745
|
+
showCommentLines: e.showCommentLines ?? !0,
|
|
1746
|
+
breakPages: e.breakPages ?? !0,
|
|
1747
|
+
classNamePrefix: this.classPrefix,
|
|
1748
|
+
onCommentClick: e.onCommentClick || (() => {
|
|
1749
|
+
}),
|
|
1750
|
+
onCommentChange: e.onCommentChange || (() => {
|
|
1751
|
+
})
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* 渲染文档
|
|
1756
|
+
*/
|
|
1757
|
+
render(e) {
|
|
1758
|
+
this.document = e, this.commentRanges.clear(), this.currentCommentIds.clear(), this.numberingCounters.clear(), this.currentFootnoteIds = [], this.currentEndnoteIds = [], this.footnoteCounter = 0, this.endnoteCounter = 0;
|
|
1759
|
+
for (const i of e.comments)
|
|
1760
|
+
this.commentRanges.set(i.id, {
|
|
1761
|
+
id: i.id,
|
|
1762
|
+
startElement: null,
|
|
1763
|
+
endElement: null,
|
|
1764
|
+
highlightElements: [],
|
|
1765
|
+
panelElement: null
|
|
1766
|
+
});
|
|
1767
|
+
this.container.innerHTML = "", this.container.className = `${this.classPrefix}-container`;
|
|
1768
|
+
const t = this.createElement("div", `${this.classPrefix}-wrapper`);
|
|
1769
|
+
this.options.breakPages ? this.renderWithPages(t, e) : this.renderSinglePage(t, e), this.container.appendChild(t), this.options.showCommentLines && (this.svgLayer = this.createSvgLayer(), this.container.appendChild(this.svgLayer)), this.options.renderComments && this.renderAllCommentBubbles();
|
|
1770
|
+
let n = !1;
|
|
1771
|
+
const r = () => {
|
|
1772
|
+
n || (requestAnimationFrame(() => {
|
|
1773
|
+
this.positionCommentBubbles(), this.updateLines(), n = !1;
|
|
1774
|
+
}), n = !0);
|
|
1775
|
+
};
|
|
1776
|
+
t.addEventListener("scroll", () => {
|
|
1777
|
+
this.positionCommentBubbles(), this.updateLines();
|
|
1778
|
+
}, { passive: !0 }), window.addEventListener("resize", r), requestAnimationFrame(() => {
|
|
1779
|
+
this.positionCommentBubbles(), this.updateLines();
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
/**
|
|
1783
|
+
* 单页渲染模式
|
|
1784
|
+
*/
|
|
1785
|
+
renderSinglePage(e, t) {
|
|
1786
|
+
const n = this.createElement("div", `${this.classPrefix}-document`), r = this.createElement("div", `${this.classPrefix}-page`), i = this.renderElement(t.body);
|
|
1787
|
+
i && r.appendChild(i), this.renderPageFootnotes(this.currentFootnoteIds, r), n.appendChild(r), e.appendChild(n), this.renderDocumentEndnotes(e);
|
|
1788
|
+
}
|
|
1789
|
+
/**
|
|
1790
|
+
* 分页渲染模式
|
|
1791
|
+
*/
|
|
1792
|
+
renderWithPages(e, t) {
|
|
1793
|
+
const n = t.body, r = n.sectionProps, i = this.splitBySection(n.children || [], r), a = this.groupByPageBreaks(i);
|
|
1794
|
+
this.totalPages = a.length;
|
|
1795
|
+
let c;
|
|
1796
|
+
for (let l = 0; l < a.length; l++) {
|
|
1797
|
+
this.currentPageNumber = l + 1;
|
|
1798
|
+
const d = this.currentFootnoteIds.length, h = a[l];
|
|
1799
|
+
if (h.length === 0) continue;
|
|
1800
|
+
let u = h[0].sectProps || r;
|
|
1801
|
+
const f = this.createPageElement(u);
|
|
1802
|
+
u != null && u.headerRefs && this.renderHeaderFooter(
|
|
1803
|
+
u.headerRefs,
|
|
1804
|
+
u,
|
|
1805
|
+
l,
|
|
1806
|
+
c !== u,
|
|
1807
|
+
f,
|
|
1808
|
+
"header"
|
|
1809
|
+
);
|
|
1810
|
+
for (const y of h) {
|
|
1811
|
+
const v = this.createSectionContent(y.sectProps);
|
|
1812
|
+
for (const k of y.elements) {
|
|
1813
|
+
const E = this.renderElement(k);
|
|
1814
|
+
E && v.appendChild(E);
|
|
1815
|
+
}
|
|
1816
|
+
f.appendChild(v), u = y.sectProps || u;
|
|
1817
|
+
}
|
|
1818
|
+
const b = this.currentFootnoteIds.slice(d);
|
|
1819
|
+
this.renderPageFootnotes(b, f), u != null && u.footerRefs && this.renderHeaderFooter(
|
|
1820
|
+
u.footerRefs,
|
|
1821
|
+
u,
|
|
1822
|
+
l,
|
|
1823
|
+
c !== u,
|
|
1824
|
+
f,
|
|
1825
|
+
"footer"
|
|
1826
|
+
), e.appendChild(f), c = u;
|
|
1827
|
+
}
|
|
1828
|
+
this.renderDocumentEndnotes(e);
|
|
1829
|
+
}
|
|
1830
|
+
/**
|
|
1831
|
+
* 按 Section 分割内容
|
|
1832
|
+
*/
|
|
1833
|
+
splitBySection(e, t) {
|
|
1834
|
+
var a, c;
|
|
1835
|
+
const n = [];
|
|
1836
|
+
let r = { sectProps: null, elements: [], pageBreak: !1 };
|
|
1837
|
+
n.push(r);
|
|
1838
|
+
for (const l of e)
|
|
1839
|
+
if (l.type === m.Paragraph && (a = l.props) != null && a.pageBreakBefore && (r.pageBreak = !0, r = { sectProps: null, elements: [], pageBreak: !1 }, n.push(r)), r.elements.push(l), l.type === m.Paragraph) {
|
|
1840
|
+
const d = l, h = (c = d.props) == null ? void 0 : c.sectionProps;
|
|
1841
|
+
let p = !1;
|
|
1842
|
+
const u = (f) => {
|
|
1843
|
+
for (const b of f) {
|
|
1844
|
+
if (b.type === m.Break) {
|
|
1845
|
+
const y = b;
|
|
1846
|
+
if (y.breakType === "page" || y.breakType === "lastRenderedPageBreak") {
|
|
1847
|
+
p = !0;
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
b.type === m.Run && b.children && u(b.children);
|
|
1852
|
+
}
|
|
1853
|
+
};
|
|
1854
|
+
this.options.breakPages && d.children && u(d.children), (h || p) && (r.sectProps = h || null, r.pageBreak = p, r = { sectProps: null, elements: [], pageBreak: !1 }, n.push(r));
|
|
1855
|
+
}
|
|
1856
|
+
let i = null;
|
|
1857
|
+
for (let l = n.length - 1; l >= 0; l--)
|
|
1858
|
+
n[l].sectProps === null ? n[l].sectProps = i || t || null : i = n[l].sectProps;
|
|
1859
|
+
return n;
|
|
1860
|
+
}
|
|
1861
|
+
/**
|
|
1862
|
+
* 按分页符分组
|
|
1863
|
+
*/
|
|
1864
|
+
groupByPageBreaks(e) {
|
|
1865
|
+
const t = [];
|
|
1866
|
+
let n = [];
|
|
1867
|
+
t.push(n);
|
|
1868
|
+
let r = null;
|
|
1869
|
+
for (const i of e)
|
|
1870
|
+
n.push(i), (i.pageBreak || this.isPageBreakSection(r, i.sectProps)) && (n = [], t.push(n)), r = i.sectProps;
|
|
1871
|
+
return t.filter((i) => i.length > 0);
|
|
1872
|
+
}
|
|
1873
|
+
/**
|
|
1874
|
+
* 检查是否因为 Section 属性变化需要分页
|
|
1875
|
+
*/
|
|
1876
|
+
isPageBreakSection(e, t) {
|
|
1877
|
+
if (!e || !t) return !1;
|
|
1878
|
+
const n = e.pageSize, r = t.pageSize;
|
|
1879
|
+
return !n || !r ? !1 : n.orientation !== r.orientation || n.width !== r.width || n.height !== r.height;
|
|
1880
|
+
}
|
|
1881
|
+
/**
|
|
1882
|
+
* 创建页面元素
|
|
1883
|
+
*/
|
|
1884
|
+
createPageElement(e) {
|
|
1885
|
+
const t = this.createElement("section", `${this.classPrefix}-page`);
|
|
1886
|
+
if (e && (e.pageSize && (e.pageSize.width && (t.style.width = e.pageSize.width), e.pageSize.height && (t.style.minHeight = e.pageSize.height)), e.pageMargins)) {
|
|
1887
|
+
const n = e.pageMargins;
|
|
1888
|
+
n.top && (t.style.paddingTop = n.top), n.right && (t.style.paddingRight = n.right), n.bottom && (t.style.paddingBottom = n.bottom), n.left && (t.style.paddingLeft = n.left);
|
|
1889
|
+
}
|
|
1890
|
+
return t;
|
|
1891
|
+
}
|
|
1892
|
+
/**
|
|
1893
|
+
* 创建 Section 内容区域
|
|
1894
|
+
*/
|
|
1895
|
+
createSectionContent(e) {
|
|
1896
|
+
const t = this.createElement("article", `${this.classPrefix}-section-content`);
|
|
1897
|
+
if (e != null && e.columns) {
|
|
1898
|
+
const n = e.columns;
|
|
1899
|
+
n.numberOfColumns && n.numberOfColumns > 1 && (t.style.columnCount = String(n.numberOfColumns), n.space && (t.style.columnGap = n.space), n.separator && (t.style.columnRule = "1px solid #ccc"));
|
|
1900
|
+
}
|
|
1901
|
+
return t;
|
|
1902
|
+
}
|
|
1903
|
+
/**
|
|
1904
|
+
* 渲染页眉或页脚
|
|
1905
|
+
*/
|
|
1906
|
+
renderHeaderFooter(e, t, n, r, i, a) {
|
|
1907
|
+
var p, u;
|
|
1908
|
+
if (!e || e.length === 0) return;
|
|
1909
|
+
let c = null;
|
|
1910
|
+
if (t.titlePage && r && (c = e.find((f) => f.type === "first")), c || n % 2 === 1 && (c = e.find((f) => f.type === "even")), c || (c = e.find((f) => f.type === "default")), !c) return;
|
|
1911
|
+
const l = a === "header" ? (p = this.document) == null ? void 0 : p.headers : (u = this.document) == null ? void 0 : u.footers, d = l == null ? void 0 : l.get(c.id);
|
|
1912
|
+
if (!d) return;
|
|
1913
|
+
const h = this.createElement("div", `${this.classPrefix}-${a}`);
|
|
1914
|
+
for (const f of d.children || []) {
|
|
1915
|
+
const b = this.renderElement(f);
|
|
1916
|
+
b && h.appendChild(b);
|
|
1917
|
+
}
|
|
1918
|
+
if (t.pageMargins) {
|
|
1919
|
+
const f = t.pageMargins;
|
|
1920
|
+
a === "header" && f.header && f.top ? (h.style.marginTop = `calc(${f.header} - ${f.top})`, h.style.minHeight = `calc(${f.top} - ${f.header})`) : a === "footer" && f.footer && f.bottom && (h.style.marginBottom = `calc(${f.footer} - ${f.bottom})`, h.style.minHeight = `calc(${f.bottom} - ${f.footer})`);
|
|
1921
|
+
}
|
|
1922
|
+
a === "header" ? i.insertBefore(h, i.firstChild) : i.appendChild(h);
|
|
1923
|
+
}
|
|
1924
|
+
/**
|
|
1925
|
+
* 渲染所有评论气泡(右侧固定面板)
|
|
1926
|
+
*/
|
|
1927
|
+
renderAllCommentBubbles() {
|
|
1928
|
+
var n;
|
|
1929
|
+
const e = this.createElement("div", `${this.classPrefix}-comments-layer`);
|
|
1930
|
+
this.container.appendChild(e);
|
|
1931
|
+
const t = ((n = this.document) == null ? void 0 : n.comments) || [];
|
|
1932
|
+
console.log("[DEBUG] renderAllCommentBubbles - Total comments:", t.length), t.forEach((r) => {
|
|
1933
|
+
var i;
|
|
1934
|
+
console.log("[DEBUG] Comment:", {
|
|
1935
|
+
id: r.id,
|
|
1936
|
+
author: r.author,
|
|
1937
|
+
date: r.date,
|
|
1938
|
+
childrenCount: ((i = r.children) == null ? void 0 : i.length) || 0,
|
|
1939
|
+
text: this.getCommentText(r)
|
|
1940
|
+
});
|
|
1941
|
+
}), console.log("[DEBUG] Comment ranges count:", this.commentRanges.size);
|
|
1942
|
+
for (const r of t) {
|
|
1943
|
+
const i = this.commentRanges.get(r.id);
|
|
1944
|
+
if (i && i.highlightElements.length > 0) {
|
|
1945
|
+
const a = this.createCommentBubble(r);
|
|
1946
|
+
i.panelElement = a, e.appendChild(a);
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
/**
|
|
1951
|
+
* 定位评论气泡到对应的高亮文字旁边
|
|
1952
|
+
* 原文不可见时隐藏评论
|
|
1953
|
+
*/
|
|
1954
|
+
positionCommentBubbles() {
|
|
1955
|
+
const e = [], n = window.innerHeight - 40;
|
|
1956
|
+
for (const [, i] of this.commentRanges) {
|
|
1957
|
+
if (!i.panelElement || i.highlightElements.length === 0) continue;
|
|
1958
|
+
const c = i.highlightElements[0].getBoundingClientRect(), l = c.top + c.height / 2;
|
|
1959
|
+
l > 60 && l < n ? (e.push({ range: i, top: c.top }), i.panelElement.style.display = "block") : i.panelElement.style.display = "none";
|
|
1960
|
+
}
|
|
1961
|
+
e.sort((i, a) => i.top - a.top);
|
|
1962
|
+
let r = 60;
|
|
1963
|
+
for (const { range: i, top: a } of e) {
|
|
1964
|
+
let c = Math.max(a, r + 8);
|
|
1965
|
+
c = Math.min(c, n - 100), i.panelElement.style.top = `${c}px`, r = c + i.panelElement.offsetHeight;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
/**
|
|
1969
|
+
* 创建 SVG 连线层
|
|
1970
|
+
*/
|
|
1971
|
+
createSvgLayer() {
|
|
1972
|
+
const e = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
1973
|
+
return e.classList.add(`${this.classPrefix}-lines`), e;
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* 更新所有连线
|
|
1977
|
+
*/
|
|
1978
|
+
updateLines() {
|
|
1979
|
+
if (this.svgLayer) {
|
|
1980
|
+
this.svgLayer.innerHTML = "";
|
|
1981
|
+
for (const [e] of this.commentRanges) {
|
|
1982
|
+
const t = e === this.activeCommentId;
|
|
1983
|
+
this.drawCommentLine(e, t);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
/**
|
|
1988
|
+
* 绘制单个评论的连线
|
|
1989
|
+
*/
|
|
1990
|
+
drawCommentLine(e, t) {
|
|
1991
|
+
const n = this.commentRanges.get(e);
|
|
1992
|
+
if (!n || !n.highlightElements.length || !n.panelElement || !this.svgLayer || n.panelElement.style.display === "none") return;
|
|
1993
|
+
const r = n.highlightElements[0].getBoundingClientRect(), i = n.panelElement.getBoundingClientRect(), a = r.right, c = r.top + r.height / 2, l = i.left, d = i.top + 16, h = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
1994
|
+
h.setAttribute("x1", String(a)), h.setAttribute("y1", String(c)), h.setAttribute("x2", String(l)), h.setAttribute("y2", String(d)), h.setAttribute("stroke", "#ef4444"), h.setAttribute("stroke-width", t ? "2" : "1"), this.svgLayer.appendChild(h);
|
|
1995
|
+
}
|
|
1996
|
+
/**
|
|
1997
|
+
* 渲染元素
|
|
1998
|
+
*/
|
|
1999
|
+
renderElement(e) {
|
|
2000
|
+
switch (e.type) {
|
|
2001
|
+
case m.Document:
|
|
2002
|
+
return this.renderDocument(e);
|
|
2003
|
+
case m.Paragraph:
|
|
2004
|
+
return this.renderParagraph(e);
|
|
2005
|
+
case m.Run:
|
|
2006
|
+
return this.renderRun(e);
|
|
2007
|
+
case m.Text:
|
|
2008
|
+
return this.renderText(e);
|
|
2009
|
+
case m.Break:
|
|
2010
|
+
return this.renderBreak(e);
|
|
2011
|
+
case m.Tab:
|
|
2012
|
+
return this.renderTab();
|
|
2013
|
+
case m.Symbol:
|
|
2014
|
+
return this.renderSymbol(e);
|
|
2015
|
+
case m.SimpleField:
|
|
2016
|
+
return this.renderSimpleField(e);
|
|
2017
|
+
case m.ComplexField:
|
|
2018
|
+
return this.renderComplexField(e);
|
|
2019
|
+
case m.FieldInstruction:
|
|
2020
|
+
return this.renderFieldInstruction(e);
|
|
2021
|
+
case m.Table:
|
|
2022
|
+
return this.renderTable(e);
|
|
2023
|
+
case m.TableRow:
|
|
2024
|
+
return this.renderTableRow(e);
|
|
2025
|
+
case m.TableCell:
|
|
2026
|
+
return this.renderTableCell(e);
|
|
2027
|
+
case m.Hyperlink:
|
|
2028
|
+
return this.renderHyperlink(e);
|
|
2029
|
+
case m.Drawing:
|
|
2030
|
+
return this.renderDrawing(e);
|
|
2031
|
+
case m.Image:
|
|
2032
|
+
return this.renderImage(e);
|
|
2033
|
+
case m.CommentRangeStart:
|
|
2034
|
+
return this.renderCommentRangeStart(e);
|
|
2035
|
+
case m.CommentRangeEnd:
|
|
2036
|
+
return this.renderCommentRangeEnd(e);
|
|
2037
|
+
case m.CommentReference:
|
|
2038
|
+
return this.renderCommentReference(e);
|
|
2039
|
+
case m.FootnoteReference:
|
|
2040
|
+
return this.renderFootnoteReference(e);
|
|
2041
|
+
case m.EndnoteReference:
|
|
2042
|
+
return this.renderEndnoteReference(e);
|
|
2043
|
+
case m.Footnote:
|
|
2044
|
+
return this.renderFootnote(e);
|
|
2045
|
+
case m.Endnote:
|
|
2046
|
+
return this.renderEndnote(e);
|
|
2047
|
+
case m.BookmarkStart:
|
|
2048
|
+
return this.renderBookmarkStart(e);
|
|
2049
|
+
case m.BookmarkEnd:
|
|
2050
|
+
return this.renderBookmarkEnd(e);
|
|
2051
|
+
default:
|
|
2052
|
+
return null;
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
/**
|
|
2056
|
+
* 渲染文档
|
|
2057
|
+
*/
|
|
2058
|
+
renderDocument(e) {
|
|
2059
|
+
const t = this.createElement("article", `${this.classPrefix}-body`);
|
|
2060
|
+
return this.renderChildren(e.children || [], t), t;
|
|
2061
|
+
}
|
|
2062
|
+
/**
|
|
2063
|
+
* 渲染段落
|
|
2064
|
+
*/
|
|
2065
|
+
renderParagraph(e) {
|
|
2066
|
+
const t = this.createElement("p", `${this.classPrefix}-p`);
|
|
2067
|
+
this.commentStartInParagraph.clear(), e.props && this.applyParagraphStyles(t, e.props);
|
|
2068
|
+
const n = this.renderNumbering(e.props);
|
|
2069
|
+
return n && (t.insertBefore(n, t.firstChild), t.classList.add(`${this.classPrefix}-list-item`)), this.renderChildren(e.children || [], t), (t.childNodes.length === 0 || t.childNodes.length === 1 && n) && t.appendChild(document.createElement("br")), this.commentStartInParagraph.size > 0 && this.options.renderComments && (t.dataset.commentIds = Array.from(this.commentStartInParagraph).join(",")), t;
|
|
2070
|
+
}
|
|
2071
|
+
/**
|
|
2072
|
+
* 渲染编号
|
|
2073
|
+
*/
|
|
2074
|
+
renderNumbering(e) {
|
|
2075
|
+
var h, p;
|
|
2076
|
+
if (!(e != null && e.numbering) || !((h = this.document) != null && h.numberingMap))
|
|
2077
|
+
return null;
|
|
2078
|
+
const { id: t, level: n } = e.numbering, r = this.document.numberingMap.get(t);
|
|
2079
|
+
if (!r)
|
|
2080
|
+
return null;
|
|
2081
|
+
const i = r.levels.find((u) => u.level === n);
|
|
2082
|
+
if (!i)
|
|
2083
|
+
return null;
|
|
2084
|
+
const a = this.getNumberingContent(r, i, t, n), c = this.createElement("span", `${this.classPrefix}-numbering`);
|
|
2085
|
+
c.textContent = a, i.runProps && this.applyRunStyles(c, i.runProps);
|
|
2086
|
+
const l = this.createElement("span", `${this.classPrefix}-numbering-suffix`);
|
|
2087
|
+
switch (i.suffix) {
|
|
2088
|
+
case "tab":
|
|
2089
|
+
l.innerHTML = " ";
|
|
2090
|
+
break;
|
|
2091
|
+
case "space":
|
|
2092
|
+
l.innerHTML = " ";
|
|
2093
|
+
break;
|
|
2094
|
+
}
|
|
2095
|
+
const d = this.createElement("span", `${this.classPrefix}-numbering-wrapper`);
|
|
2096
|
+
if (d.appendChild(c), d.appendChild(l), (p = i.paragraphProps) != null && p.indentation) {
|
|
2097
|
+
const u = i.paragraphProps.indentation;
|
|
2098
|
+
u.left && (d.style.marginLeft = u.left), u.hanging && (d.style.textIndent = `-${u.hanging}`, d.style.paddingLeft = u.hanging);
|
|
2099
|
+
}
|
|
2100
|
+
return d;
|
|
2101
|
+
}
|
|
2102
|
+
/**
|
|
2103
|
+
* 获取编号内容
|
|
2104
|
+
*/
|
|
2105
|
+
getNumberingContent(e, t, n, r) {
|
|
2106
|
+
const i = t.format, a = t.text;
|
|
2107
|
+
if (i === "bullet")
|
|
2108
|
+
return a || "•";
|
|
2109
|
+
const c = `${n}-${r}`;
|
|
2110
|
+
let l = this.numberingCounters.get(c) ?? t.start - 1;
|
|
2111
|
+
l++, this.numberingCounters.set(c, l);
|
|
2112
|
+
for (let h = r + 1; h <= 8; h++)
|
|
2113
|
+
this.numberingCounters.delete(`${n}-${h}`);
|
|
2114
|
+
let d = a;
|
|
2115
|
+
for (let h = 0; h <= r; h++) {
|
|
2116
|
+
const p = this.numberingCounters.get(`${n}-${h}`) ?? 1, u = e.levels.find((y) => y.level === h), f = (u == null ? void 0 : u.format) || "decimal", b = this.formatNumber(p, f);
|
|
2117
|
+
d = d.replace(`%${h + 1}`, b);
|
|
2118
|
+
}
|
|
2119
|
+
return d;
|
|
2120
|
+
}
|
|
2121
|
+
/**
|
|
2122
|
+
* 格式化编号
|
|
2123
|
+
*/
|
|
2124
|
+
formatNumber(e, t) {
|
|
2125
|
+
switch (t) {
|
|
2126
|
+
case "decimal":
|
|
2127
|
+
return String(e);
|
|
2128
|
+
case "decimalZero":
|
|
2129
|
+
return e < 10 ? `0${e}` : String(e);
|
|
2130
|
+
case "lowerLetter":
|
|
2131
|
+
return this.toLetters(e, !1);
|
|
2132
|
+
case "upperLetter":
|
|
2133
|
+
return this.toLetters(e, !0);
|
|
2134
|
+
case "lowerRoman":
|
|
2135
|
+
return this.toRoman(e).toLowerCase();
|
|
2136
|
+
case "upperRoman":
|
|
2137
|
+
return this.toRoman(e);
|
|
2138
|
+
case "chineseCountingThousand":
|
|
2139
|
+
case "chineseCounting":
|
|
2140
|
+
return this.toChinese(e);
|
|
2141
|
+
case "ideographTraditional":
|
|
2142
|
+
return this.toChineseTraditional(e);
|
|
2143
|
+
case "bullet":
|
|
2144
|
+
return "•";
|
|
2145
|
+
default:
|
|
2146
|
+
return String(e);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
/**
|
|
2150
|
+
* 数字转字母
|
|
2151
|
+
*/
|
|
2152
|
+
toLetters(e, t) {
|
|
2153
|
+
const n = t ? 65 : 97;
|
|
2154
|
+
let r = "";
|
|
2155
|
+
for (; e > 0; )
|
|
2156
|
+
e--, r = String.fromCharCode(n + e % 26) + r, e = Math.floor(e / 26);
|
|
2157
|
+
return r;
|
|
2158
|
+
}
|
|
2159
|
+
/**
|
|
2160
|
+
* 数字转罗马数字
|
|
2161
|
+
*/
|
|
2162
|
+
toRoman(e) {
|
|
2163
|
+
const t = [
|
|
2164
|
+
[1e3, "M"],
|
|
2165
|
+
[900, "CM"],
|
|
2166
|
+
[500, "D"],
|
|
2167
|
+
[400, "CD"],
|
|
2168
|
+
[100, "C"],
|
|
2169
|
+
[90, "XC"],
|
|
2170
|
+
[50, "L"],
|
|
2171
|
+
[40, "XL"],
|
|
2172
|
+
[10, "X"],
|
|
2173
|
+
[9, "IX"],
|
|
2174
|
+
[5, "V"],
|
|
2175
|
+
[4, "IV"],
|
|
2176
|
+
[1, "I"]
|
|
2177
|
+
];
|
|
2178
|
+
let n = "";
|
|
2179
|
+
for (const [r, i] of t)
|
|
2180
|
+
for (; e >= r; )
|
|
2181
|
+
n += i, e -= r;
|
|
2182
|
+
return n;
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* 数字转中文数字
|
|
2186
|
+
*/
|
|
2187
|
+
toChinese(e) {
|
|
2188
|
+
const t = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"], n = ["", "十", "百", "千", "万"];
|
|
2189
|
+
if (e <= 10)
|
|
2190
|
+
return e === 10 ? "十" : t[e];
|
|
2191
|
+
let r = "", i = 0;
|
|
2192
|
+
for (; e > 0; ) {
|
|
2193
|
+
const a = e % 10;
|
|
2194
|
+
a !== 0 ? r = t[a] + n[i] + r : r && !r.startsWith("零") && (r = "零" + r), e = Math.floor(e / 10), i++;
|
|
2195
|
+
}
|
|
2196
|
+
return r.startsWith("一十") && (r = r.substring(1)), r;
|
|
2197
|
+
}
|
|
2198
|
+
/**
|
|
2199
|
+
* 数字转中文传统数字(甲乙丙丁...)
|
|
2200
|
+
*/
|
|
2201
|
+
toChineseTraditional(e) {
|
|
2202
|
+
const t = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"];
|
|
2203
|
+
return e >= 1 && e <= 10 ? t[e - 1] : String(e);
|
|
2204
|
+
}
|
|
2205
|
+
/**
|
|
2206
|
+
* 创建评论气泡
|
|
2207
|
+
*/
|
|
2208
|
+
createCommentBubble(e) {
|
|
2209
|
+
const t = this.createElement("div", `${this.classPrefix}-comment-bubble`);
|
|
2210
|
+
t.dataset.commentId = e.id;
|
|
2211
|
+
const n = e.initials || e.author.charAt(0).toUpperCase(), r = this.formatDate(e.date), i = this.getCommentText(e);
|
|
2212
|
+
t.innerHTML = `
|
|
2213
|
+
<div class="${this.classPrefix}-comment-header">
|
|
2214
|
+
<div class="${this.classPrefix}-comment-avatar">${this.escapeHtml(n)}</div>
|
|
2215
|
+
<div class="${this.classPrefix}-comment-meta">
|
|
2216
|
+
<span class="${this.classPrefix}-comment-author">${this.escapeHtml(e.author)}</span>
|
|
2217
|
+
<span class="${this.classPrefix}-comment-date">${r}</span>
|
|
2218
|
+
</div>
|
|
2219
|
+
</div>
|
|
2220
|
+
<div class="${this.classPrefix}-comment-content">${this.escapeHtml(i)}</div>
|
|
2221
|
+
${this.options.enableCommentEdit ? `
|
|
2222
|
+
<div class="${this.classPrefix}-comment-actions">
|
|
2223
|
+
<button class="${this.classPrefix}-comment-btn edit" title="编辑">
|
|
2224
|
+
<svg viewBox="0 0 24 24" width="14" height="14"><path fill="currentColor" d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg>
|
|
2225
|
+
</button>
|
|
2226
|
+
<button class="${this.classPrefix}-comment-btn delete" title="删除">
|
|
2227
|
+
<svg viewBox="0 0 24 24" width="14" height="14"><path fill="currentColor" d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>
|
|
2228
|
+
</button>
|
|
2229
|
+
</div>
|
|
2230
|
+
` : ""}
|
|
2231
|
+
`, t.addEventListener("mouseenter", () => this.highlightComment(e.id)), t.addEventListener("mouseleave", () => this.unhighlightComment(e.id)), t.addEventListener("click", () => {
|
|
2232
|
+
this.selectComment(e.id), this.options.onCommentClick(e);
|
|
2233
|
+
});
|
|
2234
|
+
const a = t.querySelector(".edit");
|
|
2235
|
+
a == null || a.addEventListener("click", (l) => {
|
|
2236
|
+
l.stopPropagation(), this.editComment(e);
|
|
2237
|
+
});
|
|
2238
|
+
const c = t.querySelector(".delete");
|
|
2239
|
+
return c == null || c.addEventListener("click", (l) => {
|
|
2240
|
+
l.stopPropagation(), this.deleteComment(e.id);
|
|
2241
|
+
}), t;
|
|
2242
|
+
}
|
|
2243
|
+
/**
|
|
2244
|
+
* 获取评论文本内容
|
|
2245
|
+
*/
|
|
2246
|
+
getCommentText(e) {
|
|
2247
|
+
const t = [], n = (i) => {
|
|
2248
|
+
for (const a of i)
|
|
2249
|
+
a.type === m.Text && t.push(a.text), a.children && n(a.children);
|
|
2250
|
+
};
|
|
2251
|
+
n(e.children || []);
|
|
2252
|
+
const r = t.join("");
|
|
2253
|
+
return !r && e.rawText ? (console.log("[DEBUG] Comment", e.id, "using rawText:", e.rawText), e.rawText) : (console.log("[DEBUG] Comment", e.id, "text result:", r), r || "");
|
|
2254
|
+
}
|
|
2255
|
+
/**
|
|
2256
|
+
* 高亮评论
|
|
2257
|
+
*/
|
|
2258
|
+
highlightComment(e) {
|
|
2259
|
+
var n;
|
|
2260
|
+
this.activeCommentId = e;
|
|
2261
|
+
const t = this.commentRanges.get(e);
|
|
2262
|
+
t && (t.highlightElements.forEach((r) => {
|
|
2263
|
+
r.classList.add(`${this.classPrefix}-highlight--active`);
|
|
2264
|
+
}), (n = t.panelElement) == null || n.classList.add(`${this.classPrefix}-comment-bubble--active`)), this.updateLines();
|
|
2265
|
+
}
|
|
2266
|
+
/**
|
|
2267
|
+
* 取消高亮评论
|
|
2268
|
+
*/
|
|
2269
|
+
unhighlightComment(e) {
|
|
2270
|
+
var n;
|
|
2271
|
+
this.activeCommentId === e && (this.activeCommentId = null);
|
|
2272
|
+
const t = this.commentRanges.get(e);
|
|
2273
|
+
t && (t.highlightElements.forEach((r) => {
|
|
2274
|
+
r.classList.remove(`${this.classPrefix}-highlight--active`);
|
|
2275
|
+
}), (n = t.panelElement) == null || n.classList.remove(`${this.classPrefix}-comment-bubble--active`)), this.updateLines();
|
|
2276
|
+
}
|
|
2277
|
+
/**
|
|
2278
|
+
* 选中评论
|
|
2279
|
+
*/
|
|
2280
|
+
selectComment(e) {
|
|
2281
|
+
this.activeCommentId = e, this.updateLines();
|
|
2282
|
+
}
|
|
2283
|
+
/**
|
|
2284
|
+
* 编辑评论
|
|
2285
|
+
*/
|
|
2286
|
+
editComment(e) {
|
|
2287
|
+
const t = this.getCommentText(e), n = prompt("编辑评论:", t);
|
|
2288
|
+
if (n !== null && n !== t) {
|
|
2289
|
+
const r = { type: m.Text, text: n }, i = { type: m.Run, children: [r] }, a = { type: m.Paragraph, children: [i] };
|
|
2290
|
+
e.children = [a];
|
|
2291
|
+
const c = this.commentRanges.get(e.id);
|
|
2292
|
+
if (c != null && c.panelElement) {
|
|
2293
|
+
const l = c.panelElement.querySelector(`.${this.classPrefix}-comment-content`);
|
|
2294
|
+
l && (l.textContent = n);
|
|
2295
|
+
}
|
|
2296
|
+
this.options.onCommentChange(e, "update");
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
/**
|
|
2300
|
+
* 删除评论
|
|
2301
|
+
*/
|
|
2302
|
+
deleteComment(e) {
|
|
2303
|
+
var r, i;
|
|
2304
|
+
if (!confirm("确定要删除这条评论吗?")) return;
|
|
2305
|
+
const t = (r = this.document) == null ? void 0 : r.commentMap.get(e);
|
|
2306
|
+
if (!t) return;
|
|
2307
|
+
const n = this.commentRanges.get(e);
|
|
2308
|
+
if (n && (n.highlightElements.forEach((a) => {
|
|
2309
|
+
a.classList.remove(`${this.classPrefix}-highlight`), a.classList.remove(`${this.classPrefix}-highlight--active`);
|
|
2310
|
+
}), (i = n.panelElement) == null || i.remove()), this.document) {
|
|
2311
|
+
const a = this.document.comments.indexOf(t);
|
|
2312
|
+
a > -1 && this.document.comments.splice(a, 1), this.document.commentMap.delete(e);
|
|
2313
|
+
}
|
|
2314
|
+
this.commentRanges.delete(e), this.options.onCommentChange(t, "delete"), this.updateLines();
|
|
2315
|
+
}
|
|
2316
|
+
/**
|
|
2317
|
+
* 应用段落样式
|
|
2318
|
+
*/
|
|
2319
|
+
applyParagraphStyles(e, t) {
|
|
2320
|
+
const n = [];
|
|
2321
|
+
if (t.justification) {
|
|
2322
|
+
const r = {
|
|
2323
|
+
left: "left",
|
|
2324
|
+
center: "center",
|
|
2325
|
+
right: "right",
|
|
2326
|
+
both: "justify"
|
|
2327
|
+
};
|
|
2328
|
+
n.push(`text-align: ${r[t.justification] || "left"}`);
|
|
2329
|
+
}
|
|
2330
|
+
if (t.indentation && (t.indentation.left && n.push(`padding-left: ${t.indentation.left}`), t.indentation.right && n.push(`padding-right: ${t.indentation.right}`), t.indentation.firstLine && n.push(`text-indent: ${t.indentation.firstLine}`)), t.spacing && (t.spacing.before && n.push(`margin-top: ${t.spacing.before}`), t.spacing.after && n.push(`margin-bottom: ${t.spacing.after}`), t.spacing.line !== void 0)) {
|
|
2331
|
+
const r = t.spacing.line;
|
|
2332
|
+
switch (t.spacing.lineRule) {
|
|
2333
|
+
case "auto":
|
|
2334
|
+
n.push(`line-height: ${(r / 240).toFixed(2)}`);
|
|
2335
|
+
break;
|
|
2336
|
+
case "atLeast":
|
|
2337
|
+
n.push(`line-height: calc(100% + ${r / 20}pt)`);
|
|
2338
|
+
break;
|
|
2339
|
+
case "exact":
|
|
2340
|
+
default:
|
|
2341
|
+
n.push(`line-height: ${r / 20}pt`);
|
|
2342
|
+
break;
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
n.length > 0 && (e.style.cssText = n.join("; "));
|
|
2346
|
+
}
|
|
2347
|
+
/**
|
|
2348
|
+
* 渲染 Run
|
|
2349
|
+
*/
|
|
2350
|
+
renderRun(e) {
|
|
2351
|
+
if (this.skipFieldContent && !(e.children || []).some(
|
|
2352
|
+
(r) => r.type === m.ComplexField && r.charType === "end"
|
|
2353
|
+
))
|
|
2354
|
+
return null;
|
|
2355
|
+
const t = this.createElement("span", `${this.classPrefix}-run`);
|
|
2356
|
+
if (this.currentCommentIds.size > 0) {
|
|
2357
|
+
t.classList.add(`${this.classPrefix}-highlight`);
|
|
2358
|
+
for (const n of this.currentCommentIds) {
|
|
2359
|
+
t.classList.add(`${this.classPrefix}-highlight-${n}`), t.dataset.commentId = n;
|
|
2360
|
+
const r = this.commentRanges.get(n);
|
|
2361
|
+
r && r.highlightElements.push(t);
|
|
2362
|
+
}
|
|
2363
|
+
t.addEventListener("click", () => {
|
|
2364
|
+
const n = t.dataset.commentId;
|
|
2365
|
+
n && this.highlightComment(n);
|
|
2366
|
+
});
|
|
2367
|
+
}
|
|
2368
|
+
return e.props && this.applyRunStyles(t, e.props), this.renderChildren(e.children || [], t), t.childNodes.length === 0 ? null : t;
|
|
2369
|
+
}
|
|
2370
|
+
/**
|
|
2371
|
+
* 应用 Run 样式
|
|
2372
|
+
*/
|
|
2373
|
+
applyRunStyles(e, t) {
|
|
2374
|
+
const n = [];
|
|
2375
|
+
t.bold && n.push("font-weight: bold"), t.italic && n.push("font-style: italic");
|
|
2376
|
+
const r = [];
|
|
2377
|
+
if (t.underline && t.underline !== "none" && (e.classList.add(`${this.classPrefix}-underline-${t.underline}`), this.isComplexUnderline(t.underline) || r.push("underline")), t.strike && r.push("line-through"), t.dstrike && e.classList.add(`${this.classPrefix}-dstrike`), r.length > 0 && n.push(`text-decoration: ${r.join(" ")}`), t.vertAlign && e.classList.add(`${this.classPrefix}-${t.vertAlign}`), t.color && n.push(`color: ${t.color}`), t.fontSize && n.push(`font-size: ${t.fontSize}`), t.fontFamily && n.push(`font-family: "${t.fontFamily}"`), t.highlight) {
|
|
2378
|
+
const i = {
|
|
2379
|
+
yellow: "#ffff00",
|
|
2380
|
+
green: "#00ff00",
|
|
2381
|
+
cyan: "#00ffff",
|
|
2382
|
+
magenta: "#ff00ff",
|
|
2383
|
+
blue: "#0000ff",
|
|
2384
|
+
red: "#ff0000",
|
|
2385
|
+
darkBlue: "#000080",
|
|
2386
|
+
darkCyan: "#008080",
|
|
2387
|
+
darkGreen: "#008000",
|
|
2388
|
+
darkMagenta: "#800080",
|
|
2389
|
+
darkRed: "#800000",
|
|
2390
|
+
darkYellow: "#808000",
|
|
2391
|
+
darkGray: "#808080",
|
|
2392
|
+
lightGray: "#c0c0c0",
|
|
2393
|
+
black: "#000000"
|
|
2394
|
+
};
|
|
2395
|
+
n.push(`background-color: ${i[t.highlight] || t.highlight}`);
|
|
2396
|
+
}
|
|
2397
|
+
n.length > 0 && (e.style.cssText = n.join("; "));
|
|
2398
|
+
}
|
|
2399
|
+
/**
|
|
2400
|
+
* 检查是否是复杂下划线样式(需要特殊 CSS 处理)
|
|
2401
|
+
*/
|
|
2402
|
+
isComplexUnderline(e) {
|
|
2403
|
+
return [
|
|
2404
|
+
"double",
|
|
2405
|
+
"thick",
|
|
2406
|
+
"dotted",
|
|
2407
|
+
"dottedHeavy",
|
|
2408
|
+
"dash",
|
|
2409
|
+
"dashedHeavy",
|
|
2410
|
+
"dashLong",
|
|
2411
|
+
"dashLongHeavy",
|
|
2412
|
+
"dotDash",
|
|
2413
|
+
"dashDotHeavy",
|
|
2414
|
+
"dotDotDash",
|
|
2415
|
+
"dashDotDotHeavy",
|
|
2416
|
+
"wave",
|
|
2417
|
+
"wavyHeavy",
|
|
2418
|
+
"wavyDouble"
|
|
2419
|
+
].includes(e);
|
|
2420
|
+
}
|
|
2421
|
+
/**
|
|
2422
|
+
* 渲染文本
|
|
2423
|
+
*/
|
|
2424
|
+
renderText(e) {
|
|
2425
|
+
if (this.skipFieldContent)
|
|
2426
|
+
return null;
|
|
2427
|
+
const t = document.createElement("span");
|
|
2428
|
+
return t.textContent = e.text, t;
|
|
2429
|
+
}
|
|
2430
|
+
/**
|
|
2431
|
+
* 渲染换行
|
|
2432
|
+
*/
|
|
2433
|
+
renderBreak(e) {
|
|
2434
|
+
switch (e.breakType) {
|
|
2435
|
+
case "page":
|
|
2436
|
+
case "lastRenderedPageBreak":
|
|
2437
|
+
const t = this.createElement("div", `${this.classPrefix}-page-break`);
|
|
2438
|
+
return t.style.pageBreakAfter = "always", t;
|
|
2439
|
+
case "column":
|
|
2440
|
+
const n = this.createElement("span", `${this.classPrefix}-column-break`);
|
|
2441
|
+
return n.style.breakAfter = "column", n;
|
|
2442
|
+
default:
|
|
2443
|
+
return document.createElement("br");
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
/**
|
|
2447
|
+
* 渲染 Tab
|
|
2448
|
+
*/
|
|
2449
|
+
renderTab() {
|
|
2450
|
+
const e = this.createElement("span", `${this.classPrefix}-tab`);
|
|
2451
|
+
return e.innerHTML = " ", e;
|
|
2452
|
+
}
|
|
2453
|
+
/**
|
|
2454
|
+
* 渲染 Symbol 字符
|
|
2455
|
+
* 处理 Word 中的特殊符号字符(如 Wingdings、Symbol 字体中的符号)
|
|
2456
|
+
*/
|
|
2457
|
+
renderSymbol(e) {
|
|
2458
|
+
const t = this.createElement("span", `${this.classPrefix}-symbol`);
|
|
2459
|
+
return e.font && (t.style.fontFamily = `"${e.font}", "Segoe UI Symbol", "Apple Symbols", sans-serif`), e.char ? t.textContent = e.char : t.textContent = "□", t;
|
|
2460
|
+
}
|
|
2461
|
+
/**
|
|
2462
|
+
* 渲染简单域 - 如 PAGE, NUMPAGES 等
|
|
2463
|
+
*/
|
|
2464
|
+
renderSimpleField(e) {
|
|
2465
|
+
const t = e.instruction.trim().toUpperCase(), n = this.evaluateFieldInstruction(t);
|
|
2466
|
+
if (n !== null) {
|
|
2467
|
+
const i = this.createElement("span", `${this.classPrefix}-field`);
|
|
2468
|
+
return i.textContent = n, i;
|
|
2469
|
+
}
|
|
2470
|
+
const r = this.createElement("span", `${this.classPrefix}-field`);
|
|
2471
|
+
return this.renderChildren(e.children || [], r), r;
|
|
2472
|
+
}
|
|
2473
|
+
/**
|
|
2474
|
+
* 渲染复杂域字符
|
|
2475
|
+
*/
|
|
2476
|
+
renderComplexField(e) {
|
|
2477
|
+
switch (e.charType) {
|
|
2478
|
+
case "begin":
|
|
2479
|
+
return this.inComplexField = !0, this.skipFieldContent = !1, this.currentFieldInstruction = "", null;
|
|
2480
|
+
case "separate":
|
|
2481
|
+
const t = this.evaluateFieldInstruction(this.currentFieldInstruction.trim().toUpperCase());
|
|
2482
|
+
if (t !== null) {
|
|
2483
|
+
this.skipFieldContent = !0;
|
|
2484
|
+
const n = this.createElement("span", `${this.classPrefix}-field`);
|
|
2485
|
+
return n.textContent = t, n;
|
|
2486
|
+
}
|
|
2487
|
+
return null;
|
|
2488
|
+
case "end":
|
|
2489
|
+
return this.inComplexField = !1, this.skipFieldContent = !1, this.currentFieldInstruction = "", null;
|
|
2490
|
+
default:
|
|
2491
|
+
return null;
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
/**
|
|
2495
|
+
* 渲染域指令
|
|
2496
|
+
*/
|
|
2497
|
+
renderFieldInstruction(e) {
|
|
2498
|
+
return this.inComplexField && (this.currentFieldInstruction += e.text), null;
|
|
2499
|
+
}
|
|
2500
|
+
/**
|
|
2501
|
+
* 计算域值
|
|
2502
|
+
*/
|
|
2503
|
+
evaluateFieldInstruction(e) {
|
|
2504
|
+
switch (e.split(/\s+/)[0]) {
|
|
2505
|
+
case "PAGE":
|
|
2506
|
+
return String(this.currentPageNumber);
|
|
2507
|
+
case "NUMPAGES":
|
|
2508
|
+
return String(this.totalPages);
|
|
2509
|
+
case "DATE":
|
|
2510
|
+
return (/* @__PURE__ */ new Date()).toLocaleDateString("zh-CN");
|
|
2511
|
+
case "TIME":
|
|
2512
|
+
return (/* @__PURE__ */ new Date()).toLocaleTimeString("zh-CN");
|
|
2513
|
+
default:
|
|
2514
|
+
return null;
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
/**
|
|
2518
|
+
* 渲染表格
|
|
2519
|
+
*/
|
|
2520
|
+
renderTable(e) {
|
|
2521
|
+
var r, i, a;
|
|
2522
|
+
const t = this.createElement("table", `${this.classPrefix}-table`);
|
|
2523
|
+
if (this.tableVerticalMerges.push(this.currentVerticalMerge), this.currentVerticalMerge = /* @__PURE__ */ new Map(), this.tableBordersStack.push(this.currentTableBorders), this.currentTableBorders = (r = e.props) == null ? void 0 : r.borders, this.currentTableRowCount = ((i = e.children) == null ? void 0 : i.length) || 0, this.currentTableColCount = ((a = e.columns) == null ? void 0 : a.length) || 0, this.currentTableRowIndex = 0, e.columns && e.columns.length > 0) {
|
|
2524
|
+
const c = document.createElement("colgroup");
|
|
2525
|
+
for (const l of e.columns) {
|
|
2526
|
+
const d = document.createElement("col");
|
|
2527
|
+
l.width && (d.style.width = l.width), c.appendChild(d);
|
|
2528
|
+
}
|
|
2529
|
+
t.appendChild(c);
|
|
2530
|
+
}
|
|
2531
|
+
e.props && this.applyTableStyles(t, e.props);
|
|
2532
|
+
const n = document.createElement("tbody");
|
|
2533
|
+
for (const c of e.children || []) {
|
|
2534
|
+
this.currentCellCol = 0;
|
|
2535
|
+
const l = this.renderTableRow(c);
|
|
2536
|
+
n.appendChild(l), this.currentTableRowIndex++;
|
|
2537
|
+
}
|
|
2538
|
+
return t.appendChild(n), this.currentVerticalMerge = this.tableVerticalMerges.pop() || /* @__PURE__ */ new Map(), this.currentTableBorders = this.tableBordersStack.pop(), t;
|
|
2539
|
+
}
|
|
2540
|
+
/**
|
|
2541
|
+
* 应用表格样式
|
|
2542
|
+
*/
|
|
2543
|
+
applyTableStyles(e, t) {
|
|
2544
|
+
t.width && (t.widthType, e.style.width = t.width), t.justification === "center" && (e.style.marginLeft = "auto", e.style.marginRight = "auto"), t.cellSpacing && (e.style.borderSpacing = t.cellSpacing, e.style.borderCollapse = "separate");
|
|
2545
|
+
}
|
|
2546
|
+
/**
|
|
2547
|
+
* 将边框属性转换为 CSS 字符串
|
|
2548
|
+
*/
|
|
2549
|
+
borderToCss(e) {
|
|
2550
|
+
if (!e || !e.style)
|
|
2551
|
+
return "none";
|
|
2552
|
+
const t = this.parseBorderType(e.style);
|
|
2553
|
+
if (t === "none")
|
|
2554
|
+
return "none";
|
|
2555
|
+
const n = e.width || "1px", r = e.color || "black";
|
|
2556
|
+
return `${n} ${t} ${r}`;
|
|
2557
|
+
}
|
|
2558
|
+
/**
|
|
2559
|
+
* 将 Word 边框类型转换为 CSS 边框样式
|
|
2560
|
+
*/
|
|
2561
|
+
parseBorderType(e) {
|
|
2562
|
+
switch (e) {
|
|
2563
|
+
case "single":
|
|
2564
|
+
return "solid";
|
|
2565
|
+
case "dashDotStroked":
|
|
2566
|
+
return "solid";
|
|
2567
|
+
case "dashed":
|
|
2568
|
+
return "dashed";
|
|
2569
|
+
case "dashSmallGap":
|
|
2570
|
+
return "dashed";
|
|
2571
|
+
case "dotDash":
|
|
2572
|
+
return "dotted";
|
|
2573
|
+
case "dotDotDash":
|
|
2574
|
+
return "dotted";
|
|
2575
|
+
case "dotted":
|
|
2576
|
+
return "dotted";
|
|
2577
|
+
case "double":
|
|
2578
|
+
return "double";
|
|
2579
|
+
case "doubleWave":
|
|
2580
|
+
return "double";
|
|
2581
|
+
case "inset":
|
|
2582
|
+
return "inset";
|
|
2583
|
+
case "nil":
|
|
2584
|
+
return "none";
|
|
2585
|
+
case "none":
|
|
2586
|
+
return "none";
|
|
2587
|
+
case "outset":
|
|
2588
|
+
return "outset";
|
|
2589
|
+
case "thick":
|
|
2590
|
+
return "solid";
|
|
2591
|
+
case "thickThinLargeGap":
|
|
2592
|
+
return "solid";
|
|
2593
|
+
case "thickThinMediumGap":
|
|
2594
|
+
return "solid";
|
|
2595
|
+
case "thickThinSmallGap":
|
|
2596
|
+
return "solid";
|
|
2597
|
+
case "thinThickLargeGap":
|
|
2598
|
+
return "solid";
|
|
2599
|
+
case "thinThickMediumGap":
|
|
2600
|
+
return "solid";
|
|
2601
|
+
case "thinThickSmallGap":
|
|
2602
|
+
return "solid";
|
|
2603
|
+
case "thinThickThinLargeGap":
|
|
2604
|
+
return "solid";
|
|
2605
|
+
case "thinThickThinMediumGap":
|
|
2606
|
+
return "solid";
|
|
2607
|
+
case "thinThickThinSmallGap":
|
|
2608
|
+
return "solid";
|
|
2609
|
+
case "threeDEmboss":
|
|
2610
|
+
return "solid";
|
|
2611
|
+
case "threeDEngrave":
|
|
2612
|
+
return "solid";
|
|
2613
|
+
case "triple":
|
|
2614
|
+
return "double";
|
|
2615
|
+
case "wave":
|
|
2616
|
+
return "solid";
|
|
2617
|
+
default:
|
|
2618
|
+
return "solid";
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
/**
|
|
2622
|
+
* 应用单元格边框样式
|
|
2623
|
+
*/
|
|
2624
|
+
applyCellBorders(e, t, n, r, i) {
|
|
2625
|
+
const a = this.currentTableBorders, c = n === 0, l = n === this.currentTableRowCount - 1, d = r === 0, h = r + i >= this.currentTableColCount;
|
|
2626
|
+
let p = t == null ? void 0 : t.top;
|
|
2627
|
+
p || (c ? p = a == null ? void 0 : a.top : p = a == null ? void 0 : a.insideH), p && (e.style.borderTop = this.borderToCss(p));
|
|
2628
|
+
let u = t == null ? void 0 : t.bottom;
|
|
2629
|
+
u || (l ? u = a == null ? void 0 : a.bottom : u = a == null ? void 0 : a.insideH), u && (e.style.borderBottom = this.borderToCss(u));
|
|
2630
|
+
let f = t == null ? void 0 : t.left;
|
|
2631
|
+
f || (d ? f = a == null ? void 0 : a.left : f = a == null ? void 0 : a.insideV), f && (e.style.borderLeft = this.borderToCss(f));
|
|
2632
|
+
let b = t == null ? void 0 : t.right;
|
|
2633
|
+
b || (h ? b = a == null ? void 0 : a.right : b = a == null ? void 0 : a.insideV), b && (e.style.borderRight = this.borderToCss(b));
|
|
2634
|
+
}
|
|
2635
|
+
/**
|
|
2636
|
+
* 渲染表格行
|
|
2637
|
+
*/
|
|
2638
|
+
renderTableRow(e) {
|
|
2639
|
+
const t = this.createElement("tr", `${this.classPrefix}-tr`);
|
|
2640
|
+
this.currentCellCol = 0;
|
|
2641
|
+
for (const n of e.children || []) {
|
|
2642
|
+
const r = this.renderTableCell(n);
|
|
2643
|
+
r && t.appendChild(r);
|
|
2644
|
+
}
|
|
2645
|
+
return t;
|
|
2646
|
+
}
|
|
2647
|
+
/**
|
|
2648
|
+
* 渲染表格单元格
|
|
2649
|
+
*/
|
|
2650
|
+
renderTableCell(e) {
|
|
2651
|
+
const t = this.createElement("td", `${this.classPrefix}-td`), n = e.props, r = this.currentCellCol, i = (n == null ? void 0 : n.gridSpan) || 1;
|
|
2652
|
+
if (n != null && n.verticalMerge)
|
|
2653
|
+
if (n.verticalMerge === "restart")
|
|
2654
|
+
this.currentVerticalMerge.set(r, t), t.rowSpan = 1;
|
|
2655
|
+
else {
|
|
2656
|
+
const a = this.currentVerticalMerge.get(r);
|
|
2657
|
+
if (a)
|
|
2658
|
+
return a.rowSpan += 1, this.currentCellCol += i, null;
|
|
2659
|
+
}
|
|
2660
|
+
else
|
|
2661
|
+
this.currentVerticalMerge.delete(r);
|
|
2662
|
+
return n && (n.width && (t.style.width = n.width), n.verticalAlign && (t.style.verticalAlign = n.verticalAlign), n.shading && (t.style.backgroundColor = n.shading), i > 1 && (t.colSpan = i)), this.applyCellBorders(
|
|
2663
|
+
t,
|
|
2664
|
+
n == null ? void 0 : n.borders,
|
|
2665
|
+
this.currentTableRowIndex,
|
|
2666
|
+
r,
|
|
2667
|
+
i
|
|
2668
|
+
), this.renderChildren(e.children || [], t), this.currentCellCol += i, t;
|
|
2669
|
+
}
|
|
2670
|
+
/**
|
|
2671
|
+
* 渲染超链接
|
|
2672
|
+
*/
|
|
2673
|
+
renderHyperlink(e) {
|
|
2674
|
+
const t = document.createElement("a");
|
|
2675
|
+
return t.className = `${this.classPrefix}-link`, e.href ? (t.href = e.href, t.target = "_blank", t.rel = "noopener noreferrer") : e.anchor && (t.href = `#${e.anchor}`), this.renderChildren(e.children || [], t), t;
|
|
2676
|
+
}
|
|
2677
|
+
/**
|
|
2678
|
+
* 渲染绘图
|
|
2679
|
+
*/
|
|
2680
|
+
renderDrawing(e) {
|
|
2681
|
+
const t = this.createElement("span", `${this.classPrefix}-drawing`);
|
|
2682
|
+
return this.renderChildren(e.children || [], t), t;
|
|
2683
|
+
}
|
|
2684
|
+
/**
|
|
2685
|
+
* 渲染图片
|
|
2686
|
+
*/
|
|
2687
|
+
renderImage(e) {
|
|
2688
|
+
const t = document.createElement("img");
|
|
2689
|
+
return t.className = `${this.classPrefix}-image`, t.src = e.src, e.width && (t.style.width = e.width), e.height && (t.style.height = e.height), e.alt && (t.alt = e.alt), t;
|
|
2690
|
+
}
|
|
2691
|
+
/**
|
|
2692
|
+
* 渲染评论范围开始
|
|
2693
|
+
*/
|
|
2694
|
+
renderCommentRangeStart(e) {
|
|
2695
|
+
this.currentCommentIds.add(e.id), this.commentStartInParagraph.add(e.id);
|
|
2696
|
+
const t = this.createElement("span", `${this.classPrefix}-comment-start`);
|
|
2697
|
+
t.dataset.commentId = e.id;
|
|
2698
|
+
const n = this.commentRanges.get(e.id);
|
|
2699
|
+
return n && (n.startElement = t), t;
|
|
2700
|
+
}
|
|
2701
|
+
/**
|
|
2702
|
+
* 渲染评论范围结束
|
|
2703
|
+
*/
|
|
2704
|
+
renderCommentRangeEnd(e) {
|
|
2705
|
+
this.currentCommentIds.delete(e.id);
|
|
2706
|
+
const t = this.createElement("span", `${this.classPrefix}-comment-end`);
|
|
2707
|
+
t.dataset.commentId = e.id;
|
|
2708
|
+
const n = this.commentRanges.get(e.id);
|
|
2709
|
+
return n && (n.endElement = t), t;
|
|
2710
|
+
}
|
|
2711
|
+
/**
|
|
2712
|
+
* 渲染评论引用
|
|
2713
|
+
*/
|
|
2714
|
+
renderCommentReference(e) {
|
|
2715
|
+
const t = this.createElement("span", `${this.classPrefix}-comment-ref`);
|
|
2716
|
+
return t.dataset.commentId = e.id, t.textContent = "📝", t.title = "查看评论", t.addEventListener("click", () => {
|
|
2717
|
+
this.highlightComment(e.id);
|
|
2718
|
+
}), t;
|
|
2719
|
+
}
|
|
2720
|
+
/**
|
|
2721
|
+
* 渲染书签开始标记
|
|
2722
|
+
* 创建一个锚点元素,供超链接跳转使用
|
|
2723
|
+
*/
|
|
2724
|
+
renderBookmarkStart(e) {
|
|
2725
|
+
if (e.name.startsWith("_"))
|
|
2726
|
+
return this.createElement("span");
|
|
2727
|
+
const t = this.createElement("span", `${this.classPrefix}-bookmark`);
|
|
2728
|
+
return t.id = e.name, t.dataset.bookmarkId = e.id, t.dataset.bookmarkName = e.name, t;
|
|
2729
|
+
}
|
|
2730
|
+
/**
|
|
2731
|
+
* 渲染书签结束标记
|
|
2732
|
+
* 书签结束标记不需要渲染任何可见内容
|
|
2733
|
+
*/
|
|
2734
|
+
renderBookmarkEnd(e) {
|
|
2735
|
+
return this.createElement("span");
|
|
2736
|
+
}
|
|
2737
|
+
/**
|
|
2738
|
+
* 渲染脚注引用(文档正文中的上标数字)
|
|
2739
|
+
*/
|
|
2740
|
+
renderFootnoteReference(e) {
|
|
2741
|
+
this.footnoteCounter++, this.currentFootnoteIds.push(e.id);
|
|
2742
|
+
const t = this.createElement("sup", `${this.classPrefix}-footnote-ref`);
|
|
2743
|
+
return t.dataset.footnoteId = e.id, t.textContent = String(this.footnoteCounter), t.title = "脚注", t.addEventListener("click", () => {
|
|
2744
|
+
const n = document.getElementById(`${this.classPrefix}-footnote-${e.id}`);
|
|
2745
|
+
n == null || n.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
2746
|
+
}), t;
|
|
2747
|
+
}
|
|
2748
|
+
/**
|
|
2749
|
+
* 渲染尾注引用(文档正文中的上标数字)
|
|
2750
|
+
*/
|
|
2751
|
+
renderEndnoteReference(e) {
|
|
2752
|
+
this.endnoteCounter++, this.currentEndnoteIds.push(e.id);
|
|
2753
|
+
const t = this.createElement("sup", `${this.classPrefix}-endnote-ref`);
|
|
2754
|
+
return t.dataset.endnoteId = e.id, t.textContent = String(this.endnoteCounter), t.title = "尾注", t.addEventListener("click", () => {
|
|
2755
|
+
const n = document.getElementById(`${this.classPrefix}-endnote-${e.id}`);
|
|
2756
|
+
n == null || n.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
2757
|
+
}), t;
|
|
2758
|
+
}
|
|
2759
|
+
/**
|
|
2760
|
+
* 渲染脚注内容
|
|
2761
|
+
*/
|
|
2762
|
+
renderFootnote(e) {
|
|
2763
|
+
const t = this.createElement("li", `${this.classPrefix}-footnote`);
|
|
2764
|
+
return t.id = `${this.classPrefix}-footnote-${e.id}`, t.dataset.footnoteId = e.id, this.renderChildren(e.children || [], t), t;
|
|
2765
|
+
}
|
|
2766
|
+
/**
|
|
2767
|
+
* 渲染尾注内容
|
|
2768
|
+
*/
|
|
2769
|
+
renderEndnote(e) {
|
|
2770
|
+
const t = this.createElement("li", `${this.classPrefix}-endnote`);
|
|
2771
|
+
return t.id = `${this.classPrefix}-endnote-${e.id}`, t.dataset.endnoteId = e.id, this.renderChildren(e.children || [], t), t;
|
|
2772
|
+
}
|
|
2773
|
+
/**
|
|
2774
|
+
* 渲染页面脚注区域
|
|
2775
|
+
*/
|
|
2776
|
+
renderPageFootnotes(e, t) {
|
|
2777
|
+
var a;
|
|
2778
|
+
if (e.length === 0 || !((a = this.document) != null && a.footnotes)) return;
|
|
2779
|
+
const n = this.createElement("div", `${this.classPrefix}-footnotes-section`), r = this.createElement("hr", `${this.classPrefix}-footnotes-separator`);
|
|
2780
|
+
n.appendChild(r);
|
|
2781
|
+
const i = this.createElement("ol", `${this.classPrefix}-footnotes-list`);
|
|
2782
|
+
for (const c of e) {
|
|
2783
|
+
const l = this.document.footnotes.get(c);
|
|
2784
|
+
if (l) {
|
|
2785
|
+
const d = this.renderFootnote(l);
|
|
2786
|
+
i.appendChild(d);
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
n.appendChild(i), t.appendChild(n);
|
|
2790
|
+
}
|
|
2791
|
+
/**
|
|
2792
|
+
* 渲染文档尾注区域
|
|
2793
|
+
*/
|
|
2794
|
+
renderDocumentEndnotes(e) {
|
|
2795
|
+
var i;
|
|
2796
|
+
if (this.currentEndnoteIds.length === 0 || !((i = this.document) != null && i.endnotes)) return;
|
|
2797
|
+
const t = this.createElement("div", `${this.classPrefix}-endnotes-section`), n = this.createElement("h3", `${this.classPrefix}-endnotes-title`);
|
|
2798
|
+
n.textContent = "尾注", t.appendChild(n);
|
|
2799
|
+
const r = this.createElement("ol", `${this.classPrefix}-endnotes-list`);
|
|
2800
|
+
for (const a of this.currentEndnoteIds) {
|
|
2801
|
+
const c = this.document.endnotes.get(a);
|
|
2802
|
+
if (c) {
|
|
2803
|
+
const l = this.renderEndnote(c);
|
|
2804
|
+
r.appendChild(l);
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
t.appendChild(r), e.appendChild(t);
|
|
2808
|
+
}
|
|
2809
|
+
/**
|
|
2810
|
+
* 渲染子元素
|
|
2811
|
+
*/
|
|
2812
|
+
renderChildren(e, t) {
|
|
2813
|
+
for (const n of e) {
|
|
2814
|
+
const r = this.renderElement(n);
|
|
2815
|
+
r && t.appendChild(r);
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
/**
|
|
2819
|
+
* 创建元素
|
|
2820
|
+
*/
|
|
2821
|
+
createElement(e, t) {
|
|
2822
|
+
const n = document.createElement(e);
|
|
2823
|
+
return t && (n.className = t), n;
|
|
2824
|
+
}
|
|
2825
|
+
/**
|
|
2826
|
+
* 格式化日期
|
|
2827
|
+
*/
|
|
2828
|
+
formatDate(e) {
|
|
2829
|
+
try {
|
|
2830
|
+
return new Date(e).toLocaleDateString("zh-CN", {
|
|
2831
|
+
year: "numeric",
|
|
2832
|
+
month: "2-digit",
|
|
2833
|
+
day: "2-digit"
|
|
2834
|
+
});
|
|
2835
|
+
} catch {
|
|
2836
|
+
return e;
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
/**
|
|
2840
|
+
* 转义 HTML
|
|
2841
|
+
*/
|
|
2842
|
+
escapeHtml(e) {
|
|
2843
|
+
const t = document.createElement("div");
|
|
2844
|
+
return t.textContent = e, t.innerHTML;
|
|
2845
|
+
}
|
|
2846
|
+
/**
|
|
2847
|
+
* 获取文档对象
|
|
2848
|
+
*/
|
|
2849
|
+
getDocument() {
|
|
2850
|
+
return this.document;
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
class xe {
|
|
2854
|
+
constructor(e) {
|
|
2855
|
+
g(this, "parser");
|
|
2856
|
+
g(this, "renderer");
|
|
2857
|
+
g(this, "document", null);
|
|
2858
|
+
this.parser = new we(), this.renderer = new ke(e);
|
|
2859
|
+
}
|
|
2860
|
+
/**
|
|
2861
|
+
* 渲染 DOCX 文件
|
|
2862
|
+
*/
|
|
2863
|
+
async render(e) {
|
|
2864
|
+
this.document = await this.parser.parse(e), this.renderer.render(this.document);
|
|
2865
|
+
}
|
|
2866
|
+
/**
|
|
2867
|
+
* 获取文档对象
|
|
2868
|
+
*/
|
|
2869
|
+
getDocument() {
|
|
2870
|
+
return this.document;
|
|
2871
|
+
}
|
|
2872
|
+
/**
|
|
2873
|
+
* 获取所有评论
|
|
2874
|
+
*/
|
|
2875
|
+
getComments() {
|
|
2876
|
+
var e;
|
|
2877
|
+
return ((e = this.document) == null ? void 0 : e.comments) || [];
|
|
2878
|
+
}
|
|
2879
|
+
/**
|
|
2880
|
+
* 获取解析器(用于保存修改)
|
|
2881
|
+
*/
|
|
2882
|
+
getParser() {
|
|
2883
|
+
return this.parser;
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
async function Me(o, e, t) {
|
|
2887
|
+
const n = new xe({
|
|
2888
|
+
container: e,
|
|
2889
|
+
...t
|
|
2890
|
+
});
|
|
2891
|
+
return await n.render(o), n;
|
|
2892
|
+
}
|
|
2893
|
+
export {
|
|
2894
|
+
C as DOCX_PARTS,
|
|
2895
|
+
we as DocumentParser,
|
|
2896
|
+
ke as DocumentRenderer,
|
|
2897
|
+
xe as DocxRender,
|
|
2898
|
+
m as DomType,
|
|
2899
|
+
U as XML_NS,
|
|
2900
|
+
K as applyTintShade,
|
|
2901
|
+
Ee as buildCommentTree,
|
|
2902
|
+
$e as buildFontFamily,
|
|
2903
|
+
Ae as cleanupFontStyles,
|
|
2904
|
+
Ne as getEmbedFontRefs,
|
|
2905
|
+
Fe as getFontDeclaration,
|
|
2906
|
+
Pe as getSubstituteFontName,
|
|
2907
|
+
Re as hasEmbeddedFont,
|
|
2908
|
+
oe as loadEmbeddedFonts,
|
|
2909
|
+
ye as parseCommentsExtended,
|
|
2910
|
+
J as parseFontTable,
|
|
2911
|
+
j as parseTheme,
|
|
2912
|
+
Me as renderDocx,
|
|
2913
|
+
Y as resolveThemeColor,
|
|
2914
|
+
Te as resolveThemeFont
|
|
2915
|
+
};
|