@hyebook/vue3-adapter 2.3.2 → 2.3.3
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/core/src/player/ebook-player.d.ts +12 -0
- package/dist/core/src/player/ebook-player.d.ts.map +1 -1
- package/dist/core/src/player/ebook-player.js +406 -53
- package/dist/core/src/workbench/editor-workbench.d.ts +4 -0
- package/dist/core/src/workbench/editor-workbench.d.ts.map +1 -1
- package/dist/core/src/workbench/editor-workbench.js +284 -34
- package/package.json +2 -2
|
@@ -49,6 +49,14 @@ export declare class EBookPlayer implements EBookPlayerHandle {
|
|
|
49
49
|
private renderTextBlock;
|
|
50
50
|
private renderNonTextBlock;
|
|
51
51
|
private getTextBlockContent;
|
|
52
|
+
private textBlockToHTML;
|
|
53
|
+
private paragraphTypeToTag;
|
|
54
|
+
private runToHTML;
|
|
55
|
+
private inlineElementToHTML;
|
|
56
|
+
private inlineImageAlignStyleParts;
|
|
57
|
+
private renderImageBlock;
|
|
58
|
+
private renderVideoBlock;
|
|
59
|
+
private renderTableBlock;
|
|
52
60
|
private createAnnotationBuckets;
|
|
53
61
|
private toBlockKey;
|
|
54
62
|
private applyHighlightMarks;
|
|
@@ -60,6 +68,10 @@ export declare class EBookPlayer implements EBookPlayerHandle {
|
|
|
60
68
|
private handleSelectionChange;
|
|
61
69
|
private resolveTextContainer;
|
|
62
70
|
private getSelectionOffsets;
|
|
71
|
+
private collectSelectionSegments;
|
|
72
|
+
private getContainerTextLength;
|
|
73
|
+
private getBoundaryOffsetInContainer;
|
|
74
|
+
private getRangeTextByOffsets;
|
|
63
75
|
private hideSelectionToolbar;
|
|
64
76
|
private clearSelection;
|
|
65
77
|
private handleDocumentPointerDown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ebook-player.d.ts","sourceRoot":"","sources":["../../../../../core/src/player/ebook-player.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ebook-player.d.ts","sourceRoot":"","sources":["../../../../../core/src/player/ebook-player.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PlayerEngine } from "./engine";
|
|
2
2
|
const EBOOK_PLAYER_STYLE_ID = "hy-ebook-lite-player-style";
|
|
3
|
-
const EBOOK_PLAYER_STYLE_VERSION = "0.
|
|
3
|
+
const EBOOK_PLAYER_STYLE_VERSION = "0.2.0";
|
|
4
4
|
const HIGHLIGHT_ICON_SVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3 22V12.5H6V8.5H18V12.5H21V22H3Z" stroke="#333333" stroke-width="2" stroke-linejoin="round"/><path d="M8.5 8.5V4L15.5 2V8.5" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
5
5
|
const NOTE_ICON_SVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15.4998 4.49951L19.4998 8.4995" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M3.99977 15.9995L17.9997 2L21.9998 5.9995L7.99975 19.9995L2.99976 20.9995L3.99977 15.9995Z" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M4.49976 15.9995L7.99975 19.4995" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M6.49976 17.4995L17.4998 6.4995" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
6
6
|
const BOOKMARK_ICON_SVG = `<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 3C0 1.34315 1.34315 0 3 0H27C28.6569 0 30 1.34315 30 3V38.1989C30 38.9837 29.1374 39.4627 28.4713 39.0477L15 30.6562L1.52873 39.0477C0.862627 39.4627 0 38.9837 0 38.1989L0 3Z" fill="#4FCEBB"/></svg>`;
|
|
@@ -9,15 +9,33 @@ const EBOOK_PLAYER_CSS = `
|
|
|
9
9
|
.hyepl-content{position:relative}
|
|
10
10
|
.hyepl-page{margin:0 0 16px}
|
|
11
11
|
.hyepl-page:last-child{margin-bottom:0}
|
|
12
|
-
.hyepl-block{margin:0 0 10px;
|
|
12
|
+
.hyepl-block{margin:0 0 10px;word-break:break-word}
|
|
13
13
|
.hyepl-block:last-child{margin-bottom:0}
|
|
14
|
-
.hyepl-block-text{position:relative;padding-right:18px}
|
|
14
|
+
.hyepl-block-text{position:relative;padding-right:18px;white-space:normal}
|
|
15
|
+
.hyepl-block-text p,.hyepl-block-text h1,.hyepl-block-text h2,.hyepl-block-text h3,.hyepl-block-text h4,.hyepl-block-text blockquote{margin:0 0 .75em;line-height:1.7}
|
|
16
|
+
.hyepl-block-text p:last-child,.hyepl-block-text h1:last-child,.hyepl-block-text h2:last-child,.hyepl-block-text h3:last-child,.hyepl-block-text h4:last-child,.hyepl-block-text blockquote:last-child{margin-bottom:0}
|
|
17
|
+
.hyepl-block-text h1{font-size:24px;line-height:1.3}
|
|
18
|
+
.hyepl-block-text h2{font-size:20px;line-height:1.35}
|
|
19
|
+
.hyepl-block-text h3{font-size:16px;line-height:1.45}
|
|
20
|
+
.hyepl-block-text h4{font-size:14px;line-height:1.5}
|
|
21
|
+
.hyepl-block-text blockquote{padding-left:12px;border-left:3px solid #cbd5e1;color:#475569}
|
|
22
|
+
.hyepl-block-text sup,.hyepl-block-text sub{font-size:.6em;line-height:0;position:relative;vertical-align:baseline}
|
|
23
|
+
.hyepl-block-text sup{top:-.5em}
|
|
24
|
+
.hyepl-block-text sub{top:.5em}
|
|
25
|
+
.hyepl-inline-media{display:inline-block;vertical-align:middle;max-width:100%}
|
|
26
|
+
.hyepl-inline-image{height:auto;border-radius:6px}
|
|
27
|
+
.hyepl-inline-video{border-radius:8px;background:#000}
|
|
28
|
+
.hyepl-block-image img,.hyepl-block-video video{display:block;max-width:100%;width:100%;height:auto;border-radius:8px}
|
|
29
|
+
.hyepl-block-image figcaption,.hyepl-block-video figcaption{margin-top:6px;font-size:12px;color:#64748b}
|
|
30
|
+
.hyepl-block-table{overflow:auto}
|
|
31
|
+
.hyepl-block-table table{width:100%;border-collapse:collapse;table-layout:fixed}
|
|
32
|
+
.hyepl-block-table th,.hyepl-block-table td{border:1px solid #cbd5e1;padding:6px 8px;vertical-align:top;min-width:68px}
|
|
15
33
|
.hyepl-block-muted{color:#64748b}
|
|
16
34
|
.hyepl-highlight{background:var(--hyepl-highlight-color,#fff59d);color:inherit;padding:0 .08em;border-radius:.2em}
|
|
17
35
|
.hyepl-note{background:rgba(14,116,144,.14);border-bottom:2px solid #0e7490;color:inherit;padding:0 .04em;border-radius:.2em}
|
|
18
36
|
.hyepl-bookmark-flag{position:absolute;top:4px;right:0;display:inline-flex;align-items:center;justify-content:center;width:12px;height:16px;pointer-events:none;user-select:none}
|
|
19
37
|
.hyepl-bookmark-flag svg{display:block;width:12px;height:16px}
|
|
20
|
-
.hyepl-selection-toolbar{position:fixed;z-index:
|
|
38
|
+
.hyepl-selection-toolbar{position:fixed;z-index:10070;display:none;align-items:stretch;gap:0;padding:8px 10px;border-radius:14px;border:1px solid #e5e7eb;background:#ffffff;box-shadow:0 10px 24px rgba(15,23,42,.14);transform:translate(-50%,-100%);overflow:visible}
|
|
21
39
|
.hyepl-selection-toolbar.show{display:flex}
|
|
22
40
|
.hyepl-selection-toolbar:after{content:"";position:absolute;bottom:-10px;left:50%;transform:translateX(-50%);border-width:10px 10px 0 10px;border-style:solid;border-color:#ffffff transparent transparent transparent;filter:drop-shadow(0 1px 0 #e5e7eb);pointer-events:none}
|
|
23
41
|
|
|
@@ -248,7 +266,7 @@ export class EBookPlayer {
|
|
|
248
266
|
blockTextNode.className = "hyepl-block hyepl-block-text";
|
|
249
267
|
blockTextNode.dataset.pageId = pageId;
|
|
250
268
|
blockTextNode.dataset.blockId = block.id;
|
|
251
|
-
blockTextNode.
|
|
269
|
+
blockTextNode.innerHTML = this.textBlockToHTML(block);
|
|
252
270
|
const blockKey = this.toBlockKey(pageId, block.id);
|
|
253
271
|
const highlights = buckets.highlightsByBlock.get(blockKey) || [];
|
|
254
272
|
const notes = buckets.notesByBlock.get(blockKey) || [];
|
|
@@ -261,20 +279,17 @@ export class EBookPlayer {
|
|
|
261
279
|
return blockTextNode;
|
|
262
280
|
}
|
|
263
281
|
renderNonTextBlock(block) {
|
|
264
|
-
const node = document.createElement("div");
|
|
265
|
-
node.className = "hyepl-block hyepl-block-muted";
|
|
266
282
|
if (block.type === "image") {
|
|
267
|
-
|
|
268
|
-
return node;
|
|
283
|
+
return this.renderImageBlock(block);
|
|
269
284
|
}
|
|
270
285
|
if (block.type === "video") {
|
|
271
|
-
|
|
272
|
-
return node;
|
|
286
|
+
return this.renderVideoBlock(block);
|
|
273
287
|
}
|
|
274
288
|
if (block.type === "table") {
|
|
275
|
-
|
|
276
|
-
return node;
|
|
289
|
+
return this.renderTableBlock(block);
|
|
277
290
|
}
|
|
291
|
+
const node = document.createElement("div");
|
|
292
|
+
node.className = "hyepl-block hyepl-block-muted";
|
|
278
293
|
node.textContent = "[内容块]";
|
|
279
294
|
return node;
|
|
280
295
|
}
|
|
@@ -285,6 +300,222 @@ export class EBookPlayer {
|
|
|
285
300
|
})
|
|
286
301
|
.join("\n");
|
|
287
302
|
}
|
|
303
|
+
textBlockToHTML(block) {
|
|
304
|
+
const paragraphs = block.content?.paragraphs ?? [];
|
|
305
|
+
if (!paragraphs.length) {
|
|
306
|
+
return "<p><br></p>";
|
|
307
|
+
}
|
|
308
|
+
return paragraphs
|
|
309
|
+
.map((paragraph) => {
|
|
310
|
+
const tag = this.paragraphTypeToTag(paragraph.type);
|
|
311
|
+
const inlineById = Object.fromEntries((paragraph.inlineElements ?? []).map((item) => [item.id, item]));
|
|
312
|
+
const styleTokens = [
|
|
313
|
+
`text-align:${paragraph.align || "left"}`,
|
|
314
|
+
paragraph.lineHeight ? `line-height:${paragraph.lineHeight}` : "",
|
|
315
|
+
paragraph.spacingBefore !== undefined
|
|
316
|
+
? `margin-top:${paragraph.spacingBefore}px`
|
|
317
|
+
: "",
|
|
318
|
+
paragraph.spacingAfter !== undefined
|
|
319
|
+
? `margin-bottom:${paragraph.spacingAfter}px`
|
|
320
|
+
: "",
|
|
321
|
+
paragraph.indent !== undefined
|
|
322
|
+
? `text-indent:${paragraph.indent}em`
|
|
323
|
+
: "",
|
|
324
|
+
].filter(Boolean);
|
|
325
|
+
const body = paragraph.runs
|
|
326
|
+
?.map((run) => this.runToHTML(run, inlineById))
|
|
327
|
+
.join("") || "<br>";
|
|
328
|
+
const styleAttr = styleTokens.length
|
|
329
|
+
? ` style="${escapeAttribute(styleTokens.join(";"))}"`
|
|
330
|
+
: "";
|
|
331
|
+
return `<${tag}${styleAttr}>${body}</${tag}>`;
|
|
332
|
+
})
|
|
333
|
+
.join("");
|
|
334
|
+
}
|
|
335
|
+
paragraphTypeToTag(type) {
|
|
336
|
+
if (type === "h1" || type === "h2" || type === "h3" || type === "h4") {
|
|
337
|
+
return type;
|
|
338
|
+
}
|
|
339
|
+
if (type === "quote") {
|
|
340
|
+
return "blockquote";
|
|
341
|
+
}
|
|
342
|
+
return "p";
|
|
343
|
+
}
|
|
344
|
+
runToHTML(run, inlineById) {
|
|
345
|
+
const inlineElement = run.inlineRef
|
|
346
|
+
? inlineById?.[run.inlineRef]
|
|
347
|
+
: undefined;
|
|
348
|
+
if (run.inlineRef && inlineElement) {
|
|
349
|
+
return this.inlineElementToHTML(inlineElement);
|
|
350
|
+
}
|
|
351
|
+
let text = escapeHtml(run.text || "").replace(/\n/g, "<br>");
|
|
352
|
+
const marks = run.marks || {};
|
|
353
|
+
const styleTokens = [];
|
|
354
|
+
if (marks.fontSize) {
|
|
355
|
+
styleTokens.push(`font-size:${marks.fontSize}px`);
|
|
356
|
+
}
|
|
357
|
+
if (marks.fontFamily) {
|
|
358
|
+
styleTokens.push(`font-family:${marks.fontFamily}`);
|
|
359
|
+
}
|
|
360
|
+
if (marks.color) {
|
|
361
|
+
styleTokens.push(`color:${marks.color}`);
|
|
362
|
+
}
|
|
363
|
+
if (marks.backgroundColor) {
|
|
364
|
+
styleTokens.push(`background-color:${marks.backgroundColor}`);
|
|
365
|
+
}
|
|
366
|
+
if (styleTokens.length) {
|
|
367
|
+
text = `<span style="${escapeAttribute(styleTokens.join(";"))}">${text}</span>`;
|
|
368
|
+
}
|
|
369
|
+
if (marks.bold) {
|
|
370
|
+
text = `<strong>${text}</strong>`;
|
|
371
|
+
}
|
|
372
|
+
if (marks.italic) {
|
|
373
|
+
text = `<em>${text}</em>`;
|
|
374
|
+
}
|
|
375
|
+
if (marks.underline) {
|
|
376
|
+
text = `<u>${text}</u>`;
|
|
377
|
+
}
|
|
378
|
+
if (marks.strike) {
|
|
379
|
+
text = `<s>${text}</s>`;
|
|
380
|
+
}
|
|
381
|
+
if (marks.sup) {
|
|
382
|
+
text = `<sup>${text}</sup>`;
|
|
383
|
+
}
|
|
384
|
+
if (marks.sub) {
|
|
385
|
+
text = `<sub>${text}</sub>`;
|
|
386
|
+
}
|
|
387
|
+
return text || "<br>";
|
|
388
|
+
}
|
|
389
|
+
inlineElementToHTML(element) {
|
|
390
|
+
if (element.type === "image") {
|
|
391
|
+
const sizeStyle = [
|
|
392
|
+
element.width !== undefined ? `width:${element.width}px` : "",
|
|
393
|
+
element.height !== undefined ? `height:${element.height}px` : "",
|
|
394
|
+
...(element.align
|
|
395
|
+
? this.inlineImageAlignStyleParts(element.align)
|
|
396
|
+
: []),
|
|
397
|
+
]
|
|
398
|
+
.filter(Boolean)
|
|
399
|
+
.join(";");
|
|
400
|
+
return `<img class="hyepl-inline-media hyepl-inline-image" src="${escapeAttribute(element.src)}" alt="${escapeAttribute(element.alt || "")}" style="${escapeAttribute(sizeStyle)}" />`;
|
|
401
|
+
}
|
|
402
|
+
if (element.type === "video") {
|
|
403
|
+
const sizeStyle = [
|
|
404
|
+
element.width !== undefined ? `width:${element.width}px` : "",
|
|
405
|
+
element.height !== undefined ? `height:${element.height}px` : "",
|
|
406
|
+
]
|
|
407
|
+
.filter(Boolean)
|
|
408
|
+
.join(";");
|
|
409
|
+
const posterAttr = element.poster
|
|
410
|
+
? ` poster="${escapeAttribute(element.poster)}"`
|
|
411
|
+
: "";
|
|
412
|
+
return `<video class="hyepl-inline-media hyepl-inline-video" src="${escapeAttribute(element.src)}" controls${posterAttr} style="${escapeAttribute(sizeStyle)}"></video>`;
|
|
413
|
+
}
|
|
414
|
+
return "";
|
|
415
|
+
}
|
|
416
|
+
inlineImageAlignStyleParts(align) {
|
|
417
|
+
if (align === "center") {
|
|
418
|
+
return ["display:block", "margin-left:auto", "margin-right:auto"];
|
|
419
|
+
}
|
|
420
|
+
if (align === "right") {
|
|
421
|
+
return ["display:block", "margin-left:auto", "margin-right:0"];
|
|
422
|
+
}
|
|
423
|
+
if (align === "left") {
|
|
424
|
+
return ["display:block", "margin-left:0", "margin-right:auto"];
|
|
425
|
+
}
|
|
426
|
+
return [];
|
|
427
|
+
}
|
|
428
|
+
renderImageBlock(block) {
|
|
429
|
+
const figure = document.createElement("figure");
|
|
430
|
+
figure.className = "hyepl-block hyepl-block-image";
|
|
431
|
+
const image = document.createElement("img");
|
|
432
|
+
image.src = block.src;
|
|
433
|
+
image.alt = block.alt || "";
|
|
434
|
+
image.style.objectFit = block.fit || "contain";
|
|
435
|
+
figure.append(image);
|
|
436
|
+
if (block.caption) {
|
|
437
|
+
const caption = document.createElement("figcaption");
|
|
438
|
+
caption.textContent = block.caption;
|
|
439
|
+
figure.append(caption);
|
|
440
|
+
}
|
|
441
|
+
return figure;
|
|
442
|
+
}
|
|
443
|
+
renderVideoBlock(block) {
|
|
444
|
+
const figure = document.createElement("figure");
|
|
445
|
+
figure.className = "hyepl-block hyepl-block-video";
|
|
446
|
+
const video = document.createElement("video");
|
|
447
|
+
video.src = block.src;
|
|
448
|
+
video.controls = block.controls !== false;
|
|
449
|
+
video.autoplay = Boolean(block.autoplay);
|
|
450
|
+
video.muted = Boolean(block.muted);
|
|
451
|
+
video.loop = Boolean(block.loop);
|
|
452
|
+
if (block.poster) {
|
|
453
|
+
video.poster = block.poster;
|
|
454
|
+
}
|
|
455
|
+
figure.append(video);
|
|
456
|
+
return figure;
|
|
457
|
+
}
|
|
458
|
+
renderTableBlock(block) {
|
|
459
|
+
const wrapper = document.createElement("div");
|
|
460
|
+
wrapper.className = "hyepl-block hyepl-block-table";
|
|
461
|
+
const table = document.createElement("table");
|
|
462
|
+
if (block.style) {
|
|
463
|
+
table.setAttribute("style", block.style);
|
|
464
|
+
}
|
|
465
|
+
const tbody = document.createElement("tbody");
|
|
466
|
+
block.rows.forEach((row) => {
|
|
467
|
+
const tr = document.createElement("tr");
|
|
468
|
+
(row.cells || []).forEach((cell) => {
|
|
469
|
+
const node = document.createElement(cell.isHeader ? "th" : "td");
|
|
470
|
+
const rowSpan = Math.max(1, Math.round(cell.rowSpan || 1));
|
|
471
|
+
const colSpan = Math.max(1, Math.round(cell.colSpan || 1));
|
|
472
|
+
if (rowSpan > 1) {
|
|
473
|
+
node.rowSpan = rowSpan;
|
|
474
|
+
}
|
|
475
|
+
if (colSpan > 1) {
|
|
476
|
+
node.colSpan = colSpan;
|
|
477
|
+
}
|
|
478
|
+
if (cell.style) {
|
|
479
|
+
node.setAttribute("style", cell.style);
|
|
480
|
+
}
|
|
481
|
+
if (cell.textStyle?.color) {
|
|
482
|
+
node.style.color = cell.textStyle.color;
|
|
483
|
+
}
|
|
484
|
+
if (cell.textStyle?.fontFamily) {
|
|
485
|
+
node.style.fontFamily = cell.textStyle.fontFamily;
|
|
486
|
+
}
|
|
487
|
+
if (cell.textStyle?.fontSize !== undefined) {
|
|
488
|
+
node.style.fontSize = `${Math.round(cell.textStyle.fontSize)}px`;
|
|
489
|
+
}
|
|
490
|
+
if (cell.html) {
|
|
491
|
+
node.innerHTML = cell.html;
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
node.textContent = cell.text || "";
|
|
495
|
+
}
|
|
496
|
+
if (!node.textContent && !node.children.length) {
|
|
497
|
+
node.innerHTML = "<br>";
|
|
498
|
+
}
|
|
499
|
+
tr.append(node);
|
|
500
|
+
});
|
|
501
|
+
if (!tr.children.length) {
|
|
502
|
+
const td = document.createElement("td");
|
|
503
|
+
td.innerHTML = "<br>";
|
|
504
|
+
tr.append(td);
|
|
505
|
+
}
|
|
506
|
+
tbody.append(tr);
|
|
507
|
+
});
|
|
508
|
+
if (!tbody.children.length) {
|
|
509
|
+
const tr = document.createElement("tr");
|
|
510
|
+
const td = document.createElement("td");
|
|
511
|
+
td.innerHTML = "<br>";
|
|
512
|
+
tr.append(td);
|
|
513
|
+
tbody.append(tr);
|
|
514
|
+
}
|
|
515
|
+
table.append(tbody);
|
|
516
|
+
wrapper.append(table);
|
|
517
|
+
return wrapper;
|
|
518
|
+
}
|
|
288
519
|
createAnnotationBuckets(annotations) {
|
|
289
520
|
const highlightsByBlock = new Map();
|
|
290
521
|
const notesByBlock = new Map();
|
|
@@ -438,20 +669,13 @@ export class EBookPlayer {
|
|
|
438
669
|
return;
|
|
439
670
|
}
|
|
440
671
|
const range = selection.getRangeAt(0);
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
if (!startContainer || !endContainer || startContainer !== endContainer) {
|
|
672
|
+
const segments = this.collectSelectionSegments(selection, range);
|
|
673
|
+
if (!segments?.length) {
|
|
444
674
|
this.hideSelectionToolbar();
|
|
445
675
|
return;
|
|
446
676
|
}
|
|
447
|
-
const
|
|
448
|
-
if (!
|
|
449
|
-
this.hideSelectionToolbar();
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
const pageId = startContainer.dataset.pageId;
|
|
453
|
-
const blockId = startContainer.dataset.blockId;
|
|
454
|
-
if (!pageId || !blockId) {
|
|
677
|
+
const firstSegment = segments[0];
|
|
678
|
+
if (!firstSegment) {
|
|
455
679
|
this.hideSelectionToolbar();
|
|
456
680
|
return;
|
|
457
681
|
}
|
|
@@ -461,10 +685,11 @@ export class EBookPlayer {
|
|
|
461
685
|
return;
|
|
462
686
|
}
|
|
463
687
|
this.selectionDraft = {
|
|
464
|
-
pageId,
|
|
465
|
-
blockId,
|
|
466
|
-
range:
|
|
688
|
+
pageId: firstSegment.pageId,
|
|
689
|
+
blockId: firstSegment.blockId,
|
|
690
|
+
range: firstSegment.range,
|
|
467
691
|
text: selection.toString().trim(),
|
|
692
|
+
segments,
|
|
468
693
|
};
|
|
469
694
|
this.selectionToolbar.style.left = `${Math.round(rect.left + rect.width / 2)}px`;
|
|
470
695
|
this.selectionToolbar.style.top = `${Math.round(rect.top - 20)}px`;
|
|
@@ -501,6 +726,103 @@ export class EBookPlayer {
|
|
|
501
726
|
const end = endRange.toString().length;
|
|
502
727
|
return this.normalizeOffsetRange(start, end);
|
|
503
728
|
}
|
|
729
|
+
collectSelectionSegments(selection, range) {
|
|
730
|
+
const startContainer = this.resolveTextContainer(range.startContainer);
|
|
731
|
+
const endContainer = this.resolveTextContainer(range.endContainer);
|
|
732
|
+
if (!startContainer || !endContainer) {
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
const textContainers = Array.from(this.content.querySelectorAll(".hyepl-block-text"));
|
|
736
|
+
const startIndex = textContainers.indexOf(startContainer);
|
|
737
|
+
const endIndex = textContainers.indexOf(endContainer);
|
|
738
|
+
if (startIndex < 0 || endIndex < 0) {
|
|
739
|
+
return null;
|
|
740
|
+
}
|
|
741
|
+
const from = Math.min(startIndex, endIndex);
|
|
742
|
+
const to = Math.max(startIndex, endIndex);
|
|
743
|
+
const segments = [];
|
|
744
|
+
for (let index = from; index <= to; index += 1) {
|
|
745
|
+
const container = textContainers[index];
|
|
746
|
+
if (!container) {
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
const pageId = container.dataset.pageId;
|
|
750
|
+
const blockId = container.dataset.blockId;
|
|
751
|
+
if (!pageId || !blockId) {
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
let start = 0;
|
|
755
|
+
let end = this.getContainerTextLength(container);
|
|
756
|
+
if (container === startContainer) {
|
|
757
|
+
const boundaryOffset = this.getBoundaryOffsetInContainer(container, range.startContainer, range.startOffset);
|
|
758
|
+
if (boundaryOffset === null) {
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
start = boundaryOffset;
|
|
762
|
+
}
|
|
763
|
+
if (container === endContainer) {
|
|
764
|
+
const boundaryOffset = this.getBoundaryOffsetInContainer(container, range.endContainer, range.endOffset);
|
|
765
|
+
if (boundaryOffset === null) {
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
end = boundaryOffset;
|
|
769
|
+
}
|
|
770
|
+
const normalized = this.normalizeOffsetRange(start, end);
|
|
771
|
+
if (!normalized) {
|
|
772
|
+
continue;
|
|
773
|
+
}
|
|
774
|
+
const text = this.getRangeTextByOffsets(container, normalized);
|
|
775
|
+
segments.push({
|
|
776
|
+
pageId,
|
|
777
|
+
blockId,
|
|
778
|
+
range: normalized,
|
|
779
|
+
text,
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
if (!segments.length) {
|
|
783
|
+
const fallback = this.getSelectionOffsets(startContainer, selection);
|
|
784
|
+
if (!fallback) {
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
const pageId = startContainer.dataset.pageId;
|
|
788
|
+
const blockId = startContainer.dataset.blockId;
|
|
789
|
+
if (!pageId || !blockId) {
|
|
790
|
+
return null;
|
|
791
|
+
}
|
|
792
|
+
return [
|
|
793
|
+
{
|
|
794
|
+
pageId,
|
|
795
|
+
blockId,
|
|
796
|
+
range: fallback,
|
|
797
|
+
text: selection.toString().trim(),
|
|
798
|
+
},
|
|
799
|
+
];
|
|
800
|
+
}
|
|
801
|
+
return segments;
|
|
802
|
+
}
|
|
803
|
+
getContainerTextLength(container) {
|
|
804
|
+
const range = document.createRange();
|
|
805
|
+
range.selectNodeContents(container);
|
|
806
|
+
return range.toString().length;
|
|
807
|
+
}
|
|
808
|
+
getBoundaryOffsetInContainer(container, boundaryNode, boundaryOffset) {
|
|
809
|
+
if (!container.contains(boundaryNode) && container !== boundaryNode) {
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
const range = document.createRange();
|
|
813
|
+
range.selectNodeContents(container);
|
|
814
|
+
try {
|
|
815
|
+
range.setEnd(boundaryNode, boundaryOffset);
|
|
816
|
+
}
|
|
817
|
+
catch {
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
return range.toString().length;
|
|
821
|
+
}
|
|
822
|
+
getRangeTextByOffsets(container, offsets) {
|
|
823
|
+
const range = this.createRangeFromOffsets(container, offsets.start, offsets.end);
|
|
824
|
+
return range ? range.toString().trim() : "";
|
|
825
|
+
}
|
|
504
826
|
hideSelectionToolbar() {
|
|
505
827
|
this.selectionToolbar.classList.remove("show");
|
|
506
828
|
this.selectionDraft = null;
|
|
@@ -529,18 +851,28 @@ export class EBookPlayer {
|
|
|
529
851
|
if (!this.selectionDraft) {
|
|
530
852
|
return;
|
|
531
853
|
}
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
854
|
+
const segments = this.selectionDraft.segments && this.selectionDraft.segments.length
|
|
855
|
+
? this.selectionDraft.segments
|
|
856
|
+
: [
|
|
857
|
+
{
|
|
858
|
+
pageId: this.selectionDraft.pageId,
|
|
859
|
+
blockId: this.selectionDraft.blockId,
|
|
860
|
+
range: this.selectionDraft.range,
|
|
861
|
+
text: this.selectionDraft.text,
|
|
862
|
+
},
|
|
863
|
+
];
|
|
864
|
+
for (const segment of segments) {
|
|
865
|
+
const payload = {
|
|
866
|
+
pageId: segment.pageId,
|
|
867
|
+
blockId: segment.blockId,
|
|
868
|
+
range: segment.range,
|
|
869
|
+
...(segment.text ? { selectedText: segment.text } : {}),
|
|
870
|
+
...(this.selectionOptions.highlightColor
|
|
871
|
+
? { color: this.selectionOptions.highlightColor }
|
|
872
|
+
: {}),
|
|
873
|
+
};
|
|
874
|
+
await this.createHighlight(payload, "user");
|
|
875
|
+
}
|
|
544
876
|
this.clearSelection();
|
|
545
877
|
this.hideSelectionToolbar();
|
|
546
878
|
}
|
|
@@ -548,24 +880,34 @@ export class EBookPlayer {
|
|
|
548
880
|
if (!this.selectionDraft) {
|
|
549
881
|
return;
|
|
550
882
|
}
|
|
551
|
-
const defaultText =
|
|
883
|
+
const defaultText = "";
|
|
552
884
|
const content = this.promptTextWithLimit("请输入笔记内容", defaultText, this.inputLimits.noteMaxLength);
|
|
553
885
|
if (content === null) {
|
|
554
886
|
return;
|
|
555
887
|
}
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
888
|
+
const segments = this.selectionDraft.segments && this.selectionDraft.segments.length
|
|
889
|
+
? this.selectionDraft.segments
|
|
890
|
+
: [
|
|
891
|
+
{
|
|
892
|
+
pageId: this.selectionDraft.pageId,
|
|
893
|
+
blockId: this.selectionDraft.blockId,
|
|
894
|
+
range: this.selectionDraft.range,
|
|
895
|
+
text: this.selectionDraft.text,
|
|
896
|
+
},
|
|
897
|
+
];
|
|
898
|
+
for (const segment of segments) {
|
|
899
|
+
const payload = {
|
|
900
|
+
pageId: segment.pageId,
|
|
901
|
+
blockId: segment.blockId,
|
|
902
|
+
range: segment.range,
|
|
903
|
+
content,
|
|
904
|
+
...(segment.text ? { selectedText: segment.text } : {}),
|
|
905
|
+
...(this.selectionOptions.noteColor
|
|
906
|
+
? { color: this.selectionOptions.noteColor }
|
|
907
|
+
: {}),
|
|
908
|
+
};
|
|
909
|
+
await this.createNote(payload, "user");
|
|
910
|
+
}
|
|
569
911
|
this.clearSelection();
|
|
570
912
|
this.hideSelectionToolbar();
|
|
571
913
|
}
|
|
@@ -748,3 +1090,14 @@ function createRuntimeProvider(provider, getRuntimeDocument) {
|
|
|
748
1090
|
function cloneEbookDoc(doc) {
|
|
749
1091
|
return JSON.parse(JSON.stringify(doc));
|
|
750
1092
|
}
|
|
1093
|
+
function escapeHtml(value) {
|
|
1094
|
+
return value
|
|
1095
|
+
.replace(/&/g, "&")
|
|
1096
|
+
.replace(/</g, "<")
|
|
1097
|
+
.replace(/>/g, ">")
|
|
1098
|
+
.replace(/\"/g, """)
|
|
1099
|
+
.replace(/'/g, "'");
|
|
1100
|
+
}
|
|
1101
|
+
function escapeAttribute(value) {
|
|
1102
|
+
return escapeHtml(value);
|
|
1103
|
+
}
|
|
@@ -41,9 +41,13 @@ export interface EditorWorkbenchExtensionActionButton {
|
|
|
41
41
|
export interface EditorWorkbenchExtensionOptions {
|
|
42
42
|
actions?: EditorWorkbenchExtensionActionButton[];
|
|
43
43
|
}
|
|
44
|
+
export type EditorWorkbenchDebugLevel = "info" | "warn" | "error";
|
|
44
45
|
export interface EditorWorkbenchDebugOptions {
|
|
45
46
|
enabled?: boolean;
|
|
46
47
|
prefix?: string;
|
|
48
|
+
level?: EditorWorkbenchDebugLevel;
|
|
49
|
+
groups?: string[];
|
|
50
|
+
includeWordImportSource?: boolean;
|
|
47
51
|
}
|
|
48
52
|
export interface EditorWorkbenchPreviewAnnotationActions {
|
|
49
53
|
canDelete?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-workbench.d.ts","sourceRoot":"","sources":["../../../../../core/src/workbench/editor-workbench.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,QAAQ,EAKR,kBAAkB,EAWnB,MAAM,gBAAgB,CAAC;AA+LxB,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC5C,kBAAkB,CAAC,EAAE,uCAAuC,CAAC;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,gCAAgC,CAAC;IAC9C,SAAS,CAAC,EAAE,+BAA+B,CAAC;IAC5C,KAAK,CAAC,EAAE,OAAO,GAAG,2BAA2B,CAAC;IAC9C,MAAM,CAAC,EAAE,4BAA4B,CAAC;IACtC,UAAU,CAAC,EAAE,gCAAgC,CAAC;IAC9C,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,gCAAgC;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qCAAqC;IACpD,WAAW,EAAE,MAAM,QAAQ,CAAC;IAC5B,YAAY,EAAE,MAAM,OAAO,CAAC;IAC5B,OAAO,EAAE,MAAM,QAAQ,GAAG,SAAS,CAAC;IACpC,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,KAAK,IAAI,CAAC;IAC9C,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,oCAAoC;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CACR,OAAO,EAAE,qCAAqC,EAC9C,KAAK,EAAE,UAAU,KACd,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,CAAC,EAAE,oCAAoC,EAAE,CAAC;CAClD;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"editor-workbench.d.ts","sourceRoot":"","sources":["../../../../../core/src/workbench/editor-workbench.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,12 +4,12 @@ const WORKBENCH_STYLE_ID = "hy-ebook-workbench-style";
|
|
|
4
4
|
const WORKBENCH_STYLE_VERSION = "0.3.0";
|
|
5
5
|
const WORKBENCH_CSS = `
|
|
6
6
|
.hyewb-root{font-family:"Noto Sans SC","PingFang SC","Microsoft YaHei",sans-serif;color:#0f172a;background:#f8fbff;border:1px solid #d8e0ea;border-radius:12px;padding:12px;display:grid;gap:10px;position:relative;--hyewb-top-shield-height:0px}
|
|
7
|
-
.hyewb-root::before{content:"";position:absolute;left:0;right:0;top:0;height:var(--hyewb-top-shield-height);background:#f8fbff;z-index:
|
|
7
|
+
.hyewb-root::before{content:"";position:absolute;left:0;right:0;top:0;height:var(--hyewb-top-shield-height);background:#f8fbff;z-index:10030;pointer-events:none}
|
|
8
8
|
.hyewb-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}
|
|
9
9
|
.hyewb-title{font-size:14px;font-weight:600}
|
|
10
10
|
.hyewb-header-actions{margin-left:auto;display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
11
11
|
.hyewb-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
12
|
-
.hyewb-top-control{position:relative;z-index:
|
|
12
|
+
.hyewb-top-control{position:relative;z-index:10040;background:#f8fbff;isolation:isolate}
|
|
13
13
|
.hyewb-btn{border:1px solid #94a3b8;background:#fff;color:#0f172a;border-radius:8px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0;width:34px;height:34px;flex:0 0 auto}
|
|
14
14
|
.hyewb-btn.hyewb-btn-text{width:auto;min-width:96px;padding:0 12px}
|
|
15
15
|
.hyewb-header-action-btn{height:34px}
|
|
@@ -33,7 +33,7 @@ const WORKBENCH_CSS = `
|
|
|
33
33
|
.hyewb-preview-layout.with-annotation-panel{grid-template-columns:minmax(0,1fr) 300px}
|
|
34
34
|
.hyewb-canvas{position:relative;background:#fff;border:1px solid #d9e3ee;border-radius:8px;min-height:420px;padding:20px 24px;box-shadow:0 6px 16px rgba(15,23,42,.08);margin:16px auto;max-width:100%;box-sizing:border-box;}
|
|
35
35
|
.hyewb-editor{min-height:360px;outline:none;line-height:1.7;font-size:16px;color:#1e293b}
|
|
36
|
-
.hyewb-float{position:fixed;z-index:
|
|
36
|
+
.hyewb-float{position:fixed;z-index:10070;display:none;align-items:center;gap:6px;padding:6px 8px;border-radius:10px;border:1px solid #0f172a;background:rgba(15,23,42,.96);box-shadow:0 10px 24px rgba(15,23,42,.22)}
|
|
37
37
|
.hyewb-float.show{display:inline-flex}
|
|
38
38
|
.hyewb-float .hyewb-btn{border-color:#334155;background:#1e293b;color:#f8fafc;width:30px;height:30px}
|
|
39
39
|
.hyewb-float .hyewb-btn:hover{background:#334155}
|
|
@@ -138,7 +138,7 @@ const WORKBENCH_CSS = `
|
|
|
138
138
|
.hyewb-media-handle[data-handle="w"]{left:-6px;top:calc(50% - 5px);cursor:ew-resize}
|
|
139
139
|
.hyewb-media-list{margin:0;padding-left:18px;color:#334155;font-size:13px;display:grid;gap:4px}
|
|
140
140
|
.hyewb-status{font-size:12px;color:#475569}
|
|
141
|
-
.hyewb-upload-backdrop{position:fixed;inset:0;display:none;align-items:center;justify-content:center;background:rgba(15,23,42,.45);z-index:
|
|
141
|
+
.hyewb-upload-backdrop{position:fixed;inset:0;display:none;align-items:center;justify-content:center;background:rgba(15,23,42,.45);z-index:10100;padding:16px}
|
|
142
142
|
.hyewb-upload-backdrop.show{display:flex}
|
|
143
143
|
.hyewb-upload-dialog{position:relative;width:min(520px,100%);background:#fff;border:1px solid #cbd5e1;border-radius:12px;padding:14px;display:grid;gap:10px;box-shadow:0 16px 34px rgba(15,23,42,.28)}
|
|
144
144
|
.hyewb-upload-title{font-size:14px;font-weight:600;color:#0f172a}
|
|
@@ -147,7 +147,7 @@ const WORKBENCH_CSS = `
|
|
|
147
147
|
.hyewb-upload-progress{height:8px;background:#e2e8f0;border-radius:999px;overflow:hidden}
|
|
148
148
|
.hyewb-upload-progress > span{display:block;height:100%;width:0;background:#0b7285;transition:width .18s ease}
|
|
149
149
|
.hyewb-upload-error{min-height:18px;font-size:12px;color:#b91c1c;margin:0}
|
|
150
|
-
.hyewb-preview-note-backdrop{position:fixed;inset:0;display:none;align-items:center;justify-content:center;background:rgba(15,23,42,.45);z-index:
|
|
150
|
+
.hyewb-preview-note-backdrop{position:fixed;inset:0;display:none;align-items:center;justify-content:center;background:rgba(15,23,42,.45);z-index:10110;padding:16px}
|
|
151
151
|
.hyewb-preview-note-backdrop.show{display:flex}
|
|
152
152
|
.hyewb-preview-note-dialog{width:min(520px,100%);background:#fff;border:1px solid #cbd5e1;border-radius:12px;padding:14px;display:grid;gap:10px;box-shadow:0 16px 34px rgba(15,23,42,.28)}
|
|
153
153
|
.hyewb-preview-note-title{margin:0;font-size:14px;font-weight:600;color:#0f172a}
|
|
@@ -171,7 +171,7 @@ const WORKBENCH_CSS = `
|
|
|
171
171
|
.hyewb-preview-annotation-item:hover .hyewb-preview-annotation-delete{opacity:1;pointer-events:auto}
|
|
172
172
|
.hyewb-preview-annotation-delete svg{width:14px;height:14px}
|
|
173
173
|
.hyewb-preview-annotation-empty{margin:0;color:#64748b;font-size:13px}
|
|
174
|
-
.hyewb-preview-selection-toolbar{position:fixed;z-index:
|
|
174
|
+
.hyewb-preview-selection-toolbar{position:fixed;z-index:10070;display:none;align-items:center;gap:8px;padding:6px 8px;border-radius:10px;border:1px solid #0f172a;background:rgba(15,23,42,.96);box-shadow:0 10px 24px rgba(15,23,42,.22);transform:translate(-50%,-100%)}
|
|
175
175
|
.hyewb-preview-selection-toolbar.show{display:inline-flex}
|
|
176
176
|
.hyewb-preview-selection-btn{width:32px;height:32px;padding:0;display:inline-flex;align-items:center;justify-content:center;border:1px solid #334155;background:#1e293b;color:#f8fafc;border-radius:8px;cursor:pointer}
|
|
177
177
|
.hyewb-preview-selection-btn:hover{background:#334155}
|
|
@@ -572,11 +572,11 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
572
572
|
bgColorInput.append(bgColorChip);
|
|
573
573
|
const lineHeightSelect = document.createElement("select");
|
|
574
574
|
lineHeightSelect.className = "hyewb-select";
|
|
575
|
-
["1.
|
|
575
|
+
["1.0", "1.15", "1.5", "2.0", "2.5", "3.0"].forEach((value) => {
|
|
576
576
|
const optionNode = document.createElement("option");
|
|
577
577
|
optionNode.value = value;
|
|
578
578
|
optionNode.textContent = value;
|
|
579
|
-
if (value === "1.
|
|
579
|
+
if (value === "1.5") {
|
|
580
580
|
optionNode.selected = true;
|
|
581
581
|
}
|
|
582
582
|
lineHeightSelect.append(optionNode);
|
|
@@ -897,20 +897,66 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
897
897
|
const status = document.createElement("p");
|
|
898
898
|
status.className = "hyewb-status";
|
|
899
899
|
status.textContent = "已加载默认编辑器能力";
|
|
900
|
+
const debugConfig = typeof options.debug === "object" && options.debug !== null
|
|
901
|
+
? options.debug
|
|
902
|
+
: undefined;
|
|
900
903
|
const debugEnabled = options.debug === true ||
|
|
901
|
-
(
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
const
|
|
904
|
+
Boolean(debugConfig && debugConfig.enabled !== false);
|
|
905
|
+
const debugPrefix = debugConfig?.prefix || "[hyebook:workbench]";
|
|
906
|
+
const normalizeDebugLevel = (level) => {
|
|
907
|
+
if (level === "warn" || level === "error") {
|
|
908
|
+
return level;
|
|
909
|
+
}
|
|
910
|
+
return "info";
|
|
911
|
+
};
|
|
912
|
+
const debugLevel = normalizeDebugLevel(debugConfig?.level);
|
|
913
|
+
const debugLevelRank = {
|
|
914
|
+
info: 1,
|
|
915
|
+
warn: 2,
|
|
916
|
+
error: 3,
|
|
917
|
+
};
|
|
918
|
+
const debugGroups = Array.isArray(debugConfig?.groups) && debugConfig.groups.length
|
|
919
|
+
? new Set(debugConfig.groups
|
|
920
|
+
.map((group) => String(group || "").trim())
|
|
921
|
+
.filter(Boolean))
|
|
922
|
+
: null;
|
|
923
|
+
const shouldLogDebugGroup = (group) => {
|
|
924
|
+
if (!debugGroups || !debugGroups.size || !group) {
|
|
925
|
+
return true;
|
|
926
|
+
}
|
|
927
|
+
return debugGroups.has(group);
|
|
928
|
+
};
|
|
929
|
+
const debugLog = (message, logOptions) => {
|
|
910
930
|
if (!debugEnabled) {
|
|
911
931
|
return;
|
|
912
932
|
}
|
|
913
|
-
|
|
933
|
+
const level = normalizeDebugLevel(logOptions?.level);
|
|
934
|
+
if (debugLevelRank[level] < debugLevelRank[debugLevel]) {
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
if (!shouldLogDebugGroup(logOptions?.group)) {
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
const scopedPrefix = logOptions?.group
|
|
941
|
+
? `${debugPrefix}:${logOptions.group}`
|
|
942
|
+
: debugPrefix;
|
|
943
|
+
const messageText = `${scopedPrefix} ${message}`;
|
|
944
|
+
if (logOptions &&
|
|
945
|
+
Object.prototype.hasOwnProperty.call(logOptions, "payload")) {
|
|
946
|
+
console[level](messageText, logOptions.payload);
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
console[level](messageText);
|
|
950
|
+
};
|
|
951
|
+
const wordImportSourceLoggingEnabled = debugEnabled && (debugConfig?.includeWordImportSource ?? true);
|
|
952
|
+
const debugWordImport = (message, logOptions) => {
|
|
953
|
+
if (!wordImportSourceLoggingEnabled) {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
debugLog(message, {
|
|
957
|
+
...logOptions,
|
|
958
|
+
group: logOptions?.group || "word-import",
|
|
959
|
+
});
|
|
914
960
|
};
|
|
915
961
|
let lastDebugStatusMessage = "";
|
|
916
962
|
const flushDebugStatus = () => {
|
|
@@ -919,7 +965,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
919
965
|
return;
|
|
920
966
|
}
|
|
921
967
|
lastDebugStatusMessage = nextMessage;
|
|
922
|
-
debugLog(nextMessage);
|
|
968
|
+
debugLog(nextMessage, { group: "status" });
|
|
923
969
|
};
|
|
924
970
|
const statusObserver = debugEnabled && typeof MutationObserver !== "undefined"
|
|
925
971
|
? new MutationObserver(() => {
|
|
@@ -1356,28 +1402,77 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
1356
1402
|
}
|
|
1357
1403
|
};
|
|
1358
1404
|
const importDocxFile = async (file) => {
|
|
1405
|
+
const maxSize = options.importDocx?.maxSizeBytes;
|
|
1406
|
+
debugWordImport("收到 Word 导入请求", {
|
|
1407
|
+
group: "word-import-file",
|
|
1408
|
+
payload: {
|
|
1409
|
+
fileName: file.name,
|
|
1410
|
+
mimeType: file.type || "",
|
|
1411
|
+
sizeBytes: file.size,
|
|
1412
|
+
maxSizeBytes: maxSize ?? null,
|
|
1413
|
+
},
|
|
1414
|
+
});
|
|
1359
1415
|
const isDocx = isDocxMime(file.type) || file.name.toLowerCase().endsWith(".docx");
|
|
1360
1416
|
if (!isDocx) {
|
|
1417
|
+
debugWordImport("文件校验失败:非 docx", {
|
|
1418
|
+
level: "warn",
|
|
1419
|
+
group: "word-import-file",
|
|
1420
|
+
});
|
|
1361
1421
|
status.textContent = "仅支持导入 .docx 文件";
|
|
1362
1422
|
return;
|
|
1363
1423
|
}
|
|
1364
|
-
const maxSize = options.importDocx?.maxSizeBytes;
|
|
1365
1424
|
if (maxSize && file.size > maxSize) {
|
|
1425
|
+
debugWordImport("文件校验失败:超过大小限制", {
|
|
1426
|
+
level: "warn",
|
|
1427
|
+
group: "word-import-file",
|
|
1428
|
+
payload: {
|
|
1429
|
+
sizeBytes: file.size,
|
|
1430
|
+
maxSizeBytes: maxSize,
|
|
1431
|
+
},
|
|
1432
|
+
});
|
|
1366
1433
|
status.textContent = `Word 文件大小不能超过 ${Math.round(maxSize / 1024 / 1024)}MB`;
|
|
1367
1434
|
return;
|
|
1368
1435
|
}
|
|
1369
1436
|
status.textContent = `正在导入 Word:${file.name}`;
|
|
1370
1437
|
let imageUploadIndex = 0;
|
|
1438
|
+
let importRoute = "ooxml";
|
|
1439
|
+
const xmlSourceInfo = createDocxXmlParseDebugInfo();
|
|
1371
1440
|
try {
|
|
1372
1441
|
const mammothNamespace = await import("mammoth");
|
|
1373
1442
|
const mammothModule = resolveMammothModule(mammothNamespace);
|
|
1374
1443
|
const arrayBuffer = await file.arrayBuffer();
|
|
1375
|
-
|
|
1444
|
+
debugWordImport("文件已读取为 ArrayBuffer", {
|
|
1445
|
+
group: "word-import-file",
|
|
1446
|
+
payload: {
|
|
1447
|
+
byteLength: arrayBuffer.byteLength,
|
|
1448
|
+
},
|
|
1449
|
+
});
|
|
1450
|
+
const xmlPreferredFlowBlocks = await parseDocxFlowBlocksFromXml(arrayBuffer, resolveDocxImportMaxFlowBlockWidth(state.doc.settings.page, paperWidth), xmlSourceInfo);
|
|
1451
|
+
debugWordImport("OOXML 源信息摘要", {
|
|
1452
|
+
group: "word-import-xml",
|
|
1453
|
+
payload: xmlSourceInfo,
|
|
1454
|
+
});
|
|
1376
1455
|
if (xmlPreferredFlowBlocks?.length) {
|
|
1456
|
+
debugWordImport("命中 OOXML 高保真解析路径", {
|
|
1457
|
+
group: "word-import-result",
|
|
1458
|
+
payload: {
|
|
1459
|
+
route: "ooxml",
|
|
1460
|
+
flowBlockCount: xmlPreferredFlowBlocks.length,
|
|
1461
|
+
paragraphCount: xmlSourceInfo.paragraphCount,
|
|
1462
|
+
tableCount: xmlSourceInfo.tableCount,
|
|
1463
|
+
},
|
|
1464
|
+
});
|
|
1377
1465
|
syncEditorToDoc();
|
|
1378
1466
|
const nextDoc = clone(state.doc);
|
|
1379
1467
|
const page = getCurrentPage(nextDoc, state.pageIndex);
|
|
1380
1468
|
if (!page) {
|
|
1469
|
+
debugWordImport("导入失败:当前页不存在", {
|
|
1470
|
+
level: "error",
|
|
1471
|
+
group: "word-import-result",
|
|
1472
|
+
payload: {
|
|
1473
|
+
route: "ooxml",
|
|
1474
|
+
},
|
|
1475
|
+
});
|
|
1381
1476
|
status.textContent = "当前页面不存在,导入失败";
|
|
1382
1477
|
return;
|
|
1383
1478
|
}
|
|
@@ -1385,9 +1480,31 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
1385
1480
|
nextDoc.meta.updatedAt = new Date().toISOString();
|
|
1386
1481
|
editorRenderKey = "";
|
|
1387
1482
|
updateStateDoc(nextDoc, "Word 导入成功(高保真文本样式)");
|
|
1483
|
+
debugWordImport("Word 导入成功", {
|
|
1484
|
+
group: "word-import-result",
|
|
1485
|
+
payload: {
|
|
1486
|
+
route: "ooxml",
|
|
1487
|
+
flowBlockCount: xmlPreferredFlowBlocks.length,
|
|
1488
|
+
},
|
|
1489
|
+
});
|
|
1388
1490
|
return;
|
|
1389
1491
|
}
|
|
1492
|
+
importRoute = "mammoth";
|
|
1493
|
+
debugWordImport("OOXML 结果为空,回退到 Mammoth 路径", {
|
|
1494
|
+
level: "warn",
|
|
1495
|
+
group: "word-import-xml",
|
|
1496
|
+
payload: {
|
|
1497
|
+
reason: xmlSourceInfo.error || "OOXML parser returned empty result",
|
|
1498
|
+
},
|
|
1499
|
+
});
|
|
1390
1500
|
const defaultTextStyle = await extractDocxDefaultTextStyle(arrayBuffer);
|
|
1501
|
+
debugWordImport("默认文本样式提取结果", {
|
|
1502
|
+
group: "word-import-mammoth",
|
|
1503
|
+
payload: {
|
|
1504
|
+
hasDefaultTextStyle: Boolean(defaultTextStyle),
|
|
1505
|
+
defaultTextStyle: defaultTextStyle || null,
|
|
1506
|
+
},
|
|
1507
|
+
});
|
|
1391
1508
|
const result = await mammothModule.convertToHtml({ arrayBuffer }, {
|
|
1392
1509
|
convertImage: mammothModule.images.imgElement(async (image) => {
|
|
1393
1510
|
const imageUploader = ensureMediaUploader("image");
|
|
@@ -1400,23 +1517,72 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
1400
1517
|
const contentType = normalizeDocxImageMime(image.contentType) || "image/png";
|
|
1401
1518
|
const extension = fileExtensionByMime(contentType);
|
|
1402
1519
|
const imageFile = base64ToFile(base64, contentType, `docx-image-${Date.now()}-${imageUploadIndex}.${extension}`);
|
|
1520
|
+
debugWordImport("开始上传内嵌图片", {
|
|
1521
|
+
group: "word-import-mammoth",
|
|
1522
|
+
payload: {
|
|
1523
|
+
index: imageUploadIndex,
|
|
1524
|
+
contentType,
|
|
1525
|
+
fileName: imageFile.name,
|
|
1526
|
+
sizeBytes: imageFile.size,
|
|
1527
|
+
},
|
|
1528
|
+
});
|
|
1403
1529
|
const uploadResult = await uploadMediaFile(imageFile, "image", (percent) => {
|
|
1404
1530
|
status.textContent = `第 ${imageUploadIndex} 张图片上传中:${formatUploadProgress(percent)}%`;
|
|
1405
1531
|
});
|
|
1406
1532
|
if (!uploadResult?.url) {
|
|
1407
1533
|
throw new Error(`第 ${imageUploadIndex} 张图片上传成功但未返回可用地址`);
|
|
1408
1534
|
}
|
|
1535
|
+
debugWordImport("内嵌图片上传完成", {
|
|
1536
|
+
group: "word-import-mammoth",
|
|
1537
|
+
payload: {
|
|
1538
|
+
index: imageUploadIndex,
|
|
1539
|
+
url: uploadResult.url,
|
|
1540
|
+
},
|
|
1541
|
+
});
|
|
1409
1542
|
return {
|
|
1410
1543
|
src: uploadResult.url,
|
|
1411
1544
|
alt: uploadResult.alt || imageFile.name,
|
|
1412
1545
|
};
|
|
1413
1546
|
}),
|
|
1414
1547
|
});
|
|
1548
|
+
const mammothMessages = result.messages || [];
|
|
1549
|
+
if (mammothMessages.length) {
|
|
1550
|
+
debugWordImport("Mammoth 兼容性提示", {
|
|
1551
|
+
level: "warn",
|
|
1552
|
+
group: "word-import-mammoth",
|
|
1553
|
+
payload: mammothMessages.map((item, index) => ({
|
|
1554
|
+
index: index + 1,
|
|
1555
|
+
type: item.type,
|
|
1556
|
+
message: item.message,
|
|
1557
|
+
})),
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
else {
|
|
1561
|
+
debugWordImport("Mammoth 未返回兼容性提示", {
|
|
1562
|
+
group: "word-import-mammoth",
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1415
1565
|
const flowBlocks = parseRichHTMLToFlowBlocks(result.value || "", defaultTextStyle);
|
|
1566
|
+
debugWordImport("Mammoth HTML 已转换为 FlowBlocks", {
|
|
1567
|
+
group: "word-import-result",
|
|
1568
|
+
payload: {
|
|
1569
|
+
route: importRoute,
|
|
1570
|
+
flowBlockCount: flowBlocks.length,
|
|
1571
|
+
compatibilityMessageCount: mammothMessages.length,
|
|
1572
|
+
embeddedImageCount: imageUploadIndex,
|
|
1573
|
+
},
|
|
1574
|
+
});
|
|
1416
1575
|
syncEditorToDoc();
|
|
1417
1576
|
const nextDoc = clone(state.doc);
|
|
1418
1577
|
const page = getCurrentPage(nextDoc, state.pageIndex);
|
|
1419
1578
|
if (!page) {
|
|
1579
|
+
debugWordImport("导入失败:当前页不存在", {
|
|
1580
|
+
level: "error",
|
|
1581
|
+
group: "word-import-result",
|
|
1582
|
+
payload: {
|
|
1583
|
+
route: importRoute,
|
|
1584
|
+
},
|
|
1585
|
+
});
|
|
1420
1586
|
status.textContent = "当前页面不存在,导入失败";
|
|
1421
1587
|
return;
|
|
1422
1588
|
}
|
|
@@ -1424,11 +1590,31 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
1424
1590
|
nextDoc.meta.updatedAt = new Date().toISOString();
|
|
1425
1591
|
editorRenderKey = "";
|
|
1426
1592
|
updateStateDoc(nextDoc, "Word 导入成功");
|
|
1427
|
-
if (
|
|
1428
|
-
status.textContent = `Word 导入成功(${
|
|
1429
|
-
}
|
|
1593
|
+
if (mammothMessages.length) {
|
|
1594
|
+
status.textContent = `Word 导入成功(${mammothMessages.length} 条兼容性提示)`;
|
|
1595
|
+
}
|
|
1596
|
+
debugWordImport("Word 导入成功", {
|
|
1597
|
+
group: "word-import-result",
|
|
1598
|
+
payload: {
|
|
1599
|
+
route: importRoute,
|
|
1600
|
+
flowBlockCount: flowBlocks.length,
|
|
1601
|
+
compatibilityMessageCount: mammothMessages.length,
|
|
1602
|
+
embeddedImageCount: imageUploadIndex,
|
|
1603
|
+
},
|
|
1604
|
+
});
|
|
1430
1605
|
}
|
|
1431
1606
|
catch (error) {
|
|
1607
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1608
|
+
debugWordImport("Word 导入失败", {
|
|
1609
|
+
level: "error",
|
|
1610
|
+
group: "word-import-result",
|
|
1611
|
+
payload: {
|
|
1612
|
+
route: importRoute,
|
|
1613
|
+
embeddedImageCount: imageUploadIndex,
|
|
1614
|
+
error: errorMessage,
|
|
1615
|
+
xmlSourceInfo,
|
|
1616
|
+
},
|
|
1617
|
+
});
|
|
1432
1618
|
status.textContent =
|
|
1433
1619
|
error instanceof Error
|
|
1434
1620
|
? `Word 导入失败:${error.message}`
|
|
@@ -5716,25 +5902,89 @@ function resolveMammothModule(namespace) {
|
|
|
5716
5902
|
const candidate = namespace?.default ?? namespace;
|
|
5717
5903
|
return candidate;
|
|
5718
5904
|
}
|
|
5719
|
-
|
|
5905
|
+
function createDocxXmlParseDebugInfo() {
|
|
5906
|
+
return {
|
|
5907
|
+
archiveLoaded: false,
|
|
5908
|
+
hasDocumentXml: false,
|
|
5909
|
+
hasStylesXml: false,
|
|
5910
|
+
hasThemeXml: false,
|
|
5911
|
+
paragraphCount: 0,
|
|
5912
|
+
tableCount: 0,
|
|
5913
|
+
blockCount: 0,
|
|
5914
|
+
};
|
|
5915
|
+
}
|
|
5916
|
+
function countDocxBodyNodeKinds(documentXml) {
|
|
5917
|
+
const parser = new DOMParser();
|
|
5918
|
+
const documentDoc = parser.parseFromString(documentXml, "application/xml");
|
|
5919
|
+
const body = findDescendantByLocalName(documentDoc.documentElement, "body");
|
|
5920
|
+
if (!body) {
|
|
5921
|
+
return {
|
|
5922
|
+
paragraphCount: 0,
|
|
5923
|
+
tableCount: 0,
|
|
5924
|
+
};
|
|
5925
|
+
}
|
|
5926
|
+
let paragraphCount = 0;
|
|
5927
|
+
let tableCount = 0;
|
|
5928
|
+
for (const child of Array.from(body.children)) {
|
|
5929
|
+
const name = xmlLocalName(child);
|
|
5930
|
+
if (name === "p") {
|
|
5931
|
+
paragraphCount += 1;
|
|
5932
|
+
continue;
|
|
5933
|
+
}
|
|
5934
|
+
if (name === "tbl") {
|
|
5935
|
+
tableCount += 1;
|
|
5936
|
+
}
|
|
5937
|
+
}
|
|
5938
|
+
return {
|
|
5939
|
+
paragraphCount,
|
|
5940
|
+
tableCount,
|
|
5941
|
+
};
|
|
5942
|
+
}
|
|
5943
|
+
async function parseDocxFlowBlocksFromXml(arrayBuffer, maxFlowBlockWidth, debugInfo) {
|
|
5720
5944
|
try {
|
|
5721
5945
|
const archive = await loadDocxArchive(arrayBuffer);
|
|
5722
5946
|
if (!archive) {
|
|
5947
|
+
if (debugInfo) {
|
|
5948
|
+
debugInfo.error = "DOCX archive load failed";
|
|
5949
|
+
}
|
|
5723
5950
|
return undefined;
|
|
5724
5951
|
}
|
|
5725
|
-
const
|
|
5726
|
-
|
|
5727
|
-
|
|
5952
|
+
const documentEntry = archive.file("word/document.xml");
|
|
5953
|
+
const stylesEntry = archive.file("word/styles.xml");
|
|
5954
|
+
const themeEntry = archive.file("word/theme/theme1.xml");
|
|
5955
|
+
if (debugInfo) {
|
|
5956
|
+
debugInfo.archiveLoaded = true;
|
|
5957
|
+
debugInfo.hasDocumentXml = Boolean(documentEntry);
|
|
5958
|
+
debugInfo.hasStylesXml = Boolean(stylesEntry);
|
|
5959
|
+
debugInfo.hasThemeXml = Boolean(themeEntry);
|
|
5960
|
+
}
|
|
5961
|
+
const documentXml = await documentEntry?.async("string");
|
|
5728
5962
|
if (!documentXml) {
|
|
5963
|
+
if (debugInfo) {
|
|
5964
|
+
debugInfo.error = "word/document.xml missing or empty";
|
|
5965
|
+
}
|
|
5729
5966
|
return undefined;
|
|
5730
5967
|
}
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
.
|
|
5734
|
-
|
|
5735
|
-
|
|
5968
|
+
if (debugInfo) {
|
|
5969
|
+
const counts = countDocxBodyNodeKinds(documentXml);
|
|
5970
|
+
debugInfo.paragraphCount = counts.paragraphCount;
|
|
5971
|
+
debugInfo.tableCount = counts.tableCount;
|
|
5972
|
+
}
|
|
5973
|
+
const stylesXml = await stylesEntry?.async("string");
|
|
5974
|
+
const themeXml = await themeEntry?.async("string");
|
|
5975
|
+
const blocks = parseDocxBodyToFlowBlocks(documentXml, stylesXml, themeXml, maxFlowBlockWidth);
|
|
5976
|
+
if (debugInfo) {
|
|
5977
|
+
debugInfo.blockCount = blocks?.length || 0;
|
|
5978
|
+
if (!blocks?.length && !debugInfo.error) {
|
|
5979
|
+
debugInfo.error = "OOXML parser returned no flow blocks";
|
|
5980
|
+
}
|
|
5981
|
+
}
|
|
5982
|
+
return blocks;
|
|
5736
5983
|
}
|
|
5737
|
-
catch {
|
|
5984
|
+
catch (error) {
|
|
5985
|
+
if (debugInfo) {
|
|
5986
|
+
debugInfo.error = error instanceof Error ? error.message : String(error);
|
|
5987
|
+
}
|
|
5738
5988
|
return undefined;
|
|
5739
5989
|
}
|
|
5740
5990
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyebook/vue3-adapter",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.3",
|
|
4
4
|
"description": "Vue3 adapter for hy-ebook core",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dist"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@hyebook/core": "^2.3.
|
|
20
|
+
"@hyebook/core": "^2.3.3"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "tsc -p tsconfig.json",
|