@hyebook/vue3-adapter 0.2.5 → 2.2.7
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/engine.d.ts +42 -2
- package/dist/core/src/player/engine.d.ts.map +1 -1
- package/dist/core/src/player/engine.js +338 -8
- package/dist/core/src/types/player.d.ts +59 -4
- package/dist/core/src/types/player.d.ts.map +1 -1
- package/dist/core/src/workbench/editor-workbench.d.ts +5 -1
- package/dist/core/src/workbench/editor-workbench.d.ts.map +1 -1
- package/dist/core/src/workbench/editor-workbench.js +189 -112
- package/dist/vue3-adapter/src/index.d.ts +2 -1
- package/dist/vue3-adapter/src/index.d.ts.map +1 -1
- package/dist/vue3-adapter/src/index.js +1 -1
- package/package.json +2 -2
|
@@ -1,25 +1,65 @@
|
|
|
1
1
|
import type { EbookDoc } from "../types/ebook";
|
|
2
|
-
import type { PlayerDataProvider, ReaderNote, ReaderProgress } from "../types/player";
|
|
2
|
+
import type { ReaderAnnotationChangeSource, ReaderAnnotationCreateEvent, ReaderAnnotationDeleteEvent, ReaderAnnotations, ReaderAnnotationsChangeEvent, ReaderAnnotationUpdateEvent, ReaderHighlight, PlayerDataProvider, PlayerEngineOptions, PlayerFeatures, ReaderNote, ReaderProgress } from "../types/player";
|
|
3
3
|
export interface PlayerState {
|
|
4
4
|
currentPage: number;
|
|
5
5
|
zoom: number;
|
|
6
|
+
highlights: ReaderHighlight[];
|
|
6
7
|
notes: ReaderNote[];
|
|
7
8
|
progress: ReaderProgress | null;
|
|
8
9
|
}
|
|
10
|
+
type AnnotationCreateListener = (event: ReaderAnnotationCreateEvent) => void;
|
|
11
|
+
type AnnotationUpdateListener = (event: ReaderAnnotationUpdateEvent) => void;
|
|
12
|
+
type AnnotationDeleteListener = (event: ReaderAnnotationDeleteEvent) => void;
|
|
13
|
+
type AnnotationsChangeListener = (event: ReaderAnnotationsChangeEvent) => void;
|
|
9
14
|
export declare class PlayerEngine {
|
|
10
15
|
private provider;
|
|
16
|
+
private features;
|
|
11
17
|
private doc;
|
|
12
18
|
private state;
|
|
13
|
-
|
|
19
|
+
private annotationCreateListeners;
|
|
20
|
+
private annotationUpdateListeners;
|
|
21
|
+
private annotationDeleteListeners;
|
|
22
|
+
private annotationsChangeListeners;
|
|
23
|
+
constructor(provider: PlayerDataProvider, options?: PlayerEngineOptions);
|
|
14
24
|
load(): Promise<EbookDoc>;
|
|
15
25
|
getDocument(): EbookDoc;
|
|
16
26
|
getState(): PlayerState;
|
|
27
|
+
getHighlights(): ReaderHighlight[];
|
|
28
|
+
getNotes(): ReaderNote[];
|
|
29
|
+
getAnnotations(): ReaderAnnotations;
|
|
30
|
+
getFeatures(): Required<PlayerFeatures>;
|
|
31
|
+
isBuiltInNotesModuleEnabled(): boolean;
|
|
32
|
+
reloadAnnotations(): Promise<ReaderAnnotations>;
|
|
33
|
+
goToHighlight(highlightId: string): number | null;
|
|
34
|
+
goToNote(noteId: string): number | null;
|
|
17
35
|
goToPage(index: number): number;
|
|
18
36
|
nextPage(): number;
|
|
19
37
|
prevPage(): number;
|
|
20
38
|
setZoom(zoom: number): number;
|
|
21
39
|
saveProgress(): Promise<void>;
|
|
40
|
+
createHighlight(highlight: Omit<ReaderHighlight, "id" | "createdAt" | "updatedAt" | "bookId">, source?: ReaderAnnotationChangeSource): Promise<ReaderHighlight>;
|
|
41
|
+
updateHighlight(highlightId: string, patch: Partial<Omit<ReaderHighlight, "id" | "bookId" | "createdAt">>, source?: ReaderAnnotationChangeSource): Promise<ReaderHighlight | null>;
|
|
42
|
+
deleteHighlight(highlightId: string, source?: ReaderAnnotationChangeSource): Promise<boolean>;
|
|
22
43
|
addNote(note: Omit<ReaderNote, "id" | "createdAt" | "updatedAt" | "bookId">): Promise<ReaderNote>;
|
|
44
|
+
createNote(note: Omit<ReaderNote, "id" | "createdAt" | "updatedAt" | "bookId">, source?: ReaderAnnotationChangeSource): Promise<ReaderNote>;
|
|
45
|
+
updateNote(noteId: string, patch: Partial<Omit<ReaderNote, "id" | "bookId" | "createdAt">>, source?: ReaderAnnotationChangeSource): Promise<ReaderNote | null>;
|
|
46
|
+
deleteNote(noteId: string, source?: ReaderAnnotationChangeSource): Promise<boolean>;
|
|
47
|
+
onAnnotationCreate(listener: AnnotationCreateListener): () => void;
|
|
48
|
+
onAnnotationUpdate(listener: AnnotationUpdateListener): () => void;
|
|
49
|
+
onAnnotationDelete(listener: AnnotationDeleteListener): () => void;
|
|
50
|
+
onAnnotationsChange(listener: AnnotationsChangeListener): () => void;
|
|
23
51
|
private restoreUserState;
|
|
52
|
+
private loadAnnotationsState;
|
|
53
|
+
private findPageIndexByPageId;
|
|
54
|
+
private normalizeRange;
|
|
55
|
+
private normalizeAnnotations;
|
|
56
|
+
private mapPreviewAnnotationsToReader;
|
|
57
|
+
private persistAnnotations;
|
|
58
|
+
private emitAnnotationCreate;
|
|
59
|
+
private emitAnnotationUpdate;
|
|
60
|
+
private emitAnnotationDelete;
|
|
61
|
+
private emitAnnotationsChange;
|
|
62
|
+
private notifyListeners;
|
|
24
63
|
}
|
|
64
|
+
export {};
|
|
25
65
|
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../../../core/src/player/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../../../core/src/player/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
import { assertEbookDoc } from "../utils/validate";
|
|
2
|
+
const DEFAULT_PLAYER_FEATURES = {
|
|
3
|
+
useBuiltInNotesModule: true,
|
|
4
|
+
};
|
|
2
5
|
export class PlayerEngine {
|
|
3
|
-
constructor(provider) {
|
|
6
|
+
constructor(provider, options = {}) {
|
|
4
7
|
this.doc = null;
|
|
5
8
|
this.state = {
|
|
6
9
|
currentPage: 0,
|
|
7
10
|
zoom: 1,
|
|
11
|
+
highlights: [],
|
|
8
12
|
notes: [],
|
|
9
13
|
progress: null,
|
|
10
14
|
};
|
|
15
|
+
this.annotationCreateListeners = new Set();
|
|
16
|
+
this.annotationUpdateListeners = new Set();
|
|
17
|
+
this.annotationDeleteListeners = new Set();
|
|
18
|
+
this.annotationsChangeListeners = new Set();
|
|
11
19
|
this.provider = provider;
|
|
20
|
+
this.features = {
|
|
21
|
+
useBuiltInNotesModule: options.features?.useBuiltInNotesModule ??
|
|
22
|
+
DEFAULT_PLAYER_FEATURES.useBuiltInNotesModule,
|
|
23
|
+
};
|
|
12
24
|
}
|
|
13
25
|
async load() {
|
|
14
26
|
try {
|
|
@@ -30,7 +42,48 @@ export class PlayerEngine {
|
|
|
30
42
|
return JSON.parse(JSON.stringify(this.doc));
|
|
31
43
|
}
|
|
32
44
|
getState() {
|
|
33
|
-
return
|
|
45
|
+
return clone(this.state);
|
|
46
|
+
}
|
|
47
|
+
getHighlights() {
|
|
48
|
+
return clone(this.state.highlights);
|
|
49
|
+
}
|
|
50
|
+
getNotes() {
|
|
51
|
+
return clone(this.state.notes);
|
|
52
|
+
}
|
|
53
|
+
getAnnotations() {
|
|
54
|
+
return {
|
|
55
|
+
highlights: this.getHighlights(),
|
|
56
|
+
notes: this.getNotes(),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
getFeatures() {
|
|
60
|
+
return { ...this.features };
|
|
61
|
+
}
|
|
62
|
+
isBuiltInNotesModuleEnabled() {
|
|
63
|
+
return this.features.useBuiltInNotesModule;
|
|
64
|
+
}
|
|
65
|
+
async reloadAnnotations() {
|
|
66
|
+
if (!this.doc) {
|
|
67
|
+
throw new Error("Document is not loaded. Call load() first.");
|
|
68
|
+
}
|
|
69
|
+
await this.loadAnnotationsState();
|
|
70
|
+
return this.getAnnotations();
|
|
71
|
+
}
|
|
72
|
+
goToHighlight(highlightId) {
|
|
73
|
+
const target = this.state.highlights.find((item) => item.id === highlightId);
|
|
74
|
+
if (!target) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const pageIndex = this.findPageIndexByPageId(target.pageId);
|
|
78
|
+
return pageIndex >= 0 ? this.goToPage(pageIndex) : null;
|
|
79
|
+
}
|
|
80
|
+
goToNote(noteId) {
|
|
81
|
+
const target = this.state.notes.find((item) => item.id === noteId);
|
|
82
|
+
if (!target) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const pageIndex = this.findPageIndexByPageId(target.pageId);
|
|
86
|
+
return pageIndex >= 0 ? this.goToPage(pageIndex) : null;
|
|
34
87
|
}
|
|
35
88
|
goToPage(index) {
|
|
36
89
|
const doc = this.getDocument();
|
|
@@ -62,7 +115,62 @@ export class PlayerEngine {
|
|
|
62
115
|
this.state.progress = progress;
|
|
63
116
|
await this.provider.saveProgress(progress);
|
|
64
117
|
}
|
|
118
|
+
async createHighlight(highlight, source = "api") {
|
|
119
|
+
const doc = this.getDocument();
|
|
120
|
+
const now = new Date().toISOString();
|
|
121
|
+
const nextHighlight = {
|
|
122
|
+
...highlight,
|
|
123
|
+
range: this.normalizeRange(highlight.range),
|
|
124
|
+
id: `highlight-${Date.now()}`,
|
|
125
|
+
bookId: doc.id,
|
|
126
|
+
createdAt: now,
|
|
127
|
+
updatedAt: now,
|
|
128
|
+
};
|
|
129
|
+
this.state.highlights.push(nextHighlight);
|
|
130
|
+
await this.persistAnnotations();
|
|
131
|
+
this.emitAnnotationCreate("highlight", nextHighlight, source);
|
|
132
|
+
return clone(nextHighlight);
|
|
133
|
+
}
|
|
134
|
+
async updateHighlight(highlightId, patch, source = "api") {
|
|
135
|
+
const index = this.state.highlights.findIndex((item) => item.id === highlightId);
|
|
136
|
+
if (index < 0) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
const current = this.state.highlights[index];
|
|
140
|
+
if (!current) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
const nextHighlight = {
|
|
144
|
+
...current,
|
|
145
|
+
...patch,
|
|
146
|
+
id: current.id,
|
|
147
|
+
bookId: current.bookId,
|
|
148
|
+
createdAt: current.createdAt,
|
|
149
|
+
updatedAt: new Date().toISOString(),
|
|
150
|
+
range: patch.range ? this.normalizeRange(patch.range) : current.range,
|
|
151
|
+
};
|
|
152
|
+
this.state.highlights[index] = nextHighlight;
|
|
153
|
+
await this.persistAnnotations();
|
|
154
|
+
this.emitAnnotationUpdate("highlight", current, nextHighlight, source);
|
|
155
|
+
return clone(nextHighlight);
|
|
156
|
+
}
|
|
157
|
+
async deleteHighlight(highlightId, source = "api") {
|
|
158
|
+
const index = this.state.highlights.findIndex((item) => item.id === highlightId);
|
|
159
|
+
if (index < 0) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
const [removedHighlight] = this.state.highlights.splice(index, 1);
|
|
163
|
+
if (!removedHighlight) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
await this.persistAnnotations();
|
|
167
|
+
this.emitAnnotationDelete("highlight", removedHighlight, source);
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
65
170
|
async addNote(note) {
|
|
171
|
+
return this.createNote(note, "api");
|
|
172
|
+
}
|
|
173
|
+
async createNote(note, source = "api") {
|
|
66
174
|
const doc = this.getDocument();
|
|
67
175
|
const now = new Date().toISOString();
|
|
68
176
|
const nextNote = {
|
|
@@ -73,10 +181,69 @@ export class PlayerEngine {
|
|
|
73
181
|
updatedAt: now,
|
|
74
182
|
};
|
|
75
183
|
this.state.notes.push(nextNote);
|
|
76
|
-
|
|
77
|
-
|
|
184
|
+
await this.persistAnnotations();
|
|
185
|
+
this.emitAnnotationCreate("note", nextNote, source);
|
|
186
|
+
return clone(nextNote);
|
|
187
|
+
}
|
|
188
|
+
async updateNote(noteId, patch, source = "api") {
|
|
189
|
+
const index = this.state.notes.findIndex((item) => item.id === noteId);
|
|
190
|
+
if (index < 0) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
const current = this.state.notes[index];
|
|
194
|
+
if (!current) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const nextNote = {
|
|
198
|
+
...current,
|
|
199
|
+
...patch,
|
|
200
|
+
id: current.id,
|
|
201
|
+
bookId: current.bookId,
|
|
202
|
+
createdAt: current.createdAt,
|
|
203
|
+
updatedAt: new Date().toISOString(),
|
|
204
|
+
...(patch.range ? { range: this.normalizeRange(patch.range) } : {}),
|
|
205
|
+
};
|
|
206
|
+
this.state.notes[index] = nextNote;
|
|
207
|
+
await this.persistAnnotations();
|
|
208
|
+
this.emitAnnotationUpdate("note", current, nextNote, source);
|
|
209
|
+
return clone(nextNote);
|
|
210
|
+
}
|
|
211
|
+
async deleteNote(noteId, source = "api") {
|
|
212
|
+
const index = this.state.notes.findIndex((item) => item.id === noteId);
|
|
213
|
+
if (index < 0) {
|
|
214
|
+
return false;
|
|
78
215
|
}
|
|
79
|
-
|
|
216
|
+
const [removedNote] = this.state.notes.splice(index, 1);
|
|
217
|
+
if (!removedNote) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
await this.persistAnnotations();
|
|
221
|
+
this.emitAnnotationDelete("note", removedNote, source);
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
onAnnotationCreate(listener) {
|
|
225
|
+
this.annotationCreateListeners.add(listener);
|
|
226
|
+
return () => {
|
|
227
|
+
this.annotationCreateListeners.delete(listener);
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
onAnnotationUpdate(listener) {
|
|
231
|
+
this.annotationUpdateListeners.add(listener);
|
|
232
|
+
return () => {
|
|
233
|
+
this.annotationUpdateListeners.delete(listener);
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
onAnnotationDelete(listener) {
|
|
237
|
+
this.annotationDeleteListeners.add(listener);
|
|
238
|
+
return () => {
|
|
239
|
+
this.annotationDeleteListeners.delete(listener);
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
onAnnotationsChange(listener) {
|
|
243
|
+
this.annotationsChangeListeners.add(listener);
|
|
244
|
+
return () => {
|
|
245
|
+
this.annotationsChangeListeners.delete(listener);
|
|
246
|
+
};
|
|
80
247
|
}
|
|
81
248
|
async restoreUserState() {
|
|
82
249
|
if (!this.doc) {
|
|
@@ -90,10 +257,170 @@ export class PlayerEngine {
|
|
|
90
257
|
this.state.zoom = progress.zoom;
|
|
91
258
|
}
|
|
92
259
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
260
|
+
await this.loadAnnotationsState();
|
|
261
|
+
}
|
|
262
|
+
async loadAnnotationsState() {
|
|
263
|
+
if (!this.doc) {
|
|
264
|
+
return;
|
|
96
265
|
}
|
|
266
|
+
let restoredFromAnnotationsProvider = false;
|
|
267
|
+
if (this.provider.loadAnnotations) {
|
|
268
|
+
const annotations = await this.provider.loadAnnotations(this.doc.id);
|
|
269
|
+
if (annotations) {
|
|
270
|
+
const normalized = this.normalizeAnnotations(annotations);
|
|
271
|
+
this.state.highlights = normalized.highlights;
|
|
272
|
+
this.state.notes = normalized.notes;
|
|
273
|
+
restoredFromAnnotationsProvider = true;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (!restoredFromAnnotationsProvider) {
|
|
277
|
+
const fromDocument = this.mapPreviewAnnotationsToReader(this.doc.meta.previewAnnotations, this.doc.id);
|
|
278
|
+
this.state.highlights = fromDocument.highlights;
|
|
279
|
+
this.state.notes = fromDocument.notes;
|
|
280
|
+
if (this.provider.loadNotes) {
|
|
281
|
+
const notes = await this.provider.loadNotes(this.doc.id);
|
|
282
|
+
this.state.notes = Array.isArray(notes) ? clone(notes) : [];
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
findPageIndexByPageId(pageId) {
|
|
287
|
+
if (!this.doc) {
|
|
288
|
+
return -1;
|
|
289
|
+
}
|
|
290
|
+
return this.doc.pages.findIndex((page) => page.id === pageId);
|
|
291
|
+
}
|
|
292
|
+
normalizeRange(range) {
|
|
293
|
+
const safeStart = Math.max(0, Math.floor(range.start || 0));
|
|
294
|
+
const safeEnd = Math.max(0, Math.floor(range.end || 0));
|
|
295
|
+
return safeStart <= safeEnd
|
|
296
|
+
? { start: safeStart, end: safeEnd }
|
|
297
|
+
: { start: safeEnd, end: safeStart };
|
|
298
|
+
}
|
|
299
|
+
normalizeAnnotations(annotations) {
|
|
300
|
+
const highlights = Array.isArray(annotations?.highlights)
|
|
301
|
+
? clone(annotations.highlights)
|
|
302
|
+
: [];
|
|
303
|
+
const notes = Array.isArray(annotations?.notes)
|
|
304
|
+
? clone(annotations.notes)
|
|
305
|
+
: [];
|
|
306
|
+
return { highlights, notes };
|
|
307
|
+
}
|
|
308
|
+
mapPreviewAnnotationsToReader(annotations, bookId) {
|
|
309
|
+
const now = new Date().toISOString();
|
|
310
|
+
const safe = annotations || { highlights: [], notes: [] };
|
|
311
|
+
const highlights = safe.highlights.map((item, index) => {
|
|
312
|
+
const range = this.normalizeRange({ start: item.start, end: item.end });
|
|
313
|
+
return {
|
|
314
|
+
id: item.id || `highlight-preview-${index}`,
|
|
315
|
+
bookId,
|
|
316
|
+
pageId: item.pageId,
|
|
317
|
+
blockId: item.blockId || "preview-flow-text",
|
|
318
|
+
range,
|
|
319
|
+
...(item.selectedText !== undefined
|
|
320
|
+
? { selectedText: item.selectedText }
|
|
321
|
+
: {}),
|
|
322
|
+
...(item.color !== undefined ? { color: item.color } : {}),
|
|
323
|
+
createdAt: item.createdAt || now,
|
|
324
|
+
updatedAt: item.updatedAt || item.createdAt || now,
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
const notes = safe.notes.map((item, index) => {
|
|
328
|
+
const range = this.normalizeRange({ start: item.start, end: item.end });
|
|
329
|
+
return {
|
|
330
|
+
id: item.id || `note-preview-${index}`,
|
|
331
|
+
bookId,
|
|
332
|
+
pageId: item.pageId,
|
|
333
|
+
blockId: "preview-flow-text",
|
|
334
|
+
range,
|
|
335
|
+
content: item.text,
|
|
336
|
+
...(item.color !== undefined ? { color: item.color } : {}),
|
|
337
|
+
createdAt: item.createdAt || now,
|
|
338
|
+
updatedAt: item.updatedAt || item.createdAt || now,
|
|
339
|
+
};
|
|
340
|
+
});
|
|
341
|
+
return {
|
|
342
|
+
highlights,
|
|
343
|
+
notes,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
async persistAnnotations() {
|
|
347
|
+
if (!this.doc) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const all = this.getAnnotations();
|
|
351
|
+
if (this.provider.saveAnnotations) {
|
|
352
|
+
await this.provider.saveAnnotations(this.doc.id, all);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (this.provider.saveNotes) {
|
|
356
|
+
await this.provider.saveNotes(this.doc.id, all.notes);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
emitAnnotationCreate(kind, annotation, source) {
|
|
360
|
+
const all = this.getAnnotations();
|
|
361
|
+
const event = {
|
|
362
|
+
kind,
|
|
363
|
+
source,
|
|
364
|
+
annotation: clone(annotation),
|
|
365
|
+
all,
|
|
366
|
+
};
|
|
367
|
+
this.notifyListeners(this.annotationCreateListeners, event);
|
|
368
|
+
this.emitAnnotationsChange({
|
|
369
|
+
action: "create",
|
|
370
|
+
kind,
|
|
371
|
+
source,
|
|
372
|
+
all,
|
|
373
|
+
current: event.annotation,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
emitAnnotationUpdate(kind, previous, current, source) {
|
|
377
|
+
const all = this.getAnnotations();
|
|
378
|
+
const event = {
|
|
379
|
+
kind,
|
|
380
|
+
source,
|
|
381
|
+
previous: clone(previous),
|
|
382
|
+
current: clone(current),
|
|
383
|
+
all,
|
|
384
|
+
};
|
|
385
|
+
this.notifyListeners(this.annotationUpdateListeners, event);
|
|
386
|
+
this.emitAnnotationsChange({
|
|
387
|
+
action: "update",
|
|
388
|
+
kind,
|
|
389
|
+
source,
|
|
390
|
+
all,
|
|
391
|
+
current: event.current,
|
|
392
|
+
previous: event.previous,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
emitAnnotationDelete(kind, annotation, source) {
|
|
396
|
+
const all = this.getAnnotations();
|
|
397
|
+
const event = {
|
|
398
|
+
kind,
|
|
399
|
+
source,
|
|
400
|
+
annotation: clone(annotation),
|
|
401
|
+
all,
|
|
402
|
+
};
|
|
403
|
+
this.notifyListeners(this.annotationDeleteListeners, event);
|
|
404
|
+
this.emitAnnotationsChange({
|
|
405
|
+
action: "delete",
|
|
406
|
+
kind,
|
|
407
|
+
source,
|
|
408
|
+
all,
|
|
409
|
+
previous: event.annotation,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
emitAnnotationsChange(event) {
|
|
413
|
+
this.notifyListeners(this.annotationsChangeListeners, event);
|
|
414
|
+
}
|
|
415
|
+
notifyListeners(listeners, event) {
|
|
416
|
+
listeners.forEach((listener) => {
|
|
417
|
+
try {
|
|
418
|
+
listener(event);
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
this.provider.onError?.(toError(error));
|
|
422
|
+
}
|
|
423
|
+
});
|
|
97
424
|
}
|
|
98
425
|
}
|
|
99
426
|
function toError(error) {
|
|
@@ -102,3 +429,6 @@ function toError(error) {
|
|
|
102
429
|
}
|
|
103
430
|
return new Error(String(error));
|
|
104
431
|
}
|
|
432
|
+
function clone(value) {
|
|
433
|
+
return JSON.parse(JSON.stringify(value));
|
|
434
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { EbookDoc } from "./ebook";
|
|
2
|
+
export interface ReaderRange {
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
}
|
|
2
6
|
export interface ReaderProgress {
|
|
3
7
|
bookId: string;
|
|
4
8
|
lastPage: number;
|
|
@@ -10,19 +14,70 @@ export interface ReaderNote {
|
|
|
10
14
|
bookId: string;
|
|
11
15
|
pageId: string;
|
|
12
16
|
blockId: string;
|
|
13
|
-
range?:
|
|
14
|
-
start: number;
|
|
15
|
-
end: number;
|
|
16
|
-
};
|
|
17
|
+
range?: ReaderRange;
|
|
17
18
|
content: string;
|
|
18
19
|
color?: string;
|
|
19
20
|
createdAt: string;
|
|
20
21
|
updatedAt: string;
|
|
21
22
|
}
|
|
23
|
+
export interface ReaderHighlight {
|
|
24
|
+
id: string;
|
|
25
|
+
bookId: string;
|
|
26
|
+
pageId: string;
|
|
27
|
+
blockId: string;
|
|
28
|
+
range: ReaderRange;
|
|
29
|
+
selectedText?: string;
|
|
30
|
+
color?: string;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
}
|
|
34
|
+
export interface ReaderAnnotations {
|
|
35
|
+
highlights: ReaderHighlight[];
|
|
36
|
+
notes: ReaderNote[];
|
|
37
|
+
}
|
|
38
|
+
export type ReaderAnnotationKind = "highlight" | "note";
|
|
39
|
+
export type ReaderAnnotationAction = "create" | "update" | "delete";
|
|
40
|
+
export type ReaderAnnotationChangeSource = "api" | "user";
|
|
41
|
+
export type ReaderAnnotation = ReaderHighlight | ReaderNote;
|
|
42
|
+
export interface ReaderAnnotationCreateEvent {
|
|
43
|
+
kind: ReaderAnnotationKind;
|
|
44
|
+
source: ReaderAnnotationChangeSource;
|
|
45
|
+
annotation: ReaderAnnotation;
|
|
46
|
+
all: ReaderAnnotations;
|
|
47
|
+
}
|
|
48
|
+
export interface ReaderAnnotationUpdateEvent {
|
|
49
|
+
kind: ReaderAnnotationKind;
|
|
50
|
+
source: ReaderAnnotationChangeSource;
|
|
51
|
+
previous: ReaderAnnotation;
|
|
52
|
+
current: ReaderAnnotation;
|
|
53
|
+
all: ReaderAnnotations;
|
|
54
|
+
}
|
|
55
|
+
export interface ReaderAnnotationDeleteEvent {
|
|
56
|
+
kind: ReaderAnnotationKind;
|
|
57
|
+
source: ReaderAnnotationChangeSource;
|
|
58
|
+
annotation: ReaderAnnotation;
|
|
59
|
+
all: ReaderAnnotations;
|
|
60
|
+
}
|
|
61
|
+
export interface ReaderAnnotationsChangeEvent {
|
|
62
|
+
action: ReaderAnnotationAction;
|
|
63
|
+
kind: ReaderAnnotationKind;
|
|
64
|
+
source: ReaderAnnotationChangeSource;
|
|
65
|
+
all: ReaderAnnotations;
|
|
66
|
+
current?: ReaderAnnotation;
|
|
67
|
+
previous?: ReaderAnnotation;
|
|
68
|
+
}
|
|
69
|
+
export interface PlayerFeatures {
|
|
70
|
+
useBuiltInNotesModule?: boolean;
|
|
71
|
+
}
|
|
72
|
+
export interface PlayerEngineOptions {
|
|
73
|
+
features?: PlayerFeatures;
|
|
74
|
+
}
|
|
22
75
|
export interface PlayerDataProvider {
|
|
23
76
|
getData: () => Promise<EbookDoc>;
|
|
24
77
|
loadProgress?: (bookId: string) => Promise<ReaderProgress | null>;
|
|
25
78
|
saveProgress?: (progress: ReaderProgress) => Promise<void>;
|
|
79
|
+
loadAnnotations?: (bookId: string) => Promise<ReaderAnnotations | null>;
|
|
80
|
+
saveAnnotations?: (bookId: string, annotations: ReaderAnnotations) => Promise<void>;
|
|
26
81
|
loadNotes?: (bookId: string) => Promise<ReaderNote[]>;
|
|
27
82
|
saveNotes?: (bookId: string, notes: ReaderNote[]) => Promise<void>;
|
|
28
83
|
onError?: (error: Error) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"player.d.ts","sourceRoot":"","sources":["../../../../../core/src/types/player.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE;
|
|
1
|
+
{"version":3,"file":"player.d.ts","sourceRoot":"","sources":["../../../../../core/src/types/player.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,7 +14,8 @@ export interface EditorWorkbenchOptions {
|
|
|
14
14
|
pageWidth?: number;
|
|
15
15
|
upload?: EditorWorkbenchUploadOptions;
|
|
16
16
|
importDocx?: EditorWorkbenchDocxImportOptions;
|
|
17
|
-
onDocumentChange?: (doc: EbookDoc) => void
|
|
17
|
+
onDocumentChange?: (doc: EbookDoc) => void | Promise<void>;
|
|
18
|
+
onFullscreenSave?: (doc: EbookDoc) => void | Promise<void>;
|
|
18
19
|
}
|
|
19
20
|
export interface EditorWorkbenchPreviewAnnotationActions {
|
|
20
21
|
canDelete?: boolean;
|
|
@@ -52,9 +53,12 @@ export interface EditorWorkbenchUploadOptions {
|
|
|
52
53
|
export interface EditorWorkbenchHandle {
|
|
53
54
|
destroy: () => void;
|
|
54
55
|
getDocument: () => EbookDoc;
|
|
56
|
+
isFullscreen: () => boolean;
|
|
55
57
|
getMode: () => Mode;
|
|
56
58
|
getPageIndex: () => number;
|
|
57
59
|
importDocx: (file: File) => Promise<void>;
|
|
60
|
+
openFullscreen: () => void;
|
|
61
|
+
closeFullscreenAndSave: () => Promise<void>;
|
|
58
62
|
setMode: (mode: Mode) => void;
|
|
59
63
|
loadPreviewAnnotations: () => PreviewAnnotations;
|
|
60
64
|
savePreviewAnnotations: (annotations: PreviewAnnotations | null | undefined) => PreviewAnnotations;
|
|
@@ -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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"}
|
|
@@ -144,6 +144,14 @@ const WORKBENCH_CSS = `
|
|
|
144
144
|
.hyewb-upload-progress{height:8px;background:#e2e8f0;border-radius:999px;overflow:hidden}
|
|
145
145
|
.hyewb-upload-progress > span{display:block;height:100%;width:0;background:#0b7285;transition:width .18s ease}
|
|
146
146
|
.hyewb-upload-error{min-height:18px;font-size:12px;color:#b91c1c;margin:0}
|
|
147
|
+
.hyewb-preview-note-backdrop{position:fixed;inset:0;display:none;align-items:center;justify-content:center;background:rgba(15,23,42,.45);z-index:10080;padding:16px}
|
|
148
|
+
.hyewb-preview-note-backdrop.show{display:flex}
|
|
149
|
+
.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)}
|
|
150
|
+
.hyewb-preview-note-title{margin:0;font-size:14px;font-weight:600;color:#0f172a}
|
|
151
|
+
.hyewb-preview-note-input{width:100%;min-height:120px;resize:vertical;border:1px solid #94a3b8;border-radius:8px;padding:8px 10px;background:#fff;color:#0f172a;box-sizing:border-box;font-family:inherit;font-size:14px;line-height:1.5}
|
|
152
|
+
.hyewb-preview-note-actions{display:flex;justify-content:flex-end;gap:8px}
|
|
153
|
+
.hyewb-preview-note-btn{height:34px;padding:0 12px;border-radius:8px;border:1px solid #94a3b8;background:#fff;color:#0f172a;cursor:pointer}
|
|
154
|
+
.hyewb-preview-note-btn.primary{border-color:#0b7285;background:#0b7285;color:#fff}
|
|
147
155
|
.hyewb-preview-highlight-mark{background:var(--hyewb-highlight-color,#fff59d);color:inherit;padding:0 .08em;border-radius:.2em}
|
|
148
156
|
.hyewb-preview-note-mark{background:rgba(14,116,144,.14);border-bottom:2px solid #0e7490;color:inherit;padding:0 .04em;border-radius:.2em}
|
|
149
157
|
.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}
|
|
@@ -167,8 +175,10 @@ const WORKBENCH_CSS = `
|
|
|
167
175
|
.hyewb-preview-selection-btn svg{width:16px;height:16px}
|
|
168
176
|
.hyewb-preview-annotation-flash{animation:hyewb-preview-annotation-pulse .9s ease}
|
|
169
177
|
@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)}}
|
|
170
|
-
.hyewb-
|
|
171
|
-
.hyewb-
|
|
178
|
+
.hyewb-overlay{position:fixed;inset:0;z-index:2147483000;background:rgba(15,23,42,.35);padding:0;box-sizing:border-box;overflow:auto}
|
|
179
|
+
.hyewb-overlay-layer{min-height:100%;display:flex;align-items:stretch;justify-content:stretch}
|
|
180
|
+
.hyewb-root.hyewb-overlay-active{width:100%;max-width:none;min-height:100%;margin:0;border-radius:0;box-shadow:none}
|
|
181
|
+
.hyewb-root.hyewb-overlay-active .hyewb-editor,.hyewb-root.hyewb-overlay-active .hyewb-preview{min-height:1000px}
|
|
172
182
|
`;
|
|
173
183
|
export const DEFAULT_EDITOR_WORKBENCH_FEATURES = {
|
|
174
184
|
textToolbar: true,
|
|
@@ -445,7 +455,8 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
445
455
|
title.className = "hyewb-title";
|
|
446
456
|
title.textContent = options.title ?? "hy-ebook Editor Workbench";
|
|
447
457
|
const fullscreenBtn = createButton("fullscreen");
|
|
448
|
-
|
|
458
|
+
fullscreenBtn.style.marginLeft = "auto";
|
|
459
|
+
header.append(title, fullscreenBtn);
|
|
449
460
|
const toolbar = document.createElement("div");
|
|
450
461
|
toolbar.className = "hyewb-row hyewb-top-control";
|
|
451
462
|
const boldBtn = createButton("bold");
|
|
@@ -714,8 +725,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
714
725
|
const addPageBtn = createButton("addPage");
|
|
715
726
|
const pageInfo = document.createElement("span");
|
|
716
727
|
pageInfo.className = "hyewb-status";
|
|
717
|
-
|
|
718
|
-
pageRow.append(prevPageBtn, nextPageBtn, addPageBtn, pageInfo, fullscreenBtn);
|
|
728
|
+
pageRow.append(prevPageBtn, nextPageBtn, addPageBtn, pageInfo);
|
|
719
729
|
const previewLayout = document.createElement("div");
|
|
720
730
|
previewLayout.className = "hyewb-preview-layout";
|
|
721
731
|
const shell = document.createElement("div");
|
|
@@ -779,6 +789,35 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
779
789
|
previewNoteBtn.setAttribute("aria-label", "创建笔记");
|
|
780
790
|
previewNoteBtn.append(createIconPlaceholder("notebook-pen"));
|
|
781
791
|
previewSelectionToolbar.append(previewHighlightBtn, previewNoteBtn);
|
|
792
|
+
const preservePreviewSelectionOnToolbarPointerDown = (event) => {
|
|
793
|
+
// Keep native text selection active while clicking toolbar actions.
|
|
794
|
+
event.preventDefault();
|
|
795
|
+
event.stopPropagation();
|
|
796
|
+
};
|
|
797
|
+
previewSelectionToolbar.addEventListener("mousedown", preservePreviewSelectionOnToolbarPointerDown);
|
|
798
|
+
const previewNoteBackdrop = document.createElement("div");
|
|
799
|
+
previewNoteBackdrop.className = "hyewb-preview-note-backdrop";
|
|
800
|
+
const previewNoteDialog = document.createElement("div");
|
|
801
|
+
previewNoteDialog.className = "hyewb-preview-note-dialog";
|
|
802
|
+
const previewNoteTitle = document.createElement("h4");
|
|
803
|
+
previewNoteTitle.className = "hyewb-preview-note-title";
|
|
804
|
+
previewNoteTitle.textContent = "新增笔记";
|
|
805
|
+
const previewNoteInput = document.createElement("textarea");
|
|
806
|
+
previewNoteInput.className = "hyewb-preview-note-input";
|
|
807
|
+
previewNoteInput.placeholder = "请输入笔记内容";
|
|
808
|
+
const previewNoteActions = document.createElement("div");
|
|
809
|
+
previewNoteActions.className = "hyewb-preview-note-actions";
|
|
810
|
+
const previewNoteCancelBtn = document.createElement("button");
|
|
811
|
+
previewNoteCancelBtn.type = "button";
|
|
812
|
+
previewNoteCancelBtn.className = "hyewb-preview-note-btn";
|
|
813
|
+
previewNoteCancelBtn.textContent = "取消";
|
|
814
|
+
const previewNoteConfirmBtn = document.createElement("button");
|
|
815
|
+
previewNoteConfirmBtn.type = "button";
|
|
816
|
+
previewNoteConfirmBtn.className = "hyewb-preview-note-btn primary";
|
|
817
|
+
previewNoteConfirmBtn.textContent = "保存";
|
|
818
|
+
previewNoteActions.append(previewNoteCancelBtn, previewNoteConfirmBtn);
|
|
819
|
+
previewNoteDialog.append(previewNoteTitle, previewNoteInput, previewNoteActions);
|
|
820
|
+
previewNoteBackdrop.append(previewNoteDialog);
|
|
782
821
|
const floatingToolbar = document.createElement("div");
|
|
783
822
|
floatingToolbar.className = "hyewb-float";
|
|
784
823
|
const floatBoldBtn = createButton("bold");
|
|
@@ -853,7 +892,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
853
892
|
const colorGrid = document.createElement("div");
|
|
854
893
|
colorGrid.className = "hyewb-color-grid";
|
|
855
894
|
colorPalette.append(colorGrid);
|
|
856
|
-
root.append(header, toolbar, pageRow, previewLayout, status, colorPalette, tablePicker, tableTools, tableRowDeleteBtn, tableMoveHandle, tableScaleHandle, tableColEdgeLayer, tableRowEdgeLayer, tableRowGapInsertBtn, tableColGapInsertBtn, tableDropIndicator, tableContextMenu, uploadBackdrop, docxInput, previewSelectionToolbar);
|
|
895
|
+
root.append(header, toolbar, pageRow, previewLayout, status, colorPalette, tablePicker, tableTools, tableRowDeleteBtn, tableMoveHandle, tableScaleHandle, tableColEdgeLayer, tableRowEdgeLayer, tableRowGapInsertBtn, tableColGapInsertBtn, tableDropIndicator, tableContextMenu, uploadBackdrop, previewNoteBackdrop, docxInput, previewSelectionToolbar);
|
|
857
896
|
container.innerHTML = "";
|
|
858
897
|
root.append(floatingToolbar);
|
|
859
898
|
container.append(root);
|
|
@@ -882,6 +921,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
882
921
|
let selectedTableColIndex = null;
|
|
883
922
|
let annotationActiveTab = previewAnnotationOptions.annotationListDefaultTab;
|
|
884
923
|
let previewSelectionDraft = null;
|
|
924
|
+
let previewNoteDialogDraft = null;
|
|
885
925
|
const isTableGapInsertTarget = (node) => {
|
|
886
926
|
if (!node) {
|
|
887
927
|
return false;
|
|
@@ -897,27 +937,25 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
897
937
|
speedMbps: undefined,
|
|
898
938
|
error: undefined,
|
|
899
939
|
};
|
|
900
|
-
let
|
|
940
|
+
let fullscreenOverlay = null;
|
|
941
|
+
let fullscreenAnchor = null;
|
|
942
|
+
let bodyOverflowBeforeOverlay = null;
|
|
943
|
+
let isOverlayFullscreen = false;
|
|
901
944
|
const setButtonIcon = (button, iconName) => {
|
|
902
945
|
button.innerHTML = "";
|
|
903
946
|
button.append(createIconPlaceholder(iconName));
|
|
904
947
|
};
|
|
905
|
-
const getFullscreenElement = () => {
|
|
906
|
-
const webkitDocument = document;
|
|
907
|
-
return (document.fullscreenElement ||
|
|
908
|
-
webkitDocument.webkitFullscreenElement ||
|
|
909
|
-
null);
|
|
910
|
-
};
|
|
911
948
|
const isWorkbenchFullscreen = () => {
|
|
912
|
-
return
|
|
949
|
+
return isOverlayFullscreen;
|
|
913
950
|
};
|
|
914
951
|
const updateFullscreenButtonState = () => {
|
|
915
952
|
const isFullscreen = isWorkbenchFullscreen();
|
|
916
953
|
setButtonActive(fullscreenBtn, isFullscreen);
|
|
917
954
|
setButtonIcon(fullscreenBtn, isFullscreen ? "fullscreen-exit" : "fullscreen-enter");
|
|
918
|
-
const label = isFullscreen ? "
|
|
955
|
+
const label = isFullscreen ? "保存并退出" : "全屏";
|
|
919
956
|
fullscreenBtn.title = label;
|
|
920
957
|
fullscreenBtn.setAttribute("aria-label", label);
|
|
958
|
+
fullscreenBtn.style.display = isFullscreen ? "inline-flex" : "none";
|
|
921
959
|
};
|
|
922
960
|
const updateShellViewportHeight = () => {
|
|
923
961
|
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
@@ -948,67 +986,82 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
948
986
|
const rounded = Math.round(top);
|
|
949
987
|
return Math.min(rounded, maxTop);
|
|
950
988
|
};
|
|
951
|
-
const
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
989
|
+
const syncWorkbenchLayoutAfterFullscreenChange = () => {
|
|
990
|
+
updateFullscreenButtonState();
|
|
991
|
+
updateShellViewportHeight();
|
|
992
|
+
updateTopControlShieldHeight();
|
|
993
|
+
updateInlineResizeOverlay();
|
|
994
|
+
syncTableToolsPosition();
|
|
995
|
+
syncFocusedTableControls();
|
|
996
|
+
syncPreviewSelectionToolbar();
|
|
997
|
+
};
|
|
998
|
+
const openWorkbenchFullscreen = () => {
|
|
999
|
+
if (isWorkbenchFullscreen()) {
|
|
955
1000
|
return;
|
|
956
1001
|
}
|
|
957
|
-
|
|
958
|
-
|
|
1002
|
+
const parentNode = root.parentNode;
|
|
1003
|
+
if (!parentNode) {
|
|
959
1004
|
return;
|
|
960
1005
|
}
|
|
961
|
-
|
|
1006
|
+
fullscreenAnchor = document.createComment("hyewb-fullscreen-anchor");
|
|
1007
|
+
parentNode.insertBefore(fullscreenAnchor, root);
|
|
1008
|
+
fullscreenOverlay = document.createElement("div");
|
|
1009
|
+
fullscreenOverlay.className = "hyewb-overlay";
|
|
1010
|
+
const fullscreenOverlayLayer = document.createElement("div");
|
|
1011
|
+
fullscreenOverlayLayer.className = "hyewb-overlay-layer";
|
|
1012
|
+
fullscreenOverlay.append(fullscreenOverlayLayer);
|
|
1013
|
+
fullscreenOverlayLayer.append(root);
|
|
1014
|
+
document.body.append(fullscreenOverlay);
|
|
1015
|
+
bodyOverflowBeforeOverlay = document.body.style.overflow;
|
|
1016
|
+
document.body.style.overflow = "hidden";
|
|
1017
|
+
root.classList.add("hyewb-overlay-active");
|
|
1018
|
+
isOverlayFullscreen = true;
|
|
1019
|
+
status.textContent = "已进入页面全屏编辑";
|
|
1020
|
+
syncWorkbenchLayoutAfterFullscreenChange();
|
|
962
1021
|
};
|
|
963
|
-
const
|
|
964
|
-
|
|
965
|
-
if (typeof document.exitFullscreen === "function") {
|
|
966
|
-
await document.exitFullscreen();
|
|
1022
|
+
const closeWorkbenchFullscreen = () => {
|
|
1023
|
+
if (!isWorkbenchFullscreen()) {
|
|
967
1024
|
return;
|
|
968
1025
|
}
|
|
969
|
-
if (
|
|
970
|
-
|
|
971
|
-
|
|
1026
|
+
if (fullscreenAnchor && fullscreenAnchor.parentNode) {
|
|
1027
|
+
fullscreenAnchor.parentNode.insertBefore(root, fullscreenAnchor);
|
|
1028
|
+
fullscreenAnchor.parentNode.removeChild(fullscreenAnchor);
|
|
972
1029
|
}
|
|
973
|
-
|
|
974
|
-
|
|
1030
|
+
else {
|
|
1031
|
+
container.append(root);
|
|
975
1032
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
if (isWorkbenchFullscreen()) {
|
|
980
|
-
await exitWorkbenchFullscreen();
|
|
981
|
-
}
|
|
982
|
-
else {
|
|
983
|
-
await requestWorkbenchFullscreen();
|
|
984
|
-
}
|
|
1033
|
+
fullscreenAnchor = null;
|
|
1034
|
+
if (fullscreenOverlay && fullscreenOverlay.parentNode) {
|
|
1035
|
+
fullscreenOverlay.parentNode.removeChild(fullscreenOverlay);
|
|
985
1036
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1037
|
+
fullscreenOverlay = null;
|
|
1038
|
+
root.classList.remove("hyewb-overlay-active");
|
|
1039
|
+
isOverlayFullscreen = false;
|
|
1040
|
+
if (bodyOverflowBeforeOverlay !== null) {
|
|
1041
|
+
document.body.style.overflow = bodyOverflowBeforeOverlay;
|
|
1042
|
+
bodyOverflowBeforeOverlay = null;
|
|
992
1043
|
}
|
|
1044
|
+
syncWorkbenchLayoutAfterFullscreenChange();
|
|
993
1045
|
};
|
|
994
|
-
const
|
|
995
|
-
if (!
|
|
996
|
-
return;
|
|
997
|
-
}
|
|
998
|
-
shouldRestoreFullscreenAfterFilePicker = false;
|
|
999
|
-
if (isWorkbenchFullscreen()) {
|
|
1046
|
+
const closeWorkbenchFullscreenAndSave = async () => {
|
|
1047
|
+
if (!isWorkbenchFullscreen()) {
|
|
1000
1048
|
return;
|
|
1001
1049
|
}
|
|
1002
1050
|
try {
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1051
|
+
syncEditorToDoc({ emitChange: false });
|
|
1052
|
+
const snapshot = clone(state.doc);
|
|
1053
|
+
if (options.onFullscreenSave) {
|
|
1054
|
+
await options.onFullscreenSave(snapshot);
|
|
1055
|
+
}
|
|
1056
|
+
else {
|
|
1057
|
+
await Promise.resolve(options.onDocumentChange?.(snapshot));
|
|
1058
|
+
}
|
|
1059
|
+
closeWorkbenchFullscreen();
|
|
1060
|
+
status.textContent = "已保存并退出页面全屏";
|
|
1007
1061
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
updateTopControlShieldHeight();
|
|
1062
|
+
catch (error) {
|
|
1063
|
+
const errorMessage = error instanceof Error && error.message ? error.message : "请稍后重试";
|
|
1064
|
+
status.textContent = `保存失败:${errorMessage}`;
|
|
1012
1065
|
}
|
|
1013
1066
|
};
|
|
1014
1067
|
const formatUploadProgress = (percent) => {
|
|
@@ -1029,6 +1082,48 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
1029
1082
|
uploadProgressBar.style.width = `${formatUploadProgress(uploadState.progress)}%`;
|
|
1030
1083
|
uploadError.textContent = uploadState.error || "";
|
|
1031
1084
|
};
|
|
1085
|
+
const closePreviewNoteDialog = () => {
|
|
1086
|
+
previewNoteDialogDraft = null;
|
|
1087
|
+
previewNoteInput.value = "";
|
|
1088
|
+
previewNoteBackdrop.classList.remove("show");
|
|
1089
|
+
previewNoteInput.blur();
|
|
1090
|
+
};
|
|
1091
|
+
const openPreviewNoteDialog = (draft) => {
|
|
1092
|
+
previewNoteDialogDraft = { ...draft };
|
|
1093
|
+
previewNoteInput.value = draft.text || "";
|
|
1094
|
+
previewNoteBackdrop.classList.add("show");
|
|
1095
|
+
window.setTimeout(() => {
|
|
1096
|
+
previewNoteInput.focus();
|
|
1097
|
+
previewNoteInput.select();
|
|
1098
|
+
}, 0);
|
|
1099
|
+
};
|
|
1100
|
+
const savePreviewNoteFromDialog = () => {
|
|
1101
|
+
if (!previewNoteDialogDraft) {
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
const noteText = previewNoteInput.value.trim();
|
|
1105
|
+
if (!noteText) {
|
|
1106
|
+
status.textContent = "请输入笔记内容";
|
|
1107
|
+
previewNoteInput.focus();
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
const current = normalizePreviewAnnotations(state.doc.meta.previewAnnotations);
|
|
1111
|
+
current.notes = mergeNoteRecords(current.notes, {
|
|
1112
|
+
id: `note-${Date.now()}-${Math.round(Math.random() * 10000)}`,
|
|
1113
|
+
pageId: previewNoteDialogDraft.pageId,
|
|
1114
|
+
start: previewNoteDialogDraft.start,
|
|
1115
|
+
end: previewNoteDialogDraft.end,
|
|
1116
|
+
text: noteText,
|
|
1117
|
+
selectedText: previewNoteDialogDraft.text,
|
|
1118
|
+
color: "#0e7490",
|
|
1119
|
+
createdAt: new Date().toISOString(),
|
|
1120
|
+
});
|
|
1121
|
+
annotationActiveTab = "notes";
|
|
1122
|
+
savePreviewAnnotations(current);
|
|
1123
|
+
window.getSelection()?.removeAllRanges();
|
|
1124
|
+
closePreviewNoteDialog();
|
|
1125
|
+
hidePreviewSelectionToolbar();
|
|
1126
|
+
};
|
|
1032
1127
|
const closeUploadDialog = () => {
|
|
1033
1128
|
if (uploadState.uploading) {
|
|
1034
1129
|
return;
|
|
@@ -2883,7 +2978,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
2883
2978
|
});
|
|
2884
2979
|
colorGrid.append(swatch);
|
|
2885
2980
|
});
|
|
2886
|
-
const syncEditorToDoc = () => {
|
|
2981
|
+
const syncEditorToDoc = (options) => {
|
|
2887
2982
|
if (state.mode !== "editor") {
|
|
2888
2983
|
return;
|
|
2889
2984
|
}
|
|
@@ -2895,7 +2990,9 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
2895
2990
|
page.blocks = replaceFlowBlocks(page.blocks, flowBlocks);
|
|
2896
2991
|
state.doc.meta.updatedAt = new Date().toISOString();
|
|
2897
2992
|
editor.setDocument(state.doc);
|
|
2898
|
-
|
|
2993
|
+
if (options?.emitChange !== false) {
|
|
2994
|
+
emitDocumentChange();
|
|
2995
|
+
}
|
|
2899
2996
|
};
|
|
2900
2997
|
const updateAlign = (align) => {
|
|
2901
2998
|
if (selectedInlineImage &&
|
|
@@ -3419,12 +3516,12 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
3419
3516
|
previewArea.classList.toggle("show", state.mode === "preview");
|
|
3420
3517
|
editorArea.style.display = state.mode === "editor" ? "block" : "none";
|
|
3421
3518
|
const showEditorControls = state.mode === "editor";
|
|
3422
|
-
header.style.display =
|
|
3519
|
+
header.style.display =
|
|
3520
|
+
showEditorControls || isWorkbenchFullscreen() ? "flex" : "none";
|
|
3423
3521
|
toolbar.style.display =
|
|
3424
3522
|
showEditorControls && state.features.textToolbar ? "flex" : "none";
|
|
3425
|
-
pageRow.style.display =
|
|
3426
|
-
addPageBtn.style.display =
|
|
3427
|
-
showEditorControls && state.features.pageNav ? "inline-flex" : "none";
|
|
3523
|
+
pageRow.style.display = "none";
|
|
3524
|
+
addPageBtn.style.display = "none";
|
|
3428
3525
|
videoAddBtn.style.display = state.features.video ? "inline-block" : "none";
|
|
3429
3526
|
imageUploadBtn.style.display = "inline-block";
|
|
3430
3527
|
status.style.display = showEditorControls ? "block" : "none";
|
|
@@ -3735,26 +3832,25 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
3735
3832
|
if (!previewSelectionDraft) {
|
|
3736
3833
|
return;
|
|
3737
3834
|
}
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3835
|
+
openPreviewNoteDialog(previewSelectionDraft);
|
|
3836
|
+
});
|
|
3837
|
+
previewNoteConfirmBtn.addEventListener("click", () => {
|
|
3838
|
+
savePreviewNoteFromDialog();
|
|
3839
|
+
});
|
|
3840
|
+
previewNoteCancelBtn.addEventListener("click", () => {
|
|
3841
|
+
closePreviewNoteDialog();
|
|
3842
|
+
});
|
|
3843
|
+
previewNoteBackdrop.addEventListener("click", () => {
|
|
3844
|
+
closePreviewNoteDialog();
|
|
3845
|
+
});
|
|
3846
|
+
previewNoteDialog.addEventListener("click", (event) => {
|
|
3847
|
+
event.stopPropagation();
|
|
3848
|
+
});
|
|
3849
|
+
previewNoteInput.addEventListener("keydown", (event) => {
|
|
3850
|
+
if ((event.ctrlKey || event.metaKey) && event.key === "Enter") {
|
|
3851
|
+
event.preventDefault();
|
|
3852
|
+
savePreviewNoteFromDialog();
|
|
3742
3853
|
}
|
|
3743
|
-
const current = normalizePreviewAnnotations(state.doc.meta.previewAnnotations);
|
|
3744
|
-
current.notes = mergeNoteRecords(current.notes, {
|
|
3745
|
-
id: `note-${Date.now()}-${Math.round(Math.random() * 10000)}`,
|
|
3746
|
-
pageId: previewSelectionDraft.pageId,
|
|
3747
|
-
start: previewSelectionDraft.start,
|
|
3748
|
-
end: previewSelectionDraft.end,
|
|
3749
|
-
text: noteText,
|
|
3750
|
-
selectedText: previewSelectionDraft.text,
|
|
3751
|
-
color: "#0e7490",
|
|
3752
|
-
createdAt: new Date().toISOString(),
|
|
3753
|
-
});
|
|
3754
|
-
annotationActiveTab = "notes";
|
|
3755
|
-
savePreviewAnnotations(current);
|
|
3756
|
-
window.getSelection()?.removeAllRanges();
|
|
3757
|
-
hidePreviewSelectionToolbar();
|
|
3758
3854
|
});
|
|
3759
3855
|
floatLeftBtn.addEventListener("click", () => updateAlign("left"));
|
|
3760
3856
|
floatCenterBtn.addEventListener("click", () => updateAlign("center"));
|
|
@@ -4446,19 +4542,6 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
4446
4542
|
};
|
|
4447
4543
|
window.addEventListener("resize", handleWindowResize);
|
|
4448
4544
|
window.addEventListener("scroll", handleWindowScroll, true);
|
|
4449
|
-
const handleFullscreenChange = () => {
|
|
4450
|
-
window.requestAnimationFrame(() => {
|
|
4451
|
-
updateFullscreenButtonState();
|
|
4452
|
-
updateShellViewportHeight();
|
|
4453
|
-
updateTopControlShieldHeight();
|
|
4454
|
-
updateInlineResizeOverlay();
|
|
4455
|
-
syncTableToolsPosition();
|
|
4456
|
-
syncFocusedTableControls();
|
|
4457
|
-
syncPreviewSelectionToolbar();
|
|
4458
|
-
});
|
|
4459
|
-
};
|
|
4460
|
-
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
|
4461
|
-
document.addEventListener("webkitfullscreenchange", handleFullscreenChange);
|
|
4462
4545
|
document.addEventListener("selectionchange", handleSelectionChange);
|
|
4463
4546
|
const handleDocumentPointerDownForPalette = (event) => {
|
|
4464
4547
|
const clickTarget = event.target;
|
|
@@ -4526,12 +4609,15 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
4526
4609
|
const handleDocumentKeyDown = (event) => {
|
|
4527
4610
|
if (event.key === "Escape") {
|
|
4528
4611
|
hideTableContextMenu();
|
|
4612
|
+
if (previewNoteBackdrop.classList.contains("show")) {
|
|
4613
|
+
closePreviewNoteDialog();
|
|
4614
|
+
}
|
|
4529
4615
|
}
|
|
4530
4616
|
};
|
|
4531
4617
|
document.addEventListener("pointerdown", handleDocumentPointerDownForPalette);
|
|
4532
4618
|
document.addEventListener("keydown", handleDocumentKeyDown);
|
|
4533
4619
|
fullscreenBtn.addEventListener("click", () => {
|
|
4534
|
-
void
|
|
4620
|
+
void closeWorkbenchFullscreenAndSave();
|
|
4535
4621
|
});
|
|
4536
4622
|
tableAddBtn.addEventListener("mousedown", preserveSelectionForInputControl);
|
|
4537
4623
|
videoAddBtn.addEventListener("mousedown", preserveSelectionForInputControl);
|
|
@@ -4562,12 +4648,10 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
4562
4648
|
status.textContent = "请先切换到编辑模式后再导入 Word";
|
|
4563
4649
|
return;
|
|
4564
4650
|
}
|
|
4565
|
-
shouldRestoreFullscreenAfterFilePicker = isWorkbenchFullscreen();
|
|
4566
4651
|
docxInput.value = "";
|
|
4567
4652
|
docxInput.click();
|
|
4568
4653
|
});
|
|
4569
4654
|
docxInput.addEventListener("change", () => {
|
|
4570
|
-
void restoreWorkbenchFullscreenIfNeeded();
|
|
4571
4655
|
const picked = docxInput.files?.[0] || null;
|
|
4572
4656
|
docxInput.value = "";
|
|
4573
4657
|
if (!picked) {
|
|
@@ -4575,11 +4659,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
4575
4659
|
}
|
|
4576
4660
|
void importDocxFile(picked);
|
|
4577
4661
|
});
|
|
4578
|
-
uploadInput.addEventListener("click", () => {
|
|
4579
|
-
shouldRestoreFullscreenAfterFilePicker = isWorkbenchFullscreen();
|
|
4580
|
-
});
|
|
4581
4662
|
uploadInput.addEventListener("change", () => {
|
|
4582
|
-
void restoreWorkbenchFullscreenIfNeeded();
|
|
4583
4663
|
const picked = uploadInput.files?.[0] || null;
|
|
4584
4664
|
uploadState.progress = 0;
|
|
4585
4665
|
uploadState.speedMbps = undefined;
|
|
@@ -4614,10 +4694,6 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
4614
4694
|
uploadDialog.addEventListener("click", (event) => {
|
|
4615
4695
|
event.stopPropagation();
|
|
4616
4696
|
});
|
|
4617
|
-
const handleWindowFocusForFullscreenRestore = () => {
|
|
4618
|
-
void restoreWorkbenchFullscreenIfNeeded();
|
|
4619
|
-
};
|
|
4620
|
-
window.addEventListener("focus", handleWindowFocusForFullscreenRestore);
|
|
4621
4697
|
prevPageBtn.addEventListener("click", () => jumpPage(-1));
|
|
4622
4698
|
nextPageBtn.addEventListener("click", () => jumpPage(1));
|
|
4623
4699
|
addPageBtn.addEventListener("click", addPage);
|
|
@@ -4628,6 +4704,7 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
4628
4704
|
emitDocumentChange();
|
|
4629
4705
|
return {
|
|
4630
4706
|
destroy: () => {
|
|
4707
|
+
closeWorkbenchFullscreen();
|
|
4631
4708
|
hideTablePicker();
|
|
4632
4709
|
hideTableTools();
|
|
4633
4710
|
document.removeEventListener("selectionchange", handleSelectionChange);
|
|
@@ -4635,17 +4712,17 @@ export function mountEditorWorkbench(container, options = {}) {
|
|
|
4635
4712
|
document.removeEventListener("pointerup", onMediaPointerUp);
|
|
4636
4713
|
window.removeEventListener("resize", handleWindowResize);
|
|
4637
4714
|
window.removeEventListener("scroll", handleWindowScroll, true);
|
|
4638
|
-
window.removeEventListener("focus", handleWindowFocusForFullscreenRestore);
|
|
4639
4715
|
document.removeEventListener("pointerdown", handleDocumentPointerDownForPalette);
|
|
4640
4716
|
document.removeEventListener("keydown", handleDocumentKeyDown);
|
|
4641
|
-
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
|
4642
|
-
document.removeEventListener("webkitfullscreenchange", handleFullscreenChange);
|
|
4643
4717
|
container.innerHTML = "";
|
|
4644
4718
|
},
|
|
4645
4719
|
getDocument: () => clone(state.doc),
|
|
4720
|
+
isFullscreen: isWorkbenchFullscreen,
|
|
4646
4721
|
getMode: () => state.mode,
|
|
4647
4722
|
getPageIndex: () => state.pageIndex,
|
|
4648
4723
|
importDocx: importDocxFile,
|
|
4724
|
+
openFullscreen: openWorkbenchFullscreen,
|
|
4725
|
+
closeFullscreenAndSave: closeWorkbenchFullscreenAndSave,
|
|
4649
4726
|
setMode,
|
|
4650
4727
|
loadPreviewAnnotations,
|
|
4651
4728
|
savePreviewAnnotations,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { EditorEngine, PlayerEngine, type EditorWorkbenchHandle, type EditorWorkbenchOptions, type EbookDoc, type PlayerDataProvider } from "@hyebook/core";
|
|
1
|
+
import { EditorEngine, PlayerEngine, type EditorWorkbenchHandle, type EditorWorkbenchOptions, type EbookDoc, type PlayerDataProvider, type PlayerEngineOptions } from "@hyebook/core";
|
|
2
2
|
export interface Vue3EditorAdapterOptions {
|
|
3
3
|
initialDoc: EbookDoc;
|
|
4
4
|
onDocumentChange?: (doc: EbookDoc) => void;
|
|
5
5
|
}
|
|
6
6
|
export interface Vue3PlayerAdapterOptions {
|
|
7
7
|
provider: PlayerDataProvider;
|
|
8
|
+
engineOptions?: PlayerEngineOptions;
|
|
8
9
|
}
|
|
9
10
|
export interface Vue3EditorWorkbenchOptions extends EditorWorkbenchOptions {
|
|
10
11
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,YAAY,EAEZ,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,QAAQ,EACb,KAAK,kBAAkB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,YAAY,EAEZ,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACzB,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,QAAQ,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACrC;AAED,MAAM,WAAW,0BAA2B,SAAQ,sBAAsB;CAAG;AAE7E,MAAM,WAAW,yBAA0B,SAAQ,qBAAqB;CAAG;AAE3E,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,YAAY,CAId;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,YAAY,CAEd;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,WAAW,EACtB,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAE3B"}
|
|
@@ -5,7 +5,7 @@ export function createVue3EditorAdapter(options) {
|
|
|
5
5
|
return engine;
|
|
6
6
|
}
|
|
7
7
|
export function createVue3PlayerAdapter(options) {
|
|
8
|
-
return new PlayerEngine(options.provider);
|
|
8
|
+
return new PlayerEngine(options.provider, options.engineOptions);
|
|
9
9
|
}
|
|
10
10
|
export function mountVue3EditorWorkbench(container, options = {}) {
|
|
11
11
|
return mountEditorWorkbench(container, options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyebook/vue3-adapter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.2.7",
|
|
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": "^
|
|
20
|
+
"@hyebook/core": "^2.2.7"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "tsc -p tsconfig.json",
|