@prose-reader/enhancer-annotations 1.221.0 → 1.223.0
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/Commands.d.ts +19 -13
- package/dist/{highlights → annotations}/ReaderHighlights.d.ts +4 -4
- package/dist/{highlights → annotations}/SpineItemHighlight.d.ts +6 -5
- package/dist/{highlights → annotations}/SpineItemHighlights.d.ts +4 -4
- package/dist/annotations/types.d.ts +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +144 -165
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +142 -164
- package/dist/index.umd.cjs.map +1 -1
- package/dist/types.d.ts +11 -18
- package/package.json +2 -2
- package/dist/highlights/Highlight.d.ts +0 -21
- package/dist/highlights/consolidate.d.ts +0 -3
- package/dist/report.d.ts +0 -8
- /package/dist/{highlights → annotations}/utils.d.ts +0 -0
package/dist/Commands.d.ts
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
import { DestroyableClass } from '@prose-reader/core';
|
|
2
|
-
import {
|
|
3
|
-
type
|
|
4
|
-
selection
|
|
2
|
+
import { Annotation } from './types';
|
|
3
|
+
type AnnotationSharedParams = Omit<Annotation, "id" | "cfi"> & {
|
|
4
|
+
selection?: Selection;
|
|
5
|
+
};
|
|
6
|
+
type AnnotateParams = AnnotationSharedParams & {
|
|
5
7
|
itemIndex: number;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
};
|
|
9
|
+
type AnnotateAbsolutePageParams = AnnotationSharedParams & {
|
|
10
|
+
absolutePageIndex: number;
|
|
8
11
|
};
|
|
9
12
|
export declare class Commands extends DestroyableClass {
|
|
10
13
|
private commandSubject;
|
|
11
|
-
readonly
|
|
12
|
-
type: "
|
|
13
|
-
data:
|
|
14
|
+
readonly annotate$: import('rxjs').Observable<{
|
|
15
|
+
type: "annotate";
|
|
16
|
+
data: (AnnotateParams | AnnotateAbsolutePageParams) & {
|
|
17
|
+
absolutePageIndex?: number;
|
|
18
|
+
};
|
|
14
19
|
}>;
|
|
15
20
|
readonly add$: import('rxjs').Observable<{
|
|
16
21
|
type: "add";
|
|
17
|
-
data:
|
|
22
|
+
data: Annotation | Annotation[];
|
|
18
23
|
}>;
|
|
19
24
|
readonly delete$: import('rxjs').Observable<{
|
|
20
25
|
type: "delete";
|
|
@@ -23,7 +28,7 @@ export declare class Commands extends DestroyableClass {
|
|
|
23
28
|
readonly update$: import('rxjs').Observable<{
|
|
24
29
|
type: "update";
|
|
25
30
|
id: string;
|
|
26
|
-
data: Pick<
|
|
31
|
+
data: Pick<AnnotationSharedParams, "highlightColor" | "notes">;
|
|
27
32
|
}>;
|
|
28
33
|
readonly select$: import('rxjs').Observable<{
|
|
29
34
|
type: "select";
|
|
@@ -32,10 +37,11 @@ export declare class Commands extends DestroyableClass {
|
|
|
32
37
|
readonly reset$: import('rxjs').Observable<{
|
|
33
38
|
type: "reset";
|
|
34
39
|
}>;
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
annotate: (params: AnnotateParams) => void;
|
|
41
|
+
annotateAbsolutePage: (params: AnnotateAbsolutePageParams) => void;
|
|
42
|
+
add: (data: Annotation | Annotation[]) => void;
|
|
37
43
|
delete: (id: string) => void;
|
|
38
|
-
update: (id: string, data: Pick<
|
|
44
|
+
update: (id: string, data: Pick<AnnotationSharedParams, "highlightColor" | "notes">) => void;
|
|
39
45
|
select: (id: string | undefined) => void;
|
|
40
46
|
reset: () => void;
|
|
41
47
|
destroy(): void;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { DestroyableClass, Reader } from '@prose-reader/core';
|
|
2
2
|
import { BehaviorSubject } from 'rxjs';
|
|
3
|
-
import { ProseHighlight } from './Highlight';
|
|
4
3
|
import { SpineItemHighlights } from './SpineItemHighlights';
|
|
4
|
+
import { RuntimeAnnotation } from './types';
|
|
5
5
|
export declare class ReaderHighlights extends DestroyableClass {
|
|
6
6
|
private reader;
|
|
7
7
|
private highlights;
|
|
8
8
|
private selectedHighlight;
|
|
9
9
|
private spineItemHighlights;
|
|
10
10
|
tap$: SpineItemHighlights["tap$"];
|
|
11
|
-
constructor(reader: Reader, highlights: BehaviorSubject<
|
|
12
|
-
getHighlightsForTarget: (target: EventTarget) =>
|
|
11
|
+
constructor(reader: Reader, highlights: BehaviorSubject<RuntimeAnnotation[]>, selectedHighlight: BehaviorSubject<string | undefined>);
|
|
12
|
+
getHighlightsForTarget: (target: EventTarget) => RuntimeAnnotation[];
|
|
13
13
|
isTargetWithinHighlight: (target: EventTarget) => boolean;
|
|
14
|
-
layout():
|
|
14
|
+
layout(): import('rxjs').Observable<((null | undefined)[] | null)[] | null>;
|
|
15
15
|
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { DestroyableClass, Reader, SpineItem } from '@prose-reader/core';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
|
-
import {
|
|
3
|
+
import { RuntimeAnnotation } from './types';
|
|
4
4
|
export declare class SpineItemHighlight extends DestroyableClass {
|
|
5
5
|
private spineItem;
|
|
6
6
|
private containerElement;
|
|
7
7
|
private reader;
|
|
8
|
-
readonly highlight:
|
|
8
|
+
readonly highlight: RuntimeAnnotation;
|
|
9
9
|
private isSelected;
|
|
10
10
|
private container;
|
|
11
11
|
readonly tap$: Observable<{
|
|
12
12
|
event: Event;
|
|
13
|
-
highlight:
|
|
13
|
+
highlight: RuntimeAnnotation;
|
|
14
14
|
}>;
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
private resolvedCfi$;
|
|
16
|
+
constructor(spineItem: SpineItem, containerElement: HTMLElement, reader: Reader, highlight: RuntimeAnnotation, isSelected: Observable<boolean>);
|
|
17
|
+
render(): Observable<null | undefined>;
|
|
17
18
|
isWithinTarget(target: Node): boolean;
|
|
18
19
|
destroy(): void;
|
|
19
20
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { DestroyableClass, Reader, SpineItem } from '@prose-reader/core';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
|
-
import { ProseHighlight } from './Highlight';
|
|
4
3
|
import { SpineItemHighlight } from './SpineItemHighlight';
|
|
4
|
+
import { RuntimeAnnotation } from './types';
|
|
5
5
|
export declare class SpineItemHighlights extends DestroyableClass {
|
|
6
|
-
private
|
|
6
|
+
private annotations$;
|
|
7
7
|
private spineItem;
|
|
8
8
|
private reader;
|
|
9
9
|
private selectedHighlight;
|
|
10
10
|
private layer;
|
|
11
11
|
private highlights;
|
|
12
12
|
readonly tap$: SpineItemHighlight["tap$"];
|
|
13
|
-
constructor(
|
|
14
|
-
layout():
|
|
13
|
+
constructor(annotations$: Observable<RuntimeAnnotation[]>, spineItem: SpineItem, reader: Reader, selectedHighlight: Observable<string | undefined>);
|
|
14
|
+
layout(): Observable<(null | undefined)[] | null>;
|
|
15
15
|
getHighlightsForTarget(target: EventTarget): SpineItemHighlight[];
|
|
16
16
|
destroy(): void;
|
|
17
17
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isDefined } from 'reactjrx';
|
|
2
|
-
import { Subject, filter, fromEvent, map, share, skip, tap, takeUntil, switchMap, distinctUntilChanged, of,
|
|
2
|
+
import { Subject, filter, fromEvent, map, share, shareReplay, skip, tap, takeUntil, merge, first, switchMap, distinctUntilChanged, of, forkJoin, defaultIfEmpty, BehaviorSubject, debounceTime, combineLatest } from 'rxjs';
|
|
3
3
|
import { DestroyableClass } from '@prose-reader/core';
|
|
4
4
|
|
|
5
5
|
class Commands extends DestroyableClass {
|
|
6
6
|
commandSubject = new Subject();
|
|
7
|
-
|
|
8
|
-
filter((command) => command.type === "
|
|
7
|
+
annotate$ = this.commandSubject.pipe(
|
|
8
|
+
filter((command) => command.type === "annotate")
|
|
9
9
|
);
|
|
10
10
|
add$ = this.commandSubject.pipe(
|
|
11
11
|
filter((command) => command.type === "add")
|
|
@@ -22,8 +22,11 @@ class Commands extends DestroyableClass {
|
|
|
22
22
|
reset$ = this.commandSubject.pipe(
|
|
23
23
|
filter((command) => command.type === "reset")
|
|
24
24
|
);
|
|
25
|
-
|
|
26
|
-
this.commandSubject.next({ type: "
|
|
25
|
+
annotate = (params) => {
|
|
26
|
+
this.commandSubject.next({ type: "annotate", data: params });
|
|
27
|
+
};
|
|
28
|
+
annotateAbsolutePage = (params) => {
|
|
29
|
+
this.commandSubject.next({ type: "annotate", data: params });
|
|
27
30
|
};
|
|
28
31
|
add = (data) => {
|
|
29
32
|
this.commandSubject.next({ type: "add", data });
|
|
@@ -46,44 +49,6 @@ class Commands extends DestroyableClass {
|
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
51
|
|
|
49
|
-
class ProseHighlight {
|
|
50
|
-
cfi;
|
|
51
|
-
endCfi;
|
|
52
|
-
itemIndex;
|
|
53
|
-
color;
|
|
54
|
-
contents;
|
|
55
|
-
range;
|
|
56
|
-
selectionAsText;
|
|
57
|
-
/**
|
|
58
|
-
* Unique local ID. This is to ensure unicity
|
|
59
|
-
* for duplicate selections
|
|
60
|
-
*/
|
|
61
|
-
id;
|
|
62
|
-
constructor(params) {
|
|
63
|
-
this.cfi = params.cfi;
|
|
64
|
-
this.endCfi = params.endCfi;
|
|
65
|
-
this.itemIndex = params.itemIndex;
|
|
66
|
-
this.color = params.color;
|
|
67
|
-
this.contents = params.contents;
|
|
68
|
-
this.id = params.id;
|
|
69
|
-
this.selectionAsText = params.selectionAsText;
|
|
70
|
-
}
|
|
71
|
-
update(params) {
|
|
72
|
-
Object.assign(this, params);
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
toJSON() {
|
|
76
|
-
return {
|
|
77
|
-
cfi: this.cfi,
|
|
78
|
-
endCfi: this.endCfi,
|
|
79
|
-
color: this.color,
|
|
80
|
-
contents: this.contents,
|
|
81
|
-
id: this.id,
|
|
82
|
-
selectionAsText: this.selectionAsText
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
52
|
const createElementForRange = (range, container, color) => {
|
|
88
53
|
const rects = Array.from(range.getClientRects());
|
|
89
54
|
const lineGroups = /* @__PURE__ */ new Map();
|
|
@@ -156,7 +121,10 @@ class SpineItemHighlight extends DestroyableClass {
|
|
|
156
121
|
map((event) => ({ event, highlight: this.highlight })),
|
|
157
122
|
share()
|
|
158
123
|
);
|
|
159
|
-
this.
|
|
124
|
+
this.resolvedCfi$ = this.spineItem.loaded$.pipe(
|
|
125
|
+
map(() => this.reader.cfi.resolveCfi({ cfi: this.highlight.cfi })),
|
|
126
|
+
shareReplay({ refCount: true, bufferSize: 1 })
|
|
127
|
+
);
|
|
160
128
|
this.isSelected.pipe(
|
|
161
129
|
skip(1),
|
|
162
130
|
tap((isSelected2) => {
|
|
@@ -168,38 +136,47 @@ class SpineItemHighlight extends DestroyableClass {
|
|
|
168
136
|
}),
|
|
169
137
|
takeUntil(this.destroy$)
|
|
170
138
|
).subscribe();
|
|
139
|
+
merge(this.resolvedCfi$).pipe(takeUntil(this.destroy$)).subscribe();
|
|
171
140
|
}
|
|
172
141
|
container;
|
|
173
142
|
tap$;
|
|
143
|
+
resolvedCfi$;
|
|
174
144
|
render() {
|
|
175
|
-
this.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
145
|
+
return this.resolvedCfi$.pipe(
|
|
146
|
+
first(),
|
|
147
|
+
map((resolvedCfi) => {
|
|
148
|
+
if (!resolvedCfi || !resolvedCfi.isRange) return void 0;
|
|
149
|
+
const range = resolvedCfi.range;
|
|
150
|
+
this.container.innerHTML = "";
|
|
151
|
+
if (!range) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const rectElements = createElementForRange(
|
|
155
|
+
range,
|
|
156
|
+
this.container,
|
|
157
|
+
this.highlight.highlightColor ?? "yellow"
|
|
158
|
+
);
|
|
159
|
+
rectElements.forEach((elt) => {
|
|
160
|
+
elt.style.pointerEvents = "initial";
|
|
161
|
+
elt.style.cursor = "pointer";
|
|
162
|
+
elt.dataset.highlightRect = this.highlight.id;
|
|
163
|
+
this.container.appendChild(elt);
|
|
164
|
+
});
|
|
165
|
+
const firstElement = rectElements[0];
|
|
166
|
+
if (firstElement && this.highlight.notes) {
|
|
167
|
+
const noteIcon = document.createElement("span");
|
|
168
|
+
noteIcon.textContent = "📝";
|
|
169
|
+
noteIcon.style.position = "absolute";
|
|
170
|
+
noteIcon.style.top = "0";
|
|
171
|
+
noteIcon.style.left = "0";
|
|
172
|
+
noteIcon.style.transform = "translate(-0%, -80%)";
|
|
173
|
+
noteIcon.style.fontSize = "18px";
|
|
174
|
+
noteIcon.style.opacity = "50%";
|
|
175
|
+
firstElement.appendChild(noteIcon);
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
})
|
|
184
179
|
);
|
|
185
|
-
rectElements.forEach((elt) => {
|
|
186
|
-
elt.style.pointerEvents = "initial";
|
|
187
|
-
elt.style.cursor = "pointer";
|
|
188
|
-
elt.dataset.highlightRect = this.highlight.id;
|
|
189
|
-
this.container.appendChild(elt);
|
|
190
|
-
});
|
|
191
|
-
const firstElement = rectElements[0];
|
|
192
|
-
if (firstElement && this.highlight.contents?.length) {
|
|
193
|
-
const noteIcon = document.createElement("span");
|
|
194
|
-
noteIcon.textContent = "📝";
|
|
195
|
-
noteIcon.style.position = "absolute";
|
|
196
|
-
noteIcon.style.top = "0";
|
|
197
|
-
noteIcon.style.left = "0";
|
|
198
|
-
noteIcon.style.transform = "translate(-0%, -80%)";
|
|
199
|
-
noteIcon.style.fontSize = "18px";
|
|
200
|
-
noteIcon.style.opacity = "50%";
|
|
201
|
-
firstElement.appendChild(noteIcon);
|
|
202
|
-
}
|
|
203
180
|
}
|
|
204
181
|
isWithinTarget(target) {
|
|
205
182
|
return this.container.contains(target);
|
|
@@ -211,9 +188,9 @@ class SpineItemHighlight extends DestroyableClass {
|
|
|
211
188
|
}
|
|
212
189
|
|
|
213
190
|
class SpineItemHighlights extends DestroyableClass {
|
|
214
|
-
constructor(
|
|
191
|
+
constructor(annotations$, spineItem, reader, selectedHighlight) {
|
|
215
192
|
super();
|
|
216
|
-
this.
|
|
193
|
+
this.annotations$ = annotations$;
|
|
217
194
|
this.spineItem = spineItem;
|
|
218
195
|
this.reader = reader;
|
|
219
196
|
this.selectedHighlight = selectedHighlight;
|
|
@@ -222,7 +199,7 @@ class SpineItemHighlights extends DestroyableClass {
|
|
|
222
199
|
this.spineItem.containerElement,
|
|
223
200
|
firstLayerElement
|
|
224
201
|
);
|
|
225
|
-
const itemHighlights$ = this.
|
|
202
|
+
const itemHighlights$ = this.annotations$.pipe(
|
|
226
203
|
switchMap((annotations) => {
|
|
227
204
|
this.highlights.forEach((highlight) => highlight.destroy());
|
|
228
205
|
this.highlights = [];
|
|
@@ -251,7 +228,7 @@ class SpineItemHighlights extends DestroyableClass {
|
|
|
251
228
|
(highlights) => merge(...highlights.map((highlight) => highlight.tap$))
|
|
252
229
|
)
|
|
253
230
|
);
|
|
254
|
-
|
|
231
|
+
annotations$.subscribe();
|
|
255
232
|
}
|
|
256
233
|
layer;
|
|
257
234
|
highlights = [];
|
|
@@ -259,7 +236,9 @@ class SpineItemHighlights extends DestroyableClass {
|
|
|
259
236
|
layout() {
|
|
260
237
|
const firstLayerElement = this.spineItem.renderer.documentContainer ?? document.createElement("div");
|
|
261
238
|
layoutAnnotationLayer(firstLayerElement, this.layer);
|
|
262
|
-
|
|
239
|
+
return forkJoin(
|
|
240
|
+
this.highlights.map((highlight) => highlight.render())
|
|
241
|
+
).pipe(defaultIfEmpty(null));
|
|
263
242
|
}
|
|
264
243
|
getHighlightsForTarget(target) {
|
|
265
244
|
return this.highlights.filter(
|
|
@@ -321,97 +300,97 @@ class ReaderHighlights extends DestroyableClass {
|
|
|
321
300
|
return !!this.getHighlightsForTarget(target).length;
|
|
322
301
|
};
|
|
323
302
|
layout() {
|
|
324
|
-
|
|
303
|
+
return forkJoin(
|
|
304
|
+
this.spineItemHighlights.value.map((item) => item.layout())
|
|
305
|
+
).pipe(defaultIfEmpty(null));
|
|
325
306
|
}
|
|
326
307
|
}
|
|
327
308
|
|
|
328
|
-
const consolidate = (highlight, reader) => {
|
|
329
|
-
const { itemIndex } = reader.cfi.parseCfi(highlight.cfi ?? "");
|
|
330
|
-
const spineItem = reader.spineItemsManager.get(itemIndex);
|
|
331
|
-
if (!spineItem) return of(highlight);
|
|
332
|
-
return of(highlight).pipe(
|
|
333
|
-
withLatestFrom(spineItem.isReady$),
|
|
334
|
-
tap(([, isItemReady]) => {
|
|
335
|
-
const startCfi = reader.cfi.resolveCfi({ cfi: highlight.cfi ?? "" });
|
|
336
|
-
const resolvedFocusCfi = reader.cfi.resolveCfi({
|
|
337
|
-
cfi: highlight.endCfi ?? ""
|
|
338
|
-
});
|
|
339
|
-
if (startCfi?.node && resolvedFocusCfi?.node && isItemReady) {
|
|
340
|
-
const range = startCfi?.node.ownerDocument?.createRange();
|
|
341
|
-
range?.setStart(startCfi?.node, startCfi.offset ?? 0);
|
|
342
|
-
range?.setEnd(resolvedFocusCfi?.node, resolvedFocusCfi.offset ?? 0);
|
|
343
|
-
highlight.range = range;
|
|
344
|
-
highlight.selectionAsText = range?.toString();
|
|
345
|
-
} else {
|
|
346
|
-
highlight.range = void 0;
|
|
347
|
-
}
|
|
348
|
-
}),
|
|
349
|
-
map(() => highlight)
|
|
350
|
-
);
|
|
351
|
-
};
|
|
352
|
-
|
|
353
309
|
const d = () => {
|
|
354
310
|
if (!(typeof window > "u"))
|
|
355
311
|
return window;
|
|
356
312
|
};
|
|
357
|
-
function
|
|
313
|
+
function h() {
|
|
358
314
|
var n;
|
|
359
315
|
const e = (n = d()) == null ? void 0 : n.__PROSE_READER_DEBUG;
|
|
360
316
|
return e === true || e === "true";
|
|
361
317
|
}
|
|
362
|
-
const
|
|
363
|
-
namespace: (
|
|
364
|
-
debug: n ? e ? Function.prototype.bind.call(console.debug, console,
|
|
318
|
+
const u = (e, n = h(), t) => ({
|
|
319
|
+
namespace: (o, l) => u(`[${e}] [${o}]`, l, t),
|
|
320
|
+
debug: n ? e ? Function.prototype.bind.call(console.debug, console, e) : Function.prototype.bind.call(console.debug, console) : () => {
|
|
365
321
|
},
|
|
366
|
-
info: n ? e ? Function.prototype.bind.call(
|
|
322
|
+
info: n ? e ? Function.prototype.bind.call(
|
|
323
|
+
console.info,
|
|
324
|
+
console,
|
|
325
|
+
`%c${e}`,
|
|
326
|
+
t != null && t.color ? `color: ${t.color}` : void 0
|
|
327
|
+
) : Function.prototype.bind.call(console.info, console) : () => {
|
|
367
328
|
},
|
|
368
|
-
log: n ? e ? Function.prototype.bind.call(console.log, console,
|
|
329
|
+
log: n ? e ? Function.prototype.bind.call(console.log, console, e) : Function.prototype.bind.call(console.log, console) : () => {
|
|
369
330
|
},
|
|
370
|
-
warn: n ? e ? Function.prototype.bind.call(console.warn, console,
|
|
331
|
+
warn: n ? e ? Function.prototype.bind.call(console.warn, console, e) : Function.prototype.bind.call(console.warn, console) : () => {
|
|
371
332
|
},
|
|
372
|
-
error: n ? e ? Function.prototype.bind.call(console.error, console,
|
|
333
|
+
error: n ? e ? Function.prototype.bind.call(console.error, console, e) : Function.prototype.bind.call(console.error, console) : () => {
|
|
373
334
|
}
|
|
374
|
-
}),
|
|
375
|
-
...
|
|
376
|
-
namespace: (e, n) =>
|
|
335
|
+
}), F = {
|
|
336
|
+
...u(),
|
|
337
|
+
namespace: (e, n, t) => u(e, n, t)
|
|
377
338
|
};
|
|
378
339
|
|
|
379
340
|
const name = "@prose-reader/enhancer-annotations";
|
|
380
341
|
|
|
381
342
|
const IS_DEBUG_ENABLED = true;
|
|
382
|
-
const report =
|
|
343
|
+
const report = F.namespace(name, IS_DEBUG_ENABLED);
|
|
383
344
|
|
|
384
345
|
const annotationsEnhancer = (next) => (options) => {
|
|
385
346
|
const reader = next(options);
|
|
386
347
|
const commands = new Commands();
|
|
387
|
-
const
|
|
348
|
+
const annotationsSubject = new BehaviorSubject([]);
|
|
388
349
|
const selectedHighlightSubject = new BehaviorSubject(
|
|
389
350
|
void 0
|
|
390
351
|
);
|
|
391
|
-
const
|
|
352
|
+
const annotations$ = annotationsSubject.asObservable().pipe(
|
|
353
|
+
distinctUntilChanged(),
|
|
354
|
+
tap((annotations) => {
|
|
355
|
+
report.debug("annotations", annotations);
|
|
356
|
+
}),
|
|
357
|
+
shareReplay({
|
|
358
|
+
refCount: true,
|
|
359
|
+
bufferSize: 1
|
|
360
|
+
})
|
|
361
|
+
);
|
|
392
362
|
const readerHighlights = new ReaderHighlights(
|
|
393
363
|
reader,
|
|
394
|
-
|
|
364
|
+
annotationsSubject,
|
|
395
365
|
selectedHighlightSubject
|
|
396
366
|
);
|
|
397
|
-
const
|
|
398
|
-
|
|
367
|
+
const resolveItemInformation = (params) => {
|
|
368
|
+
if (params.itemIndex !== void 0)
|
|
369
|
+
return { itemIndex: params.itemIndex, pageIndex: void 0 };
|
|
370
|
+
if (params.absolutePageIndex !== void 0) {
|
|
371
|
+
return reader.spine.locator.getSpineInfoFromAbsolutePageIndex({
|
|
372
|
+
absolutePageIndex: params.absolutePageIndex
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
return void 0;
|
|
376
|
+
};
|
|
377
|
+
const annotated$ = commands.annotate$.pipe(
|
|
378
|
+
map(({ data: { selection, ...rest } }) => {
|
|
379
|
+
const { itemIndex, pageIndex = 0 } = resolveItemInformation(rest) ?? {};
|
|
399
380
|
const spineItem = reader.spineItemsManager.get(itemIndex);
|
|
400
381
|
if (!spineItem) return void 0;
|
|
401
|
-
const range = reader.selection.createOrderedRangeFromSelection({
|
|
382
|
+
const range = selection ? reader.selection.createOrderedRangeFromSelection({
|
|
402
383
|
selection,
|
|
403
384
|
spineItem
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
endCfi,
|
|
410
|
-
itemIndex,
|
|
385
|
+
}) : void 0;
|
|
386
|
+
const cfi = range ? reader.cfi.generateCfiFromRange(range, spineItem.item) : reader.cfi.generateCfiForSpineItemPage({ pageIndex, spineItem });
|
|
387
|
+
const highlight = {
|
|
388
|
+
cfi,
|
|
389
|
+
itemIndex: spineItem.index,
|
|
411
390
|
id: window.crypto.randomUUID(),
|
|
412
391
|
...rest
|
|
413
|
-
}
|
|
414
|
-
|
|
392
|
+
};
|
|
393
|
+
annotationsSubject.next([...annotationsSubject.getValue(), highlight]);
|
|
415
394
|
return [highlight.id];
|
|
416
395
|
}),
|
|
417
396
|
filter(isDefined),
|
|
@@ -421,28 +400,31 @@ const annotationsEnhancer = (next) => (options) => {
|
|
|
421
400
|
map(({ data }) => {
|
|
422
401
|
const annotations = Array.isArray(data) ? data : [data];
|
|
423
402
|
const addedHighlights = annotations.map((annotation) => {
|
|
424
|
-
const { itemIndex } = reader.cfi.parseCfi(annotation.cfi ?? "");
|
|
425
|
-
const highlight =
|
|
403
|
+
const { itemIndex = 0 } = reader.cfi.parseCfi(annotation.cfi ?? "");
|
|
404
|
+
const highlight = {
|
|
405
|
+
...annotation,
|
|
406
|
+
itemIndex
|
|
407
|
+
};
|
|
426
408
|
return highlight;
|
|
427
409
|
});
|
|
428
|
-
|
|
429
|
-
...
|
|
410
|
+
annotationsSubject.next([
|
|
411
|
+
...annotationsSubject.getValue(),
|
|
430
412
|
...addedHighlights
|
|
431
413
|
]);
|
|
432
414
|
})
|
|
433
415
|
);
|
|
434
416
|
const delete$ = commands.delete$.pipe(
|
|
435
417
|
tap(({ id }) => {
|
|
436
|
-
|
|
437
|
-
|
|
418
|
+
annotationsSubject.next(
|
|
419
|
+
annotationsSubject.getValue().filter((highlight) => highlight.id !== id)
|
|
438
420
|
);
|
|
439
421
|
})
|
|
440
422
|
);
|
|
441
423
|
const update$ = commands.update$.pipe(
|
|
442
424
|
tap(({ id, data }) => {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
return highlight.id === id ? highlight
|
|
425
|
+
annotationsSubject.next(
|
|
426
|
+
annotationsSubject.getValue().map((highlight) => {
|
|
427
|
+
return highlight.id === id ? { ...highlight, ...data } : highlight;
|
|
446
428
|
})
|
|
447
429
|
);
|
|
448
430
|
})
|
|
@@ -454,55 +436,52 @@ const annotationsEnhancer = (next) => (options) => {
|
|
|
454
436
|
);
|
|
455
437
|
const reset$ = commands.reset$.pipe(
|
|
456
438
|
tap(() => {
|
|
457
|
-
|
|
439
|
+
annotationsSubject.next([]);
|
|
458
440
|
})
|
|
459
441
|
);
|
|
460
|
-
const
|
|
442
|
+
const renderAnnotations$ = merge(annotations$, reader.layout$).pipe(
|
|
461
443
|
debounceTime(50),
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
)
|
|
444
|
+
switchMap(() => readerHighlights.layout())
|
|
445
|
+
);
|
|
446
|
+
const candidates$ = reader.layoutInfo$.pipe(
|
|
447
|
+
switchMap(
|
|
448
|
+
({ pages }) => combineLatest(
|
|
449
|
+
pages.map((page) => {
|
|
450
|
+
const item = reader.spineItemsManager.get(page.itemIndex);
|
|
451
|
+
if (!item) return of(false);
|
|
452
|
+
if (item.renditionLayout === "pre-paginated") return of(true);
|
|
453
|
+
if (page.firstVisibleNode) return of(true);
|
|
454
|
+
return of(false);
|
|
455
|
+
})
|
|
468
456
|
)
|
|
469
|
-
)
|
|
470
|
-
tap((consolidatedHighlights) => {
|
|
471
|
-
const consolidatedExistingHighlights = highlightsSubject.value.map(
|
|
472
|
-
(highlight) => consolidatedHighlights.find((c) => c.id === highlight.id) ?? highlight
|
|
473
|
-
);
|
|
474
|
-
highlightsSubject.next(consolidatedExistingHighlights);
|
|
475
|
-
readerHighlights.layout();
|
|
476
|
-
})
|
|
457
|
+
)
|
|
477
458
|
);
|
|
478
459
|
merge(
|
|
479
|
-
|
|
460
|
+
annotated$,
|
|
480
461
|
add$,
|
|
481
462
|
delete$,
|
|
482
463
|
update$,
|
|
483
464
|
select$,
|
|
484
465
|
reset$,
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
tap((annotations) => {
|
|
488
|
-
report.debug("highlights", annotations);
|
|
489
|
-
})
|
|
490
|
-
)
|
|
466
|
+
renderAnnotations$,
|
|
467
|
+
annotations$
|
|
491
468
|
).pipe(takeUntil(reader.$.destroy$)).subscribe();
|
|
492
469
|
return {
|
|
493
470
|
...reader,
|
|
494
471
|
__PROSE_READER_ENHANCER_ANNOTATIONS: true,
|
|
495
472
|
destroy: () => {
|
|
496
|
-
|
|
473
|
+
annotationsSubject.complete();
|
|
497
474
|
commands.destroy();
|
|
498
475
|
readerHighlights.destroy();
|
|
499
476
|
reader.destroy();
|
|
500
477
|
},
|
|
501
478
|
annotations: {
|
|
502
|
-
|
|
479
|
+
annotations$,
|
|
503
480
|
highlightTap$: readerHighlights.tap$,
|
|
481
|
+
candidates$,
|
|
504
482
|
isTargetWithinHighlight: readerHighlights.isTargetWithinHighlight,
|
|
505
|
-
|
|
483
|
+
annotate: commands.annotate,
|
|
484
|
+
annotateAbsolutePage: commands.annotateAbsolutePage,
|
|
506
485
|
add: commands.add,
|
|
507
486
|
delete: commands.delete,
|
|
508
487
|
update: commands.update,
|
|
@@ -512,5 +491,5 @@ const annotationsEnhancer = (next) => (options) => {
|
|
|
512
491
|
};
|
|
513
492
|
};
|
|
514
493
|
|
|
515
|
-
export {
|
|
494
|
+
export { annotationsEnhancer };
|
|
516
495
|
//# sourceMappingURL=index.js.map
|