@hyebook/vue3-adapter 0.2.1 → 0.2.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.
|
@@ -9,12 +9,22 @@ export interface EditorWorkbenchFeatures {
|
|
|
9
9
|
export interface EditorWorkbenchOptions {
|
|
10
10
|
initialDoc?: EbookDoc;
|
|
11
11
|
features?: Partial<EditorWorkbenchFeatures>;
|
|
12
|
+
previewAnnotations?: EditorWorkbenchPreviewAnnotationOptions;
|
|
12
13
|
title?: string;
|
|
13
14
|
pageWidth?: number;
|
|
14
15
|
upload?: EditorWorkbenchUploadOptions;
|
|
15
16
|
importDocx?: EditorWorkbenchDocxImportOptions;
|
|
16
17
|
onDocumentChange?: (doc: EbookDoc) => void;
|
|
17
18
|
}
|
|
19
|
+
export interface EditorWorkbenchPreviewAnnotationActions {
|
|
20
|
+
canDelete?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface EditorWorkbenchPreviewAnnotationOptions {
|
|
23
|
+
showAnnotationList?: boolean;
|
|
24
|
+
enablePreviewSelectionToolbar?: boolean;
|
|
25
|
+
annotationListDefaultTab?: "highlights" | "notes";
|
|
26
|
+
annotationActions?: EditorWorkbenchPreviewAnnotationActions;
|
|
27
|
+
}
|
|
18
28
|
export interface EditorWorkbenchDocxImportOptions {
|
|
19
29
|
maxSizeBytes?: number;
|
|
20
30
|
}
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"editor-workbench.d.ts","sourceRoot":"","sources":["../../../../../core/src/workbench/editor-workbench.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { addPageCommand } from "../editor/commands";
|
|
2
2
|
import { EditorEngine } from "../editor/engine";
|
|
3
3
|
const WORKBENCH_STYLE_ID = "hy-ebook-workbench-style";
|
|
4
|
+
const WORKBENCH_STYLE_VERSION = "0.2.3";
|
|
4
5
|
const WORKBENCH_CSS = `
|
|
5
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}
|
|
6
7
|
.hyewb-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}
|
|
@@ -23,7 +24,9 @@ const WORKBENCH_CSS = `
|
|
|
23
24
|
.hyewb-field-icon svg{width:14px;height:14px;stroke-width:2}
|
|
24
25
|
.hyewb-field-with-icon .hyewb-select,.hyewb-field-with-icon .hyewb-number{padding-left:30px}
|
|
25
26
|
.hyewb-shell{border:1px dashed #b8c3d1;border-radius:10px;background:#eef4ff;padding:10px;overflow-x:auto;overflow-y:auto;overscroll-behavior:auto;-webkit-overflow-scrolling:touch}
|
|
26
|
-
.hyewb-
|
|
27
|
+
.hyewb-preview-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;align-items:start}
|
|
28
|
+
.hyewb-preview-layout.with-annotation-panel{grid-template-columns:minmax(0,1fr) 300px}
|
|
29
|
+
.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:0 auto;max-width:100%;box-sizing:border-box}
|
|
27
30
|
.hyewb-editor{min-height:360px;outline:none;line-height:1.7;font-size:16px;color:#1e293b}
|
|
28
31
|
.hyewb-float{position:fixed;z-index:9999;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)}
|
|
29
32
|
.hyewb-float.show{display:inline-flex}
|
|
@@ -139,6 +142,29 @@ const WORKBENCH_CSS = `
|
|
|
139
142
|
.hyewb-upload-progress{height:8px;background:#e2e8f0;border-radius:999px;overflow:hidden}
|
|
140
143
|
.hyewb-upload-progress > span{display:block;height:100%;width:0;background:#0b7285;transition:width .18s ease}
|
|
141
144
|
.hyewb-upload-error{min-height:18px;font-size:12px;color:#b91c1c;margin:0}
|
|
145
|
+
.hyewb-preview-highlight-mark{background:var(--hyewb-highlight-color,#fff59d);color:inherit;padding:0 .08em;border-radius:.2em}
|
|
146
|
+
.hyewb-preview-note-mark{background:rgba(14,116,144,.14);border-bottom:2px solid #0e7490;color:inherit;padding:0 .04em;border-radius:.2em}
|
|
147
|
+
.hyewb-preview-annotation-panel{display:none;align-content:start;gap:10px;border:1px solid #d8e0ea;border-radius:10px;background:#ffffff;padding:12px;max-height:100%;overflow:auto}
|
|
148
|
+
.hyewb-preview-annotation-title{margin:0;font-size:14px}
|
|
149
|
+
.hyewb-preview-annotation-tabs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
|
|
150
|
+
.hyewb-preview-annotation-tab{width:auto;min-width:0;height:32px;padding:0 12px;font-size:13px;border:1px solid #cbd5e1;border-radius:8px;background:#fff;color:#0f172a;cursor:pointer}
|
|
151
|
+
.hyewb-preview-annotation-tab.active{color:#ffffff;background:#0b7285;border-color:#0b7285}
|
|
152
|
+
.hyewb-preview-annotation-list{margin:0;padding:0;list-style:none;display:grid;gap:8px}
|
|
153
|
+
.hyewb-preview-annotation-item{width:100%;text-align:left;display:grid;gap:4px;padding:8px 36px 8px 8px;border-radius:8px;border:1px solid #dce5ef;background:#f8fafc;position:relative;cursor:pointer}
|
|
154
|
+
.hyewb-preview-annotation-item:hover{background:#eef6ff;border-color:#b9d7f4}
|
|
155
|
+
.hyewb-preview-annotation-item-title{font-size:12px;color:#0f766e}
|
|
156
|
+
.hyewb-preview-annotation-item-body{font-size:13px;color:#1e293b;line-height:1.5}
|
|
157
|
+
.hyewb-preview-annotation-delete{position:absolute;right:8px;top:8px;border-radius:8px;border:1px solid #f1b3b3;background:#fff5f5;color:#b42318;width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s ease;cursor:pointer;padding:0}
|
|
158
|
+
.hyewb-preview-annotation-item:hover .hyewb-preview-annotation-delete{opacity:1;pointer-events:auto}
|
|
159
|
+
.hyewb-preview-annotation-delete svg{width:14px;height:14px}
|
|
160
|
+
.hyewb-preview-annotation-empty{margin:0;color:#64748b;font-size:13px}
|
|
161
|
+
.hyewb-preview-selection-toolbar{position:fixed;z-index:10060;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%)}
|
|
162
|
+
.hyewb-preview-selection-toolbar.show{display:inline-flex}
|
|
163
|
+
.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}
|
|
164
|
+
.hyewb-preview-selection-btn:hover{background:#334155}
|
|
165
|
+
.hyewb-preview-selection-btn svg{width:16px;height:16px}
|
|
166
|
+
.hyewb-preview-annotation-flash{animation:hyewb-preview-annotation-pulse .9s ease}
|
|
167
|
+
@keyframes hyewb-preview-annotation-pulse{0%{box-shadow:0 0 0 0 rgba(14,116,144,.4)}100%{box-shadow:0 0 0 12px rgba(14,116,144,0)}}
|
|
142
168
|
.hyewb-root:fullscreen .hyewb-editor,.hyewb-root:fullscreen .hyewb-preview{min-height:1000px}
|
|
143
169
|
.hyewb-root:-webkit-full-screen .hyewb-editor,.hyewb-root:-webkit-full-screen .hyewb-preview{min-height:1000px}
|
|
144
170
|
`;
|
|
@@ -161,11 +187,13 @@ const WORKBENCH_ICON_PATHS = {
|
|
|
161
187
|
"chevron-right": '<polyline points="9 18 15 12 9 6"/>',
|
|
162
188
|
"fullscreen-enter": '<polyline points="9 3 3 3 3 9"/><line x1="3" y1="3" x2="10" y2="10"/><polyline points="15 3 21 3 21 9"/><line x1="14" y1="10" x2="21" y2="3"/><polyline points="3 15 3 21 9 21"/><line x1="3" y1="21" x2="10" y2="14"/><polyline points="15 21 21 21 21 15"/><line x1="14" y1="14" x2="21" y2="21"/>',
|
|
163
189
|
"fullscreen-exit": '<polyline points="10 14 10 21 3 21"/><line x1="10" y1="14" x2="3" y2="21"/><polyline points="14 10 21 10 21 3"/><line x1="14" y1="10" x2="21" y2="3"/><polyline points="3 9 3 3 9 3"/><line x1="3" y1="3" x2="10" y2="10"/><polyline points="21 15 21 21 15 21"/><line x1="21" y1="21" x2="14" y2="14"/>',
|
|
190
|
+
highlighter: '<path d="M15 2l7 7-8.5 8.5-7-7z"/><path d="M12.5 11.5L2 22l6-1.5 6-6"/><line x1="13" y1="4" x2="20" y2="11"/>',
|
|
164
191
|
"file-up": '<path d="M14 2H8a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><line x1="12" y1="18" x2="12" y2="12"/><polyline points="9.5 14.5 12 12 14.5 14.5"/>',
|
|
165
192
|
image: '<rect x="3" y="5" width="18" height="14" rx="2"/><circle cx="9" cy="10" r="1.5"/><path d="M6 17l4-4 3 3 3-2 2 3"/>',
|
|
166
193
|
italic: '<line x1="10" y1="4" x2="16" y2="4"/><line x1="8" y1="20" x2="14" y2="20"/><line x1="14" y1="4" x2="10" y2="20"/>',
|
|
167
194
|
"indent-increase": '<line x1="4" y1="6" x2="14" y2="6"/><line x1="4" y1="10" x2="10" y2="10"/><line x1="4" y1="14" x2="14" y2="14"/><line x1="4" y1="18" x2="10" y2="18"/><polyline points="15 9 19 12 15 15"/>',
|
|
168
195
|
move: '<polyline points="8 4 12 1 16 4"/><line x1="12" y1="1" x2="12" y2="23"/><polyline points="8 20 12 23 16 20"/><polyline points="4 8 1 12 4 16"/><line x1="1" y1="12" x2="23" y2="12"/><polyline points="20 8 23 12 20 16"/>',
|
|
196
|
+
"notebook-pen": '<path d="M4 5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/><line x1="8" y1="7" x2="14" y2="7"/><line x1="8" y1="11" x2="14" y2="11"/><path d="M14.5 16.5l4-4 2 2-4 4-2.5.5z"/>',
|
|
169
197
|
"paint-bucket": '<path d="M7 10l6-6 7 7-6 6z"/><path d="M12 5l7 7"/><path d="M5 19a2 2 0 1 0 4 0c0-1-1-2-2-3-1 1-2 2-2 3z"/>',
|
|
170
198
|
palette: '<path d="M12 3a9 9 0 1 0 0 18h1.5a2.5 2.5 0 0 0 0-5h-1a2 2 0 0 1 0-4H16a5 5 0 0 0-4-9z"/><circle cx="7.5" cy="10" r="1"/><circle cx="10" cy="7.5" r="1"/><circle cx="14" cy="7.5" r="1"/>',
|
|
171
199
|
pilcrow: '<path d="M9 4h7v16"/><path d="M12 4v16"/><path d="M9 4a4 4 0 0 0 0 8h3"/>',
|
|
@@ -175,6 +203,7 @@ const WORKBENCH_ICON_PATHS = {
|
|
|
175
203
|
subscript: '<line x1="4" y1="8" x2="10" y2="16"/><line x1="10" y1="8" x2="4" y2="16"/><path d="M14 15c0-1.1.9-2 2-2s2 .9 2 2c0 .7-.3 1.2-.9 1.7L14 20h4"/>',
|
|
176
204
|
superscript: '<line x1="4" y1="8" x2="10" y2="16"/><line x1="10" y1="8" x2="4" y2="16"/><path d="M14 6c0-1.1.9-2 2-2s2 .9 2 2c0 .7-.3 1.2-.9 1.7L14 11h4"/>',
|
|
177
205
|
table: '<rect x="3" y="5" width="18" height="14" rx="1"/><line x1="3" y1="10" x2="21" y2="10"/><line x1="9" y1="5" x2="9" y2="19"/><line x1="15" y1="5" x2="15" y2="19"/>',
|
|
206
|
+
"trash-2": '<polyline points="3 6 5 6 21 6"/><path d="M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/>',
|
|
178
207
|
underline: '<path d="M6 4v6a6 6 0 0 0 12 0V4"/><line x1="4" y1="20" x2="20" y2="20"/>',
|
|
179
208
|
video: '<rect x="3" y="6" width="14" height="12" rx="2"/><polygon points="10 10 10 14 13 12"/><path d="M17 10l4-2v8l-4-2z"/>',
|
|
180
209
|
x: '<line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/>',
|
|
@@ -274,6 +303,16 @@ const RESIZE_HANDLES = [
|
|
|
274
303
|
"w",
|
|
275
304
|
];
|
|
276
305
|
const DEFAULT_FLOW_BLOCK_WIDTH = 620;
|
|
306
|
+
function resolvePreviewAnnotationOptions(options) {
|
|
307
|
+
return {
|
|
308
|
+
showAnnotationList: options?.showAnnotationList ?? true,
|
|
309
|
+
enablePreviewSelectionToolbar: options?.enablePreviewSelectionToolbar ?? true,
|
|
310
|
+
annotationListDefaultTab: options?.annotationListDefaultTab === "notes" ? "notes" : "highlights",
|
|
311
|
+
annotationActions: {
|
|
312
|
+
canDelete: options?.annotationActions?.canDelete ?? true,
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
}
|
|
277
316
|
export function createDefaultWorkbenchDocument() {
|
|
278
317
|
const now = new Date().toISOString();
|
|
279
318
|
return {
|
|
@@ -394,6 +433,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
394
433
|
doc: editor.getDocument(),
|
|
395
434
|
features: resolveFeatures(options.features),
|
|
396
435
|
};
|
|
436
|
+
const previewAnnotationOptions = resolvePreviewAnnotationOptions(options.previewAnnotations);
|
|
397
437
|
const paperWidth = resolvePaperWidth(options.pageWidth, state.doc.settings.page.width);
|
|
398
438
|
const root = document.createElement("section");
|
|
399
439
|
root.className = "hyewb-root";
|
|
@@ -674,6 +714,8 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
674
714
|
pageInfo.className = "hyewb-status";
|
|
675
715
|
fullscreenBtn.style.marginLeft = "auto";
|
|
676
716
|
pageRow.append(prevPageBtn, nextPageBtn, addPageBtn, pageInfo, fullscreenBtn);
|
|
717
|
+
const previewLayout = document.createElement("div");
|
|
718
|
+
previewLayout.className = "hyewb-preview-layout";
|
|
677
719
|
const shell = document.createElement("div");
|
|
678
720
|
shell.className = "hyewb-shell";
|
|
679
721
|
const canvas = document.createElement("div");
|
|
@@ -698,6 +740,43 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
698
740
|
mediaList.className = "hyewb-media-list";
|
|
699
741
|
canvas.append(editorArea, previewArea, mediaStage, inlineResizeOverlay, mediaList);
|
|
700
742
|
shell.append(canvas);
|
|
743
|
+
const annotationPanel = document.createElement("aside");
|
|
744
|
+
annotationPanel.className = "hyewb-preview-annotation-panel";
|
|
745
|
+
const annotationTitle = document.createElement("h3");
|
|
746
|
+
annotationTitle.className = "hyewb-preview-annotation-title";
|
|
747
|
+
annotationTitle.textContent = "预览标注";
|
|
748
|
+
const annotationTabs = document.createElement("div");
|
|
749
|
+
annotationTabs.className = "hyewb-preview-annotation-tabs";
|
|
750
|
+
const annotationHighlightTab = document.createElement("button");
|
|
751
|
+
annotationHighlightTab.type = "button";
|
|
752
|
+
annotationHighlightTab.className = "hyewb-preview-annotation-tab";
|
|
753
|
+
annotationHighlightTab.textContent = "高亮";
|
|
754
|
+
const annotationNoteTab = document.createElement("button");
|
|
755
|
+
annotationNoteTab.type = "button";
|
|
756
|
+
annotationNoteTab.className = "hyewb-preview-annotation-tab";
|
|
757
|
+
annotationNoteTab.textContent = "笔记";
|
|
758
|
+
annotationTabs.append(annotationHighlightTab, annotationNoteTab);
|
|
759
|
+
const annotationList = document.createElement("ul");
|
|
760
|
+
annotationList.className = "hyewb-preview-annotation-list";
|
|
761
|
+
const annotationEmpty = document.createElement("p");
|
|
762
|
+
annotationEmpty.className = "hyewb-preview-annotation-empty";
|
|
763
|
+
annotationPanel.append(annotationTitle, annotationTabs, annotationList, annotationEmpty);
|
|
764
|
+
previewLayout.append(shell, annotationPanel);
|
|
765
|
+
const previewSelectionToolbar = document.createElement("div");
|
|
766
|
+
previewSelectionToolbar.className = "hyewb-preview-selection-toolbar";
|
|
767
|
+
const previewHighlightBtn = document.createElement("button");
|
|
768
|
+
previewHighlightBtn.type = "button";
|
|
769
|
+
previewHighlightBtn.className = "hyewb-preview-selection-btn";
|
|
770
|
+
previewHighlightBtn.title = "创建高亮";
|
|
771
|
+
previewHighlightBtn.setAttribute("aria-label", "创建高亮");
|
|
772
|
+
previewHighlightBtn.append(createIconPlaceholder("highlighter"));
|
|
773
|
+
const previewNoteBtn = document.createElement("button");
|
|
774
|
+
previewNoteBtn.type = "button";
|
|
775
|
+
previewNoteBtn.className = "hyewb-preview-selection-btn";
|
|
776
|
+
previewNoteBtn.title = "创建笔记";
|
|
777
|
+
previewNoteBtn.setAttribute("aria-label", "创建笔记");
|
|
778
|
+
previewNoteBtn.append(createIconPlaceholder("notebook-pen"));
|
|
779
|
+
previewSelectionToolbar.append(previewHighlightBtn, previewNoteBtn);
|
|
701
780
|
const floatingToolbar = document.createElement("div");
|
|
702
781
|
floatingToolbar.className = "hyewb-float";
|
|
703
782
|
const floatBoldBtn = createButton("bold");
|
|
@@ -772,7 +851,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
772
851
|
const colorGrid = document.createElement("div");
|
|
773
852
|
colorGrid.className = "hyewb-color-grid";
|
|
774
853
|
colorPalette.append(colorGrid);
|
|
775
|
-
root.append(header, toolbar, pageRow,
|
|
854
|
+
root.append(header, toolbar, pageRow, previewLayout, status, colorPalette, tablePicker, tableTools, tableRowDeleteBtn, tableMoveHandle, tableScaleHandle, tableColEdgeLayer, tableRowEdgeLayer, tableRowGapInsertBtn, tableColGapInsertBtn, tableDropIndicator, tableContextMenu, uploadBackdrop, docxInput, previewSelectionToolbar);
|
|
776
855
|
container.innerHTML = "";
|
|
777
856
|
container.append(root, floatingToolbar);
|
|
778
857
|
renderWorkbenchIcons();
|
|
@@ -798,6 +877,8 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
798
877
|
let tableContextTarget = null;
|
|
799
878
|
let selectedTableRowIndex = null;
|
|
800
879
|
let selectedTableColIndex = null;
|
|
880
|
+
let annotationActiveTab = previewAnnotationOptions.annotationListDefaultTab;
|
|
881
|
+
let previewSelectionDraft = null;
|
|
801
882
|
const isTableGapInsertTarget = (node) => {
|
|
802
883
|
if (!node) {
|
|
803
884
|
return false;
|
|
@@ -1132,6 +1213,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
1132
1213
|
syncEditorToDoc();
|
|
1133
1214
|
state.mode = nextMode;
|
|
1134
1215
|
hideFloatingToolbar();
|
|
1216
|
+
hidePreviewSelectionToolbar();
|
|
1135
1217
|
render();
|
|
1136
1218
|
};
|
|
1137
1219
|
const loadPreviewAnnotations = () => {
|
|
@@ -1144,6 +1226,423 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
1144
1226
|
updateStateDoc(nextDoc);
|
|
1145
1227
|
return clone(normalized);
|
|
1146
1228
|
};
|
|
1229
|
+
const getCurrentPageId = () => {
|
|
1230
|
+
return state.doc.pages[state.pageIndex]?.id || `page-${state.pageIndex}`;
|
|
1231
|
+
};
|
|
1232
|
+
const normalizeOffsetRange = (start, end) => {
|
|
1233
|
+
const safeStart = Math.max(0, Math.floor(start || 0));
|
|
1234
|
+
const safeEnd = Math.max(0, Math.floor(end || 0));
|
|
1235
|
+
if (safeStart === safeEnd) {
|
|
1236
|
+
return null;
|
|
1237
|
+
}
|
|
1238
|
+
return safeStart < safeEnd
|
|
1239
|
+
? { start: safeStart, end: safeEnd }
|
|
1240
|
+
: { start: safeEnd, end: safeStart };
|
|
1241
|
+
};
|
|
1242
|
+
const getNodeTextLength = (rootNode) => {
|
|
1243
|
+
if (!rootNode) {
|
|
1244
|
+
return 0;
|
|
1245
|
+
}
|
|
1246
|
+
const walker = document.createTreeWalker(rootNode, NodeFilter.SHOW_TEXT);
|
|
1247
|
+
let size = 0;
|
|
1248
|
+
while (walker.nextNode()) {
|
|
1249
|
+
size += walker.currentNode.textContent?.length || 0;
|
|
1250
|
+
}
|
|
1251
|
+
return size;
|
|
1252
|
+
};
|
|
1253
|
+
const getRangeTextLength = (range) => {
|
|
1254
|
+
if (!range) {
|
|
1255
|
+
return 0;
|
|
1256
|
+
}
|
|
1257
|
+
return getNodeTextLength(range.cloneContents());
|
|
1258
|
+
};
|
|
1259
|
+
const getSelectionOffsets = (containerNode, selection) => {
|
|
1260
|
+
if (!selection.rangeCount) {
|
|
1261
|
+
return null;
|
|
1262
|
+
}
|
|
1263
|
+
const range = selection.getRangeAt(0);
|
|
1264
|
+
if (!containerNode.contains(range.startContainer) ||
|
|
1265
|
+
!containerNode.contains(range.endContainer)) {
|
|
1266
|
+
return null;
|
|
1267
|
+
}
|
|
1268
|
+
const beforeStart = range.cloneRange();
|
|
1269
|
+
beforeStart.selectNodeContents(containerNode);
|
|
1270
|
+
beforeStart.setEnd(range.startContainer, range.startOffset);
|
|
1271
|
+
const beforeEnd = range.cloneRange();
|
|
1272
|
+
beforeEnd.selectNodeContents(containerNode);
|
|
1273
|
+
beforeEnd.setEnd(range.endContainer, range.endOffset);
|
|
1274
|
+
return normalizeOffsetRange(getRangeTextLength(beforeStart), getRangeTextLength(beforeEnd));
|
|
1275
|
+
};
|
|
1276
|
+
const createRangeFromOffsets = (containerNode, start, end) => {
|
|
1277
|
+
const normalized = normalizeOffsetRange(start, end);
|
|
1278
|
+
if (!normalized) {
|
|
1279
|
+
return null;
|
|
1280
|
+
}
|
|
1281
|
+
const range = document.createRange();
|
|
1282
|
+
const walker = document.createTreeWalker(containerNode, NodeFilter.SHOW_TEXT);
|
|
1283
|
+
let cursor = 0;
|
|
1284
|
+
let startNode = null;
|
|
1285
|
+
let endNode = null;
|
|
1286
|
+
let startOffset = 0;
|
|
1287
|
+
let endOffset = 0;
|
|
1288
|
+
let lastTextNode = null;
|
|
1289
|
+
while (walker.nextNode()) {
|
|
1290
|
+
const node = walker.currentNode;
|
|
1291
|
+
const length = node.textContent?.length || 0;
|
|
1292
|
+
lastTextNode = node;
|
|
1293
|
+
const nextCursor = cursor + length;
|
|
1294
|
+
if (!startNode &&
|
|
1295
|
+
normalized.start >= cursor &&
|
|
1296
|
+
normalized.start < nextCursor) {
|
|
1297
|
+
startNode = node;
|
|
1298
|
+
startOffset = normalized.start - cursor;
|
|
1299
|
+
}
|
|
1300
|
+
if (!endNode && normalized.end > cursor && normalized.end <= nextCursor) {
|
|
1301
|
+
endNode = node;
|
|
1302
|
+
endOffset = normalized.end - cursor;
|
|
1303
|
+
break;
|
|
1304
|
+
}
|
|
1305
|
+
cursor = nextCursor;
|
|
1306
|
+
}
|
|
1307
|
+
if (!startNode && lastTextNode && normalized.start === cursor) {
|
|
1308
|
+
startNode = lastTextNode;
|
|
1309
|
+
startOffset = lastTextNode.textContent?.length || 0;
|
|
1310
|
+
}
|
|
1311
|
+
if (!endNode && lastTextNode && normalized.end === cursor) {
|
|
1312
|
+
endNode = lastTextNode;
|
|
1313
|
+
endOffset = lastTextNode.textContent?.length || 0;
|
|
1314
|
+
}
|
|
1315
|
+
if (!startNode || !endNode) {
|
|
1316
|
+
return null;
|
|
1317
|
+
}
|
|
1318
|
+
range.setStart(startNode, startOffset);
|
|
1319
|
+
range.setEnd(endNode, endOffset);
|
|
1320
|
+
return range;
|
|
1321
|
+
};
|
|
1322
|
+
const unwrapPreviewMarks = (containerNode, kinds) => {
|
|
1323
|
+
const selector = kinds
|
|
1324
|
+
.map((kind) => `mark[data-preview-annotation='${kind}']`)
|
|
1325
|
+
.join(",");
|
|
1326
|
+
if (!selector) {
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
const marks = Array.from(containerNode.querySelectorAll(selector));
|
|
1330
|
+
marks.forEach((mark) => {
|
|
1331
|
+
const parent = mark.parentNode;
|
|
1332
|
+
if (!parent) {
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
while (mark.firstChild) {
|
|
1336
|
+
parent.insertBefore(mark.firstChild, mark);
|
|
1337
|
+
}
|
|
1338
|
+
parent.removeChild(mark);
|
|
1339
|
+
});
|
|
1340
|
+
};
|
|
1341
|
+
const applyHighlightMarks = (containerNode, highlights) => {
|
|
1342
|
+
unwrapPreviewMarks(containerNode, ["highlight"]);
|
|
1343
|
+
[...highlights]
|
|
1344
|
+
.filter((item) => Number.isFinite(item.start) && Number.isFinite(item.end))
|
|
1345
|
+
.sort((a, b) => b.start - a.start)
|
|
1346
|
+
.forEach((item) => {
|
|
1347
|
+
const range = createRangeFromOffsets(containerNode, item.start, item.end);
|
|
1348
|
+
if (!range || range.collapsed) {
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
const mark = document.createElement("mark");
|
|
1352
|
+
mark.dataset.previewAnnotation = "highlight";
|
|
1353
|
+
mark.className = "hyewb-preview-highlight-mark";
|
|
1354
|
+
mark.style.setProperty("--hyewb-highlight-color", item.color || "#fff59d");
|
|
1355
|
+
try {
|
|
1356
|
+
range.surroundContents(mark);
|
|
1357
|
+
}
|
|
1358
|
+
catch {
|
|
1359
|
+
const fragment = range.extractContents();
|
|
1360
|
+
mark.append(fragment);
|
|
1361
|
+
range.insertNode(mark);
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
};
|
|
1365
|
+
const applyNoteMarks = (containerNode, notes) => {
|
|
1366
|
+
unwrapPreviewMarks(containerNode, ["note"]);
|
|
1367
|
+
[...notes]
|
|
1368
|
+
.filter((item) => Number.isFinite(item.start) && Number.isFinite(item.end))
|
|
1369
|
+
.sort((a, b) => b.start - a.start)
|
|
1370
|
+
.forEach((item) => {
|
|
1371
|
+
const range = createRangeFromOffsets(containerNode, item.start, item.end);
|
|
1372
|
+
if (!range || range.collapsed) {
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
const mark = document.createElement("mark");
|
|
1376
|
+
mark.dataset.previewAnnotation = "note";
|
|
1377
|
+
mark.dataset.previewNoteId = item.id || "";
|
|
1378
|
+
mark.className = "hyewb-preview-note-mark";
|
|
1379
|
+
try {
|
|
1380
|
+
range.surroundContents(mark);
|
|
1381
|
+
}
|
|
1382
|
+
catch {
|
|
1383
|
+
const fragment = range.extractContents();
|
|
1384
|
+
mark.append(fragment);
|
|
1385
|
+
range.insertNode(mark);
|
|
1386
|
+
}
|
|
1387
|
+
});
|
|
1388
|
+
};
|
|
1389
|
+
const mergeHighlightRecords = (records, draft) => {
|
|
1390
|
+
const normalized = normalizeOffsetRange(draft.start, draft.end);
|
|
1391
|
+
if (!normalized || !draft.pageId || !draft.blockId) {
|
|
1392
|
+
return records;
|
|
1393
|
+
}
|
|
1394
|
+
const targetColor = draft.color || "#fff59d";
|
|
1395
|
+
const sameBucket = [];
|
|
1396
|
+
const rest = [];
|
|
1397
|
+
records.forEach((item) => {
|
|
1398
|
+
if (item.pageId === draft.pageId &&
|
|
1399
|
+
item.blockId === draft.blockId &&
|
|
1400
|
+
(item.color || "#fff59d") === targetColor) {
|
|
1401
|
+
sameBucket.push(item);
|
|
1402
|
+
}
|
|
1403
|
+
else {
|
|
1404
|
+
rest.push(item);
|
|
1405
|
+
}
|
|
1406
|
+
});
|
|
1407
|
+
let mergedStart = normalized.start;
|
|
1408
|
+
let mergedEnd = normalized.end;
|
|
1409
|
+
const kept = [];
|
|
1410
|
+
sameBucket.forEach((item) => {
|
|
1411
|
+
const overlap = !(item.end < mergedStart || item.start > mergedEnd);
|
|
1412
|
+
if (overlap) {
|
|
1413
|
+
mergedStart = Math.min(mergedStart, item.start);
|
|
1414
|
+
mergedEnd = Math.max(mergedEnd, item.end);
|
|
1415
|
+
}
|
|
1416
|
+
else {
|
|
1417
|
+
kept.push(item);
|
|
1418
|
+
}
|
|
1419
|
+
});
|
|
1420
|
+
return [
|
|
1421
|
+
...rest,
|
|
1422
|
+
...kept,
|
|
1423
|
+
{
|
|
1424
|
+
...draft,
|
|
1425
|
+
start: mergedStart,
|
|
1426
|
+
end: mergedEnd,
|
|
1427
|
+
},
|
|
1428
|
+
];
|
|
1429
|
+
};
|
|
1430
|
+
const mergeNoteRecords = (records, draft) => {
|
|
1431
|
+
const index = records.findIndex((item) => {
|
|
1432
|
+
return (item.pageId === draft.pageId &&
|
|
1433
|
+
item.start === draft.start &&
|
|
1434
|
+
item.end === draft.end);
|
|
1435
|
+
});
|
|
1436
|
+
if (index === -1) {
|
|
1437
|
+
return [...records, draft];
|
|
1438
|
+
}
|
|
1439
|
+
const next = [...records];
|
|
1440
|
+
const existing = next[index];
|
|
1441
|
+
if (!existing) {
|
|
1442
|
+
return [...records, draft];
|
|
1443
|
+
}
|
|
1444
|
+
next[index] = {
|
|
1445
|
+
...existing,
|
|
1446
|
+
...draft,
|
|
1447
|
+
id: existing.id || draft.id,
|
|
1448
|
+
updatedAt: new Date().toISOString(),
|
|
1449
|
+
};
|
|
1450
|
+
return next;
|
|
1451
|
+
};
|
|
1452
|
+
const summarizePreviewText = (text, fallback, maxLength = 52) => {
|
|
1453
|
+
const raw = String(text || "")
|
|
1454
|
+
.replace(/\s+/g, " ")
|
|
1455
|
+
.trim();
|
|
1456
|
+
if (!raw) {
|
|
1457
|
+
return fallback;
|
|
1458
|
+
}
|
|
1459
|
+
return raw.length > maxLength ? `${raw.slice(0, maxLength)}...` : raw;
|
|
1460
|
+
};
|
|
1461
|
+
const flashPreviewAnnotationTarget = (node) => {
|
|
1462
|
+
if (!node || !node.classList) {
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
node.classList.remove("hyewb-preview-annotation-flash");
|
|
1466
|
+
void node.offsetWidth;
|
|
1467
|
+
node.classList.add("hyewb-preview-annotation-flash");
|
|
1468
|
+
window.setTimeout(() => {
|
|
1469
|
+
node.classList.remove("hyewb-preview-annotation-flash");
|
|
1470
|
+
}, 900);
|
|
1471
|
+
};
|
|
1472
|
+
const focusPreviewAnnotationRecord = (record, kind) => {
|
|
1473
|
+
let target = null;
|
|
1474
|
+
if (kind === "note" && "id" in record && record.id) {
|
|
1475
|
+
const noteId = String(record.id);
|
|
1476
|
+
target = previewArea.querySelector(`mark[data-preview-annotation='note'][data-preview-note-id='${noteId.replace(/["\\]/g, "\\$&")}']`);
|
|
1477
|
+
}
|
|
1478
|
+
if (!target) {
|
|
1479
|
+
const range = createRangeFromOffsets(previewArea, record.start, record.end);
|
|
1480
|
+
if (range && !range.collapsed) {
|
|
1481
|
+
const node = range.startContainer;
|
|
1482
|
+
target =
|
|
1483
|
+
node.nodeType === Node.ELEMENT_NODE
|
|
1484
|
+
? node
|
|
1485
|
+
: node.parentElement;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
if (!target ||
|
|
1489
|
+
typeof target.scrollIntoView !== "function") {
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
target.scrollIntoView({
|
|
1493
|
+
behavior: "smooth",
|
|
1494
|
+
block: "center",
|
|
1495
|
+
inline: "nearest",
|
|
1496
|
+
});
|
|
1497
|
+
flashPreviewAnnotationTarget(target);
|
|
1498
|
+
};
|
|
1499
|
+
const getPreviewAnnotationsByPage = () => {
|
|
1500
|
+
const pageId = getCurrentPageId();
|
|
1501
|
+
const annotations = normalizePreviewAnnotations(state.doc.meta.previewAnnotations);
|
|
1502
|
+
return {
|
|
1503
|
+
annotations,
|
|
1504
|
+
pageId,
|
|
1505
|
+
highlights: annotations.highlights.filter((item) => item.pageId === pageId),
|
|
1506
|
+
notes: annotations.notes.filter((item) => item.pageId === pageId),
|
|
1507
|
+
};
|
|
1508
|
+
};
|
|
1509
|
+
const renderAnnotationPanel = () => {
|
|
1510
|
+
const shouldShowPanel = state.mode === "preview" &&
|
|
1511
|
+
state.features.preview &&
|
|
1512
|
+
previewAnnotationOptions.showAnnotationList;
|
|
1513
|
+
annotationPanel.style.display = shouldShowPanel ? "grid" : "none";
|
|
1514
|
+
previewLayout.classList.toggle("with-annotation-panel", shouldShowPanel);
|
|
1515
|
+
if (!shouldShowPanel) {
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
const { highlights, notes } = getPreviewAnnotationsByPage();
|
|
1519
|
+
annotationHighlightTab.classList.toggle("active", annotationActiveTab === "highlights");
|
|
1520
|
+
annotationNoteTab.classList.toggle("active", annotationActiveTab === "notes");
|
|
1521
|
+
const activeList = annotationActiveTab === "highlights" ? highlights : notes;
|
|
1522
|
+
annotationList.innerHTML = "";
|
|
1523
|
+
if (!activeList.length) {
|
|
1524
|
+
annotationEmpty.style.display = "block";
|
|
1525
|
+
annotationEmpty.textContent =
|
|
1526
|
+
annotationActiveTab === "highlights"
|
|
1527
|
+
? "当前页暂无高亮"
|
|
1528
|
+
: "当前页暂无笔记";
|
|
1529
|
+
return;
|
|
1530
|
+
}
|
|
1531
|
+
annotationEmpty.style.display = "none";
|
|
1532
|
+
activeList.forEach((record, index) => {
|
|
1533
|
+
const item = document.createElement("li");
|
|
1534
|
+
const button = document.createElement("button");
|
|
1535
|
+
button.type = "button";
|
|
1536
|
+
button.className = "hyewb-preview-annotation-item";
|
|
1537
|
+
const heading = document.createElement("span");
|
|
1538
|
+
heading.className = "hyewb-preview-annotation-item-title";
|
|
1539
|
+
heading.textContent =
|
|
1540
|
+
annotationActiveTab === "highlights"
|
|
1541
|
+
? `高亮 ${index + 1}`
|
|
1542
|
+
: `笔记 ${index + 1}`;
|
|
1543
|
+
const body = document.createElement("span");
|
|
1544
|
+
body.className = "hyewb-preview-annotation-item-body";
|
|
1545
|
+
const fallbackRange = `[${record.start}, ${record.end}]`;
|
|
1546
|
+
body.textContent =
|
|
1547
|
+
annotationActiveTab === "highlights"
|
|
1548
|
+
? summarizePreviewText(record.selectedText, fallbackRange)
|
|
1549
|
+
: summarizePreviewText(record.text, "未命名笔记");
|
|
1550
|
+
button.append(heading, body);
|
|
1551
|
+
button.addEventListener("click", () => {
|
|
1552
|
+
focusPreviewAnnotationRecord(record, annotationActiveTab === "highlights" ? "highlight" : "note");
|
|
1553
|
+
});
|
|
1554
|
+
if (previewAnnotationOptions.annotationActions.canDelete) {
|
|
1555
|
+
const deleteButton = document.createElement("button");
|
|
1556
|
+
deleteButton.type = "button";
|
|
1557
|
+
deleteButton.className = "hyewb-preview-annotation-delete";
|
|
1558
|
+
deleteButton.title = "删除标注";
|
|
1559
|
+
deleteButton.setAttribute("aria-label", "删除标注");
|
|
1560
|
+
deleteButton.append(createIconPlaceholder("trash-2"));
|
|
1561
|
+
deleteButton.addEventListener("click", (event) => {
|
|
1562
|
+
event.preventDefault();
|
|
1563
|
+
event.stopPropagation();
|
|
1564
|
+
if (!window.confirm("确定删除这条标注吗?")) {
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
const current = normalizePreviewAnnotations(state.doc.meta.previewAnnotations);
|
|
1568
|
+
if (annotationActiveTab === "highlights") {
|
|
1569
|
+
current.highlights = current.highlights.filter((item) => {
|
|
1570
|
+
if ("id" in record && record.id && item.id) {
|
|
1571
|
+
return String(item.id) !== String(record.id);
|
|
1572
|
+
}
|
|
1573
|
+
return !(item.pageId === record.pageId &&
|
|
1574
|
+
item.start === record.start &&
|
|
1575
|
+
item.end === record.end);
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
else {
|
|
1579
|
+
current.notes = current.notes.filter((item) => {
|
|
1580
|
+
if ("id" in record && record.id && item.id) {
|
|
1581
|
+
return String(item.id) !== String(record.id);
|
|
1582
|
+
}
|
|
1583
|
+
return !(item.pageId === record.pageId &&
|
|
1584
|
+
item.start === record.start &&
|
|
1585
|
+
item.end === record.end);
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
savePreviewAnnotations(current);
|
|
1589
|
+
});
|
|
1590
|
+
button.append(deleteButton);
|
|
1591
|
+
}
|
|
1592
|
+
item.append(button);
|
|
1593
|
+
annotationList.append(item);
|
|
1594
|
+
});
|
|
1595
|
+
};
|
|
1596
|
+
const applyPreviewAnnotationsToView = () => {
|
|
1597
|
+
if (state.mode !== "preview") {
|
|
1598
|
+
previewSelectionToolbar.classList.remove("show");
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const { highlights, notes } = getPreviewAnnotationsByPage();
|
|
1602
|
+
applyHighlightMarks(previewArea, highlights);
|
|
1603
|
+
applyNoteMarks(previewArea, notes);
|
|
1604
|
+
};
|
|
1605
|
+
const hidePreviewSelectionToolbar = () => {
|
|
1606
|
+
previewSelectionToolbar.classList.remove("show");
|
|
1607
|
+
previewSelectionDraft = null;
|
|
1608
|
+
};
|
|
1609
|
+
const syncPreviewSelectionToolbar = () => {
|
|
1610
|
+
if (!previewAnnotationOptions.enablePreviewSelectionToolbar ||
|
|
1611
|
+
state.mode !== "preview") {
|
|
1612
|
+
hidePreviewSelectionToolbar();
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
const selection = window.getSelection();
|
|
1616
|
+
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
|
|
1617
|
+
hidePreviewSelectionToolbar();
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
const range = selection.getRangeAt(0);
|
|
1621
|
+
if (!previewArea.contains(range.startContainer) ||
|
|
1622
|
+
!previewArea.contains(range.endContainer)) {
|
|
1623
|
+
hidePreviewSelectionToolbar();
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
const offsets = getSelectionOffsets(previewArea, selection);
|
|
1627
|
+
if (!offsets) {
|
|
1628
|
+
hidePreviewSelectionToolbar();
|
|
1629
|
+
return;
|
|
1630
|
+
}
|
|
1631
|
+
const rect = range.getBoundingClientRect();
|
|
1632
|
+
if (!rect.width && !rect.height) {
|
|
1633
|
+
hidePreviewSelectionToolbar();
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
previewSelectionDraft = {
|
|
1637
|
+
start: offsets.start,
|
|
1638
|
+
end: offsets.end,
|
|
1639
|
+
pageId: getCurrentPageId(),
|
|
1640
|
+
text: selection.toString().trim(),
|
|
1641
|
+
};
|
|
1642
|
+
previewSelectionToolbar.style.left = `${Math.round(rect.left + rect.width / 2)}px`;
|
|
1643
|
+
previewSelectionToolbar.style.top = `${Math.round(rect.top - 8)}px`;
|
|
1644
|
+
previewSelectionToolbar.classList.add("show");
|
|
1645
|
+
};
|
|
1147
1646
|
const hideFloatingToolbar = () => {
|
|
1148
1647
|
floatingToolbar.classList.remove("show");
|
|
1149
1648
|
lastSelection = null;
|
|
@@ -2844,7 +3343,14 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
2844
3343
|
selectInlineImage(null);
|
|
2845
3344
|
rememberedParagraphIndex = null;
|
|
2846
3345
|
}
|
|
2847
|
-
|
|
3346
|
+
if (state.mode === "preview") {
|
|
3347
|
+
canvas.style.width = "100%";
|
|
3348
|
+
canvas.style.maxWidth = `${paperWidth}px`;
|
|
3349
|
+
}
|
|
3350
|
+
else {
|
|
3351
|
+
canvas.style.width = `${paperWidth}px`;
|
|
3352
|
+
canvas.style.maxWidth = "100%";
|
|
3353
|
+
}
|
|
2848
3354
|
previewArea.innerHTML = html;
|
|
2849
3355
|
previewArea.classList.toggle("show", state.mode === "preview");
|
|
2850
3356
|
editorArea.style.display = state.mode === "editor" ? "block" : "none";
|
|
@@ -2937,6 +3443,9 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
2937
3443
|
});
|
|
2938
3444
|
updateInlineResizeOverlay();
|
|
2939
3445
|
syncToolbarState();
|
|
3446
|
+
applyPreviewAnnotationsToView();
|
|
3447
|
+
renderAnnotationPanel();
|
|
3448
|
+
syncPreviewSelectionToolbar();
|
|
2940
3449
|
};
|
|
2941
3450
|
boldBtn.addEventListener("click", () => {
|
|
2942
3451
|
withSelectionCommand(() => {
|
|
@@ -3127,6 +3636,59 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
3127
3636
|
floatBgColorInput.addEventListener("click", () => {
|
|
3128
3637
|
openColorPalette(floatBgColorInput, "background");
|
|
3129
3638
|
});
|
|
3639
|
+
annotationHighlightTab.addEventListener("click", () => {
|
|
3640
|
+
annotationActiveTab = "highlights";
|
|
3641
|
+
renderAnnotationPanel();
|
|
3642
|
+
});
|
|
3643
|
+
annotationNoteTab.addEventListener("click", () => {
|
|
3644
|
+
annotationActiveTab = "notes";
|
|
3645
|
+
renderAnnotationPanel();
|
|
3646
|
+
});
|
|
3647
|
+
previewHighlightBtn.addEventListener("click", () => {
|
|
3648
|
+
if (!previewSelectionDraft) {
|
|
3649
|
+
return;
|
|
3650
|
+
}
|
|
3651
|
+
const current = normalizePreviewAnnotations(state.doc.meta.previewAnnotations);
|
|
3652
|
+
current.highlights = mergeHighlightRecords(current.highlights, {
|
|
3653
|
+
id: `hl-${Date.now()}-${Math.round(Math.random() * 10000)}`,
|
|
3654
|
+
pageId: previewSelectionDraft.pageId,
|
|
3655
|
+
blockId: "preview-flow-text",
|
|
3656
|
+
start: previewSelectionDraft.start,
|
|
3657
|
+
end: previewSelectionDraft.end,
|
|
3658
|
+
color: "#fff59d",
|
|
3659
|
+
selectedText: previewSelectionDraft.text,
|
|
3660
|
+
createdAt: new Date().toISOString(),
|
|
3661
|
+
});
|
|
3662
|
+
annotationActiveTab = "highlights";
|
|
3663
|
+
savePreviewAnnotations(current);
|
|
3664
|
+
window.getSelection()?.removeAllRanges();
|
|
3665
|
+
hidePreviewSelectionToolbar();
|
|
3666
|
+
});
|
|
3667
|
+
previewNoteBtn.addEventListener("click", () => {
|
|
3668
|
+
if (!previewSelectionDraft) {
|
|
3669
|
+
return;
|
|
3670
|
+
}
|
|
3671
|
+
const text = window.prompt("请输入笔记内容", previewSelectionDraft.text || "") || "";
|
|
3672
|
+
const noteText = text.trim();
|
|
3673
|
+
if (!noteText) {
|
|
3674
|
+
return;
|
|
3675
|
+
}
|
|
3676
|
+
const current = normalizePreviewAnnotations(state.doc.meta.previewAnnotations);
|
|
3677
|
+
current.notes = mergeNoteRecords(current.notes, {
|
|
3678
|
+
id: `note-${Date.now()}-${Math.round(Math.random() * 10000)}`,
|
|
3679
|
+
pageId: previewSelectionDraft.pageId,
|
|
3680
|
+
start: previewSelectionDraft.start,
|
|
3681
|
+
end: previewSelectionDraft.end,
|
|
3682
|
+
text: noteText,
|
|
3683
|
+
selectedText: previewSelectionDraft.text,
|
|
3684
|
+
color: "#0e7490",
|
|
3685
|
+
createdAt: new Date().toISOString(),
|
|
3686
|
+
});
|
|
3687
|
+
annotationActiveTab = "notes";
|
|
3688
|
+
savePreviewAnnotations(current);
|
|
3689
|
+
window.getSelection()?.removeAllRanges();
|
|
3690
|
+
hidePreviewSelectionToolbar();
|
|
3691
|
+
});
|
|
3130
3692
|
floatLeftBtn.addEventListener("click", () => updateAlign("left"));
|
|
3131
3693
|
floatCenterBtn.addEventListener("click", () => updateAlign("center"));
|
|
3132
3694
|
floatRightBtn.addEventListener("click", () => updateAlign("right"));
|
|
@@ -3781,12 +4343,14 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
3781
4343
|
updateInlineResizeOverlay();
|
|
3782
4344
|
syncToolbarState();
|
|
3783
4345
|
syncFocusedTableControls();
|
|
4346
|
+
syncPreviewSelectionToolbar();
|
|
3784
4347
|
};
|
|
3785
4348
|
const handleWindowResize = () => {
|
|
3786
4349
|
updateShellViewportHeight();
|
|
3787
4350
|
updateInlineResizeOverlay();
|
|
3788
4351
|
syncTableToolsPosition();
|
|
3789
4352
|
syncFocusedTableControls();
|
|
4353
|
+
syncPreviewSelectionToolbar();
|
|
3790
4354
|
if (tablePicker.classList.contains("show")) {
|
|
3791
4355
|
showTablePicker();
|
|
3792
4356
|
}
|
|
@@ -3797,6 +4361,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
3797
4361
|
updateFloatingToolbarBySelection();
|
|
3798
4362
|
syncTableToolsPosition();
|
|
3799
4363
|
syncFocusedTableControls();
|
|
4364
|
+
syncPreviewSelectionToolbar();
|
|
3800
4365
|
if (tablePicker.classList.contains("show")) {
|
|
3801
4366
|
showTablePicker();
|
|
3802
4367
|
}
|
|
@@ -3819,6 +4384,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
3819
4384
|
updateInlineResizeOverlay();
|
|
3820
4385
|
syncTableToolsPosition();
|
|
3821
4386
|
syncFocusedTableControls();
|
|
4387
|
+
syncPreviewSelectionToolbar();
|
|
3822
4388
|
});
|
|
3823
4389
|
};
|
|
3824
4390
|
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
|
@@ -4013,12 +4579,22 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
4013
4579
|
};
|
|
4014
4580
|
}
|
|
4015
4581
|
function ensureWorkbenchStyles() {
|
|
4016
|
-
|
|
4582
|
+
const existing = document.getElementById(WORKBENCH_STYLE_ID);
|
|
4583
|
+
if (existing instanceof HTMLStyleElement) {
|
|
4584
|
+
if (existing.dataset.hyewbVersion !== WORKBENCH_STYLE_VERSION ||
|
|
4585
|
+
existing.textContent !== WORKBENCH_CSS) {
|
|
4586
|
+
existing.textContent = WORKBENCH_CSS;
|
|
4587
|
+
existing.dataset.hyewbVersion = WORKBENCH_STYLE_VERSION;
|
|
4588
|
+
}
|
|
4017
4589
|
return;
|
|
4018
4590
|
}
|
|
4591
|
+
if (existing) {
|
|
4592
|
+
existing.remove();
|
|
4593
|
+
}
|
|
4019
4594
|
const style = document.createElement("style");
|
|
4020
4595
|
style.id = WORKBENCH_STYLE_ID;
|
|
4021
4596
|
style.textContent = WORKBENCH_CSS;
|
|
4597
|
+
style.dataset.hyewbVersion = WORKBENCH_STYLE_VERSION;
|
|
4022
4598
|
document.head.append(style);
|
|
4023
4599
|
}
|
|
4024
4600
|
function resolveFeatures(next, base = DEFAULT_EDITOR_WORKBENCH_FEATURES) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyebook/vue3-adapter",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.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": "^0.2.
|
|
20
|
+
"@hyebook/core": "^0.2.3"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "tsc -p tsconfig.json",
|