@embedpdf/plugin-annotation 1.4.1 → 2.0.0-next.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/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1760 -1444
- package/dist/index.js.map +1 -1
- package/dist/lib/actions.d.ts +58 -19
- package/dist/lib/annotation-plugin.d.ts +14 -5
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/reducer.d.ts +2 -1
- package/dist/lib/selectors.d.ts +10 -8
- package/dist/lib/types.d.ts +53 -10
- package/dist/preact/index.cjs +1 -1
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.js +96 -48
- package/dist/preact/index.js.map +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +96 -48
- package/dist/react/index.js.map +1 -1
- package/dist/shared/components/annotation-container.d.ts +4 -3
- package/dist/shared/components/annotation-layer.d.ts +7 -7
- package/dist/shared/components/annotation-paint-layer.d.ts +2 -1
- package/dist/shared/components/annotations/stamp.d.ts +2 -1
- package/dist/shared/components/annotations.d.ts +3 -2
- package/dist/shared/components/render-annotation.d.ts +2 -1
- package/dist/shared/components/text-markup.d.ts +2 -1
- package/dist/shared/components/types.d.ts +7 -7
- package/dist/shared/hooks/use-annotation.d.ts +8 -4
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared-preact/components/annotation-container.d.ts +4 -3
- package/dist/shared-preact/components/annotation-layer.d.ts +7 -7
- package/dist/shared-preact/components/annotation-paint-layer.d.ts +2 -1
- package/dist/shared-preact/components/annotations/stamp.d.ts +2 -1
- package/dist/shared-preact/components/annotations.d.ts +3 -2
- package/dist/shared-preact/components/render-annotation.d.ts +2 -1
- package/dist/shared-preact/components/text-markup.d.ts +2 -1
- package/dist/shared-preact/components/types.d.ts +7 -7
- package/dist/shared-preact/hooks/use-annotation.d.ts +8 -4
- package/dist/shared-preact/index.d.ts +1 -0
- package/dist/shared-react/components/annotation-container.d.ts +4 -3
- package/dist/shared-react/components/annotation-layer.d.ts +7 -7
- package/dist/shared-react/components/annotation-paint-layer.d.ts +2 -1
- package/dist/shared-react/components/annotations/stamp.d.ts +2 -1
- package/dist/shared-react/components/annotations.d.ts +3 -2
- package/dist/shared-react/components/render-annotation.d.ts +2 -1
- package/dist/shared-react/components/text-markup.d.ts +2 -1
- package/dist/shared-react/components/types.d.ts +7 -7
- package/dist/shared-react/hooks/use-annotation.d.ts +8 -4
- package/dist/shared-react/index.d.ts +1 -0
- package/dist/svelte/components/AnnotationContainer.svelte.d.ts +26 -0
- package/dist/svelte/components/AnnotationLayer.svelte.d.ts +27 -0
- package/dist/svelte/components/AnnotationPaintLayer.svelte.d.ts +8 -0
- package/dist/svelte/components/Annotations.svelte.d.ts +22 -0
- package/dist/svelte/components/PreviewRenderer.svelte.d.ts +8 -0
- package/dist/svelte/components/RenderAnnotation.svelte.d.ts +13 -0
- package/dist/svelte/components/TextMarkup.svelte.d.ts +8 -0
- package/dist/svelte/components/annotations/Circle.svelte.d.ts +26 -0
- package/dist/svelte/components/annotations/FreeText.svelte.d.ts +15 -0
- package/dist/svelte/components/annotations/Ink.svelte.d.ts +14 -0
- package/dist/svelte/components/annotations/Line.svelte.d.ts +18 -0
- package/dist/svelte/components/annotations/Polygon.svelte.d.ts +19 -0
- package/dist/svelte/components/annotations/Polyline.svelte.d.ts +17 -0
- package/dist/svelte/components/annotations/Square.svelte.d.ts +16 -0
- package/dist/svelte/components/annotations/Stamp.svelte.d.ts +13 -0
- package/dist/svelte/components/annotations/index.d.ts +8 -0
- package/dist/svelte/components/index.d.ts +9 -0
- package/dist/svelte/components/text-markup/Highlight.svelte.d.ts +13 -0
- package/dist/svelte/components/text-markup/Squiggly.svelte.d.ts +13 -0
- package/dist/svelte/components/text-markup/Strikeout.svelte.d.ts +13 -0
- package/dist/svelte/components/text-markup/Underline.svelte.d.ts +13 -0
- package/dist/svelte/components/text-markup/index.d.ts +4 -0
- package/dist/svelte/components/types.d.ts +32 -0
- package/dist/svelte/hooks/index.d.ts +1 -0
- package/dist/svelte/hooks/use-annotation.svelte.d.ts +21 -0
- package/dist/svelte/index.cjs +2 -0
- package/dist/svelte/index.cjs.map +1 -0
- package/dist/svelte/index.d.ts +4 -0
- package/dist/svelte/index.js +3083 -0
- package/dist/svelte/index.js.map +1 -0
- package/dist/svelte/types.d.ts +54 -0
- package/dist/vue/components/annotation-container.vue.d.ts +10 -5
- package/dist/vue/components/annotation-layer.vue.d.ts +13 -7
- package/dist/vue/components/annotation-paint-layer.vue.d.ts +3 -1
- package/dist/vue/components/annotations/circle.vue.d.ts +2 -1
- package/dist/vue/components/annotations/free-text.vue.d.ts +2 -1
- package/dist/vue/components/annotations/ink.vue.d.ts +2 -1
- package/dist/vue/components/annotations/line.vue.d.ts +2 -1
- package/dist/vue/components/annotations/polygon.vue.d.ts +2 -1
- package/dist/vue/components/annotations/polyline.vue.d.ts +2 -1
- package/dist/vue/components/annotations/square.vue.d.ts +2 -1
- package/dist/vue/components/annotations/stamp.vue.d.ts +3 -1
- package/dist/vue/components/annotations.vue.d.ts +7 -3
- package/dist/vue/components/preview-renderer.vue.d.ts +2 -1
- package/dist/vue/components/render-annotation.vue.d.ts +3 -1
- package/dist/vue/components/text-markup/highlight.vue.d.ts +2 -1
- package/dist/vue/components/text-markup/squiggly.vue.d.ts +2 -1
- package/dist/vue/components/text-markup/strikeout.vue.d.ts +2 -1
- package/dist/vue/components/text-markup/underline.vue.d.ts +2 -1
- package/dist/vue/components/text-markup.vue.d.ts +3 -1
- package/dist/vue/hooks/use-annotation.d.ts +21 -2682
- package/dist/vue/index.cjs +1 -1
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.d.ts +1 -0
- package/dist/vue/index.js +354 -250
- package/dist/vue/index.js.map +1 -1
- package/dist/vue/types.d.ts +23 -0
- package/package.json +20 -12
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { clamp, BasePlugin, createBehaviorEmitter
|
|
2
|
-
import { PdfAnnotationSubtype,
|
|
1
|
+
import { clamp, BasePlugin, createBehaviorEmitter } from "@embedpdf/core";
|
|
2
|
+
import { PdfAnnotationSubtype, PdfBlendMode, PdfAnnotationBorderStyle, PdfAnnotationLineEnding, PdfVerticalAlignment, PdfTextAlignment, PdfStandardFont, expandRect, rectFromPoints, uuidV4, rotateAndTranslatePoint, PdfAnnotationIcon, ignore, PdfTaskHelper, PdfErrorCode, Task } from "@embedpdf/models";
|
|
3
3
|
const ANNOTATION_PLUGIN_ID = "annotation";
|
|
4
4
|
const manifest = {
|
|
5
5
|
id: ANNOTATION_PLUGIN_ID,
|
|
@@ -16,51 +16,75 @@ const manifest = {
|
|
|
16
16
|
selectAfterCreate: true
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
+
const INIT_ANNOTATION_STATE = "ANNOTATION/INIT_STATE";
|
|
20
|
+
const CLEANUP_ANNOTATION_STATE = "ANNOTATION/CLEANUP_STATE";
|
|
21
|
+
const SET_ACTIVE_DOCUMENT = "ANNOTATION/SET_ACTIVE_DOCUMENT";
|
|
19
22
|
const SET_ANNOTATIONS = "ANNOTATION/SET_ANNOTATIONS";
|
|
20
23
|
const SELECT_ANNOTATION = "ANNOTATION/SELECT_ANNOTATION";
|
|
21
24
|
const DESELECT_ANNOTATION = "ANNOTATION/DESELECT_ANNOTATION";
|
|
22
|
-
const
|
|
25
|
+
const SET_ACTIVE_TOOL_ID = "ANNOTATION/SET_ACTIVE_TOOL_ID";
|
|
23
26
|
const CREATE_ANNOTATION = "ANNOTATION/CREATE_ANNOTATION";
|
|
24
27
|
const PATCH_ANNOTATION = "ANNOTATION/PATCH_ANNOTATION";
|
|
25
28
|
const DELETE_ANNOTATION = "ANNOTATION/DELETE_ANNOTATION";
|
|
26
29
|
const COMMIT_PENDING_CHANGES = "ANNOTATION/COMMIT";
|
|
27
30
|
const PURGE_ANNOTATION = "ANNOTATION/PURGE_ANNOTATION";
|
|
28
|
-
const
|
|
31
|
+
const ADD_COLOR_PRESET = "ANNOTATION/ADD_COLOR_PRESET";
|
|
29
32
|
const SET_TOOL_DEFAULTS = "ANNOTATION/SET_TOOL_DEFAULTS";
|
|
30
33
|
const ADD_TOOL = "ANNOTATION/ADD_TOOL";
|
|
31
|
-
|
|
34
|
+
function initAnnotationState(documentId, state) {
|
|
35
|
+
return { type: INIT_ANNOTATION_STATE, payload: { documentId, state } };
|
|
36
|
+
}
|
|
37
|
+
function cleanupAnnotationState(documentId) {
|
|
38
|
+
return { type: CLEANUP_ANNOTATION_STATE, payload: documentId };
|
|
39
|
+
}
|
|
40
|
+
const setAnnotations = (documentId, annotations) => ({
|
|
32
41
|
type: SET_ANNOTATIONS,
|
|
33
|
-
payload:
|
|
42
|
+
payload: { documentId, annotations }
|
|
34
43
|
});
|
|
35
|
-
const selectAnnotation = (pageIndex, id) => ({
|
|
44
|
+
const selectAnnotation = (documentId, pageIndex, id) => ({
|
|
36
45
|
type: SELECT_ANNOTATION,
|
|
37
|
-
payload: { pageIndex, id }
|
|
46
|
+
payload: { documentId, pageIndex, id }
|
|
38
47
|
});
|
|
39
|
-
const deselectAnnotation = () => ({
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
const deselectAnnotation = (documentId) => ({
|
|
49
|
+
type: DESELECT_ANNOTATION,
|
|
50
|
+
payload: { documentId }
|
|
51
|
+
});
|
|
52
|
+
const setActiveToolId = (documentId, toolId) => ({
|
|
53
|
+
type: SET_ACTIVE_TOOL_ID,
|
|
54
|
+
payload: { documentId, toolId }
|
|
55
|
+
});
|
|
56
|
+
const createAnnotation = (documentId, pageIndex, annotation) => ({
|
|
57
|
+
type: CREATE_ANNOTATION,
|
|
58
|
+
payload: { documentId, pageIndex, annotation }
|
|
43
59
|
});
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
60
|
+
const patchAnnotation = (documentId, pageIndex, id, patch) => ({
|
|
61
|
+
type: PATCH_ANNOTATION,
|
|
62
|
+
payload: { documentId, pageIndex, id, patch }
|
|
63
|
+
});
|
|
64
|
+
const deleteAnnotation = (documentId, pageIndex, id) => ({
|
|
47
65
|
type: DELETE_ANNOTATION,
|
|
48
|
-
payload: { pageIndex, id }
|
|
66
|
+
payload: { documentId, pageIndex, id }
|
|
67
|
+
});
|
|
68
|
+
const commitPendingChanges = (documentId) => ({
|
|
69
|
+
type: COMMIT_PENDING_CHANGES,
|
|
70
|
+
payload: { documentId }
|
|
49
71
|
});
|
|
50
|
-
const
|
|
51
|
-
const purgeAnnotation = (uid) => ({
|
|
72
|
+
const purgeAnnotation = (documentId, uid) => ({
|
|
52
73
|
type: PURGE_ANNOTATION,
|
|
53
|
-
payload: { uid }
|
|
74
|
+
payload: { documentId, uid }
|
|
54
75
|
});
|
|
55
|
-
const
|
|
56
|
-
type:
|
|
57
|
-
payload:
|
|
76
|
+
const addColorPreset = (c) => ({
|
|
77
|
+
type: ADD_COLOR_PRESET,
|
|
78
|
+
payload: c
|
|
58
79
|
});
|
|
59
80
|
const setToolDefaults = (toolId, patch) => ({
|
|
60
81
|
type: SET_TOOL_DEFAULTS,
|
|
61
82
|
payload: { toolId, patch }
|
|
62
83
|
});
|
|
63
|
-
const addTool = (tool) => ({
|
|
84
|
+
const addTool = (tool) => ({
|
|
85
|
+
type: ADD_TOOL,
|
|
86
|
+
payload: tool
|
|
87
|
+
});
|
|
64
88
|
function isInk(a) {
|
|
65
89
|
return a.object.type === PdfAnnotationSubtype.INK;
|
|
66
90
|
}
|
|
@@ -113,6 +137,7 @@ const getAnnotations = (s) => {
|
|
|
113
137
|
return out;
|
|
114
138
|
};
|
|
115
139
|
const getSelectedAnnotation = (s) => s.selectedUid ? s.byUid[s.selectedUid] : null;
|
|
140
|
+
const getAnnotationByUid = (s, uid) => s.byUid[uid] ?? null;
|
|
116
141
|
const getSelectedAnnotationByPageIndex = (s, pageIndex) => {
|
|
117
142
|
if (!s.selectedUid) return null;
|
|
118
143
|
const pageUids = s.pages[pageIndex] ?? [];
|
|
@@ -166,394 +191,942 @@ const getSidebarAnnotationsWithReplies = (s) => {
|
|
|
166
191
|
}
|
|
167
192
|
return out;
|
|
168
193
|
};
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const { onCommit, onPreview, getTool, pageSize } = context;
|
|
181
|
-
const [getStrokes, setStrokes] = useState([]);
|
|
182
|
-
const [getIsDrawing, setIsDrawing] = useState(false);
|
|
183
|
-
const timerRef = { current: null };
|
|
184
|
-
const clampToPage = (pos) => ({
|
|
185
|
-
x: clamp(pos.x, 0, pageSize.width),
|
|
186
|
-
y: clamp(pos.y, 0, pageSize.height)
|
|
187
|
-
});
|
|
188
|
-
const getDefaults = () => {
|
|
189
|
-
const tool = getTool();
|
|
190
|
-
if (!tool) return null;
|
|
191
|
-
return {
|
|
192
|
-
...tool.defaults,
|
|
193
|
-
strokeWidth: tool.defaults.strokeWidth ?? 1,
|
|
194
|
-
color: tool.defaults.color ?? "#000000",
|
|
195
|
-
opacity: tool.defaults.opacity ?? 1,
|
|
196
|
-
flags: tool.defaults.flags ?? ["print"]
|
|
197
|
-
};
|
|
198
|
-
};
|
|
199
|
-
const getPreview = () => {
|
|
200
|
-
const strokes = getStrokes();
|
|
201
|
-
if (strokes.length === 0 || strokes[0].points.length === 0) return null;
|
|
202
|
-
const defaults = getDefaults();
|
|
203
|
-
if (!defaults) return null;
|
|
204
|
-
const allPoints = strokes.flatMap((s) => s.points);
|
|
205
|
-
const bounds = expandRect(rectFromPoints(allPoints), defaults.strokeWidth / 2);
|
|
206
|
-
return {
|
|
207
|
-
type: PdfAnnotationSubtype.INK,
|
|
208
|
-
bounds,
|
|
209
|
-
data: {
|
|
210
|
-
...defaults,
|
|
211
|
-
rect: bounds,
|
|
212
|
-
inkList: strokes
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
};
|
|
216
|
-
return {
|
|
217
|
-
onPointerDown: (pos, evt) => {
|
|
218
|
-
var _a;
|
|
219
|
-
const clampedPos = clampToPage(pos);
|
|
220
|
-
setIsDrawing(true);
|
|
221
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
222
|
-
const newStrokes = [...getStrokes(), { points: [clampedPos] }];
|
|
223
|
-
setStrokes(newStrokes);
|
|
224
|
-
onPreview(getPreview());
|
|
225
|
-
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
226
|
-
},
|
|
227
|
-
onPointerMove: (pos) => {
|
|
228
|
-
if (!getIsDrawing()) return;
|
|
229
|
-
const strokes = getStrokes();
|
|
230
|
-
if (strokes.length === 0) return;
|
|
231
|
-
const clampedPos = clampToPage(pos);
|
|
232
|
-
strokes[strokes.length - 1].points.push(clampedPos);
|
|
233
|
-
setStrokes(strokes);
|
|
234
|
-
onPreview(getPreview());
|
|
235
|
-
},
|
|
236
|
-
onPointerUp: (_, evt) => {
|
|
237
|
-
var _a;
|
|
238
|
-
setIsDrawing(false);
|
|
239
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
240
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
241
|
-
timerRef.current = setTimeout(() => {
|
|
242
|
-
const strokes = getStrokes();
|
|
243
|
-
if (strokes.length > 0 && strokes[0].points.length > 1) {
|
|
244
|
-
const defaults = getDefaults();
|
|
245
|
-
if (!defaults) return;
|
|
246
|
-
const allPoints = strokes.flatMap((s) => s.points);
|
|
247
|
-
const rect = expandRect(rectFromPoints(allPoints), defaults.strokeWidth / 2);
|
|
248
|
-
onCommit({
|
|
249
|
-
...defaults,
|
|
250
|
-
inkList: strokes,
|
|
251
|
-
rect,
|
|
252
|
-
type: PdfAnnotationSubtype.INK,
|
|
253
|
-
pageIndex: context.pageIndex,
|
|
254
|
-
id: uuidV4(),
|
|
255
|
-
created: /* @__PURE__ */ new Date()
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
setStrokes([]);
|
|
259
|
-
onPreview(null);
|
|
260
|
-
}, 800);
|
|
261
|
-
},
|
|
262
|
-
onPointerCancel: (_, evt) => {
|
|
263
|
-
var _a;
|
|
264
|
-
setStrokes([]);
|
|
265
|
-
setIsDrawing(false);
|
|
266
|
-
onPreview(null);
|
|
267
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
268
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
function useClickDetector({
|
|
274
|
-
threshold = 5,
|
|
275
|
-
getTool,
|
|
276
|
-
onClickDetected
|
|
277
|
-
}) {
|
|
278
|
-
const [getStartPos, setStartPos] = useState(null);
|
|
279
|
-
const [getHasMoved, setHasMoved] = useState(false);
|
|
280
|
-
return {
|
|
281
|
-
onStart: (pos) => {
|
|
282
|
-
setStartPos(pos);
|
|
283
|
-
setHasMoved(false);
|
|
194
|
+
const defaultTools = [
|
|
195
|
+
// Text Markup Tools
|
|
196
|
+
{
|
|
197
|
+
id: "highlight",
|
|
198
|
+
name: "Highlight",
|
|
199
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.HIGHLIGHT ? 1 : 0,
|
|
200
|
+
interaction: {
|
|
201
|
+
exclusive: false,
|
|
202
|
+
textSelection: true,
|
|
203
|
+
isDraggable: false,
|
|
204
|
+
isResizable: false
|
|
284
205
|
},
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
206
|
+
defaults: {
|
|
207
|
+
type: PdfAnnotationSubtype.HIGHLIGHT,
|
|
208
|
+
color: "#FFCD45",
|
|
209
|
+
opacity: 1,
|
|
210
|
+
blendMode: PdfBlendMode.Multiply
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
id: "underline",
|
|
215
|
+
name: "Underline",
|
|
216
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.UNDERLINE ? 1 : 0,
|
|
217
|
+
interaction: {
|
|
218
|
+
exclusive: false,
|
|
219
|
+
textSelection: true,
|
|
220
|
+
isDraggable: false,
|
|
221
|
+
isResizable: false
|
|
292
222
|
},
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
223
|
+
defaults: {
|
|
224
|
+
type: PdfAnnotationSubtype.UNDERLINE,
|
|
225
|
+
color: "#E44234",
|
|
226
|
+
opacity: 1
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
id: "strikeout",
|
|
231
|
+
name: "Strikeout",
|
|
232
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.STRIKEOUT ? 1 : 0,
|
|
233
|
+
interaction: {
|
|
234
|
+
exclusive: false,
|
|
235
|
+
textSelection: true
|
|
304
236
|
},
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
237
|
+
defaults: {
|
|
238
|
+
type: PdfAnnotationSubtype.STRIKEOUT,
|
|
239
|
+
color: "#E44234",
|
|
240
|
+
opacity: 1
|
|
309
241
|
}
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
const freeTextHandlerFactory = {
|
|
313
|
-
annotationType: PdfAnnotationSubtype.FREETEXT,
|
|
314
|
-
create(context) {
|
|
315
|
-
const { onCommit, onPreview, getTool, pageSize, pageIndex } = context;
|
|
316
|
-
const [getStart, setStart] = useState(null);
|
|
317
|
-
const clampToPage = (pos) => ({
|
|
318
|
-
x: clamp(pos.x, 0, pageSize.width),
|
|
319
|
-
y: clamp(pos.y, 0, pageSize.height)
|
|
320
|
-
});
|
|
321
|
-
const getDefaults = () => {
|
|
322
|
-
const tool = getTool();
|
|
323
|
-
if (!tool) return null;
|
|
324
|
-
return {
|
|
325
|
-
...tool.defaults,
|
|
326
|
-
fontColor: tool.defaults.fontColor ?? "#000000",
|
|
327
|
-
opacity: tool.defaults.opacity ?? 1,
|
|
328
|
-
fontSize: tool.defaults.fontSize ?? 12,
|
|
329
|
-
fontFamily: tool.defaults.fontFamily ?? PdfStandardFont.Helvetica,
|
|
330
|
-
backgroundColor: tool.defaults.backgroundColor ?? "transparent",
|
|
331
|
-
textAlign: tool.defaults.textAlign ?? PdfTextAlignment.Left,
|
|
332
|
-
verticalAlign: tool.defaults.verticalAlign ?? PdfVerticalAlignment.Top,
|
|
333
|
-
contents: tool.defaults.contents ?? "Insert text here",
|
|
334
|
-
flags: tool.defaults.flags ?? ["print"]
|
|
335
|
-
};
|
|
336
|
-
};
|
|
337
|
-
const clickDetector = useClickDetector({
|
|
338
|
-
threshold: 5,
|
|
339
|
-
getTool,
|
|
340
|
-
onClickDetected: (pos, tool) => {
|
|
341
|
-
const defaults = getDefaults();
|
|
342
|
-
if (!defaults) return;
|
|
343
|
-
const clickConfig = tool.clickBehavior;
|
|
344
|
-
if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
|
|
345
|
-
const { width, height } = clickConfig.defaultSize;
|
|
346
|
-
const halfWidth = width / 2;
|
|
347
|
-
const halfHeight = height / 2;
|
|
348
|
-
const x = clamp(pos.x - halfWidth, 0, pageSize.width - width);
|
|
349
|
-
const y = clamp(pos.y - halfHeight, 0, pageSize.height - height);
|
|
350
|
-
const rect = {
|
|
351
|
-
origin: { x, y },
|
|
352
|
-
size: { width, height }
|
|
353
|
-
};
|
|
354
|
-
const contents = clickConfig.defaultContent ?? defaults.contents;
|
|
355
|
-
const anno = {
|
|
356
|
-
...defaults,
|
|
357
|
-
contents,
|
|
358
|
-
type: PdfAnnotationSubtype.FREETEXT,
|
|
359
|
-
rect,
|
|
360
|
-
pageIndex,
|
|
361
|
-
id: uuidV4(),
|
|
362
|
-
created: /* @__PURE__ */ new Date()
|
|
363
|
-
};
|
|
364
|
-
onCommit(anno);
|
|
365
|
-
}
|
|
366
|
-
});
|
|
367
|
-
const getPreview = (current) => {
|
|
368
|
-
const start = getStart();
|
|
369
|
-
if (!start) return null;
|
|
370
|
-
const defaults = getDefaults();
|
|
371
|
-
if (!defaults) return null;
|
|
372
|
-
const minX = Math.min(start.x, current.x);
|
|
373
|
-
const minY = Math.min(start.y, current.y);
|
|
374
|
-
const width = Math.abs(start.x - current.x);
|
|
375
|
-
const height = Math.abs(start.y - current.y);
|
|
376
|
-
const rect = {
|
|
377
|
-
origin: { x: minX, y: minY },
|
|
378
|
-
size: { width, height }
|
|
379
|
-
};
|
|
380
|
-
return {
|
|
381
|
-
type: PdfAnnotationSubtype.FREETEXT,
|
|
382
|
-
bounds: rect,
|
|
383
|
-
data: {
|
|
384
|
-
...defaults,
|
|
385
|
-
rect
|
|
386
|
-
}
|
|
387
|
-
};
|
|
388
|
-
};
|
|
389
|
-
return {
|
|
390
|
-
onPointerDown: (pos, evt) => {
|
|
391
|
-
var _a;
|
|
392
|
-
const clampedPos = clampToPage(pos);
|
|
393
|
-
setStart(clampedPos);
|
|
394
|
-
clickDetector.onStart(clampedPos);
|
|
395
|
-
onPreview(getPreview(clampedPos));
|
|
396
|
-
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
397
|
-
},
|
|
398
|
-
onPointerMove: (pos) => {
|
|
399
|
-
const clampedPos = clampToPage(pos);
|
|
400
|
-
clickDetector.onMove(clampedPos);
|
|
401
|
-
if (getStart() && clickDetector.hasMoved()) {
|
|
402
|
-
onPreview(getPreview(clampedPos));
|
|
403
|
-
}
|
|
404
|
-
},
|
|
405
|
-
onPointerUp: (pos, evt) => {
|
|
406
|
-
var _a;
|
|
407
|
-
const start = getStart();
|
|
408
|
-
if (!start) return;
|
|
409
|
-
const defaults = getDefaults();
|
|
410
|
-
if (!defaults) return;
|
|
411
|
-
const clampedPos = clampToPage(pos);
|
|
412
|
-
if (!clickDetector.hasMoved()) {
|
|
413
|
-
clickDetector.onEnd(clampedPos);
|
|
414
|
-
} else {
|
|
415
|
-
const minX = Math.min(start.x, clampedPos.x);
|
|
416
|
-
const minY = Math.min(start.y, clampedPos.y);
|
|
417
|
-
const width = Math.abs(start.x - clampedPos.x);
|
|
418
|
-
const height = Math.abs(start.y - clampedPos.y);
|
|
419
|
-
const rect = {
|
|
420
|
-
origin: { x: minX, y: minY },
|
|
421
|
-
size: { width, height }
|
|
422
|
-
};
|
|
423
|
-
const anno = {
|
|
424
|
-
...defaults,
|
|
425
|
-
type: PdfAnnotationSubtype.FREETEXT,
|
|
426
|
-
rect,
|
|
427
|
-
pageIndex: context.pageIndex,
|
|
428
|
-
id: uuidV4(),
|
|
429
|
-
created: /* @__PURE__ */ new Date()
|
|
430
|
-
};
|
|
431
|
-
onCommit(anno);
|
|
432
|
-
}
|
|
433
|
-
setStart(null);
|
|
434
|
-
onPreview(null);
|
|
435
|
-
clickDetector.reset();
|
|
436
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
437
|
-
},
|
|
438
|
-
onPointerLeave: (_, evt) => {
|
|
439
|
-
var _a;
|
|
440
|
-
setStart(null);
|
|
441
|
-
onPreview(null);
|
|
442
|
-
clickDetector.reset();
|
|
443
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
444
|
-
},
|
|
445
|
-
onPointerCancel: (_, evt) => {
|
|
446
|
-
var _a;
|
|
447
|
-
setStart(null);
|
|
448
|
-
onPreview(null);
|
|
449
|
-
clickDetector.reset();
|
|
450
|
-
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
451
|
-
}
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
};
|
|
455
|
-
function createArrowHandler(isClosed) {
|
|
456
|
-
const calculateGeometry = (sw) => {
|
|
457
|
-
const len = sw * 9;
|
|
458
|
-
const a = Math.PI / 6;
|
|
459
|
-
return {
|
|
460
|
-
x: -len * Math.cos(a),
|
|
461
|
-
y: len * Math.sin(a)
|
|
462
|
-
};
|
|
463
|
-
};
|
|
464
|
-
return {
|
|
465
|
-
getSvgPath: (sw) => {
|
|
466
|
-
const { x, y } = calculateGeometry(sw);
|
|
467
|
-
return isClosed ? `M 0 0 L ${x} ${y} L ${x} ${-y} Z` : `M ${x} ${y} L 0 0 L ${x} ${-y}`;
|
|
468
|
-
},
|
|
469
|
-
getLocalPoints: (sw) => {
|
|
470
|
-
const { x, y } = calculateGeometry(sw);
|
|
471
|
-
return [
|
|
472
|
-
{ x: 0, y: 0 },
|
|
473
|
-
{ x, y },
|
|
474
|
-
{ x, y: -y }
|
|
475
|
-
];
|
|
476
|
-
},
|
|
477
|
-
getRotation: (segmentAngle) => segmentAngle,
|
|
478
|
-
filled: isClosed
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
function createLineHandler(lengthFactor, rotationFn) {
|
|
482
|
-
const getHalfLength = (sw) => sw * lengthFactor / 2;
|
|
483
|
-
return {
|
|
484
|
-
getSvgPath: (sw) => {
|
|
485
|
-
const l = getHalfLength(sw);
|
|
486
|
-
return `M ${-l} 0 L ${l} 0`;
|
|
487
|
-
},
|
|
488
|
-
getLocalPoints: (sw) => {
|
|
489
|
-
const l = getHalfLength(sw);
|
|
490
|
-
return [
|
|
491
|
-
{ x: -l, y: 0 },
|
|
492
|
-
{ x: l, y: 0 }
|
|
493
|
-
];
|
|
494
|
-
},
|
|
495
|
-
getRotation: rotationFn,
|
|
496
|
-
filled: false
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
const OpenArrowHandler = createArrowHandler(false);
|
|
500
|
-
const ClosedArrowHandler = createArrowHandler(true);
|
|
501
|
-
const LINE_ENDING_HANDLERS = {
|
|
502
|
-
[PdfAnnotationLineEnding.OpenArrow]: OpenArrowHandler,
|
|
503
|
-
[PdfAnnotationLineEnding.ClosedArrow]: ClosedArrowHandler,
|
|
504
|
-
[PdfAnnotationLineEnding.ROpenArrow]: {
|
|
505
|
-
...OpenArrowHandler,
|
|
506
|
-
getRotation: (segmentAngle) => segmentAngle + Math.PI
|
|
507
242
|
},
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
243
|
+
{
|
|
244
|
+
id: "squiggly",
|
|
245
|
+
name: "Squiggly",
|
|
246
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.SQUIGGLY ? 1 : 0,
|
|
247
|
+
interaction: {
|
|
248
|
+
exclusive: false,
|
|
249
|
+
textSelection: true,
|
|
250
|
+
isDraggable: false,
|
|
251
|
+
isResizable: false
|
|
252
|
+
},
|
|
253
|
+
defaults: {
|
|
254
|
+
type: PdfAnnotationSubtype.SQUIGGLY,
|
|
255
|
+
color: "#E44234",
|
|
256
|
+
opacity: 1
|
|
257
|
+
}
|
|
511
258
|
},
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
259
|
+
// Drawing Tools
|
|
260
|
+
{
|
|
261
|
+
id: "ink",
|
|
262
|
+
name: "Pen",
|
|
263
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.INK && a.intent !== "InkHighlight" ? 5 : 0,
|
|
264
|
+
interaction: {
|
|
265
|
+
exclusive: false,
|
|
266
|
+
cursor: "crosshair",
|
|
267
|
+
isDraggable: true,
|
|
268
|
+
isResizable: true,
|
|
269
|
+
lockAspectRatio: false
|
|
516
270
|
},
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
271
|
+
defaults: {
|
|
272
|
+
type: PdfAnnotationSubtype.INK,
|
|
273
|
+
color: "#E44234",
|
|
274
|
+
opacity: 1,
|
|
275
|
+
strokeWidth: 6
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
id: "inkHighlighter",
|
|
280
|
+
name: "Ink Highlighter",
|
|
281
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.INK && a.intent === "InkHighlight" ? 10 : 0,
|
|
282
|
+
interaction: {
|
|
283
|
+
exclusive: false,
|
|
284
|
+
cursor: "crosshair",
|
|
285
|
+
isDraggable: true,
|
|
286
|
+
isResizable: true,
|
|
287
|
+
lockAspectRatio: false
|
|
523
288
|
},
|
|
524
|
-
|
|
525
|
-
|
|
289
|
+
defaults: {
|
|
290
|
+
type: PdfAnnotationSubtype.INK,
|
|
291
|
+
intent: "InkHighlight",
|
|
292
|
+
color: "#FFCD45",
|
|
293
|
+
opacity: 1,
|
|
294
|
+
strokeWidth: 14,
|
|
295
|
+
blendMode: PdfBlendMode.Multiply
|
|
296
|
+
}
|
|
526
297
|
},
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
298
|
+
// Shape Tools
|
|
299
|
+
{
|
|
300
|
+
id: "circle",
|
|
301
|
+
name: "Circle",
|
|
302
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.CIRCLE ? 1 : 0,
|
|
303
|
+
interaction: {
|
|
304
|
+
exclusive: false,
|
|
305
|
+
cursor: "crosshair",
|
|
306
|
+
isDraggable: true,
|
|
307
|
+
isResizable: true,
|
|
308
|
+
lockAspectRatio: false
|
|
531
309
|
},
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
{ x: h, y: h },
|
|
540
|
-
// BR
|
|
541
|
-
{ x: -h, y: h }
|
|
542
|
-
// BL
|
|
543
|
-
];
|
|
310
|
+
defaults: {
|
|
311
|
+
type: PdfAnnotationSubtype.CIRCLE,
|
|
312
|
+
color: "transparent",
|
|
313
|
+
opacity: 1,
|
|
314
|
+
strokeWidth: 6,
|
|
315
|
+
strokeColor: "#E44234",
|
|
316
|
+
strokeStyle: PdfAnnotationBorderStyle.SOLID
|
|
544
317
|
},
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
318
|
+
clickBehavior: {
|
|
319
|
+
enabled: true,
|
|
320
|
+
defaultSize: { width: 100, height: 100 }
|
|
321
|
+
}
|
|
548
322
|
},
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
323
|
+
{
|
|
324
|
+
id: "square",
|
|
325
|
+
name: "Square",
|
|
326
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.SQUARE ? 1 : 0,
|
|
327
|
+
interaction: {
|
|
328
|
+
exclusive: false,
|
|
329
|
+
cursor: "crosshair",
|
|
330
|
+
isDraggable: true,
|
|
331
|
+
isResizable: true,
|
|
332
|
+
lockAspectRatio: false
|
|
333
|
+
},
|
|
334
|
+
defaults: {
|
|
335
|
+
type: PdfAnnotationSubtype.SQUARE,
|
|
336
|
+
color: "transparent",
|
|
337
|
+
opacity: 1,
|
|
338
|
+
strokeWidth: 6,
|
|
339
|
+
strokeColor: "#E44234",
|
|
340
|
+
strokeStyle: PdfAnnotationBorderStyle.SOLID
|
|
341
|
+
},
|
|
342
|
+
clickBehavior: {
|
|
343
|
+
enabled: true,
|
|
344
|
+
defaultSize: { width: 100, height: 100 }
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
id: "line",
|
|
349
|
+
name: "Line",
|
|
350
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.LINE && a.intent !== "LineArrow" ? 5 : 0,
|
|
351
|
+
interaction: {
|
|
352
|
+
exclusive: false,
|
|
353
|
+
cursor: "crosshair",
|
|
354
|
+
isDraggable: true,
|
|
355
|
+
isResizable: false,
|
|
356
|
+
lockAspectRatio: false
|
|
357
|
+
},
|
|
358
|
+
defaults: {
|
|
359
|
+
type: PdfAnnotationSubtype.LINE,
|
|
360
|
+
color: "transparent",
|
|
361
|
+
opacity: 1,
|
|
362
|
+
strokeWidth: 6,
|
|
363
|
+
strokeColor: "#E44234"
|
|
364
|
+
},
|
|
365
|
+
clickBehavior: {
|
|
366
|
+
enabled: true,
|
|
367
|
+
defaultLength: 100,
|
|
368
|
+
defaultAngle: 0
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
id: "lineArrow",
|
|
373
|
+
name: "Arrow",
|
|
374
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.LINE && a.intent === "LineArrow" ? 10 : 0,
|
|
375
|
+
interaction: {
|
|
376
|
+
exclusive: false,
|
|
377
|
+
cursor: "crosshair",
|
|
378
|
+
isDraggable: true,
|
|
379
|
+
isResizable: false,
|
|
380
|
+
lockAspectRatio: false
|
|
381
|
+
},
|
|
382
|
+
defaults: {
|
|
383
|
+
type: PdfAnnotationSubtype.LINE,
|
|
384
|
+
intent: "LineArrow",
|
|
385
|
+
color: "transparent",
|
|
386
|
+
opacity: 1,
|
|
387
|
+
strokeWidth: 6,
|
|
388
|
+
strokeColor: "#E44234",
|
|
389
|
+
lineEndings: {
|
|
390
|
+
start: PdfAnnotationLineEnding.None,
|
|
391
|
+
end: PdfAnnotationLineEnding.OpenArrow
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
clickBehavior: {
|
|
395
|
+
enabled: true,
|
|
396
|
+
defaultLength: 100,
|
|
397
|
+
defaultAngle: 0
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
id: "polyline",
|
|
402
|
+
name: "Polyline",
|
|
403
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.POLYLINE ? 1 : 0,
|
|
404
|
+
interaction: {
|
|
405
|
+
exclusive: false,
|
|
406
|
+
cursor: "crosshair",
|
|
407
|
+
isDraggable: true,
|
|
408
|
+
isResizable: false,
|
|
409
|
+
lockAspectRatio: false
|
|
410
|
+
},
|
|
411
|
+
defaults: {
|
|
412
|
+
type: PdfAnnotationSubtype.POLYLINE,
|
|
413
|
+
color: "transparent",
|
|
414
|
+
opacity: 1,
|
|
415
|
+
strokeWidth: 6,
|
|
416
|
+
strokeColor: "#E44234"
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
id: "polygon",
|
|
421
|
+
name: "Polygon",
|
|
422
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.POLYGON ? 1 : 0,
|
|
423
|
+
interaction: {
|
|
424
|
+
exclusive: false,
|
|
425
|
+
cursor: "crosshair",
|
|
426
|
+
isDraggable: true,
|
|
427
|
+
isResizable: false,
|
|
428
|
+
lockAspectRatio: false
|
|
429
|
+
},
|
|
430
|
+
defaults: {
|
|
431
|
+
type: PdfAnnotationSubtype.POLYGON,
|
|
432
|
+
color: "transparent",
|
|
433
|
+
opacity: 1,
|
|
434
|
+
strokeWidth: 6,
|
|
435
|
+
strokeColor: "#E44234"
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
// Text & Stamp
|
|
439
|
+
{
|
|
440
|
+
id: "freeText",
|
|
441
|
+
name: "Free Text",
|
|
442
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.FREETEXT ? 1 : 0,
|
|
443
|
+
interaction: {
|
|
444
|
+
exclusive: false,
|
|
445
|
+
cursor: "crosshair",
|
|
446
|
+
isDraggable: true,
|
|
447
|
+
isResizable: true,
|
|
448
|
+
lockAspectRatio: false
|
|
449
|
+
},
|
|
450
|
+
defaults: {
|
|
451
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
452
|
+
contents: "Insert text",
|
|
453
|
+
fontSize: 14,
|
|
454
|
+
fontColor: "#E44234",
|
|
455
|
+
fontFamily: PdfStandardFont.Helvetica,
|
|
456
|
+
textAlign: PdfTextAlignment.Left,
|
|
457
|
+
verticalAlign: PdfVerticalAlignment.Top,
|
|
458
|
+
backgroundColor: "transparent",
|
|
459
|
+
opacity: 1
|
|
460
|
+
},
|
|
461
|
+
clickBehavior: {
|
|
462
|
+
enabled: true,
|
|
463
|
+
defaultSize: { width: 100, height: 20 },
|
|
464
|
+
defaultContent: "Insert text"
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
id: "stamp",
|
|
469
|
+
name: "Image",
|
|
470
|
+
matchScore: (a) => a.type === PdfAnnotationSubtype.STAMP ? 1 : 0,
|
|
471
|
+
interaction: {
|
|
472
|
+
exclusive: false,
|
|
473
|
+
cursor: "copy",
|
|
474
|
+
isDraggable: true,
|
|
475
|
+
isResizable: true,
|
|
476
|
+
lockAspectRatio: true
|
|
477
|
+
},
|
|
478
|
+
defaults: {
|
|
479
|
+
type: PdfAnnotationSubtype.STAMP
|
|
480
|
+
// No imageSrc by default, which tells the UI to open a file picker
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
];
|
|
484
|
+
const DEFAULT_COLORS = [
|
|
485
|
+
"#E44234",
|
|
486
|
+
"#FF8D00",
|
|
487
|
+
"#FFCD45",
|
|
488
|
+
"#5CC96E",
|
|
489
|
+
"#25D2D1",
|
|
490
|
+
"#597CE2",
|
|
491
|
+
"#C544CE",
|
|
492
|
+
"#7D2E25",
|
|
493
|
+
"#000000",
|
|
494
|
+
"#FFFFFF"
|
|
495
|
+
];
|
|
496
|
+
const initialDocumentState = () => ({
|
|
497
|
+
pages: {},
|
|
498
|
+
byUid: {},
|
|
499
|
+
selectedUid: null,
|
|
500
|
+
activeToolId: null,
|
|
501
|
+
hasPendingChanges: false
|
|
502
|
+
});
|
|
503
|
+
const patchAnno = (docState, uid, patch) => {
|
|
504
|
+
const prev = docState.byUid[uid];
|
|
505
|
+
if (!prev) return docState;
|
|
506
|
+
return {
|
|
507
|
+
...docState,
|
|
508
|
+
byUid: {
|
|
509
|
+
...docState.byUid,
|
|
510
|
+
[uid]: {
|
|
511
|
+
...prev,
|
|
512
|
+
commitState: prev.commitState === "synced" ? "dirty" : prev.commitState,
|
|
513
|
+
object: { ...prev.object, ...patch }
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
hasPendingChanges: true
|
|
517
|
+
};
|
|
518
|
+
};
|
|
519
|
+
const initialState = (cfg) => {
|
|
520
|
+
const toolMap = /* @__PURE__ */ new Map();
|
|
521
|
+
defaultTools.forEach((t) => toolMap.set(t.id, t));
|
|
522
|
+
(cfg.tools || []).forEach((t) => toolMap.set(t.id, t));
|
|
523
|
+
return {
|
|
524
|
+
documents: {},
|
|
525
|
+
activeDocumentId: null,
|
|
526
|
+
// `Array.from(toolMap.values())` now correctly returns `AnnotationTool[]`, which matches the state's type.
|
|
527
|
+
tools: Array.from(toolMap.values()),
|
|
528
|
+
colorPresets: cfg.colorPresets ?? DEFAULT_COLORS
|
|
529
|
+
};
|
|
530
|
+
};
|
|
531
|
+
const reducer = (state, action) => {
|
|
532
|
+
switch (action.type) {
|
|
533
|
+
case INIT_ANNOTATION_STATE: {
|
|
534
|
+
const { documentId, state: docState } = action.payload;
|
|
535
|
+
return {
|
|
536
|
+
...state,
|
|
537
|
+
documents: {
|
|
538
|
+
...state.documents,
|
|
539
|
+
[documentId]: docState
|
|
540
|
+
},
|
|
541
|
+
// Set as active if no active document
|
|
542
|
+
activeDocumentId: state.activeDocumentId ?? documentId
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
case CLEANUP_ANNOTATION_STATE: {
|
|
546
|
+
const documentId = action.payload;
|
|
547
|
+
const { [documentId]: removed, ...remainingDocs } = state.documents;
|
|
548
|
+
return {
|
|
549
|
+
...state,
|
|
550
|
+
documents: remainingDocs,
|
|
551
|
+
activeDocumentId: state.activeDocumentId === documentId ? null : state.activeDocumentId
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
case SET_ACTIVE_DOCUMENT: {
|
|
555
|
+
return {
|
|
556
|
+
...state,
|
|
557
|
+
activeDocumentId: action.payload
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
case SET_ANNOTATIONS: {
|
|
561
|
+
const { documentId, annotations } = action.payload;
|
|
562
|
+
const docState = state.documents[documentId];
|
|
563
|
+
if (!docState) return state;
|
|
564
|
+
const newPages = {};
|
|
565
|
+
const newByUid = {};
|
|
566
|
+
for (const [pgStr, list] of Object.entries(annotations)) {
|
|
567
|
+
const pageIndex = Number(pgStr);
|
|
568
|
+
const oldUidsOnPage = docState.pages[pageIndex] || [];
|
|
569
|
+
for (const uid of oldUidsOnPage) {
|
|
570
|
+
delete newByUid[uid];
|
|
571
|
+
}
|
|
572
|
+
const newUidsOnPage = list.map((a) => {
|
|
573
|
+
const uid = a.id;
|
|
574
|
+
newByUid[uid] = { commitState: "synced", object: a };
|
|
575
|
+
return uid;
|
|
576
|
+
});
|
|
577
|
+
newPages[pageIndex] = newUidsOnPage;
|
|
578
|
+
}
|
|
579
|
+
return {
|
|
580
|
+
...state,
|
|
581
|
+
documents: {
|
|
582
|
+
...state.documents,
|
|
583
|
+
[documentId]: {
|
|
584
|
+
...docState,
|
|
585
|
+
pages: newPages,
|
|
586
|
+
byUid: newByUid
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
case SELECT_ANNOTATION: {
|
|
592
|
+
const { documentId, id } = action.payload;
|
|
593
|
+
const docState = state.documents[documentId];
|
|
594
|
+
if (!docState) return state;
|
|
595
|
+
return {
|
|
596
|
+
...state,
|
|
597
|
+
documents: {
|
|
598
|
+
...state.documents,
|
|
599
|
+
[documentId]: { ...docState, selectedUid: id }
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
case DESELECT_ANNOTATION: {
|
|
604
|
+
const { documentId } = action.payload;
|
|
605
|
+
const docState = state.documents[documentId];
|
|
606
|
+
if (!docState) return state;
|
|
607
|
+
return {
|
|
608
|
+
...state,
|
|
609
|
+
documents: {
|
|
610
|
+
...state.documents,
|
|
611
|
+
[documentId]: { ...docState, selectedUid: null }
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
case SET_ACTIVE_TOOL_ID: {
|
|
616
|
+
const { documentId, toolId } = action.payload;
|
|
617
|
+
const docState = state.documents[documentId];
|
|
618
|
+
if (!docState) return state;
|
|
619
|
+
return {
|
|
620
|
+
...state,
|
|
621
|
+
documents: {
|
|
622
|
+
...state.documents,
|
|
623
|
+
[documentId]: { ...docState, activeToolId: toolId }
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
case CREATE_ANNOTATION: {
|
|
628
|
+
const { documentId, pageIndex, annotation } = action.payload;
|
|
629
|
+
const docState = state.documents[documentId];
|
|
630
|
+
if (!docState) return state;
|
|
631
|
+
const uid = annotation.id;
|
|
632
|
+
return {
|
|
633
|
+
...state,
|
|
634
|
+
documents: {
|
|
635
|
+
...state.documents,
|
|
636
|
+
[documentId]: {
|
|
637
|
+
...docState,
|
|
638
|
+
pages: {
|
|
639
|
+
...docState.pages,
|
|
640
|
+
[pageIndex]: [...docState.pages[pageIndex] ?? [], uid]
|
|
641
|
+
},
|
|
642
|
+
byUid: {
|
|
643
|
+
...docState.byUid,
|
|
644
|
+
[uid]: { commitState: "new", object: annotation }
|
|
645
|
+
},
|
|
646
|
+
hasPendingChanges: true
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
case DELETE_ANNOTATION: {
|
|
652
|
+
const { documentId, pageIndex, id: uid } = action.payload;
|
|
653
|
+
const docState = state.documents[documentId];
|
|
654
|
+
if (!docState || !docState.byUid[uid]) return state;
|
|
655
|
+
return {
|
|
656
|
+
...state,
|
|
657
|
+
documents: {
|
|
658
|
+
...state.documents,
|
|
659
|
+
[documentId]: {
|
|
660
|
+
...docState,
|
|
661
|
+
pages: {
|
|
662
|
+
...docState.pages,
|
|
663
|
+
[pageIndex]: (docState.pages[pageIndex] ?? []).filter((u) => u !== uid)
|
|
664
|
+
},
|
|
665
|
+
byUid: {
|
|
666
|
+
...docState.byUid,
|
|
667
|
+
[uid]: { ...docState.byUid[uid], commitState: "deleted" }
|
|
668
|
+
},
|
|
669
|
+
hasPendingChanges: true
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
case PATCH_ANNOTATION: {
|
|
675
|
+
const { documentId, id, patch } = action.payload;
|
|
676
|
+
const docState = state.documents[documentId];
|
|
677
|
+
if (!docState) return state;
|
|
678
|
+
return {
|
|
679
|
+
...state,
|
|
680
|
+
documents: {
|
|
681
|
+
...state.documents,
|
|
682
|
+
[documentId]: patchAnno(docState, id, patch)
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
case COMMIT_PENDING_CHANGES: {
|
|
687
|
+
const { documentId } = action.payload;
|
|
688
|
+
const docState = state.documents[documentId];
|
|
689
|
+
if (!docState) return state;
|
|
690
|
+
const cleaned = {};
|
|
691
|
+
for (const [uid, ta] of Object.entries(docState.byUid)) {
|
|
692
|
+
cleaned[uid] = {
|
|
693
|
+
...ta,
|
|
694
|
+
commitState: ta.commitState === "dirty" || ta.commitState === "new" ? "synced" : ta.commitState
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
return {
|
|
698
|
+
...state,
|
|
699
|
+
documents: {
|
|
700
|
+
...state.documents,
|
|
701
|
+
[documentId]: { ...docState, byUid: cleaned, hasPendingChanges: false }
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
case PURGE_ANNOTATION: {
|
|
706
|
+
const { documentId, uid } = action.payload;
|
|
707
|
+
const docState = state.documents[documentId];
|
|
708
|
+
if (!docState) return state;
|
|
709
|
+
const { [uid]: _gone, ...rest } = docState.byUid;
|
|
710
|
+
return {
|
|
711
|
+
...state,
|
|
712
|
+
documents: {
|
|
713
|
+
...state.documents,
|
|
714
|
+
[documentId]: { ...docState, byUid: rest }
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
// Global actions
|
|
719
|
+
case ADD_TOOL: {
|
|
720
|
+
const toolMap = new Map(state.tools.map((t) => [t.id, t]));
|
|
721
|
+
toolMap.set(action.payload.id, action.payload);
|
|
722
|
+
return { ...state, tools: Array.from(toolMap.values()) };
|
|
723
|
+
}
|
|
724
|
+
case SET_TOOL_DEFAULTS: {
|
|
725
|
+
const { toolId, patch } = action.payload;
|
|
726
|
+
return {
|
|
727
|
+
...state,
|
|
728
|
+
tools: state.tools.map((tool) => {
|
|
729
|
+
if (tool.id === toolId) {
|
|
730
|
+
return { ...tool, defaults: { ...tool.defaults, ...patch } };
|
|
731
|
+
}
|
|
732
|
+
return tool;
|
|
733
|
+
})
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
case ADD_COLOR_PRESET:
|
|
737
|
+
return state.colorPresets.includes(action.payload) ? state : { ...state, colorPresets: [...state.colorPresets, action.payload] };
|
|
738
|
+
default:
|
|
739
|
+
return state;
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
function useState(initialValue) {
|
|
743
|
+
let value = initialValue;
|
|
744
|
+
const getValue = () => value;
|
|
745
|
+
const setValue = (newValue) => {
|
|
746
|
+
value = newValue;
|
|
747
|
+
};
|
|
748
|
+
return [getValue, setValue];
|
|
749
|
+
}
|
|
750
|
+
const inkHandlerFactory = {
|
|
751
|
+
annotationType: PdfAnnotationSubtype.INK,
|
|
752
|
+
create(context) {
|
|
753
|
+
const { onCommit, onPreview, getTool, pageSize } = context;
|
|
754
|
+
const [getStrokes, setStrokes] = useState([]);
|
|
755
|
+
const [getIsDrawing, setIsDrawing] = useState(false);
|
|
756
|
+
const timerRef = { current: null };
|
|
757
|
+
const clampToPage = (pos) => ({
|
|
758
|
+
x: clamp(pos.x, 0, pageSize.width),
|
|
759
|
+
y: clamp(pos.y, 0, pageSize.height)
|
|
760
|
+
});
|
|
761
|
+
const getDefaults = () => {
|
|
762
|
+
const tool = getTool();
|
|
763
|
+
if (!tool) return null;
|
|
764
|
+
return {
|
|
765
|
+
...tool.defaults,
|
|
766
|
+
strokeWidth: tool.defaults.strokeWidth ?? 1,
|
|
767
|
+
color: tool.defaults.color ?? "#000000",
|
|
768
|
+
opacity: tool.defaults.opacity ?? 1,
|
|
769
|
+
flags: tool.defaults.flags ?? ["print"]
|
|
770
|
+
};
|
|
771
|
+
};
|
|
772
|
+
const getPreview = () => {
|
|
773
|
+
const strokes = getStrokes();
|
|
774
|
+
if (strokes.length === 0 || strokes[0].points.length === 0) return null;
|
|
775
|
+
const defaults = getDefaults();
|
|
776
|
+
if (!defaults) return null;
|
|
777
|
+
const allPoints = strokes.flatMap((s) => s.points);
|
|
778
|
+
const bounds = expandRect(rectFromPoints(allPoints), defaults.strokeWidth / 2);
|
|
779
|
+
return {
|
|
780
|
+
type: PdfAnnotationSubtype.INK,
|
|
781
|
+
bounds,
|
|
782
|
+
data: {
|
|
783
|
+
...defaults,
|
|
784
|
+
rect: bounds,
|
|
785
|
+
inkList: strokes
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
};
|
|
789
|
+
return {
|
|
790
|
+
onPointerDown: (pos, evt) => {
|
|
791
|
+
var _a;
|
|
792
|
+
const clampedPos = clampToPage(pos);
|
|
793
|
+
setIsDrawing(true);
|
|
794
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
795
|
+
const newStrokes = [...getStrokes(), { points: [clampedPos] }];
|
|
796
|
+
setStrokes(newStrokes);
|
|
797
|
+
onPreview(getPreview());
|
|
798
|
+
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
799
|
+
},
|
|
800
|
+
onPointerMove: (pos) => {
|
|
801
|
+
if (!getIsDrawing()) return;
|
|
802
|
+
const strokes = getStrokes();
|
|
803
|
+
if (strokes.length === 0) return;
|
|
804
|
+
const clampedPos = clampToPage(pos);
|
|
805
|
+
strokes[strokes.length - 1].points.push(clampedPos);
|
|
806
|
+
setStrokes(strokes);
|
|
807
|
+
onPreview(getPreview());
|
|
808
|
+
},
|
|
809
|
+
onPointerUp: (_, evt) => {
|
|
810
|
+
var _a;
|
|
811
|
+
setIsDrawing(false);
|
|
812
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
813
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
814
|
+
timerRef.current = setTimeout(() => {
|
|
815
|
+
const strokes = getStrokes();
|
|
816
|
+
if (strokes.length > 0 && strokes[0].points.length > 1) {
|
|
817
|
+
const defaults = getDefaults();
|
|
818
|
+
if (!defaults) return;
|
|
819
|
+
const allPoints = strokes.flatMap((s) => s.points);
|
|
820
|
+
const rect = expandRect(rectFromPoints(allPoints), defaults.strokeWidth / 2);
|
|
821
|
+
onCommit({
|
|
822
|
+
...defaults,
|
|
823
|
+
inkList: strokes,
|
|
824
|
+
rect,
|
|
825
|
+
type: PdfAnnotationSubtype.INK,
|
|
826
|
+
pageIndex: context.pageIndex,
|
|
827
|
+
id: uuidV4(),
|
|
828
|
+
created: /* @__PURE__ */ new Date()
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
setStrokes([]);
|
|
832
|
+
onPreview(null);
|
|
833
|
+
}, 800);
|
|
834
|
+
},
|
|
835
|
+
onPointerCancel: (_, evt) => {
|
|
836
|
+
var _a;
|
|
837
|
+
setStrokes([]);
|
|
838
|
+
setIsDrawing(false);
|
|
839
|
+
onPreview(null);
|
|
840
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
841
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
function useClickDetector({
|
|
847
|
+
threshold = 5,
|
|
848
|
+
getTool,
|
|
849
|
+
onClickDetected
|
|
850
|
+
}) {
|
|
851
|
+
const [getStartPos, setStartPos] = useState(null);
|
|
852
|
+
const [getHasMoved, setHasMoved] = useState(false);
|
|
853
|
+
return {
|
|
854
|
+
onStart: (pos) => {
|
|
855
|
+
setStartPos(pos);
|
|
856
|
+
setHasMoved(false);
|
|
857
|
+
},
|
|
858
|
+
onMove: (pos) => {
|
|
859
|
+
const start = getStartPos();
|
|
860
|
+
if (!start || getHasMoved()) return;
|
|
861
|
+
const distance = Math.sqrt(Math.pow(pos.x - start.x, 2) + Math.pow(pos.y - start.y, 2));
|
|
862
|
+
if (distance > threshold) {
|
|
863
|
+
setHasMoved(true);
|
|
864
|
+
}
|
|
865
|
+
},
|
|
866
|
+
onEnd: (pos) => {
|
|
867
|
+
var _a;
|
|
868
|
+
const start = getStartPos();
|
|
869
|
+
if (start && !getHasMoved()) {
|
|
870
|
+
const tool = getTool();
|
|
871
|
+
if (tool && "clickBehavior" in tool && ((_a = tool.clickBehavior) == null ? void 0 : _a.enabled)) {
|
|
872
|
+
onClickDetected(pos, tool);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
setStartPos(null);
|
|
876
|
+
setHasMoved(false);
|
|
877
|
+
},
|
|
878
|
+
hasMoved: getHasMoved,
|
|
879
|
+
reset: () => {
|
|
880
|
+
setStartPos(null);
|
|
881
|
+
setHasMoved(false);
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
const freeTextHandlerFactory = {
|
|
886
|
+
annotationType: PdfAnnotationSubtype.FREETEXT,
|
|
887
|
+
create(context) {
|
|
888
|
+
const { onCommit, onPreview, getTool, pageSize, pageIndex } = context;
|
|
889
|
+
const [getStart, setStart] = useState(null);
|
|
890
|
+
const clampToPage = (pos) => ({
|
|
891
|
+
x: clamp(pos.x, 0, pageSize.width),
|
|
892
|
+
y: clamp(pos.y, 0, pageSize.height)
|
|
893
|
+
});
|
|
894
|
+
const getDefaults = () => {
|
|
895
|
+
const tool = getTool();
|
|
896
|
+
if (!tool) return null;
|
|
897
|
+
return {
|
|
898
|
+
...tool.defaults,
|
|
899
|
+
fontColor: tool.defaults.fontColor ?? "#000000",
|
|
900
|
+
opacity: tool.defaults.opacity ?? 1,
|
|
901
|
+
fontSize: tool.defaults.fontSize ?? 12,
|
|
902
|
+
fontFamily: tool.defaults.fontFamily ?? PdfStandardFont.Helvetica,
|
|
903
|
+
backgroundColor: tool.defaults.backgroundColor ?? "transparent",
|
|
904
|
+
textAlign: tool.defaults.textAlign ?? PdfTextAlignment.Left,
|
|
905
|
+
verticalAlign: tool.defaults.verticalAlign ?? PdfVerticalAlignment.Top,
|
|
906
|
+
contents: tool.defaults.contents ?? "Insert text here",
|
|
907
|
+
flags: tool.defaults.flags ?? ["print"]
|
|
908
|
+
};
|
|
909
|
+
};
|
|
910
|
+
const clickDetector = useClickDetector({
|
|
911
|
+
threshold: 5,
|
|
912
|
+
getTool,
|
|
913
|
+
onClickDetected: (pos, tool) => {
|
|
914
|
+
const defaults = getDefaults();
|
|
915
|
+
if (!defaults) return;
|
|
916
|
+
const clickConfig = tool.clickBehavior;
|
|
917
|
+
if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
|
|
918
|
+
const { width, height } = clickConfig.defaultSize;
|
|
919
|
+
const halfWidth = width / 2;
|
|
920
|
+
const halfHeight = height / 2;
|
|
921
|
+
const x = clamp(pos.x - halfWidth, 0, pageSize.width - width);
|
|
922
|
+
const y = clamp(pos.y - halfHeight, 0, pageSize.height - height);
|
|
923
|
+
const rect = {
|
|
924
|
+
origin: { x, y },
|
|
925
|
+
size: { width, height }
|
|
926
|
+
};
|
|
927
|
+
const contents = clickConfig.defaultContent ?? defaults.contents;
|
|
928
|
+
const anno = {
|
|
929
|
+
...defaults,
|
|
930
|
+
contents,
|
|
931
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
932
|
+
rect,
|
|
933
|
+
pageIndex,
|
|
934
|
+
id: uuidV4(),
|
|
935
|
+
created: /* @__PURE__ */ new Date()
|
|
936
|
+
};
|
|
937
|
+
onCommit(anno);
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
const getPreview = (current) => {
|
|
941
|
+
const start = getStart();
|
|
942
|
+
if (!start) return null;
|
|
943
|
+
const defaults = getDefaults();
|
|
944
|
+
if (!defaults) return null;
|
|
945
|
+
const minX = Math.min(start.x, current.x);
|
|
946
|
+
const minY = Math.min(start.y, current.y);
|
|
947
|
+
const width = Math.abs(start.x - current.x);
|
|
948
|
+
const height = Math.abs(start.y - current.y);
|
|
949
|
+
const rect = {
|
|
950
|
+
origin: { x: minX, y: minY },
|
|
951
|
+
size: { width, height }
|
|
952
|
+
};
|
|
953
|
+
return {
|
|
954
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
955
|
+
bounds: rect,
|
|
956
|
+
data: {
|
|
957
|
+
...defaults,
|
|
958
|
+
rect
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
};
|
|
962
|
+
return {
|
|
963
|
+
onPointerDown: (pos, evt) => {
|
|
964
|
+
var _a;
|
|
965
|
+
const clampedPos = clampToPage(pos);
|
|
966
|
+
setStart(clampedPos);
|
|
967
|
+
clickDetector.onStart(clampedPos);
|
|
968
|
+
onPreview(getPreview(clampedPos));
|
|
969
|
+
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
970
|
+
},
|
|
971
|
+
onPointerMove: (pos) => {
|
|
972
|
+
const clampedPos = clampToPage(pos);
|
|
973
|
+
clickDetector.onMove(clampedPos);
|
|
974
|
+
if (getStart() && clickDetector.hasMoved()) {
|
|
975
|
+
onPreview(getPreview(clampedPos));
|
|
976
|
+
}
|
|
977
|
+
},
|
|
978
|
+
onPointerUp: (pos, evt) => {
|
|
979
|
+
var _a;
|
|
980
|
+
const start = getStart();
|
|
981
|
+
if (!start) return;
|
|
982
|
+
const defaults = getDefaults();
|
|
983
|
+
if (!defaults) return;
|
|
984
|
+
const clampedPos = clampToPage(pos);
|
|
985
|
+
if (!clickDetector.hasMoved()) {
|
|
986
|
+
clickDetector.onEnd(clampedPos);
|
|
987
|
+
} else {
|
|
988
|
+
const minX = Math.min(start.x, clampedPos.x);
|
|
989
|
+
const minY = Math.min(start.y, clampedPos.y);
|
|
990
|
+
const width = Math.abs(start.x - clampedPos.x);
|
|
991
|
+
const height = Math.abs(start.y - clampedPos.y);
|
|
992
|
+
const rect = {
|
|
993
|
+
origin: { x: minX, y: minY },
|
|
994
|
+
size: { width, height }
|
|
995
|
+
};
|
|
996
|
+
const anno = {
|
|
997
|
+
...defaults,
|
|
998
|
+
type: PdfAnnotationSubtype.FREETEXT,
|
|
999
|
+
rect,
|
|
1000
|
+
pageIndex: context.pageIndex,
|
|
1001
|
+
id: uuidV4(),
|
|
1002
|
+
created: /* @__PURE__ */ new Date()
|
|
1003
|
+
};
|
|
1004
|
+
onCommit(anno);
|
|
1005
|
+
}
|
|
1006
|
+
setStart(null);
|
|
1007
|
+
onPreview(null);
|
|
1008
|
+
clickDetector.reset();
|
|
1009
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
1010
|
+
},
|
|
1011
|
+
onPointerLeave: (_, evt) => {
|
|
1012
|
+
var _a;
|
|
1013
|
+
setStart(null);
|
|
1014
|
+
onPreview(null);
|
|
1015
|
+
clickDetector.reset();
|
|
1016
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
1017
|
+
},
|
|
1018
|
+
onPointerCancel: (_, evt) => {
|
|
1019
|
+
var _a;
|
|
1020
|
+
setStart(null);
|
|
1021
|
+
onPreview(null);
|
|
1022
|
+
clickDetector.reset();
|
|
1023
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
function createArrowHandler(isClosed) {
|
|
1029
|
+
const calculateGeometry = (sw) => {
|
|
1030
|
+
const len = sw * 9;
|
|
1031
|
+
const a = Math.PI / 6;
|
|
1032
|
+
return {
|
|
1033
|
+
x: -len * Math.cos(a),
|
|
1034
|
+
y: len * Math.sin(a)
|
|
1035
|
+
};
|
|
1036
|
+
};
|
|
1037
|
+
return {
|
|
1038
|
+
getSvgPath: (sw) => {
|
|
1039
|
+
const { x, y } = calculateGeometry(sw);
|
|
1040
|
+
return isClosed ? `M 0 0 L ${x} ${y} L ${x} ${-y} Z` : `M ${x} ${y} L 0 0 L ${x} ${-y}`;
|
|
1041
|
+
},
|
|
1042
|
+
getLocalPoints: (sw) => {
|
|
1043
|
+
const { x, y } = calculateGeometry(sw);
|
|
1044
|
+
return [
|
|
1045
|
+
{ x: 0, y: 0 },
|
|
1046
|
+
{ x, y },
|
|
1047
|
+
{ x, y: -y }
|
|
1048
|
+
];
|
|
1049
|
+
},
|
|
1050
|
+
getRotation: (segmentAngle) => segmentAngle,
|
|
1051
|
+
filled: isClosed
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
function createLineHandler(lengthFactor, rotationFn) {
|
|
1055
|
+
const getHalfLength = (sw) => sw * lengthFactor / 2;
|
|
1056
|
+
return {
|
|
1057
|
+
getSvgPath: (sw) => {
|
|
1058
|
+
const l = getHalfLength(sw);
|
|
1059
|
+
return `M ${-l} 0 L ${l} 0`;
|
|
1060
|
+
},
|
|
1061
|
+
getLocalPoints: (sw) => {
|
|
1062
|
+
const l = getHalfLength(sw);
|
|
1063
|
+
return [
|
|
1064
|
+
{ x: -l, y: 0 },
|
|
1065
|
+
{ x: l, y: 0 }
|
|
1066
|
+
];
|
|
1067
|
+
},
|
|
1068
|
+
getRotation: rotationFn,
|
|
1069
|
+
filled: false
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
const OpenArrowHandler = createArrowHandler(false);
|
|
1073
|
+
const ClosedArrowHandler = createArrowHandler(true);
|
|
1074
|
+
const LINE_ENDING_HANDLERS = {
|
|
1075
|
+
[PdfAnnotationLineEnding.OpenArrow]: OpenArrowHandler,
|
|
1076
|
+
[PdfAnnotationLineEnding.ClosedArrow]: ClosedArrowHandler,
|
|
1077
|
+
[PdfAnnotationLineEnding.ROpenArrow]: {
|
|
1078
|
+
...OpenArrowHandler,
|
|
1079
|
+
getRotation: (segmentAngle) => segmentAngle + Math.PI
|
|
1080
|
+
},
|
|
1081
|
+
[PdfAnnotationLineEnding.RClosedArrow]: {
|
|
1082
|
+
...ClosedArrowHandler,
|
|
1083
|
+
getRotation: (segmentAngle) => segmentAngle + Math.PI
|
|
1084
|
+
},
|
|
1085
|
+
[PdfAnnotationLineEnding.Circle]: {
|
|
1086
|
+
getSvgPath: (sw) => {
|
|
1087
|
+
const r = sw * 5 / 2;
|
|
1088
|
+
return `M ${r} 0 A ${r} ${r} 0 1 1 ${-r} 0 A ${r} ${r} 0 1 1 ${r} 0`;
|
|
1089
|
+
},
|
|
1090
|
+
getLocalPoints: (sw) => {
|
|
1091
|
+
const r = sw * 5 / 2;
|
|
1092
|
+
return [
|
|
1093
|
+
{ x: -r, y: -r },
|
|
1094
|
+
{ x: r, y: r }
|
|
1095
|
+
];
|
|
1096
|
+
},
|
|
1097
|
+
getRotation: () => 0,
|
|
1098
|
+
filled: true
|
|
1099
|
+
},
|
|
1100
|
+
[PdfAnnotationLineEnding.Square]: {
|
|
1101
|
+
getSvgPath: (sw) => {
|
|
1102
|
+
const h = sw * 6 / 2;
|
|
1103
|
+
return `M ${-h} ${-h} L ${h} ${-h} L ${h} ${h} L ${-h} ${h} Z`;
|
|
1104
|
+
},
|
|
1105
|
+
getLocalPoints: (sw) => {
|
|
1106
|
+
const h = sw * 6 / 2;
|
|
1107
|
+
return [
|
|
1108
|
+
{ x: -h, y: -h },
|
|
1109
|
+
// TL
|
|
1110
|
+
{ x: h, y: -h },
|
|
1111
|
+
// TR
|
|
1112
|
+
{ x: h, y: h },
|
|
1113
|
+
// BR
|
|
1114
|
+
{ x: -h, y: h }
|
|
1115
|
+
// BL
|
|
1116
|
+
];
|
|
1117
|
+
},
|
|
1118
|
+
getRotation: (segmentAngle) => segmentAngle,
|
|
1119
|
+
// keep your new orientation
|
|
1120
|
+
filled: true
|
|
1121
|
+
},
|
|
1122
|
+
[PdfAnnotationLineEnding.Diamond]: {
|
|
1123
|
+
getSvgPath: (sw) => {
|
|
1124
|
+
const h = sw * 6 / 2;
|
|
1125
|
+
return `M 0 ${-h} L ${h} 0 L 0 ${h} L ${-h} 0 Z`;
|
|
1126
|
+
},
|
|
1127
|
+
getLocalPoints: (sw) => {
|
|
1128
|
+
const h = sw * 6 / 2;
|
|
1129
|
+
return [
|
|
557
1130
|
{ x: 0, y: -h },
|
|
558
1131
|
{ x: h, y: 0 },
|
|
559
1132
|
{ x: 0, y: h },
|
|
@@ -1434,162 +2007,9 @@ const patchLine = (orig, ctx) => {
|
|
|
1434
2007
|
if (ctx.changes.linePoints) {
|
|
1435
2008
|
const { start, end } = ctx.changes.linePoints;
|
|
1436
2009
|
const rect = lineRectWithEndings([start, end], orig.strokeWidth, orig.lineEndings);
|
|
1437
|
-
return {
|
|
1438
|
-
rect,
|
|
1439
|
-
linePoints: { start, end }
|
|
1440
|
-
};
|
|
1441
|
-
}
|
|
1442
|
-
return ctx.changes;
|
|
1443
|
-
case "move":
|
|
1444
|
-
if (ctx.changes.rect) {
|
|
1445
|
-
const dx = ctx.changes.rect.origin.x - orig.rect.origin.x;
|
|
1446
|
-
const dy = ctx.changes.rect.origin.y - orig.rect.origin.y;
|
|
1447
|
-
return {
|
|
1448
|
-
rect: ctx.changes.rect,
|
|
1449
|
-
linePoints: {
|
|
1450
|
-
start: { x: orig.linePoints.start.x + dx, y: orig.linePoints.start.y + dy },
|
|
1451
|
-
end: { x: orig.linePoints.end.x + dx, y: orig.linePoints.end.y + dy }
|
|
1452
|
-
}
|
|
1453
|
-
};
|
|
1454
|
-
}
|
|
1455
|
-
return ctx.changes;
|
|
1456
|
-
case "resize":
|
|
1457
|
-
if (ctx.changes.rect) {
|
|
1458
|
-
const oldRect = orig.rect;
|
|
1459
|
-
const newRect = ctx.changes.rect;
|
|
1460
|
-
let scaleX = newRect.size.width / oldRect.size.width;
|
|
1461
|
-
let scaleY = newRect.size.height / oldRect.size.height;
|
|
1462
|
-
const minSize = 10;
|
|
1463
|
-
if (newRect.size.width < minSize || newRect.size.height < minSize) {
|
|
1464
|
-
scaleX = Math.max(scaleX, minSize / oldRect.size.width);
|
|
1465
|
-
scaleY = Math.max(scaleY, minSize / oldRect.size.height);
|
|
1466
|
-
ctx.changes.rect = {
|
|
1467
|
-
origin: newRect.origin,
|
|
1468
|
-
size: {
|
|
1469
|
-
width: oldRect.size.width * scaleX,
|
|
1470
|
-
height: oldRect.size.height * scaleY
|
|
1471
|
-
}
|
|
1472
|
-
};
|
|
1473
|
-
}
|
|
1474
|
-
if ((_a = ctx.metadata) == null ? void 0 : _a.maintainAspectRatio) {
|
|
1475
|
-
const minScale = Math.min(scaleX, scaleY);
|
|
1476
|
-
scaleX = minScale;
|
|
1477
|
-
scaleY = minScale;
|
|
1478
|
-
ctx.changes.rect.size = {
|
|
1479
|
-
width: oldRect.size.width * minScale,
|
|
1480
|
-
height: oldRect.size.height * minScale
|
|
1481
|
-
};
|
|
1482
|
-
}
|
|
1483
|
-
const newLinePoints = {
|
|
1484
|
-
start: {
|
|
1485
|
-
x: ctx.changes.rect.origin.x + (orig.linePoints.start.x - oldRect.origin.x) * scaleX,
|
|
1486
|
-
y: ctx.changes.rect.origin.y + (orig.linePoints.start.y - oldRect.origin.y) * scaleY
|
|
1487
|
-
},
|
|
1488
|
-
end: {
|
|
1489
|
-
x: ctx.changes.rect.origin.x + (orig.linePoints.end.x - oldRect.origin.x) * scaleX,
|
|
1490
|
-
y: ctx.changes.rect.origin.y + (orig.linePoints.end.y - oldRect.origin.y) * scaleY
|
|
1491
|
-
}
|
|
1492
|
-
};
|
|
1493
|
-
return {
|
|
1494
|
-
rect: ctx.changes.rect,
|
|
1495
|
-
linePoints: newLinePoints
|
|
1496
|
-
};
|
|
1497
|
-
}
|
|
1498
|
-
return ctx.changes;
|
|
1499
|
-
case "property-update":
|
|
1500
|
-
if (ctx.changes.strokeWidth || ctx.changes.lineEndings) {
|
|
1501
|
-
const merged = { ...orig, ...ctx.changes };
|
|
1502
|
-
const rect = lineRectWithEndings(
|
|
1503
|
-
[merged.linePoints.start, merged.linePoints.end],
|
|
1504
|
-
merged.strokeWidth,
|
|
1505
|
-
merged.lineEndings
|
|
1506
|
-
);
|
|
1507
|
-
return { ...ctx.changes, rect };
|
|
1508
|
-
}
|
|
1509
|
-
return ctx.changes;
|
|
1510
|
-
default:
|
|
1511
|
-
return ctx.changes;
|
|
1512
|
-
}
|
|
1513
|
-
};
|
|
1514
|
-
const patchPolyline = (orig, ctx) => {
|
|
1515
|
-
var _a;
|
|
1516
|
-
switch (ctx.type) {
|
|
1517
|
-
case "vertex-edit":
|
|
1518
|
-
if (ctx.changes.vertices && ctx.changes.vertices.length) {
|
|
1519
|
-
return {
|
|
1520
|
-
rect: lineRectWithEndings(ctx.changes.vertices, orig.strokeWidth, orig.lineEndings),
|
|
1521
|
-
vertices: ctx.changes.vertices
|
|
1522
|
-
};
|
|
1523
|
-
}
|
|
1524
|
-
return ctx.changes;
|
|
1525
|
-
case "move":
|
|
1526
|
-
if (ctx.changes.rect) {
|
|
1527
|
-
const dx = ctx.changes.rect.origin.x - orig.rect.origin.x;
|
|
1528
|
-
const dy = ctx.changes.rect.origin.y - orig.rect.origin.y;
|
|
1529
|
-
const moved = orig.vertices.map((p) => ({ x: p.x + dx, y: p.y + dy }));
|
|
1530
|
-
return {
|
|
1531
|
-
rect: ctx.changes.rect,
|
|
1532
|
-
vertices: moved
|
|
1533
|
-
};
|
|
1534
|
-
}
|
|
1535
|
-
return ctx.changes;
|
|
1536
|
-
case "resize":
|
|
1537
|
-
if (ctx.changes.rect) {
|
|
1538
|
-
const oldRect = orig.rect;
|
|
1539
|
-
const newRect = ctx.changes.rect;
|
|
1540
|
-
let scaleX = newRect.size.width / oldRect.size.width;
|
|
1541
|
-
let scaleY = newRect.size.height / oldRect.size.height;
|
|
1542
|
-
const minSize = 10;
|
|
1543
|
-
if (newRect.size.width < minSize || newRect.size.height < minSize) {
|
|
1544
|
-
scaleX = Math.max(scaleX, minSize / oldRect.size.width);
|
|
1545
|
-
scaleY = Math.max(scaleY, minSize / oldRect.size.height);
|
|
1546
|
-
ctx.changes.rect = {
|
|
1547
|
-
origin: newRect.origin,
|
|
1548
|
-
size: {
|
|
1549
|
-
width: oldRect.size.width * scaleX,
|
|
1550
|
-
height: oldRect.size.height * scaleY
|
|
1551
|
-
}
|
|
1552
|
-
};
|
|
1553
|
-
}
|
|
1554
|
-
if ((_a = ctx.metadata) == null ? void 0 : _a.maintainAspectRatio) {
|
|
1555
|
-
const minScale = Math.min(scaleX, scaleY);
|
|
1556
|
-
scaleX = minScale;
|
|
1557
|
-
scaleY = minScale;
|
|
1558
|
-
ctx.changes.rect.size = {
|
|
1559
|
-
width: oldRect.size.width * minScale,
|
|
1560
|
-
height: oldRect.size.height * minScale
|
|
1561
|
-
};
|
|
1562
|
-
}
|
|
1563
|
-
const scaledVertices = orig.vertices.map((vertex) => ({
|
|
1564
|
-
x: ctx.changes.rect.origin.x + (vertex.x - oldRect.origin.x) * scaleX,
|
|
1565
|
-
y: ctx.changes.rect.origin.y + (vertex.y - oldRect.origin.y) * scaleY
|
|
1566
|
-
}));
|
|
1567
|
-
return {
|
|
1568
|
-
rect: ctx.changes.rect,
|
|
1569
|
-
vertices: scaledVertices
|
|
1570
|
-
};
|
|
1571
|
-
}
|
|
1572
|
-
return ctx.changes;
|
|
1573
|
-
case "property-update":
|
|
1574
|
-
if (ctx.changes.strokeWidth !== void 0 || ctx.changes.lineEndings !== void 0) {
|
|
1575
|
-
const merged = { ...orig, ...ctx.changes };
|
|
1576
|
-
const rect = lineRectWithEndings(merged.vertices, merged.strokeWidth, merged.lineEndings);
|
|
1577
|
-
return { ...ctx.changes, rect };
|
|
1578
|
-
}
|
|
1579
|
-
return ctx.changes;
|
|
1580
|
-
default:
|
|
1581
|
-
return ctx.changes;
|
|
1582
|
-
}
|
|
1583
|
-
};
|
|
1584
|
-
const patchPolygon = (orig, ctx) => {
|
|
1585
|
-
var _a;
|
|
1586
|
-
switch (ctx.type) {
|
|
1587
|
-
case "vertex-edit":
|
|
1588
|
-
if (ctx.changes.vertices && ctx.changes.vertices.length) {
|
|
1589
|
-
const pad = orig.strokeWidth / 2;
|
|
1590
|
-
return {
|
|
1591
|
-
rect: expandRect(rectFromPoints(ctx.changes.vertices), pad),
|
|
1592
|
-
vertices: ctx.changes.vertices
|
|
2010
|
+
return {
|
|
2011
|
+
rect,
|
|
2012
|
+
linePoints: { start, end }
|
|
1593
2013
|
};
|
|
1594
2014
|
}
|
|
1595
2015
|
return ctx.changes;
|
|
@@ -1597,10 +2017,12 @@ const patchPolygon = (orig, ctx) => {
|
|
|
1597
2017
|
if (ctx.changes.rect) {
|
|
1598
2018
|
const dx = ctx.changes.rect.origin.x - orig.rect.origin.x;
|
|
1599
2019
|
const dy = ctx.changes.rect.origin.y - orig.rect.origin.y;
|
|
1600
|
-
const moved = orig.vertices.map((p) => ({ x: p.x + dx, y: p.y + dy }));
|
|
1601
2020
|
return {
|
|
1602
2021
|
rect: ctx.changes.rect,
|
|
1603
|
-
|
|
2022
|
+
linePoints: {
|
|
2023
|
+
start: { x: orig.linePoints.start.x + dx, y: orig.linePoints.start.y + dy },
|
|
2024
|
+
end: { x: orig.linePoints.end.x + dx, y: orig.linePoints.end.y + dy }
|
|
2025
|
+
}
|
|
1604
2026
|
};
|
|
1605
2027
|
}
|
|
1606
2028
|
return ctx.changes;
|
|
@@ -1631,21 +2053,30 @@ const patchPolygon = (orig, ctx) => {
|
|
|
1631
2053
|
height: oldRect.size.height * minScale
|
|
1632
2054
|
};
|
|
1633
2055
|
}
|
|
1634
|
-
const
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
2056
|
+
const newLinePoints = {
|
|
2057
|
+
start: {
|
|
2058
|
+
x: ctx.changes.rect.origin.x + (orig.linePoints.start.x - oldRect.origin.x) * scaleX,
|
|
2059
|
+
y: ctx.changes.rect.origin.y + (orig.linePoints.start.y - oldRect.origin.y) * scaleY
|
|
2060
|
+
},
|
|
2061
|
+
end: {
|
|
2062
|
+
x: ctx.changes.rect.origin.x + (orig.linePoints.end.x - oldRect.origin.x) * scaleX,
|
|
2063
|
+
y: ctx.changes.rect.origin.y + (orig.linePoints.end.y - oldRect.origin.y) * scaleY
|
|
2064
|
+
}
|
|
2065
|
+
};
|
|
1638
2066
|
return {
|
|
1639
2067
|
rect: ctx.changes.rect,
|
|
1640
|
-
|
|
2068
|
+
linePoints: newLinePoints
|
|
1641
2069
|
};
|
|
1642
2070
|
}
|
|
1643
2071
|
return ctx.changes;
|
|
1644
2072
|
case "property-update":
|
|
1645
|
-
if (ctx.changes.strokeWidth
|
|
2073
|
+
if (ctx.changes.strokeWidth || ctx.changes.lineEndings) {
|
|
1646
2074
|
const merged = { ...orig, ...ctx.changes };
|
|
1647
|
-
const
|
|
1648
|
-
|
|
2075
|
+
const rect = lineRectWithEndings(
|
|
2076
|
+
[merged.linePoints.start, merged.linePoints.end],
|
|
2077
|
+
merged.strokeWidth,
|
|
2078
|
+
merged.lineEndings
|
|
2079
|
+
);
|
|
1649
2080
|
return { ...ctx.changes, rect };
|
|
1650
2081
|
}
|
|
1651
2082
|
return ctx.changes;
|
|
@@ -1653,921 +2084,804 @@ const patchPolygon = (orig, ctx) => {
|
|
|
1653
2084
|
return ctx.changes;
|
|
1654
2085
|
}
|
|
1655
2086
|
};
|
|
1656
|
-
const
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
this.events$ = createBehaviorEmitter();
|
|
1666
|
-
this.patchRegistry = new PatchRegistry();
|
|
1667
|
-
this.isInitialLoadComplete = false;
|
|
1668
|
-
this.importQueue = [];
|
|
1669
|
-
this.config = config;
|
|
1670
|
-
this.selection = ((_a = registry.getPlugin("selection")) == null ? void 0 : _a.provides()) ?? null;
|
|
1671
|
-
this.history = ((_b = registry.getPlugin("history")) == null ? void 0 : _b.provides()) ?? null;
|
|
1672
|
-
this.interactionManager = ((_c = registry.getPlugin("interaction-manager")) == null ? void 0 : _c.provides()) ?? null;
|
|
1673
|
-
this.coreStore.onAction(SET_DOCUMENT, (_, state) => {
|
|
1674
|
-
const doc = state.core.document;
|
|
1675
|
-
this.isInitialLoadComplete = false;
|
|
1676
|
-
if (doc) this.getAllAnnotations(doc);
|
|
1677
|
-
});
|
|
1678
|
-
this.registerHandlerFactories();
|
|
1679
|
-
this.registerBuiltInPatches();
|
|
1680
|
-
}
|
|
1681
|
-
registerHandlerFactories() {
|
|
1682
|
-
this.handlerFactories.set(PdfAnnotationSubtype.CIRCLE, circleHandlerFactory);
|
|
1683
|
-
this.handlerFactories.set(PdfAnnotationSubtype.SQUARE, squareHandlerFactory);
|
|
1684
|
-
this.handlerFactories.set(PdfAnnotationSubtype.STAMP, stampHandlerFactory);
|
|
1685
|
-
this.handlerFactories.set(PdfAnnotationSubtype.POLYGON, polygonHandlerFactory);
|
|
1686
|
-
this.handlerFactories.set(PdfAnnotationSubtype.POLYLINE, polylineHandlerFactory);
|
|
1687
|
-
this.handlerFactories.set(PdfAnnotationSubtype.LINE, lineHandlerFactory);
|
|
1688
|
-
this.handlerFactories.set(PdfAnnotationSubtype.INK, inkHandlerFactory);
|
|
1689
|
-
this.handlerFactories.set(PdfAnnotationSubtype.FREETEXT, freeTextHandlerFactory);
|
|
1690
|
-
}
|
|
1691
|
-
registerBuiltInPatches() {
|
|
1692
|
-
this.patchRegistry.register(PdfAnnotationSubtype.INK, patchInk);
|
|
1693
|
-
this.patchRegistry.register(PdfAnnotationSubtype.LINE, patchLine);
|
|
1694
|
-
this.patchRegistry.register(PdfAnnotationSubtype.POLYLINE, patchPolyline);
|
|
1695
|
-
this.patchRegistry.register(PdfAnnotationSubtype.POLYGON, patchPolygon);
|
|
1696
|
-
}
|
|
1697
|
-
async initialize() {
|
|
1698
|
-
var _a, _b, _c;
|
|
1699
|
-
this.state.tools.forEach((tool) => this.registerInteractionForTool(tool));
|
|
1700
|
-
(_a = this.history) == null ? void 0 : _a.onHistoryChange((topic) => {
|
|
1701
|
-
if (topic === this.ANNOTATION_HISTORY_TOPIC && this.config.autoCommit !== false) {
|
|
1702
|
-
this.commit();
|
|
1703
|
-
}
|
|
1704
|
-
});
|
|
1705
|
-
(_b = this.interactionManager) == null ? void 0 : _b.onModeChange((s) => {
|
|
1706
|
-
var _a2;
|
|
1707
|
-
const newToolId = ((_a2 = this.state.tools.find((t) => (t.interaction.mode ?? t.id) === s.activeMode)) == null ? void 0 : _a2.id) ?? null;
|
|
1708
|
-
if (newToolId !== this.state.activeToolId) {
|
|
1709
|
-
this.dispatch(setActiveToolId(newToolId));
|
|
1710
|
-
}
|
|
1711
|
-
});
|
|
1712
|
-
(_c = this.selection) == null ? void 0 : _c.onEndSelection(() => {
|
|
1713
|
-
var _a2, _b2, _c2;
|
|
1714
|
-
const activeTool = this.getActiveTool();
|
|
1715
|
-
if (!activeTool || !activeTool.interaction.textSelection) return;
|
|
1716
|
-
const formattedSelection = (_a2 = this.selection) == null ? void 0 : _a2.getFormattedSelection();
|
|
1717
|
-
const selectionText = (_b2 = this.selection) == null ? void 0 : _b2.getSelectedText();
|
|
1718
|
-
if (!formattedSelection || !selectionText) return;
|
|
1719
|
-
for (const selection of formattedSelection) {
|
|
1720
|
-
selectionText.wait((text) => {
|
|
1721
|
-
const annotationId = uuidV4();
|
|
1722
|
-
this.createAnnotation(selection.pageIndex, {
|
|
1723
|
-
...activeTool.defaults,
|
|
1724
|
-
rect: selection.rect,
|
|
1725
|
-
segmentRects: selection.segmentRects,
|
|
1726
|
-
pageIndex: selection.pageIndex,
|
|
1727
|
-
created: /* @__PURE__ */ new Date(),
|
|
1728
|
-
id: annotationId,
|
|
1729
|
-
custom: {
|
|
1730
|
-
text: text.join("\n")
|
|
1731
|
-
}
|
|
1732
|
-
});
|
|
1733
|
-
if (this.getToolBehavior(activeTool, "deactivateToolAfterCreate")) {
|
|
1734
|
-
this.setActiveTool(null);
|
|
1735
|
-
}
|
|
1736
|
-
if (this.getToolBehavior(activeTool, "selectAfterCreate")) {
|
|
1737
|
-
this.selectAnnotation(selection.pageIndex, annotationId);
|
|
1738
|
-
}
|
|
1739
|
-
}, ignore);
|
|
1740
|
-
}
|
|
1741
|
-
(_c2 = this.selection) == null ? void 0 : _c2.clear();
|
|
1742
|
-
});
|
|
1743
|
-
}
|
|
1744
|
-
registerInteractionForTool(tool) {
|
|
1745
|
-
var _a, _b;
|
|
1746
|
-
(_a = this.interactionManager) == null ? void 0 : _a.registerMode({
|
|
1747
|
-
id: tool.interaction.mode ?? tool.id,
|
|
1748
|
-
scope: "page",
|
|
1749
|
-
exclusive: tool.interaction.exclusive,
|
|
1750
|
-
cursor: tool.interaction.cursor
|
|
1751
|
-
});
|
|
1752
|
-
if (tool.interaction.textSelection) {
|
|
1753
|
-
(_b = this.selection) == null ? void 0 : _b.enableForMode(tool.interaction.mode ?? tool.id);
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
buildCapability() {
|
|
1757
|
-
return {
|
|
1758
|
-
getPageAnnotations: (options) => this.getPageAnnotations(options),
|
|
1759
|
-
getSelectedAnnotation: () => getSelectedAnnotation(this.state),
|
|
1760
|
-
selectAnnotation: (pageIndex, id) => this.selectAnnotation(pageIndex, id),
|
|
1761
|
-
deselectAnnotation: () => this.dispatch(deselectAnnotation()),
|
|
1762
|
-
getActiveTool: () => this.getActiveTool(),
|
|
1763
|
-
setActiveTool: (toolId) => this.setActiveTool(toolId),
|
|
1764
|
-
getTools: () => this.state.tools,
|
|
1765
|
-
getTool: (toolId) => this.getTool(toolId),
|
|
1766
|
-
addTool: (tool) => {
|
|
1767
|
-
this.dispatch(addTool(tool));
|
|
1768
|
-
this.registerInteractionForTool(tool);
|
|
1769
|
-
},
|
|
1770
|
-
transformAnnotation: (annotation, options) => this.transformAnnotation(annotation, options),
|
|
1771
|
-
registerPatchFunction: (type, patchFn) => this.registerPatchFunction(type, patchFn),
|
|
1772
|
-
findToolForAnnotation: (anno) => this.findToolForAnnotation(anno),
|
|
1773
|
-
setToolDefaults: (toolId, patch) => this.dispatch(setToolDefaults(toolId, patch)),
|
|
1774
|
-
getColorPresets: () => [...this.state.colorPresets],
|
|
1775
|
-
addColorPreset: (color) => this.dispatch(addColorPreset(color)),
|
|
1776
|
-
importAnnotations: (items) => this.importAnnotations(items),
|
|
1777
|
-
createAnnotation: (pageIndex, anno, ctx) => this.createAnnotation(pageIndex, anno, ctx),
|
|
1778
|
-
updateAnnotation: (pageIndex, id, patch) => this.updateAnnotation(pageIndex, id, patch),
|
|
1779
|
-
deleteAnnotation: (pageIndex, id) => this.deleteAnnotation(pageIndex, id),
|
|
1780
|
-
renderAnnotation: (options) => this.renderAnnotation(options),
|
|
1781
|
-
onStateChange: this.state$.on,
|
|
1782
|
-
onActiveToolChange: this.activeTool$.on,
|
|
1783
|
-
onAnnotationEvent: this.events$.on,
|
|
1784
|
-
commit: () => this.commit()
|
|
1785
|
-
};
|
|
1786
|
-
}
|
|
1787
|
-
onStoreUpdated(prev, next) {
|
|
1788
|
-
this.state$.emit(next);
|
|
1789
|
-
if (prev.activeToolId !== next.activeToolId || prev.tools !== next.tools) {
|
|
1790
|
-
this.activeTool$.emit(this.getActiveTool());
|
|
1791
|
-
}
|
|
1792
|
-
}
|
|
1793
|
-
registerPatchFunction(type, patchFn) {
|
|
1794
|
-
this.patchRegistry.register(type, patchFn);
|
|
1795
|
-
}
|
|
1796
|
-
transformAnnotation(annotation, options) {
|
|
1797
|
-
const context = {
|
|
1798
|
-
type: options.type,
|
|
1799
|
-
changes: options.changes,
|
|
1800
|
-
metadata: options.metadata
|
|
1801
|
-
};
|
|
1802
|
-
return this.patchRegistry.transform(annotation, context);
|
|
1803
|
-
}
|
|
1804
|
-
registerPageHandlers(pageIndex, scale, callbacks) {
|
|
1805
|
-
var _a;
|
|
1806
|
-
const page = (_a = this.coreState.core.document) == null ? void 0 : _a.pages[pageIndex];
|
|
1807
|
-
if (!page) return () => {
|
|
1808
|
-
};
|
|
1809
|
-
if (!this.interactionManager) return () => {
|
|
1810
|
-
};
|
|
1811
|
-
const unregisterFns = [];
|
|
1812
|
-
for (const tool of this.state.tools) {
|
|
1813
|
-
if (!tool.defaults.type) continue;
|
|
1814
|
-
const factory = this.handlerFactories.get(tool.defaults.type);
|
|
1815
|
-
if (!factory) continue;
|
|
1816
|
-
const context = {
|
|
1817
|
-
pageIndex,
|
|
1818
|
-
pageSize: page.size,
|
|
1819
|
-
scale,
|
|
1820
|
-
services: callbacks.services,
|
|
1821
|
-
// Pass through services
|
|
1822
|
-
onPreview: (state) => callbacks.onPreview(tool.id, state),
|
|
1823
|
-
onCommit: (annotation, ctx) => {
|
|
1824
|
-
this.createAnnotation(pageIndex, annotation, ctx);
|
|
1825
|
-
if (this.getToolBehavior(tool, "deactivateToolAfterCreate")) {
|
|
1826
|
-
this.setActiveTool(null);
|
|
1827
|
-
}
|
|
1828
|
-
if (this.getToolBehavior(tool, "selectAfterCreate")) {
|
|
1829
|
-
this.selectAnnotation(pageIndex, annotation.id);
|
|
1830
|
-
}
|
|
1831
|
-
},
|
|
1832
|
-
getTool: () => this.state.tools.find((t) => t.id === tool.id)
|
|
1833
|
-
};
|
|
1834
|
-
const unregister = this.interactionManager.registerHandlers({
|
|
1835
|
-
modeId: tool.interaction.mode ?? tool.id,
|
|
1836
|
-
handlers: factory.create(context),
|
|
1837
|
-
pageIndex
|
|
1838
|
-
});
|
|
1839
|
-
unregisterFns.push(unregister);
|
|
1840
|
-
}
|
|
1841
|
-
return () => unregisterFns.forEach((fn) => fn());
|
|
1842
|
-
}
|
|
1843
|
-
getAllAnnotations(doc) {
|
|
1844
|
-
const task = this.engine.getAllAnnotations(doc);
|
|
1845
|
-
task.wait((annotations) => {
|
|
1846
|
-
this.dispatch(setAnnotations(annotations));
|
|
1847
|
-
this.isInitialLoadComplete = true;
|
|
1848
|
-
if (this.importQueue.length > 0) {
|
|
1849
|
-
this.processImportQueue();
|
|
2087
|
+
const patchPolyline = (orig, ctx) => {
|
|
2088
|
+
var _a;
|
|
2089
|
+
switch (ctx.type) {
|
|
2090
|
+
case "vertex-edit":
|
|
2091
|
+
if (ctx.changes.vertices && ctx.changes.vertices.length) {
|
|
2092
|
+
return {
|
|
2093
|
+
rect: lineRectWithEndings(ctx.changes.vertices, orig.strokeWidth, orig.lineEndings),
|
|
2094
|
+
vertices: ctx.changes.vertices
|
|
2095
|
+
};
|
|
1850
2096
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
)
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
const { pageIndex } = options;
|
|
1862
|
-
const doc = this.coreState.core.document;
|
|
1863
|
-
if (!doc) {
|
|
1864
|
-
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
1865
|
-
}
|
|
1866
|
-
const page = doc.pages.find((p) => p.index === pageIndex);
|
|
1867
|
-
if (!page) {
|
|
1868
|
-
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Page not found" });
|
|
1869
|
-
}
|
|
1870
|
-
return this.engine.getPageAnnotations(doc, page);
|
|
1871
|
-
}
|
|
1872
|
-
renderAnnotation({ pageIndex, annotation, options }) {
|
|
1873
|
-
const coreState = this.coreState.core;
|
|
1874
|
-
if (!coreState.document) {
|
|
1875
|
-
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
1876
|
-
}
|
|
1877
|
-
const page = coreState.document.pages.find((page2) => page2.index === pageIndex);
|
|
1878
|
-
if (!page) {
|
|
1879
|
-
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Page not found" });
|
|
1880
|
-
}
|
|
1881
|
-
return this.engine.renderPageAnnotation(coreState.document, page, annotation, options);
|
|
1882
|
-
}
|
|
1883
|
-
importAnnotations(items) {
|
|
1884
|
-
if (!this.isInitialLoadComplete) {
|
|
1885
|
-
this.importQueue.push(...items);
|
|
1886
|
-
return;
|
|
1887
|
-
}
|
|
1888
|
-
this.processImportItems(items);
|
|
1889
|
-
}
|
|
1890
|
-
processImportQueue() {
|
|
1891
|
-
if (this.importQueue.length === 0) return;
|
|
1892
|
-
const items = [...this.importQueue];
|
|
1893
|
-
this.importQueue = [];
|
|
1894
|
-
this.processImportItems(items);
|
|
1895
|
-
}
|
|
1896
|
-
processImportItems(items) {
|
|
1897
|
-
for (const item of items) {
|
|
1898
|
-
const { annotation, ctx } = item;
|
|
1899
|
-
const pageIndex = annotation.pageIndex;
|
|
1900
|
-
const id = annotation.id;
|
|
1901
|
-
this.dispatch(createAnnotation(pageIndex, annotation));
|
|
1902
|
-
if (ctx) this.pendingContexts.set(id, ctx);
|
|
1903
|
-
}
|
|
1904
|
-
if (this.config.autoCommit !== false) this.commit();
|
|
1905
|
-
}
|
|
1906
|
-
createAnnotation(pageIndex, annotation, ctx) {
|
|
1907
|
-
const id = annotation.id;
|
|
1908
|
-
const newAnnotation = {
|
|
1909
|
-
...annotation,
|
|
1910
|
-
author: annotation.author ?? this.config.annotationAuthor
|
|
1911
|
-
};
|
|
1912
|
-
const execute = () => {
|
|
1913
|
-
this.dispatch(createAnnotation(pageIndex, newAnnotation));
|
|
1914
|
-
if (ctx) this.pendingContexts.set(id, ctx);
|
|
1915
|
-
this.events$.emit({
|
|
1916
|
-
type: "create",
|
|
1917
|
-
annotation: newAnnotation,
|
|
1918
|
-
pageIndex,
|
|
1919
|
-
ctx,
|
|
1920
|
-
committed: false
|
|
1921
|
-
});
|
|
1922
|
-
};
|
|
1923
|
-
if (!this.history) {
|
|
1924
|
-
execute();
|
|
1925
|
-
if (this.config.autoCommit) this.commit();
|
|
1926
|
-
return;
|
|
1927
|
-
}
|
|
1928
|
-
const command = {
|
|
1929
|
-
execute,
|
|
1930
|
-
undo: () => {
|
|
1931
|
-
this.pendingContexts.delete(id);
|
|
1932
|
-
this.dispatch(deselectAnnotation());
|
|
1933
|
-
this.dispatch(deleteAnnotation(pageIndex, id));
|
|
1934
|
-
this.events$.emit({
|
|
1935
|
-
type: "delete",
|
|
1936
|
-
annotation: newAnnotation,
|
|
1937
|
-
pageIndex,
|
|
1938
|
-
committed: false
|
|
1939
|
-
});
|
|
2097
|
+
return ctx.changes;
|
|
2098
|
+
case "move":
|
|
2099
|
+
if (ctx.changes.rect) {
|
|
2100
|
+
const dx = ctx.changes.rect.origin.x - orig.rect.origin.x;
|
|
2101
|
+
const dy = ctx.changes.rect.origin.y - orig.rect.origin.y;
|
|
2102
|
+
const moved = orig.vertices.map((p) => ({ x: p.x + dx, y: p.y + dy }));
|
|
2103
|
+
return {
|
|
2104
|
+
rect: ctx.changes.rect,
|
|
2105
|
+
vertices: moved
|
|
2106
|
+
};
|
|
1940
2107
|
}
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2108
|
+
return ctx.changes;
|
|
2109
|
+
case "resize":
|
|
2110
|
+
if (ctx.changes.rect) {
|
|
2111
|
+
const oldRect = orig.rect;
|
|
2112
|
+
const newRect = ctx.changes.rect;
|
|
2113
|
+
let scaleX = newRect.size.width / oldRect.size.width;
|
|
2114
|
+
let scaleY = newRect.size.height / oldRect.size.height;
|
|
2115
|
+
const minSize = 10;
|
|
2116
|
+
if (newRect.size.width < minSize || newRect.size.height < minSize) {
|
|
2117
|
+
scaleX = Math.max(scaleX, minSize / oldRect.size.width);
|
|
2118
|
+
scaleY = Math.max(scaleY, minSize / oldRect.size.height);
|
|
2119
|
+
ctx.changes.rect = {
|
|
2120
|
+
origin: newRect.origin,
|
|
2121
|
+
size: {
|
|
2122
|
+
width: oldRect.size.width * scaleX,
|
|
2123
|
+
height: oldRect.size.height * scaleY
|
|
2124
|
+
}
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
if ((_a = ctx.metadata) == null ? void 0 : _a.maintainAspectRatio) {
|
|
2128
|
+
const minScale = Math.min(scaleX, scaleY);
|
|
2129
|
+
scaleX = minScale;
|
|
2130
|
+
scaleY = minScale;
|
|
2131
|
+
ctx.changes.rect.size = {
|
|
2132
|
+
width: oldRect.size.width * minScale,
|
|
2133
|
+
height: oldRect.size.height * minScale
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
const scaledVertices = orig.vertices.map((vertex) => ({
|
|
2137
|
+
x: ctx.changes.rect.origin.x + (vertex.x - oldRect.origin.x) * scaleX,
|
|
2138
|
+
y: ctx.changes.rect.origin.y + (vertex.y - oldRect.origin.y) * scaleY
|
|
2139
|
+
}));
|
|
2140
|
+
return {
|
|
2141
|
+
rect: ctx.changes.rect,
|
|
2142
|
+
vertices: scaledVertices
|
|
2143
|
+
};
|
|
1971
2144
|
}
|
|
1972
|
-
return;
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
execute,
|
|
1979
|
-
undo: () => {
|
|
1980
|
-
this.dispatch(patchAnnotation(pageIndex, id, originalPatch));
|
|
1981
|
-
this.events$.emit({
|
|
1982
|
-
type: "update",
|
|
1983
|
-
annotation: originalObject,
|
|
1984
|
-
pageIndex,
|
|
1985
|
-
patch: originalPatch,
|
|
1986
|
-
committed: false
|
|
1987
|
-
});
|
|
2145
|
+
return ctx.changes;
|
|
2146
|
+
case "property-update":
|
|
2147
|
+
if (ctx.changes.strokeWidth !== void 0 || ctx.changes.lineEndings !== void 0) {
|
|
2148
|
+
const merged = { ...orig, ...ctx.changes };
|
|
2149
|
+
const rect = lineRectWithEndings(merged.vertices, merged.strokeWidth, merged.lineEndings);
|
|
2150
|
+
return { ...ctx.changes, rect };
|
|
1988
2151
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
2152
|
+
return ctx.changes;
|
|
2153
|
+
default:
|
|
2154
|
+
return ctx.changes;
|
|
1991
2155
|
}
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
committed: false
|
|
2004
|
-
});
|
|
2005
|
-
};
|
|
2006
|
-
if (!this.history) {
|
|
2007
|
-
execute();
|
|
2008
|
-
if (this.config.autoCommit !== false) this.commit();
|
|
2009
|
-
return;
|
|
2010
|
-
}
|
|
2011
|
-
const command = {
|
|
2012
|
-
execute,
|
|
2013
|
-
undo: () => {
|
|
2014
|
-
this.dispatch(createAnnotation(pageIndex, originalAnnotation));
|
|
2015
|
-
this.events$.emit({
|
|
2016
|
-
type: "create",
|
|
2017
|
-
annotation: originalAnnotation,
|
|
2018
|
-
pageIndex,
|
|
2019
|
-
committed: false
|
|
2020
|
-
});
|
|
2156
|
+
};
|
|
2157
|
+
const patchPolygon = (orig, ctx) => {
|
|
2158
|
+
var _a;
|
|
2159
|
+
switch (ctx.type) {
|
|
2160
|
+
case "vertex-edit":
|
|
2161
|
+
if (ctx.changes.vertices && ctx.changes.vertices.length) {
|
|
2162
|
+
const pad = orig.strokeWidth / 2;
|
|
2163
|
+
return {
|
|
2164
|
+
rect: expandRect(rectFromPoints(ctx.changes.vertices), pad),
|
|
2165
|
+
vertices: ctx.changes.vertices
|
|
2166
|
+
};
|
|
2021
2167
|
}
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
setActiveTool(toolId) {
|
|
2033
|
-
var _a, _b;
|
|
2034
|
-
if (toolId === this.state.activeToolId) return;
|
|
2035
|
-
const tool = this.state.tools.find((t) => t.id === toolId);
|
|
2036
|
-
if (tool) {
|
|
2037
|
-
(_a = this.interactionManager) == null ? void 0 : _a.activate(tool.interaction.mode ?? tool.id);
|
|
2038
|
-
} else {
|
|
2039
|
-
(_b = this.interactionManager) == null ? void 0 : _b.activateDefaultMode();
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
getTool(toolId) {
|
|
2043
|
-
return this.state.tools.find((t) => t.id === toolId);
|
|
2044
|
-
}
|
|
2045
|
-
findToolForAnnotation(annotation) {
|
|
2046
|
-
let bestTool = null;
|
|
2047
|
-
let bestScore = 0;
|
|
2048
|
-
for (const tool of this.state.tools) {
|
|
2049
|
-
const score = tool.matchScore(annotation);
|
|
2050
|
-
if (score > bestScore) {
|
|
2051
|
-
bestScore = score;
|
|
2052
|
-
bestTool = tool;
|
|
2168
|
+
return ctx.changes;
|
|
2169
|
+
case "move":
|
|
2170
|
+
if (ctx.changes.rect) {
|
|
2171
|
+
const dx = ctx.changes.rect.origin.x - orig.rect.origin.x;
|
|
2172
|
+
const dy = ctx.changes.rect.origin.y - orig.rect.origin.y;
|
|
2173
|
+
const moved = orig.vertices.map((p) => ({ x: p.x + dx, y: p.y + dy }));
|
|
2174
|
+
return {
|
|
2175
|
+
rect: ctx.changes.rect,
|
|
2176
|
+
vertices: moved
|
|
2177
|
+
};
|
|
2053
2178
|
}
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
type: "update",
|
|
2091
|
-
annotation: ta.object,
|
|
2092
|
-
pageIndex: ta.object.pageIndex,
|
|
2093
|
-
patch: ta.object,
|
|
2094
|
-
committed: true
|
|
2095
|
-
});
|
|
2096
|
-
}, ignore);
|
|
2097
|
-
updates.push(updateTask);
|
|
2098
|
-
break;
|
|
2099
|
-
case "deleted":
|
|
2100
|
-
deletions.push({ ta, uid });
|
|
2101
|
-
break;
|
|
2179
|
+
return ctx.changes;
|
|
2180
|
+
case "resize":
|
|
2181
|
+
if (ctx.changes.rect) {
|
|
2182
|
+
const oldRect = orig.rect;
|
|
2183
|
+
const newRect = ctx.changes.rect;
|
|
2184
|
+
let scaleX = newRect.size.width / oldRect.size.width;
|
|
2185
|
+
let scaleY = newRect.size.height / oldRect.size.height;
|
|
2186
|
+
const minSize = 10;
|
|
2187
|
+
if (newRect.size.width < minSize || newRect.size.height < minSize) {
|
|
2188
|
+
scaleX = Math.max(scaleX, minSize / oldRect.size.width);
|
|
2189
|
+
scaleY = Math.max(scaleY, minSize / oldRect.size.height);
|
|
2190
|
+
ctx.changes.rect = {
|
|
2191
|
+
origin: newRect.origin,
|
|
2192
|
+
size: {
|
|
2193
|
+
width: oldRect.size.width * scaleX,
|
|
2194
|
+
height: oldRect.size.height * scaleY
|
|
2195
|
+
}
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
if ((_a = ctx.metadata) == null ? void 0 : _a.maintainAspectRatio) {
|
|
2199
|
+
const minScale = Math.min(scaleX, scaleY);
|
|
2200
|
+
scaleX = minScale;
|
|
2201
|
+
scaleY = minScale;
|
|
2202
|
+
ctx.changes.rect.size = {
|
|
2203
|
+
width: oldRect.size.width * minScale,
|
|
2204
|
+
height: oldRect.size.height * minScale
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
const scaledVertices = orig.vertices.map((vertex) => ({
|
|
2208
|
+
x: ctx.changes.rect.origin.x + (vertex.x - oldRect.origin.x) * scaleX,
|
|
2209
|
+
y: ctx.changes.rect.origin.y + (vertex.y - oldRect.origin.y) * scaleY
|
|
2210
|
+
}));
|
|
2211
|
+
return {
|
|
2212
|
+
rect: ctx.changes.rect,
|
|
2213
|
+
vertices: scaledVertices
|
|
2214
|
+
};
|
|
2102
2215
|
}
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
const
|
|
2109
|
-
|
|
2110
|
-
removeTask.wait(() => {
|
|
2111
|
-
this.dispatch(purgeAnnotation(uid));
|
|
2112
|
-
this.events$.emit({
|
|
2113
|
-
type: "delete",
|
|
2114
|
-
annotation: ta.object,
|
|
2115
|
-
pageIndex: ta.object.pageIndex,
|
|
2116
|
-
committed: true
|
|
2117
|
-
});
|
|
2118
|
-
task2.resolve(true);
|
|
2119
|
-
}, task2.fail);
|
|
2120
|
-
deletionTasks.push(task2);
|
|
2121
|
-
} else {
|
|
2122
|
-
this.dispatch(purgeAnnotation(uid));
|
|
2216
|
+
return ctx.changes;
|
|
2217
|
+
case "property-update":
|
|
2218
|
+
if (ctx.changes.strokeWidth !== void 0) {
|
|
2219
|
+
const merged = { ...orig, ...ctx.changes };
|
|
2220
|
+
const pad = merged.strokeWidth / 2;
|
|
2221
|
+
const rect = expandRect(rectFromPoints(merged.vertices), pad);
|
|
2222
|
+
return { ...ctx.changes, rect };
|
|
2123
2223
|
}
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
this.dispatch(commitPendingChanges());
|
|
2128
|
-
task.resolve(true);
|
|
2129
|
-
}, task.fail);
|
|
2130
|
-
return task;
|
|
2131
|
-
}
|
|
2132
|
-
/**
|
|
2133
|
-
* Gets the effective behavior setting for a tool, checking tool-specific config first,
|
|
2134
|
-
* then falling back to plugin config.
|
|
2135
|
-
*/
|
|
2136
|
-
getToolBehavior(tool, setting) {
|
|
2137
|
-
var _a;
|
|
2138
|
-
if (((_a = tool.behavior) == null ? void 0 : _a[setting]) !== void 0) {
|
|
2139
|
-
return tool.behavior[setting];
|
|
2140
|
-
}
|
|
2141
|
-
return this.config[setting] !== false;
|
|
2224
|
+
return ctx.changes;
|
|
2225
|
+
default:
|
|
2226
|
+
return ctx.changes;
|
|
2142
2227
|
}
|
|
2143
2228
|
};
|
|
2144
|
-
_AnnotationPlugin
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
}
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
name: "Strikeout",
|
|
2184
|
-
matchScore: (a) => a.type === PdfAnnotationSubtype.STRIKEOUT ? 1 : 0,
|
|
2185
|
-
interaction: {
|
|
2186
|
-
exclusive: false,
|
|
2187
|
-
textSelection: true
|
|
2188
|
-
},
|
|
2189
|
-
defaults: {
|
|
2190
|
-
type: PdfAnnotationSubtype.STRIKEOUT,
|
|
2191
|
-
color: "#E44234",
|
|
2192
|
-
opacity: 1
|
|
2193
|
-
}
|
|
2194
|
-
},
|
|
2195
|
-
{
|
|
2196
|
-
id: "squiggly",
|
|
2197
|
-
name: "Squiggly",
|
|
2198
|
-
matchScore: (a) => a.type === PdfAnnotationSubtype.SQUIGGLY ? 1 : 0,
|
|
2199
|
-
interaction: {
|
|
2200
|
-
exclusive: false,
|
|
2201
|
-
textSelection: true,
|
|
2202
|
-
isDraggable: false,
|
|
2203
|
-
isResizable: false
|
|
2204
|
-
},
|
|
2205
|
-
defaults: {
|
|
2206
|
-
type: PdfAnnotationSubtype.SQUIGGLY,
|
|
2207
|
-
color: "#E44234",
|
|
2208
|
-
opacity: 1
|
|
2229
|
+
const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
|
|
2230
|
+
constructor(id, registry, config) {
|
|
2231
|
+
var _a, _b, _c;
|
|
2232
|
+
super(id, registry);
|
|
2233
|
+
this.ANNOTATION_HISTORY_TOPIC = "annotations";
|
|
2234
|
+
this.state$ = createBehaviorEmitter();
|
|
2235
|
+
this.pendingContexts = /* @__PURE__ */ new Map();
|
|
2236
|
+
this.isInitialLoadComplete = /* @__PURE__ */ new Map();
|
|
2237
|
+
this.importQueue = /* @__PURE__ */ new Map();
|
|
2238
|
+
this.handlerFactories = /* @__PURE__ */ new Map();
|
|
2239
|
+
this.activeTool$ = createBehaviorEmitter();
|
|
2240
|
+
this.events$ = createBehaviorEmitter();
|
|
2241
|
+
this.toolsChange$ = createBehaviorEmitter();
|
|
2242
|
+
this.patchRegistry = new PatchRegistry();
|
|
2243
|
+
this.config = config;
|
|
2244
|
+
this.selection = ((_a = registry.getPlugin("selection")) == null ? void 0 : _a.provides()) ?? null;
|
|
2245
|
+
this.history = ((_b = registry.getPlugin("history")) == null ? void 0 : _b.provides()) ?? null;
|
|
2246
|
+
this.interactionManager = ((_c = registry.getPlugin("interaction-manager")) == null ? void 0 : _c.provides()) ?? null;
|
|
2247
|
+
this.registerHandlerFactories();
|
|
2248
|
+
this.registerBuiltInPatches();
|
|
2249
|
+
}
|
|
2250
|
+
// ─────────────────────────────────────────────────────────
|
|
2251
|
+
// Document Lifecycle (from BasePlugin)
|
|
2252
|
+
// ─────────────────────────────────────────────────────────
|
|
2253
|
+
onDocumentLoadingStarted(documentId) {
|
|
2254
|
+
this.dispatch(initAnnotationState(documentId, initialDocumentState()));
|
|
2255
|
+
this.pendingContexts.set(documentId, /* @__PURE__ */ new Map());
|
|
2256
|
+
this.isInitialLoadComplete.set(documentId, false);
|
|
2257
|
+
this.importQueue.set(documentId, []);
|
|
2258
|
+
this.logger.debug(
|
|
2259
|
+
"AnnotationPlugin",
|
|
2260
|
+
"DocumentOpened",
|
|
2261
|
+
`Initialized annotation state for document: ${documentId}`
|
|
2262
|
+
);
|
|
2263
|
+
}
|
|
2264
|
+
onDocumentLoaded(documentId) {
|
|
2265
|
+
const docState = this.getCoreDocument(documentId);
|
|
2266
|
+
if (docState == null ? void 0 : docState.document) {
|
|
2267
|
+
this.getAllAnnotations(documentId, docState.document);
|
|
2209
2268
|
}
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
interaction: {
|
|
2217
|
-
exclusive: false,
|
|
2218
|
-
cursor: "crosshair",
|
|
2219
|
-
isDraggable: true,
|
|
2220
|
-
isResizable: true,
|
|
2221
|
-
lockAspectRatio: false
|
|
2222
|
-
},
|
|
2223
|
-
defaults: {
|
|
2224
|
-
type: PdfAnnotationSubtype.INK,
|
|
2225
|
-
color: "#E44234",
|
|
2226
|
-
opacity: 1,
|
|
2227
|
-
strokeWidth: 6
|
|
2269
|
+
if (this.selection) {
|
|
2270
|
+
for (const tool of this.state.tools) {
|
|
2271
|
+
if (tool.interaction.textSelection) {
|
|
2272
|
+
this.selection.enableForMode(tool.interaction.mode ?? tool.id);
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2228
2275
|
}
|
|
2229
|
-
}
|
|
2230
|
-
{
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2276
|
+
}
|
|
2277
|
+
onDocumentClosed(documentId) {
|
|
2278
|
+
this.dispatch(cleanupAnnotationState(documentId));
|
|
2279
|
+
this.pendingContexts.delete(documentId);
|
|
2280
|
+
this.isInitialLoadComplete.delete(documentId);
|
|
2281
|
+
this.importQueue.delete(documentId);
|
|
2282
|
+
this.logger.debug(
|
|
2283
|
+
"AnnotationPlugin",
|
|
2284
|
+
"DocumentClosed",
|
|
2285
|
+
`Cleaned up annotation state for document: ${documentId}`
|
|
2286
|
+
);
|
|
2287
|
+
}
|
|
2288
|
+
registerHandlerFactories() {
|
|
2289
|
+
this.handlerFactories.set(PdfAnnotationSubtype.CIRCLE, circleHandlerFactory);
|
|
2290
|
+
this.handlerFactories.set(PdfAnnotationSubtype.SQUARE, squareHandlerFactory);
|
|
2291
|
+
this.handlerFactories.set(PdfAnnotationSubtype.STAMP, stampHandlerFactory);
|
|
2292
|
+
this.handlerFactories.set(PdfAnnotationSubtype.POLYGON, polygonHandlerFactory);
|
|
2293
|
+
this.handlerFactories.set(PdfAnnotationSubtype.POLYLINE, polylineHandlerFactory);
|
|
2294
|
+
this.handlerFactories.set(PdfAnnotationSubtype.LINE, lineHandlerFactory);
|
|
2295
|
+
this.handlerFactories.set(PdfAnnotationSubtype.INK, inkHandlerFactory);
|
|
2296
|
+
this.handlerFactories.set(PdfAnnotationSubtype.FREETEXT, freeTextHandlerFactory);
|
|
2297
|
+
}
|
|
2298
|
+
registerBuiltInPatches() {
|
|
2299
|
+
this.patchRegistry.register(PdfAnnotationSubtype.INK, patchInk);
|
|
2300
|
+
this.patchRegistry.register(PdfAnnotationSubtype.LINE, patchLine);
|
|
2301
|
+
this.patchRegistry.register(PdfAnnotationSubtype.POLYLINE, patchPolyline);
|
|
2302
|
+
this.patchRegistry.register(PdfAnnotationSubtype.POLYGON, patchPolygon);
|
|
2303
|
+
}
|
|
2304
|
+
async initialize() {
|
|
2305
|
+
var _a, _b;
|
|
2306
|
+
this.state.tools.forEach((tool) => this.registerInteractionForTool(tool));
|
|
2307
|
+
if (this.history) {
|
|
2308
|
+
this.history.onHistoryChange((event) => {
|
|
2309
|
+
if (event.topic === this.ANNOTATION_HISTORY_TOPIC && this.config.autoCommit !== false) {
|
|
2310
|
+
this.commit(event.documentId);
|
|
2311
|
+
}
|
|
2312
|
+
});
|
|
2248
2313
|
}
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2314
|
+
(_a = this.interactionManager) == null ? void 0 : _a.onModeChange((s) => {
|
|
2315
|
+
var _a2, _b2;
|
|
2316
|
+
const newToolId = ((_a2 = this.state.tools.find((t) => (t.interaction.mode ?? t.id) === s.activeMode)) == null ? void 0 : _a2.id) ?? null;
|
|
2317
|
+
const currentToolId = ((_b2 = this.state.documents[s.documentId]) == null ? void 0 : _b2.activeToolId) ?? null;
|
|
2318
|
+
if (newToolId !== currentToolId && s.documentId) {
|
|
2319
|
+
this.dispatch(setActiveToolId(s.documentId, newToolId));
|
|
2320
|
+
}
|
|
2321
|
+
});
|
|
2322
|
+
(_b = this.selection) == null ? void 0 : _b.onEndSelection(({ documentId }) => {
|
|
2323
|
+
var _a2, _b2, _c;
|
|
2324
|
+
const activeTool = this.getActiveTool(documentId);
|
|
2325
|
+
if (!activeTool || !activeTool.interaction.textSelection) return;
|
|
2326
|
+
const formattedSelection = (_a2 = this.selection) == null ? void 0 : _a2.getFormattedSelection();
|
|
2327
|
+
const selectionText = (_b2 = this.selection) == null ? void 0 : _b2.getSelectedText();
|
|
2328
|
+
if (!formattedSelection || !selectionText) return;
|
|
2329
|
+
for (const selection of formattedSelection) {
|
|
2330
|
+
selectionText.wait((text) => {
|
|
2331
|
+
const annotationId = uuidV4();
|
|
2332
|
+
this.createAnnotation(
|
|
2333
|
+
selection.pageIndex,
|
|
2334
|
+
{
|
|
2335
|
+
...activeTool.defaults,
|
|
2336
|
+
rect: selection.rect,
|
|
2337
|
+
segmentRects: selection.segmentRects,
|
|
2338
|
+
pageIndex: selection.pageIndex,
|
|
2339
|
+
created: /* @__PURE__ */ new Date(),
|
|
2340
|
+
id: annotationId,
|
|
2341
|
+
custom: {
|
|
2342
|
+
text: text.join("\n")
|
|
2343
|
+
}
|
|
2344
|
+
},
|
|
2345
|
+
void 0,
|
|
2346
|
+
documentId
|
|
2347
|
+
);
|
|
2348
|
+
if (this.getToolBehavior(activeTool, "deactivateToolAfterCreate")) {
|
|
2349
|
+
this.setActiveTool(null, documentId);
|
|
2350
|
+
}
|
|
2351
|
+
if (this.getToolBehavior(activeTool, "selectAfterCreate")) {
|
|
2352
|
+
this.selectAnnotation(selection.pageIndex, annotationId, documentId);
|
|
2353
|
+
}
|
|
2354
|
+
}, ignore);
|
|
2355
|
+
}
|
|
2356
|
+
(_c = this.selection) == null ? void 0 : _c.clear();
|
|
2357
|
+
});
|
|
2358
|
+
}
|
|
2359
|
+
registerInteractionForTool(tool) {
|
|
2360
|
+
var _a;
|
|
2361
|
+
(_a = this.interactionManager) == null ? void 0 : _a.registerMode({
|
|
2362
|
+
id: tool.interaction.mode ?? tool.id,
|
|
2363
|
+
scope: "page",
|
|
2364
|
+
exclusive: tool.interaction.exclusive,
|
|
2365
|
+
cursor: tool.interaction.cursor
|
|
2366
|
+
});
|
|
2367
|
+
}
|
|
2368
|
+
buildCapability() {
|
|
2369
|
+
return {
|
|
2370
|
+
// Active document operations
|
|
2371
|
+
getActiveTool: () => this.getActiveTool(),
|
|
2372
|
+
setActiveTool: (toolId) => this.setActiveTool(toolId),
|
|
2373
|
+
getState: () => this.getDocumentState(),
|
|
2374
|
+
getPageAnnotations: (options) => this.getPageAnnotations(options),
|
|
2375
|
+
getSelectedAnnotation: () => this.getSelectedAnnotation(),
|
|
2376
|
+
getAnnotationById: (id) => this.getAnnotationById(id),
|
|
2377
|
+
selectAnnotation: (pageIndex, id) => this.selectAnnotation(pageIndex, id),
|
|
2378
|
+
deselectAnnotation: () => this.deselectAnnotation(),
|
|
2379
|
+
importAnnotations: (items) => this.importAnnotations(items),
|
|
2380
|
+
createAnnotation: (pageIndex, anno, ctx) => this.createAnnotation(pageIndex, anno, ctx),
|
|
2381
|
+
updateAnnotation: (pageIndex, id, patch) => this.updateAnnotation(pageIndex, id, patch),
|
|
2382
|
+
deleteAnnotation: (pageIndex, id) => this.deleteAnnotation(pageIndex, id),
|
|
2383
|
+
renderAnnotation: (options) => this.renderAnnotation(options),
|
|
2384
|
+
commit: () => this.commit(),
|
|
2385
|
+
// Document-scoped operations
|
|
2386
|
+
forDocument: (documentId) => this.createAnnotationScope(documentId),
|
|
2387
|
+
// Global operations
|
|
2388
|
+
getTools: () => this.state.tools,
|
|
2389
|
+
getTool: (toolId) => this.getTool(toolId),
|
|
2390
|
+
addTool: (tool) => {
|
|
2391
|
+
this.dispatch(addTool(tool));
|
|
2392
|
+
this.registerInteractionForTool(tool);
|
|
2393
|
+
},
|
|
2394
|
+
findToolForAnnotation: (anno) => this.findToolForAnnotation(anno),
|
|
2395
|
+
setToolDefaults: (toolId, patch) => this.dispatch(setToolDefaults(toolId, patch)),
|
|
2396
|
+
getColorPresets: () => [...this.state.colorPresets],
|
|
2397
|
+
addColorPreset: (color) => this.dispatch(addColorPreset(color)),
|
|
2398
|
+
transformAnnotation: (annotation, options) => this.transformAnnotation(annotation, options),
|
|
2399
|
+
registerPatchFunction: (type, patchFn) => this.registerPatchFunction(type, patchFn),
|
|
2400
|
+
// Events
|
|
2401
|
+
onStateChange: this.state$.on,
|
|
2402
|
+
onActiveToolChange: this.activeTool$.on,
|
|
2403
|
+
onAnnotationEvent: this.events$.on,
|
|
2404
|
+
onToolsChange: this.toolsChange$.on
|
|
2405
|
+
};
|
|
2406
|
+
}
|
|
2407
|
+
// ─────────────────────────────────────────────────────────
|
|
2408
|
+
// Document Scoping
|
|
2409
|
+
// ─────────────────────────────────────────────────────────
|
|
2410
|
+
createAnnotationScope(documentId) {
|
|
2411
|
+
return {
|
|
2412
|
+
getState: () => this.getDocumentState(documentId),
|
|
2413
|
+
getPageAnnotations: (options) => this.getPageAnnotations(options, documentId),
|
|
2414
|
+
getSelectedAnnotation: () => this.getSelectedAnnotation(documentId),
|
|
2415
|
+
getAnnotationById: (id) => this.getAnnotationById(id, documentId),
|
|
2416
|
+
selectAnnotation: (pageIndex, id) => this.selectAnnotation(pageIndex, id, documentId),
|
|
2417
|
+
deselectAnnotation: () => this.deselectAnnotation(documentId),
|
|
2418
|
+
getActiveTool: () => this.getActiveTool(documentId),
|
|
2419
|
+
setActiveTool: (toolId) => this.setActiveTool(toolId, documentId),
|
|
2420
|
+
findToolForAnnotation: (anno) => this.findToolForAnnotation(anno),
|
|
2421
|
+
importAnnotations: (items) => this.importAnnotations(items, documentId),
|
|
2422
|
+
createAnnotation: (pageIndex, anno, ctx) => this.createAnnotation(pageIndex, anno, ctx, documentId),
|
|
2423
|
+
updateAnnotation: (pageIndex, id, patch) => this.updateAnnotation(pageIndex, id, patch, documentId),
|
|
2424
|
+
deleteAnnotation: (pageIndex, id) => this.deleteAnnotation(pageIndex, id, documentId),
|
|
2425
|
+
renderAnnotation: (options) => this.renderAnnotation(options, documentId),
|
|
2426
|
+
commit: () => this.commit(documentId),
|
|
2427
|
+
onStateChange: (listener) => this.state$.on((event) => {
|
|
2428
|
+
if (event.documentId === documentId) listener(event.state);
|
|
2429
|
+
}),
|
|
2430
|
+
onAnnotationEvent: (listener) => this.events$.on((event) => {
|
|
2431
|
+
if (event.documentId === documentId) listener(event);
|
|
2432
|
+
}),
|
|
2433
|
+
onActiveToolChange: (listener) => this.activeTool$.on((event) => {
|
|
2434
|
+
if (event.documentId === documentId) listener(event.tool);
|
|
2435
|
+
})
|
|
2436
|
+
};
|
|
2437
|
+
}
|
|
2438
|
+
onStoreUpdated(prev, next) {
|
|
2439
|
+
for (const documentId in next.documents) {
|
|
2440
|
+
const prevDoc = prev.documents[documentId];
|
|
2441
|
+
const nextDoc = next.documents[documentId];
|
|
2442
|
+
if (prevDoc !== nextDoc) {
|
|
2443
|
+
this.state$.emit({
|
|
2444
|
+
documentId,
|
|
2445
|
+
state: nextDoc
|
|
2446
|
+
});
|
|
2447
|
+
if (prevDoc && prevDoc.activeToolId !== nextDoc.activeToolId) {
|
|
2448
|
+
this.activeTool$.emit({
|
|
2449
|
+
documentId,
|
|
2450
|
+
tool: this.getActiveTool(documentId)
|
|
2451
|
+
});
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2273
2454
|
}
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
lockAspectRatio: false
|
|
2285
|
-
},
|
|
2286
|
-
defaults: {
|
|
2287
|
-
type: PdfAnnotationSubtype.SQUARE,
|
|
2288
|
-
color: "transparent",
|
|
2289
|
-
opacity: 1,
|
|
2290
|
-
strokeWidth: 6,
|
|
2291
|
-
strokeColor: "#E44234",
|
|
2292
|
-
strokeStyle: PdfAnnotationBorderStyle.SOLID
|
|
2293
|
-
},
|
|
2294
|
-
clickBehavior: {
|
|
2295
|
-
enabled: true,
|
|
2296
|
-
defaultSize: { width: 100, height: 100 }
|
|
2455
|
+
if (prev.tools !== next.tools) {
|
|
2456
|
+
for (const documentId in next.documents) {
|
|
2457
|
+
this.activeTool$.emit({
|
|
2458
|
+
documentId,
|
|
2459
|
+
tool: this.getActiveTool(documentId)
|
|
2460
|
+
});
|
|
2461
|
+
}
|
|
2462
|
+
this.toolsChange$.emit({
|
|
2463
|
+
tools: next.tools
|
|
2464
|
+
});
|
|
2297
2465
|
}
|
|
2298
|
-
}
|
|
2299
|
-
{
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2466
|
+
}
|
|
2467
|
+
registerPatchFunction(type, patchFn) {
|
|
2468
|
+
this.patchRegistry.register(type, patchFn);
|
|
2469
|
+
}
|
|
2470
|
+
transformAnnotation(annotation, options) {
|
|
2471
|
+
const context = {
|
|
2472
|
+
type: options.type,
|
|
2473
|
+
changes: options.changes,
|
|
2474
|
+
metadata: options.metadata
|
|
2475
|
+
};
|
|
2476
|
+
return this.patchRegistry.transform(annotation, context);
|
|
2477
|
+
}
|
|
2478
|
+
registerPageHandlers(documentId, pageIndex, scale, callbacks) {
|
|
2479
|
+
var _a;
|
|
2480
|
+
const docState = this.getCoreDocument(documentId);
|
|
2481
|
+
const page = (_a = docState == null ? void 0 : docState.document) == null ? void 0 : _a.pages[pageIndex];
|
|
2482
|
+
if (!page) return () => {
|
|
2483
|
+
};
|
|
2484
|
+
if (!this.interactionManager) return () => {
|
|
2485
|
+
};
|
|
2486
|
+
const unregisterFns = [];
|
|
2487
|
+
for (const tool of this.state.tools) {
|
|
2488
|
+
if (!tool.defaults.type) continue;
|
|
2489
|
+
const factory = this.handlerFactories.get(tool.defaults.type);
|
|
2490
|
+
if (!factory) continue;
|
|
2491
|
+
const context = {
|
|
2492
|
+
pageIndex,
|
|
2493
|
+
pageSize: page.size,
|
|
2494
|
+
scale,
|
|
2495
|
+
services: callbacks.services,
|
|
2496
|
+
// Pass through services
|
|
2497
|
+
onPreview: (state) => callbacks.onPreview(tool.id, state),
|
|
2498
|
+
onCommit: (annotation, ctx) => {
|
|
2499
|
+
this.createAnnotation(pageIndex, annotation, ctx, documentId);
|
|
2500
|
+
if (this.getToolBehavior(tool, "deactivateToolAfterCreate")) {
|
|
2501
|
+
this.setActiveTool(null, documentId);
|
|
2502
|
+
}
|
|
2503
|
+
if (this.getToolBehavior(tool, "selectAfterCreate")) {
|
|
2504
|
+
this.selectAnnotation(pageIndex, annotation.id, documentId);
|
|
2505
|
+
}
|
|
2506
|
+
},
|
|
2507
|
+
getTool: () => this.state.tools.find((t) => t.id === tool.id)
|
|
2508
|
+
};
|
|
2509
|
+
const unregister = this.interactionManager.registerHandlers({
|
|
2510
|
+
documentId,
|
|
2511
|
+
modeId: tool.interaction.mode ?? tool.id,
|
|
2512
|
+
handlers: factory.create(context),
|
|
2513
|
+
pageIndex
|
|
2514
|
+
});
|
|
2515
|
+
unregisterFns.push(unregister);
|
|
2321
2516
|
}
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
end: PdfAnnotationLineEnding.OpenArrow
|
|
2517
|
+
return () => unregisterFns.forEach((fn) => fn());
|
|
2518
|
+
}
|
|
2519
|
+
// ─────────────────────────────────────────────────────────
|
|
2520
|
+
// Helper Methods
|
|
2521
|
+
// ─────────────────────────────────────────────────────────
|
|
2522
|
+
getDocumentState(documentId) {
|
|
2523
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
2524
|
+
const docState = this.state.documents[id];
|
|
2525
|
+
if (!docState) {
|
|
2526
|
+
throw new Error(`Annotation state not found for document: ${id}`);
|
|
2527
|
+
}
|
|
2528
|
+
return docState;
|
|
2529
|
+
}
|
|
2530
|
+
getAllAnnotations(documentId, doc) {
|
|
2531
|
+
const task = this.engine.getAllAnnotations(doc);
|
|
2532
|
+
task.wait((annotations) => {
|
|
2533
|
+
this.dispatch(setAnnotations(documentId, annotations));
|
|
2534
|
+
this.isInitialLoadComplete.set(documentId, true);
|
|
2535
|
+
const queue = this.importQueue.get(documentId);
|
|
2536
|
+
if (queue && queue.length > 0) {
|
|
2537
|
+
this.processImportQueue(documentId);
|
|
2344
2538
|
}
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2539
|
+
this.events$.emit({
|
|
2540
|
+
type: "loaded",
|
|
2541
|
+
documentId,
|
|
2542
|
+
total: Object.values(annotations).reduce(
|
|
2543
|
+
(sum, pageAnnotations) => sum + pageAnnotations.length,
|
|
2544
|
+
0
|
|
2545
|
+
)
|
|
2546
|
+
});
|
|
2547
|
+
}, ignore);
|
|
2548
|
+
}
|
|
2549
|
+
getPageAnnotations(options, documentId) {
|
|
2550
|
+
const { pageIndex } = options;
|
|
2551
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
2552
|
+
const docState = this.getCoreDocument(id);
|
|
2553
|
+
const doc = docState == null ? void 0 : docState.document;
|
|
2554
|
+
if (!doc) {
|
|
2555
|
+
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
2350
2556
|
}
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
name: "Polyline",
|
|
2355
|
-
matchScore: (a) => a.type === PdfAnnotationSubtype.POLYLINE ? 1 : 0,
|
|
2356
|
-
interaction: {
|
|
2357
|
-
exclusive: false,
|
|
2358
|
-
cursor: "crosshair",
|
|
2359
|
-
isDraggable: true,
|
|
2360
|
-
isResizable: false,
|
|
2361
|
-
lockAspectRatio: false
|
|
2362
|
-
},
|
|
2363
|
-
defaults: {
|
|
2364
|
-
type: PdfAnnotationSubtype.POLYLINE,
|
|
2365
|
-
color: "transparent",
|
|
2366
|
-
opacity: 1,
|
|
2367
|
-
strokeWidth: 6,
|
|
2368
|
-
strokeColor: "#E44234"
|
|
2557
|
+
const page = doc.pages.find((p) => p.index === pageIndex);
|
|
2558
|
+
if (!page) {
|
|
2559
|
+
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Page not found" });
|
|
2369
2560
|
}
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
opacity: 1,
|
|
2386
|
-
strokeWidth: 6,
|
|
2387
|
-
strokeColor: "#E44234"
|
|
2561
|
+
return this.engine.getPageAnnotations(doc, page);
|
|
2562
|
+
}
|
|
2563
|
+
getSelectedAnnotation(documentId) {
|
|
2564
|
+
return getSelectedAnnotation(this.getDocumentState(documentId));
|
|
2565
|
+
}
|
|
2566
|
+
getAnnotationById(id, documentId) {
|
|
2567
|
+
const docState = this.getDocumentState(documentId);
|
|
2568
|
+
return getAnnotationByUid(docState, id);
|
|
2569
|
+
}
|
|
2570
|
+
renderAnnotation({ pageIndex, annotation, options }, documentId) {
|
|
2571
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
2572
|
+
const docState = this.getCoreDocument(id);
|
|
2573
|
+
const doc = docState == null ? void 0 : docState.document;
|
|
2574
|
+
if (!doc) {
|
|
2575
|
+
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
2388
2576
|
}
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
id: "freeText",
|
|
2393
|
-
name: "Free Text",
|
|
2394
|
-
matchScore: (a) => a.type === PdfAnnotationSubtype.FREETEXT ? 1 : 0,
|
|
2395
|
-
interaction: {
|
|
2396
|
-
exclusive: false,
|
|
2397
|
-
cursor: "crosshair",
|
|
2398
|
-
isDraggable: true,
|
|
2399
|
-
isResizable: true,
|
|
2400
|
-
lockAspectRatio: false
|
|
2401
|
-
},
|
|
2402
|
-
defaults: {
|
|
2403
|
-
type: PdfAnnotationSubtype.FREETEXT,
|
|
2404
|
-
contents: "Insert text",
|
|
2405
|
-
fontSize: 14,
|
|
2406
|
-
fontColor: "#E44234",
|
|
2407
|
-
fontFamily: PdfStandardFont.Helvetica,
|
|
2408
|
-
textAlign: PdfTextAlignment.Left,
|
|
2409
|
-
verticalAlign: PdfVerticalAlignment.Top,
|
|
2410
|
-
backgroundColor: "transparent",
|
|
2411
|
-
opacity: 1
|
|
2412
|
-
},
|
|
2413
|
-
clickBehavior: {
|
|
2414
|
-
enabled: true,
|
|
2415
|
-
defaultSize: { width: 100, height: 20 },
|
|
2416
|
-
defaultContent: "Insert text"
|
|
2577
|
+
const page = doc.pages.find((page2) => page2.index === pageIndex);
|
|
2578
|
+
if (!page) {
|
|
2579
|
+
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Page not found" });
|
|
2417
2580
|
}
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2581
|
+
return this.engine.renderPageAnnotation(doc, page, annotation, options);
|
|
2582
|
+
}
|
|
2583
|
+
importAnnotations(items, documentId) {
|
|
2584
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
2585
|
+
if (!this.isInitialLoadComplete.get(id)) {
|
|
2586
|
+
const queue = this.importQueue.get(id) || [];
|
|
2587
|
+
queue.push(...items);
|
|
2588
|
+
this.importQueue.set(id, queue);
|
|
2589
|
+
return;
|
|
2590
|
+
}
|
|
2591
|
+
this.processImportItems(id, items);
|
|
2592
|
+
}
|
|
2593
|
+
processImportQueue(documentId) {
|
|
2594
|
+
const queue = this.importQueue.get(documentId);
|
|
2595
|
+
if (!queue || queue.length === 0) return;
|
|
2596
|
+
const items = [...queue];
|
|
2597
|
+
this.importQueue.set(documentId, []);
|
|
2598
|
+
this.processImportItems(documentId, items);
|
|
2599
|
+
}
|
|
2600
|
+
processImportItems(documentId, items) {
|
|
2601
|
+
const contexts = this.pendingContexts.get(documentId);
|
|
2602
|
+
if (!contexts) return;
|
|
2603
|
+
for (const item of items) {
|
|
2604
|
+
const { annotation, ctx } = item;
|
|
2605
|
+
const pageIndex = annotation.pageIndex;
|
|
2606
|
+
const id = annotation.id;
|
|
2607
|
+
this.dispatch(createAnnotation(documentId, pageIndex, annotation));
|
|
2608
|
+
if (ctx) contexts.set(id, ctx);
|
|
2609
|
+
}
|
|
2610
|
+
if (this.config.autoCommit !== false) this.commit(documentId);
|
|
2611
|
+
}
|
|
2612
|
+
createAnnotation(pageIndex, annotation, ctx, documentId) {
|
|
2613
|
+
const id = annotation.id;
|
|
2614
|
+
const docId = documentId ?? this.getActiveDocumentId();
|
|
2615
|
+
const contexts = this.pendingContexts.get(docId);
|
|
2616
|
+
if (!contexts) return;
|
|
2617
|
+
const newAnnotation = {
|
|
2618
|
+
...annotation,
|
|
2619
|
+
author: annotation.author ?? this.config.annotationAuthor
|
|
2620
|
+
};
|
|
2621
|
+
const execute = () => {
|
|
2622
|
+
this.dispatch(createAnnotation(docId, pageIndex, newAnnotation));
|
|
2623
|
+
if (ctx) contexts.set(id, ctx);
|
|
2624
|
+
this.events$.emit({
|
|
2625
|
+
type: "create",
|
|
2626
|
+
documentId: docId,
|
|
2627
|
+
annotation: newAnnotation,
|
|
2628
|
+
pageIndex,
|
|
2629
|
+
ctx,
|
|
2630
|
+
committed: false
|
|
2631
|
+
});
|
|
2632
|
+
};
|
|
2633
|
+
if (!this.history) {
|
|
2634
|
+
execute();
|
|
2635
|
+
if (this.config.autoCommit) this.commit(docId);
|
|
2636
|
+
return;
|
|
2433
2637
|
}
|
|
2638
|
+
const command = {
|
|
2639
|
+
execute,
|
|
2640
|
+
undo: () => {
|
|
2641
|
+
contexts.delete(id);
|
|
2642
|
+
this.dispatch(deselectAnnotation(docId));
|
|
2643
|
+
this.dispatch(deleteAnnotation(docId, pageIndex, id));
|
|
2644
|
+
this.events$.emit({
|
|
2645
|
+
type: "delete",
|
|
2646
|
+
documentId: docId,
|
|
2647
|
+
annotation: newAnnotation,
|
|
2648
|
+
pageIndex,
|
|
2649
|
+
committed: false
|
|
2650
|
+
});
|
|
2651
|
+
}
|
|
2652
|
+
};
|
|
2653
|
+
const historyScope = this.history.forDocument(docId);
|
|
2654
|
+
historyScope.register(command, this.ANNOTATION_HISTORY_TOPIC);
|
|
2434
2655
|
}
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2656
|
+
buildPatch(original, patch) {
|
|
2657
|
+
if ("rect" in patch) return patch;
|
|
2658
|
+
return this.transformAnnotation(original, {
|
|
2659
|
+
type: "property-update",
|
|
2660
|
+
changes: patch
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2663
|
+
updateAnnotation(pageIndex, id, patch, documentId) {
|
|
2664
|
+
const docId = documentId ?? this.getActiveDocumentId();
|
|
2665
|
+
const docState = this.getDocumentState(docId);
|
|
2666
|
+
const originalObject = docState.byUid[id].object;
|
|
2667
|
+
const finalPatch = this.buildPatch(originalObject, {
|
|
2668
|
+
...patch,
|
|
2669
|
+
author: patch.author ?? this.config.annotationAuthor
|
|
2670
|
+
});
|
|
2671
|
+
const execute = () => {
|
|
2672
|
+
this.dispatch(patchAnnotation(docId, pageIndex, id, finalPatch));
|
|
2673
|
+
this.events$.emit({
|
|
2674
|
+
type: "update",
|
|
2675
|
+
documentId: docId,
|
|
2676
|
+
annotation: originalObject,
|
|
2677
|
+
pageIndex,
|
|
2678
|
+
patch: finalPatch,
|
|
2679
|
+
committed: false
|
|
2680
|
+
});
|
|
2681
|
+
};
|
|
2682
|
+
if (!this.history) {
|
|
2683
|
+
execute();
|
|
2684
|
+
if (this.config.autoCommit !== false) {
|
|
2685
|
+
this.commit(docId);
|
|
2459
2686
|
}
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
hasPendingChanges: false
|
|
2477
|
-
};
|
|
2478
|
-
};
|
|
2479
|
-
const reducer = (state, action) => {
|
|
2480
|
-
switch (action.type) {
|
|
2481
|
-
case SET_ANNOTATIONS: {
|
|
2482
|
-
const newPages = { ...state.pages };
|
|
2483
|
-
const newByUid = { ...state.byUid };
|
|
2484
|
-
for (const [pgStr, list] of Object.entries(action.payload)) {
|
|
2485
|
-
const pageIndex = Number(pgStr);
|
|
2486
|
-
const oldUidsOnPage = state.pages[pageIndex] || [];
|
|
2487
|
-
for (const uid of oldUidsOnPage) {
|
|
2488
|
-
delete newByUid[uid];
|
|
2489
|
-
}
|
|
2490
|
-
const newUidsOnPage = list.map((a) => {
|
|
2491
|
-
const uid = a.id;
|
|
2492
|
-
newByUid[uid] = { commitState: "synced", object: a };
|
|
2493
|
-
return uid;
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2689
|
+
const originalPatch = Object.fromEntries(
|
|
2690
|
+
Object.keys(patch).map((key) => [key, originalObject[key]])
|
|
2691
|
+
);
|
|
2692
|
+
const command = {
|
|
2693
|
+
execute,
|
|
2694
|
+
undo: () => {
|
|
2695
|
+
this.dispatch(patchAnnotation(docId, pageIndex, id, originalPatch));
|
|
2696
|
+
this.events$.emit({
|
|
2697
|
+
type: "update",
|
|
2698
|
+
documentId: docId,
|
|
2699
|
+
annotation: originalObject,
|
|
2700
|
+
pageIndex,
|
|
2701
|
+
patch: originalPatch,
|
|
2702
|
+
committed: false
|
|
2494
2703
|
});
|
|
2495
|
-
newPages[pageIndex] = newUidsOnPage;
|
|
2496
2704
|
}
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2705
|
+
};
|
|
2706
|
+
const historyScope = this.history.forDocument(docId);
|
|
2707
|
+
historyScope.register(command, this.ANNOTATION_HISTORY_TOPIC);
|
|
2708
|
+
}
|
|
2709
|
+
deleteAnnotation(pageIndex, id, documentId) {
|
|
2710
|
+
var _a;
|
|
2711
|
+
const docId = documentId ?? this.getActiveDocumentId();
|
|
2712
|
+
const docState = this.getDocumentState(docId);
|
|
2713
|
+
const originalAnnotation = (_a = docState.byUid[id]) == null ? void 0 : _a.object;
|
|
2714
|
+
if (!originalAnnotation) return;
|
|
2715
|
+
const execute = () => {
|
|
2716
|
+
this.dispatch(deselectAnnotation(docId));
|
|
2717
|
+
this.dispatch(deleteAnnotation(docId, pageIndex, id));
|
|
2718
|
+
this.events$.emit({
|
|
2719
|
+
type: "delete",
|
|
2720
|
+
documentId: docId,
|
|
2721
|
+
annotation: originalAnnotation,
|
|
2722
|
+
pageIndex,
|
|
2723
|
+
committed: false
|
|
2724
|
+
});
|
|
2725
|
+
};
|
|
2726
|
+
if (!this.history) {
|
|
2727
|
+
execute();
|
|
2728
|
+
if (this.config.autoCommit !== false) this.commit(docId);
|
|
2729
|
+
return;
|
|
2505
2730
|
}
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2731
|
+
const command = {
|
|
2732
|
+
execute,
|
|
2733
|
+
undo: () => {
|
|
2734
|
+
this.dispatch(createAnnotation(docId, pageIndex, originalAnnotation));
|
|
2735
|
+
this.events$.emit({
|
|
2736
|
+
type: "create",
|
|
2737
|
+
documentId: docId,
|
|
2738
|
+
annotation: originalAnnotation,
|
|
2739
|
+
pageIndex,
|
|
2740
|
+
committed: false
|
|
2741
|
+
});
|
|
2742
|
+
}
|
|
2743
|
+
};
|
|
2744
|
+
const historyScope = this.history.forDocument(docId);
|
|
2745
|
+
historyScope.register(command, this.ANNOTATION_HISTORY_TOPIC);
|
|
2746
|
+
}
|
|
2747
|
+
selectAnnotation(pageIndex, id, documentId) {
|
|
2748
|
+
const docId = documentId ?? this.getActiveDocumentId();
|
|
2749
|
+
this.dispatch(selectAnnotation(docId, pageIndex, id));
|
|
2750
|
+
}
|
|
2751
|
+
deselectAnnotation(documentId) {
|
|
2752
|
+
const docId = documentId ?? this.getActiveDocumentId();
|
|
2753
|
+
this.dispatch(deselectAnnotation(docId));
|
|
2754
|
+
}
|
|
2755
|
+
getActiveTool(documentId) {
|
|
2756
|
+
const docState = this.getDocumentState(documentId);
|
|
2757
|
+
if (!docState.activeToolId) return null;
|
|
2758
|
+
return this.state.tools.find((t) => t.id === docState.activeToolId) ?? null;
|
|
2759
|
+
}
|
|
2760
|
+
setActiveTool(toolId, documentId) {
|
|
2761
|
+
var _a, _b;
|
|
2762
|
+
const docId = documentId ?? this.getActiveDocumentId();
|
|
2763
|
+
const docState = this.getDocumentState(docId);
|
|
2764
|
+
if (toolId === docState.activeToolId) return;
|
|
2765
|
+
this.dispatch(setActiveToolId(docId, toolId));
|
|
2766
|
+
const tool = this.state.tools.find((t) => t.id === toolId);
|
|
2767
|
+
if (tool) {
|
|
2768
|
+
(_a = this.interactionManager) == null ? void 0 : _a.forDocument(docId).activate(tool.interaction.mode ?? tool.id);
|
|
2769
|
+
} else {
|
|
2770
|
+
(_b = this.interactionManager) == null ? void 0 : _b.forDocument(docId).activateDefaultMode();
|
|
2517
2771
|
}
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
const
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
hasPendingChanges: true
|
|
2532
|
-
};
|
|
2772
|
+
}
|
|
2773
|
+
getTool(toolId) {
|
|
2774
|
+
return this.state.tools.find((t) => t.id === toolId);
|
|
2775
|
+
}
|
|
2776
|
+
findToolForAnnotation(annotation) {
|
|
2777
|
+
let bestTool = null;
|
|
2778
|
+
let bestScore = 0;
|
|
2779
|
+
for (const tool of this.state.tools) {
|
|
2780
|
+
const score = tool.matchScore(annotation);
|
|
2781
|
+
if (score > bestScore) {
|
|
2782
|
+
bestScore = score;
|
|
2783
|
+
bestTool = tool;
|
|
2784
|
+
}
|
|
2533
2785
|
}
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2786
|
+
return bestTool;
|
|
2787
|
+
}
|
|
2788
|
+
commit(documentId) {
|
|
2789
|
+
const task = new Task();
|
|
2790
|
+
const docId = documentId ?? this.getActiveDocumentId();
|
|
2791
|
+
const docState = this.getDocumentState(docId);
|
|
2792
|
+
if (!docState.hasPendingChanges) return PdfTaskHelper.resolve(true);
|
|
2793
|
+
const coreDocState = this.getCoreDocument(docId);
|
|
2794
|
+
const doc = coreDocState == null ? void 0 : coreDocState.document;
|
|
2795
|
+
if (!doc)
|
|
2796
|
+
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
2797
|
+
const contexts = this.pendingContexts.get(docId);
|
|
2798
|
+
if (!contexts) return PdfTaskHelper.resolve(true);
|
|
2799
|
+
const creations = [];
|
|
2800
|
+
const updates = [];
|
|
2801
|
+
const deletions = [];
|
|
2802
|
+
for (const [uid, ta] of Object.entries(docState.byUid)) {
|
|
2803
|
+
if (ta.commitState === "synced") continue;
|
|
2804
|
+
const page = doc.pages.find((p) => p.index === ta.object.pageIndex);
|
|
2805
|
+
if (!page) continue;
|
|
2806
|
+
switch (ta.commitState) {
|
|
2807
|
+
case "new":
|
|
2808
|
+
const ctx = contexts.get(ta.object.id);
|
|
2809
|
+
const task2 = this.engine.createPageAnnotation(doc, page, ta.object, ctx);
|
|
2810
|
+
task2.wait(() => {
|
|
2811
|
+
this.events$.emit({
|
|
2812
|
+
type: "create",
|
|
2813
|
+
documentId: docId,
|
|
2814
|
+
annotation: ta.object,
|
|
2815
|
+
pageIndex: ta.object.pageIndex,
|
|
2816
|
+
ctx,
|
|
2817
|
+
committed: true
|
|
2818
|
+
});
|
|
2819
|
+
contexts.delete(ta.object.id);
|
|
2820
|
+
}, ignore);
|
|
2821
|
+
creations.push(task2);
|
|
2822
|
+
break;
|
|
2823
|
+
case "dirty":
|
|
2824
|
+
const updateTask = this.engine.updatePageAnnotation(doc, page, ta.object);
|
|
2825
|
+
updateTask.wait(() => {
|
|
2826
|
+
this.events$.emit({
|
|
2827
|
+
type: "update",
|
|
2828
|
+
documentId: docId,
|
|
2829
|
+
annotation: ta.object,
|
|
2830
|
+
pageIndex: ta.object.pageIndex,
|
|
2831
|
+
patch: ta.object,
|
|
2832
|
+
committed: true
|
|
2833
|
+
});
|
|
2834
|
+
}, ignore);
|
|
2835
|
+
updates.push(updateTask);
|
|
2836
|
+
break;
|
|
2837
|
+
case "deleted":
|
|
2838
|
+
deletions.push({ ta, uid });
|
|
2839
|
+
break;
|
|
2840
|
+
}
|
|
2549
2841
|
}
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2842
|
+
const deletionTasks = [];
|
|
2843
|
+
for (const { ta, uid } of deletions) {
|
|
2844
|
+
const page = doc.pages.find((p) => p.index === ta.object.pageIndex);
|
|
2845
|
+
if (ta.commitState === "deleted" && ta.object.id) {
|
|
2846
|
+
const task2 = new Task();
|
|
2847
|
+
const removeTask = this.engine.removePageAnnotation(doc, page, ta.object);
|
|
2848
|
+
removeTask.wait(() => {
|
|
2849
|
+
this.dispatch(purgeAnnotation(docId, uid));
|
|
2850
|
+
this.events$.emit({
|
|
2851
|
+
type: "delete",
|
|
2852
|
+
documentId: docId,
|
|
2853
|
+
annotation: ta.object,
|
|
2854
|
+
pageIndex: ta.object.pageIndex,
|
|
2855
|
+
committed: true
|
|
2856
|
+
});
|
|
2857
|
+
task2.resolve(true);
|
|
2858
|
+
}, task2.fail);
|
|
2859
|
+
deletionTasks.push(task2);
|
|
2860
|
+
} else {
|
|
2861
|
+
this.dispatch(purgeAnnotation(docId, uid));
|
|
2559
2862
|
}
|
|
2560
|
-
return { ...state, byUid: cleaned, hasPendingChanges: false };
|
|
2561
2863
|
}
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2864
|
+
const allWriteTasks = [...creations, ...updates, ...deletionTasks];
|
|
2865
|
+
Task.allSettled(allWriteTasks).wait(() => {
|
|
2866
|
+
this.dispatch(commitPendingChanges(docId));
|
|
2867
|
+
task.resolve(true);
|
|
2868
|
+
}, task.fail);
|
|
2869
|
+
return task;
|
|
2870
|
+
}
|
|
2871
|
+
/**
|
|
2872
|
+
* Gets the effective behavior setting for a tool, checking tool-specific config first,
|
|
2873
|
+
* then falling back to plugin config.
|
|
2874
|
+
*/
|
|
2875
|
+
getToolBehavior(tool, setting) {
|
|
2876
|
+
var _a;
|
|
2877
|
+
if (((_a = tool.behavior) == null ? void 0 : _a[setting]) !== void 0) {
|
|
2878
|
+
return tool.behavior[setting];
|
|
2566
2879
|
}
|
|
2567
|
-
|
|
2568
|
-
return state;
|
|
2880
|
+
return this.config[setting] !== false;
|
|
2569
2881
|
}
|
|
2570
2882
|
};
|
|
2883
|
+
_AnnotationPlugin.id = "annotation";
|
|
2884
|
+
let AnnotationPlugin = _AnnotationPlugin;
|
|
2571
2885
|
function createToolPredicate(id) {
|
|
2572
2886
|
return (tool) => {
|
|
2573
2887
|
return (tool == null ? void 0 : tool.id) === id;
|
|
@@ -2597,6 +2911,7 @@ export {
|
|
|
2597
2911
|
AnnotationPlugin,
|
|
2598
2912
|
AnnotationPluginPackage,
|
|
2599
2913
|
createToolPredicate,
|
|
2914
|
+
getAnnotationByUid,
|
|
2600
2915
|
getAnnotations,
|
|
2601
2916
|
getAnnotationsByPageIndex,
|
|
2602
2917
|
getSelectedAnnotation,
|
|
@@ -2604,6 +2919,7 @@ export {
|
|
|
2604
2919
|
getSidebarAnnotationsWithReplies,
|
|
2605
2920
|
getSidebarAnnotationsWithRepliesGroupedByPage,
|
|
2606
2921
|
getToolDefaultsById,
|
|
2922
|
+
initialDocumentState,
|
|
2607
2923
|
initialState,
|
|
2608
2924
|
isAnnotationSelected,
|
|
2609
2925
|
isCircle,
|