@embedpdf/plugin-annotation 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +509 -161
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +191 -29
- package/dist/index.d.ts +191 -29
- package/dist/index.js +512 -161
- package/dist/index.js.map +1 -1
- package/dist/preact/index.cjs +305 -126
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.js +303 -121
- package/dist/preact/index.js.map +1 -1
- package/package.json +10 -6
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,14 @@ __export(index_exports, {
|
|
|
23
23
|
ANNOTATION_PLUGIN_ID: () => ANNOTATION_PLUGIN_ID,
|
|
24
24
|
AnnotationPlugin: () => AnnotationPlugin,
|
|
25
25
|
AnnotationPluginPackage: () => AnnotationPluginPackage,
|
|
26
|
+
getAnnotations: () => getAnnotations,
|
|
27
|
+
getAnnotationsByPageIndex: () => getAnnotationsByPageIndex,
|
|
28
|
+
getSelectedAnnotation: () => getSelectedAnnotation,
|
|
29
|
+
getSelectedAnnotationByPageIndex: () => getSelectedAnnotationByPageIndex,
|
|
30
|
+
getSelectedAnnotationMode: () => getSelectedAnnotationMode,
|
|
31
|
+
getSelectedAnnotationWithPageIndex: () => getSelectedAnnotationWithPageIndex,
|
|
32
|
+
isAnnotationSelected: () => isAnnotationSelected,
|
|
33
|
+
isInAnnotationMode: () => isInAnnotationMode,
|
|
26
34
|
manifest: () => manifest
|
|
27
35
|
});
|
|
28
36
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -34,104 +42,132 @@ var manifest = {
|
|
|
34
42
|
name: "Annotation Plugin",
|
|
35
43
|
version: "1.0.0",
|
|
36
44
|
provides: ["annotation"],
|
|
37
|
-
requires: [],
|
|
38
|
-
optional: [],
|
|
45
|
+
requires: ["interaction-manager", "selection"],
|
|
46
|
+
optional: ["history"],
|
|
39
47
|
defaultConfig: {
|
|
40
|
-
enabled: true
|
|
48
|
+
enabled: true,
|
|
49
|
+
autoCommit: true
|
|
41
50
|
}
|
|
42
51
|
};
|
|
43
52
|
|
|
44
53
|
// src/lib/annotation-plugin.ts
|
|
45
54
|
var import_core = require("@embedpdf/core");
|
|
46
|
-
|
|
47
|
-
// ../models/dist/index.js
|
|
48
|
-
var PdfSoftHyphenMarker = "\xAD";
|
|
49
|
-
var PdfZeroWidthSpace = "\u200B";
|
|
50
|
-
var PdfWordJoiner = "\u2060";
|
|
51
|
-
var PdfBomOrZwnbsp = "\uFEFF";
|
|
52
|
-
var PdfNonCharacterFFFE = "\uFFFE";
|
|
53
|
-
var PdfNonCharacterFFFF = "\uFFFF";
|
|
54
|
-
var PdfUnwantedTextMarkers = Object.freeze([
|
|
55
|
-
PdfSoftHyphenMarker,
|
|
56
|
-
PdfZeroWidthSpace,
|
|
57
|
-
PdfWordJoiner,
|
|
58
|
-
PdfBomOrZwnbsp,
|
|
59
|
-
PdfNonCharacterFFFE,
|
|
60
|
-
PdfNonCharacterFFFF
|
|
61
|
-
]);
|
|
62
|
-
var PdfUnwantedTextRegex = new RegExp(`[${PdfUnwantedTextMarkers.join("")}]`, "g");
|
|
63
|
-
var PdfAnnotationSubtype = /* @__PURE__ */ ((PdfAnnotationSubtype2) => {
|
|
64
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["UNKNOWN"] = 0] = "UNKNOWN";
|
|
65
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["TEXT"] = 1] = "TEXT";
|
|
66
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["LINK"] = 2] = "LINK";
|
|
67
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["FREETEXT"] = 3] = "FREETEXT";
|
|
68
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["LINE"] = 4] = "LINE";
|
|
69
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["SQUARE"] = 5] = "SQUARE";
|
|
70
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["CIRCLE"] = 6] = "CIRCLE";
|
|
71
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["POLYGON"] = 7] = "POLYGON";
|
|
72
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["POLYLINE"] = 8] = "POLYLINE";
|
|
73
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["HIGHLIGHT"] = 9] = "HIGHLIGHT";
|
|
74
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["UNDERLINE"] = 10] = "UNDERLINE";
|
|
75
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["SQUIGGLY"] = 11] = "SQUIGGLY";
|
|
76
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["STRIKEOUT"] = 12] = "STRIKEOUT";
|
|
77
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["STAMP"] = 13] = "STAMP";
|
|
78
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["CARET"] = 14] = "CARET";
|
|
79
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["INK"] = 15] = "INK";
|
|
80
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["POPUP"] = 16] = "POPUP";
|
|
81
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["FILEATTACHMENT"] = 17] = "FILEATTACHMENT";
|
|
82
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["SOUND"] = 18] = "SOUND";
|
|
83
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["MOVIE"] = 19] = "MOVIE";
|
|
84
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["WIDGET"] = 20] = "WIDGET";
|
|
85
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["SCREEN"] = 21] = "SCREEN";
|
|
86
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["PRINTERMARK"] = 22] = "PRINTERMARK";
|
|
87
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["TRAPNET"] = 23] = "TRAPNET";
|
|
88
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["WATERMARK"] = 24] = "WATERMARK";
|
|
89
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["THREED"] = 25] = "THREED";
|
|
90
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["RICHMEDIA"] = 26] = "RICHMEDIA";
|
|
91
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["XFAWIDGET"] = 27] = "XFAWIDGET";
|
|
92
|
-
PdfAnnotationSubtype2[PdfAnnotationSubtype2["REDACT"] = 28] = "REDACT";
|
|
93
|
-
return PdfAnnotationSubtype2;
|
|
94
|
-
})(PdfAnnotationSubtype || {});
|
|
95
|
-
function ignore() {
|
|
96
|
-
}
|
|
55
|
+
var import_models = require("@embedpdf/models");
|
|
97
56
|
|
|
98
57
|
// src/lib/actions.ts
|
|
99
|
-
var SET_ANNOTATIONS = "SET_ANNOTATIONS";
|
|
100
|
-
var
|
|
101
|
-
var
|
|
102
|
-
var
|
|
103
|
-
var
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
58
|
+
var SET_ANNOTATIONS = "ANNOTATION/SET_ANNOTATIONS";
|
|
59
|
+
var REINDEX_PAGE_ANNOTATIONS = "ANNOTATION/REINDEX_PAGE";
|
|
60
|
+
var SELECT_ANNOTATION = "ANNOTATION/SELECT_ANNOTATION";
|
|
61
|
+
var DESELECT_ANNOTATION = "ANNOTATION/DESELECT_ANNOTATION";
|
|
62
|
+
var SET_ANNOTATION_MODE = "ANNOTATION/SET_ANNOTATION_MODE";
|
|
63
|
+
var UPDATE_TOOL_DEFAULTS = "ANNOTATION/UPDATE_TOOL_DEFAULTS";
|
|
64
|
+
var ADD_COLOR_PRESET = "ANNOTATION/ADD_COLOR_PRESET";
|
|
65
|
+
var CREATE_ANNOTATION = "ANNOTATION/CREATE_ANNOTATION";
|
|
66
|
+
var PATCH_ANNOTATION = "ANNOTATION/PATCH_ANNOTATION";
|
|
67
|
+
var DELETE_ANNOTATION = "ANNOTATION/DELETE_ANNOTATION";
|
|
68
|
+
var COMMIT_PENDING_CHANGES = "ANNOTATION/COMMIT";
|
|
69
|
+
var STORE_PDF_ID = "ANNOTATION/STORE_PDF_ID";
|
|
70
|
+
var PURGE_ANNOTATION = "ANNOTATION/PURGE_ANNOTATION";
|
|
71
|
+
var setAnnotations = (p) => ({
|
|
72
|
+
type: SET_ANNOTATIONS,
|
|
73
|
+
payload: p
|
|
74
|
+
});
|
|
75
|
+
var reindexPageAnnotations = (pageIndex) => ({
|
|
76
|
+
type: REINDEX_PAGE_ANNOTATIONS,
|
|
77
|
+
payload: { pageIndex }
|
|
78
|
+
});
|
|
79
|
+
var selectAnnotation = (pageIndex, localId) => ({
|
|
80
|
+
type: SELECT_ANNOTATION,
|
|
81
|
+
payload: { pageIndex, localId }
|
|
82
|
+
});
|
|
83
|
+
var deselectAnnotation = () => ({ type: DESELECT_ANNOTATION });
|
|
84
|
+
var setAnnotationMode = (m) => ({
|
|
85
|
+
type: SET_ANNOTATION_MODE,
|
|
86
|
+
payload: m
|
|
87
|
+
});
|
|
88
|
+
var updateToolDefaults = (subtype, patch) => ({ type: UPDATE_TOOL_DEFAULTS, payload: { subtype, patch } });
|
|
89
|
+
var addColorPreset = (c) => ({
|
|
90
|
+
type: ADD_COLOR_PRESET,
|
|
91
|
+
payload: c
|
|
92
|
+
});
|
|
93
|
+
var createAnnotation = (pageIndex, localId, annotation) => ({
|
|
94
|
+
type: CREATE_ANNOTATION,
|
|
95
|
+
payload: { pageIndex, localId, annotation }
|
|
96
|
+
});
|
|
97
|
+
var patchAnnotation = (pageIndex, localId, patch) => ({
|
|
98
|
+
type: PATCH_ANNOTATION,
|
|
99
|
+
payload: { pageIndex, localId, patch }
|
|
100
|
+
});
|
|
101
|
+
var deleteAnnotation = (pageIndex, localId) => ({
|
|
102
|
+
type: DELETE_ANNOTATION,
|
|
103
|
+
payload: { pageIndex, localId }
|
|
104
|
+
});
|
|
105
|
+
var commitPendingChanges = () => ({ type: COMMIT_PENDING_CHANGES });
|
|
106
|
+
var storePdfId = (uid, pdfId) => ({
|
|
107
|
+
type: STORE_PDF_ID,
|
|
108
|
+
payload: { uid, pdfId }
|
|
109
|
+
});
|
|
110
|
+
var purgeAnnotation = (uid) => ({
|
|
111
|
+
type: PURGE_ANNOTATION,
|
|
112
|
+
payload: { uid }
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// src/lib/utils.ts
|
|
116
|
+
var makeUid = (pageIndex, localId) => `p${pageIndex}#${localId}`;
|
|
117
|
+
var parseUid = (uid) => {
|
|
118
|
+
const [pg, rest] = uid.slice(1).split("#");
|
|
119
|
+
return { pageIndex: Number(pg), localId: Number(rest) };
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// src/lib/selectors.ts
|
|
123
|
+
var makeUid2 = (page, id) => `p${page}#${id}`;
|
|
124
|
+
var getAnnotationsByPageIndex = (s, page) => (s.pages[page] ?? []).map((uid) => s.byUid[uid]);
|
|
125
|
+
var getAnnotations = (s) => {
|
|
126
|
+
const out = {};
|
|
127
|
+
for (const p of Object.keys(s.pages).map(Number)) out[p] = getAnnotationsByPageIndex(s, p);
|
|
128
|
+
return out;
|
|
129
|
+
};
|
|
130
|
+
var getSelectedAnnotation = (s) => s.selectedUid ? s.byUid[s.selectedUid] : null;
|
|
131
|
+
var getSelectedAnnotationWithPageIndex = (s) => {
|
|
132
|
+
if (!s.selectedUid) return null;
|
|
133
|
+
const { pageIndex, localId } = parseUid(s.selectedUid);
|
|
134
|
+
return { pageIndex, localId, annotation: s.byUid[s.selectedUid].object };
|
|
135
|
+
};
|
|
136
|
+
var getSelectedAnnotationByPageIndex = (s, pageIndex) => {
|
|
137
|
+
if (!s.selectedUid) return null;
|
|
138
|
+
const pageUids = s.pages[pageIndex] ?? [];
|
|
139
|
+
if (pageUids.includes(s.selectedUid)) {
|
|
140
|
+
return s.byUid[s.selectedUid];
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
};
|
|
144
|
+
var isInAnnotationMode = (s) => s.annotationMode !== null;
|
|
145
|
+
var getSelectedAnnotationMode = (s) => s.annotationMode;
|
|
146
|
+
var isAnnotationSelected = (s, page, id) => s.selectedUid === makeUid2(page, id);
|
|
128
147
|
|
|
129
148
|
// src/lib/annotation-plugin.ts
|
|
130
149
|
var AnnotationPlugin = class extends import_core.BasePlugin {
|
|
131
|
-
constructor(id, registry, engine) {
|
|
150
|
+
constructor(id, registry, engine, config) {
|
|
132
151
|
super(id, registry);
|
|
152
|
+
this.ANNOTATION_HISTORY_TOPIC = "annotations";
|
|
133
153
|
this.state$ = (0, import_core.createBehaviorEmitter)();
|
|
154
|
+
/** Map <subtype> → <modeId>. Filled once in `initialize()`. */
|
|
155
|
+
this.modeBySubtype = /* @__PURE__ */ new Map();
|
|
156
|
+
/** The inverse map for quick lookup in onModeChange(). */
|
|
157
|
+
this.subtypeByMode = /* @__PURE__ */ new Map();
|
|
158
|
+
this.modeChange$ = (0, import_core.createBehaviorEmitter)();
|
|
159
|
+
this.activeTool$ = (0, import_core.createBehaviorEmitter)({
|
|
160
|
+
mode: null,
|
|
161
|
+
defaults: null
|
|
162
|
+
});
|
|
134
163
|
this.engine = engine;
|
|
164
|
+
this.config = config;
|
|
165
|
+
const selection = registry.getPlugin("selection");
|
|
166
|
+
this.selection = selection?.provides() ?? null;
|
|
167
|
+
const history = registry.getPlugin("history");
|
|
168
|
+
this.history = history?.provides() ?? null;
|
|
169
|
+
const interactionManager = registry.getPlugin("interaction-manager");
|
|
170
|
+
this.interactionManager = interactionManager?.provides() ?? null;
|
|
135
171
|
this.coreStore.onAction(import_core.SET_DOCUMENT, (_action, state) => {
|
|
136
172
|
const doc = state.core.document;
|
|
137
173
|
if (doc) {
|
|
@@ -140,146 +176,450 @@ var AnnotationPlugin = class extends import_core.BasePlugin {
|
|
|
140
176
|
});
|
|
141
177
|
}
|
|
142
178
|
async initialize() {
|
|
179
|
+
for (const [subtype, defaults] of (0, import_core.enumEntries)(this.state.toolDefaults)) {
|
|
180
|
+
this.registerTool(subtype, defaults);
|
|
181
|
+
}
|
|
182
|
+
this.history?.onHistoryChange((topic) => {
|
|
183
|
+
if (topic === this.ANNOTATION_HISTORY_TOPIC && this.config.autoCommit !== false) {
|
|
184
|
+
this.commit();
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
this.interactionManager?.onModeChange((s) => {
|
|
188
|
+
const newSubtype = this.subtypeByMode.get(s.activeMode) ?? null;
|
|
189
|
+
if (newSubtype !== this.state.annotationMode) {
|
|
190
|
+
this.dispatch(setAnnotationMode(newSubtype));
|
|
191
|
+
this.modeChange$.emit(newSubtype);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
this.selection?.onEndSelection(() => {
|
|
195
|
+
if (!this.state.annotationMode) return;
|
|
196
|
+
const formattedSelection = this.selection?.getFormattedSelection();
|
|
197
|
+
if (!formattedSelection) return;
|
|
198
|
+
for (const selection of formattedSelection) {
|
|
199
|
+
const rect = selection.rect;
|
|
200
|
+
const segmentRects = selection.segmentRects;
|
|
201
|
+
const type = this.state.annotationMode;
|
|
202
|
+
const color = this.state.toolDefaults[type].color;
|
|
203
|
+
const opacity = this.state.toolDefaults[type].opacity;
|
|
204
|
+
this.createAnnotation(selection.pageIndex, {
|
|
205
|
+
type,
|
|
206
|
+
rect,
|
|
207
|
+
segmentRects,
|
|
208
|
+
color,
|
|
209
|
+
opacity,
|
|
210
|
+
pageIndex: selection.pageIndex,
|
|
211
|
+
id: Date.now() + Math.random()
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
this.selection?.clear();
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
registerTool(subtype, defaults) {
|
|
218
|
+
const modeId = defaults.interaction.mode;
|
|
219
|
+
const interactionMode = {
|
|
220
|
+
id: modeId,
|
|
221
|
+
scope: "page",
|
|
222
|
+
exclusive: defaults.interaction.exclusive,
|
|
223
|
+
cursor: defaults.interaction.cursor
|
|
224
|
+
};
|
|
225
|
+
this.interactionManager?.registerMode(interactionMode);
|
|
226
|
+
if (defaults.textSelection) {
|
|
227
|
+
this.selection?.enableForMode(modeId);
|
|
228
|
+
}
|
|
229
|
+
this.modeBySubtype.set(subtype, modeId);
|
|
230
|
+
this.subtypeByMode.set(modeId, subtype);
|
|
143
231
|
}
|
|
144
232
|
buildCapability() {
|
|
145
233
|
return {
|
|
146
234
|
getPageAnnotations: (options) => {
|
|
147
235
|
return this.getPageAnnotations(options);
|
|
148
236
|
},
|
|
237
|
+
getSelectedAnnotation: () => {
|
|
238
|
+
return getSelectedAnnotation(this.state);
|
|
239
|
+
},
|
|
149
240
|
selectAnnotation: (pageIndex, annotationId) => {
|
|
150
241
|
this.selectAnnotation(pageIndex, annotationId);
|
|
151
242
|
},
|
|
152
243
|
deselectAnnotation: () => {
|
|
153
244
|
this.dispatch(deselectAnnotation());
|
|
154
245
|
},
|
|
155
|
-
|
|
156
|
-
return this.
|
|
246
|
+
getAnnotationMode: () => {
|
|
247
|
+
return this.state.annotationMode;
|
|
248
|
+
},
|
|
249
|
+
setAnnotationMode: (subtype) => {
|
|
250
|
+
if (subtype === this.state.annotationMode) return;
|
|
251
|
+
if (subtype) {
|
|
252
|
+
const mode = this.modeBySubtype.get(subtype);
|
|
253
|
+
if (!mode) throw new Error(`Mode missing for subtype ${subtype}`);
|
|
254
|
+
this.interactionManager?.activate(mode);
|
|
255
|
+
} else {
|
|
256
|
+
this.interactionManager?.activate("default");
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
getToolDefaults: (subtype) => {
|
|
260
|
+
const defaults = this.state.toolDefaults[subtype];
|
|
261
|
+
if (!defaults) {
|
|
262
|
+
throw new Error(`No defaults found for subtype: ${subtype}`);
|
|
263
|
+
}
|
|
264
|
+
return defaults;
|
|
157
265
|
},
|
|
158
|
-
|
|
159
|
-
this.dispatch(
|
|
266
|
+
setToolDefaults: (subtype, patch) => {
|
|
267
|
+
this.dispatch(updateToolDefaults(subtype, patch));
|
|
160
268
|
},
|
|
161
|
-
|
|
269
|
+
getColorPresets: () => [...this.state.colorPresets],
|
|
270
|
+
addColorPreset: (color) => this.dispatch(addColorPreset(color)),
|
|
271
|
+
createAnnotation: (pageIndex, annotation) => this.createAnnotation(pageIndex, annotation),
|
|
272
|
+
updateAnnotation: (pageIndex, localId, patch) => this.updateAnnotation(pageIndex, localId, patch),
|
|
273
|
+
deleteAnnotation: (pageIndex, localId) => this.deleteAnnotation(pageIndex, localId),
|
|
274
|
+
onStateChange: this.state$.on,
|
|
275
|
+
onModeChange: this.modeChange$.on,
|
|
276
|
+
onActiveToolChange: this.activeTool$.on,
|
|
277
|
+
commit: () => this.commit()
|
|
162
278
|
};
|
|
163
279
|
}
|
|
164
|
-
|
|
165
|
-
|
|
280
|
+
emitActiveTool(state) {
|
|
281
|
+
const mode = state.annotationMode;
|
|
282
|
+
this.activeTool$.emit({
|
|
283
|
+
mode,
|
|
284
|
+
defaults: mode ? state.toolDefaults[mode] : null
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
onStoreUpdated(prev, next) {
|
|
288
|
+
this.state$.emit(next);
|
|
289
|
+
if (prev.annotationMode !== next.annotationMode || prev.toolDefaults[prev.annotationMode ?? import_models.PdfAnnotationSubtype.HIGHLIGHT] !== next.toolDefaults[next.annotationMode ?? import_models.PdfAnnotationSubtype.HIGHLIGHT]) {
|
|
290
|
+
this.emitActiveTool(next);
|
|
291
|
+
}
|
|
166
292
|
}
|
|
167
293
|
getAllAnnotations(doc) {
|
|
168
294
|
const task = this.engine.getAllAnnotations(doc);
|
|
169
|
-
task.wait((annotations) => this.dispatch(setAnnotations(annotations)), ignore);
|
|
295
|
+
task.wait((annotations) => this.dispatch(setAnnotations(annotations)), import_models.ignore);
|
|
170
296
|
}
|
|
171
297
|
getPageAnnotations(options) {
|
|
172
298
|
const { pageIndex } = options;
|
|
173
299
|
const doc = this.coreState.core.document;
|
|
174
300
|
if (!doc) {
|
|
175
|
-
|
|
301
|
+
return import_models.PdfTaskHelper.reject({ code: import_models.PdfErrorCode.NotFound, message: "Document not found" });
|
|
176
302
|
}
|
|
177
303
|
const page = doc.pages.find((p) => p.index === pageIndex);
|
|
178
304
|
if (!page) {
|
|
179
|
-
|
|
305
|
+
return import_models.PdfTaskHelper.reject({ code: import_models.PdfErrorCode.NotFound, message: "Page not found" });
|
|
180
306
|
}
|
|
181
307
|
return this.engine.getPageAnnotations(doc, page);
|
|
182
308
|
}
|
|
183
309
|
selectAnnotation(pageIndex, annotationId) {
|
|
184
|
-
|
|
185
|
-
|
|
310
|
+
this.dispatch(selectAnnotation(pageIndex, annotationId));
|
|
311
|
+
}
|
|
312
|
+
createAnnotation(pageIndex, annotation) {
|
|
313
|
+
const localId = annotation.id;
|
|
314
|
+
const execute = () => this.dispatch(createAnnotation(pageIndex, localId, annotation));
|
|
315
|
+
if (!this.history) {
|
|
316
|
+
execute();
|
|
317
|
+
if (this.config.autoCommit) this.commit();
|
|
186
318
|
return;
|
|
187
319
|
}
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
320
|
+
const command = {
|
|
321
|
+
execute,
|
|
322
|
+
undo: () => {
|
|
323
|
+
this.dispatch(deselectAnnotation());
|
|
324
|
+
this.dispatch(deleteAnnotation(pageIndex, localId));
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
this.history.register(command, this.ANNOTATION_HISTORY_TOPIC);
|
|
192
328
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
329
|
+
updateAnnotation(pageIndex, localId, patch) {
|
|
330
|
+
if (!this.history) {
|
|
331
|
+
this.dispatch(patchAnnotation(pageIndex, localId, patch));
|
|
332
|
+
if (this.config.autoCommit !== false) {
|
|
333
|
+
this.commit();
|
|
334
|
+
}
|
|
335
|
+
return;
|
|
197
336
|
}
|
|
198
|
-
|
|
199
|
-
|
|
337
|
+
const originalObject = this.state.byUid[makeUid(pageIndex, localId)].object;
|
|
338
|
+
const originalPatch = Object.fromEntries(
|
|
339
|
+
Object.keys(patch).map((key) => [key, originalObject[key]])
|
|
340
|
+
);
|
|
341
|
+
const command = {
|
|
342
|
+
execute: () => this.dispatch(patchAnnotation(pageIndex, localId, patch)),
|
|
343
|
+
undo: () => this.dispatch(patchAnnotation(pageIndex, localId, originalPatch))
|
|
344
|
+
};
|
|
345
|
+
this.history.register(command, this.ANNOTATION_HISTORY_TOPIC);
|
|
346
|
+
}
|
|
347
|
+
deleteAnnotation(pageIndex, localId) {
|
|
348
|
+
if (!this.history) {
|
|
349
|
+
this.dispatch(deselectAnnotation());
|
|
350
|
+
this.dispatch(deleteAnnotation(pageIndex, localId));
|
|
351
|
+
if (this.config.autoCommit !== false) {
|
|
352
|
+
this.commit();
|
|
353
|
+
}
|
|
354
|
+
return;
|
|
200
355
|
}
|
|
356
|
+
const originalAnnotation = this.state.byUid[makeUid(pageIndex, localId)].object;
|
|
357
|
+
const command = {
|
|
358
|
+
execute: () => {
|
|
359
|
+
this.dispatch(deselectAnnotation());
|
|
360
|
+
this.dispatch(deleteAnnotation(pageIndex, localId));
|
|
361
|
+
},
|
|
362
|
+
undo: () => this.dispatch(createAnnotation(pageIndex, localId, originalAnnotation))
|
|
363
|
+
};
|
|
364
|
+
this.history.register(command, this.ANNOTATION_HISTORY_TOPIC);
|
|
365
|
+
}
|
|
366
|
+
commit() {
|
|
367
|
+
const task = new import_models.Task();
|
|
368
|
+
if (!this.state.hasPendingChanges) return import_models.PdfTaskHelper.resolve(true);
|
|
201
369
|
const doc = this.coreState.core.document;
|
|
202
|
-
if (!doc)
|
|
203
|
-
return
|
|
370
|
+
if (!doc)
|
|
371
|
+
return import_models.PdfTaskHelper.reject({ code: import_models.PdfErrorCode.NotFound, message: "Document not found" });
|
|
372
|
+
const creations = [];
|
|
373
|
+
const updates = [];
|
|
374
|
+
const deletionsByPage = /* @__PURE__ */ new Map();
|
|
375
|
+
const affectedPages = /* @__PURE__ */ new Set();
|
|
376
|
+
for (const [uid, ta] of Object.entries(this.state.byUid)) {
|
|
377
|
+
if (ta.commitState === "synced") continue;
|
|
378
|
+
const { pageIndex } = parseUid(uid);
|
|
379
|
+
const page = doc.pages.find((p) => p.index === pageIndex);
|
|
380
|
+
if (!page) continue;
|
|
381
|
+
affectedPages.add(pageIndex);
|
|
382
|
+
switch (ta.commitState) {
|
|
383
|
+
case "new":
|
|
384
|
+
const task2 = this.engine.createPageAnnotation(doc, page, ta.object);
|
|
385
|
+
task2.wait((annoId) => this.dispatch(storePdfId(uid, annoId)), import_models.ignore);
|
|
386
|
+
creations.push(task2);
|
|
387
|
+
break;
|
|
388
|
+
case "dirty":
|
|
389
|
+
updates.push(
|
|
390
|
+
this.engine.updatePageAnnotation(doc, page, { ...ta.object, id: ta.pdfId })
|
|
391
|
+
);
|
|
392
|
+
break;
|
|
393
|
+
case "deleted":
|
|
394
|
+
if (!deletionsByPage.has(pageIndex)) {
|
|
395
|
+
deletionsByPage.set(pageIndex, []);
|
|
396
|
+
}
|
|
397
|
+
deletionsByPage.get(pageIndex).push({ ta, uid });
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
204
400
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
401
|
+
const deletionTasks = [];
|
|
402
|
+
for (const [pageIndex, deletions] of deletionsByPage.entries()) {
|
|
403
|
+
const page = doc.pages.find((p) => p.index === pageIndex);
|
|
404
|
+
deletions.sort((a, b) => (b.ta.pdfId ?? -1) - (a.ta.pdfId ?? -1));
|
|
405
|
+
for (const { ta, uid } of deletions) {
|
|
406
|
+
if (ta.pdfId !== void 0) {
|
|
407
|
+
const task2 = new import_models.Task();
|
|
408
|
+
const removeTask = this.engine.removePageAnnotation(doc, page, {
|
|
409
|
+
...ta.object,
|
|
410
|
+
id: ta.pdfId
|
|
411
|
+
});
|
|
412
|
+
removeTask.wait(() => {
|
|
413
|
+
this.dispatch(purgeAnnotation(uid));
|
|
414
|
+
task2.resolve(true);
|
|
415
|
+
}, task2.fail);
|
|
416
|
+
deletionTasks.push(task2);
|
|
417
|
+
} else {
|
|
418
|
+
this.dispatch(purgeAnnotation(uid));
|
|
419
|
+
}
|
|
420
|
+
}
|
|
211
421
|
}
|
|
422
|
+
const allWriteTasks = [...creations, ...updates, ...deletionTasks];
|
|
423
|
+
import_models.Task.allSettled(allWriteTasks).wait(() => {
|
|
424
|
+
for (const pageIndex of affectedPages) {
|
|
425
|
+
this.dispatch(reindexPageAnnotations(pageIndex));
|
|
426
|
+
}
|
|
427
|
+
this.dispatch(commitPendingChanges());
|
|
428
|
+
task.resolve(true);
|
|
429
|
+
}, task.fail);
|
|
430
|
+
return task;
|
|
212
431
|
}
|
|
213
432
|
};
|
|
214
433
|
AnnotationPlugin.id = "annotation";
|
|
215
434
|
|
|
216
435
|
// src/lib/reducer.ts
|
|
217
|
-
var
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
436
|
+
var import_models2 = require("@embedpdf/models");
|
|
437
|
+
var DEFAULT_COLORS = [
|
|
438
|
+
"#E44234",
|
|
439
|
+
"#FF8D00",
|
|
440
|
+
"#FFCD45",
|
|
441
|
+
"#5CC96E",
|
|
442
|
+
"#25D2D1",
|
|
443
|
+
"#597CE2",
|
|
444
|
+
"#C544CE",
|
|
445
|
+
"#7D2E25"
|
|
446
|
+
];
|
|
447
|
+
var patchAnno = (state, uid, patch) => {
|
|
448
|
+
const prev = state.byUid[uid];
|
|
449
|
+
if (!prev) return state;
|
|
450
|
+
return {
|
|
451
|
+
...state,
|
|
452
|
+
byUid: {
|
|
453
|
+
...state.byUid,
|
|
454
|
+
[uid]: {
|
|
455
|
+
...prev,
|
|
456
|
+
commitState: prev.commitState === "synced" ? "dirty" : prev.commitState,
|
|
457
|
+
object: { ...prev.object, ...patch }
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
hasPendingChanges: true
|
|
461
|
+
};
|
|
221
462
|
};
|
|
463
|
+
var initialState = (cfg) => ({
|
|
464
|
+
pages: {},
|
|
465
|
+
byUid: {},
|
|
466
|
+
selectedUid: null,
|
|
467
|
+
annotationMode: null,
|
|
468
|
+
toolDefaults: {
|
|
469
|
+
[import_models2.PdfAnnotationSubtype.HIGHLIGHT]: {
|
|
470
|
+
name: "Highlight",
|
|
471
|
+
color: "#FFCD45",
|
|
472
|
+
opacity: 1,
|
|
473
|
+
interaction: { mode: "highlight", exclusive: false },
|
|
474
|
+
textSelection: true
|
|
475
|
+
},
|
|
476
|
+
[import_models2.PdfAnnotationSubtype.UNDERLINE]: {
|
|
477
|
+
name: "Underline",
|
|
478
|
+
color: "#E44234",
|
|
479
|
+
opacity: 1,
|
|
480
|
+
interaction: { mode: "underline", exclusive: false },
|
|
481
|
+
textSelection: true
|
|
482
|
+
},
|
|
483
|
+
[import_models2.PdfAnnotationSubtype.STRIKEOUT]: {
|
|
484
|
+
name: "Strikeout",
|
|
485
|
+
color: "#E44234",
|
|
486
|
+
opacity: 1,
|
|
487
|
+
interaction: { mode: "strikeout", exclusive: false },
|
|
488
|
+
textSelection: true
|
|
489
|
+
},
|
|
490
|
+
[import_models2.PdfAnnotationSubtype.SQUIGGLY]: {
|
|
491
|
+
name: "Squiggly",
|
|
492
|
+
color: "#E44234",
|
|
493
|
+
opacity: 1,
|
|
494
|
+
interaction: { mode: "squiggly", exclusive: false },
|
|
495
|
+
textSelection: true
|
|
496
|
+
},
|
|
497
|
+
...cfg.toolDefaults
|
|
498
|
+
},
|
|
499
|
+
colorPresets: cfg.colorPresets ?? DEFAULT_COLORS,
|
|
500
|
+
hasPendingChanges: false
|
|
501
|
+
});
|
|
222
502
|
var reducer = (state, action) => {
|
|
223
503
|
switch (action.type) {
|
|
224
|
-
|
|
504
|
+
/* ───── bulk load from engine ───── */
|
|
505
|
+
case SET_ANNOTATIONS: {
|
|
506
|
+
const newPages = { ...state.pages };
|
|
507
|
+
const newByUid = { ...state.byUid };
|
|
508
|
+
for (const [pgStr, list] of Object.entries(action.payload)) {
|
|
509
|
+
const pageIndex = Number(pgStr);
|
|
510
|
+
const oldUidsOnPage = state.pages[pageIndex] || [];
|
|
511
|
+
for (const uid of oldUidsOnPage) {
|
|
512
|
+
delete newByUid[uid];
|
|
513
|
+
}
|
|
514
|
+
const newUidsOnPage = list.map((a, index) => {
|
|
515
|
+
const localId = Date.now() + Math.random() + index;
|
|
516
|
+
const uid = makeUid(pageIndex, localId);
|
|
517
|
+
newByUid[uid] = { localId, pdfId: a.id, commitState: "synced", object: a };
|
|
518
|
+
return uid;
|
|
519
|
+
});
|
|
520
|
+
newPages[pageIndex] = newUidsOnPage;
|
|
521
|
+
}
|
|
522
|
+
return { ...state, pages: newPages, byUid: newByUid };
|
|
523
|
+
}
|
|
524
|
+
/* ───── GUI bits ───── */
|
|
525
|
+
case SET_ANNOTATION_MODE:
|
|
526
|
+
return { ...state, annotationMode: action.payload };
|
|
527
|
+
case SELECT_ANNOTATION:
|
|
225
528
|
return {
|
|
226
529
|
...state,
|
|
227
|
-
|
|
228
|
-
// Clear selection if the annotations have changed
|
|
229
|
-
selectedAnnotation: null
|
|
530
|
+
selectedUid: makeUid(action.payload.pageIndex, action.payload.localId)
|
|
230
531
|
};
|
|
231
|
-
case
|
|
532
|
+
case DESELECT_ANNOTATION:
|
|
533
|
+
return { ...state, selectedUid: null };
|
|
534
|
+
case ADD_COLOR_PRESET:
|
|
535
|
+
return state.colorPresets.includes(action.payload) ? state : { ...state, colorPresets: [...state.colorPresets, action.payload] };
|
|
536
|
+
case UPDATE_TOOL_DEFAULTS: {
|
|
537
|
+
const { subtype, patch } = action.payload;
|
|
232
538
|
return {
|
|
233
539
|
...state,
|
|
234
|
-
|
|
540
|
+
toolDefaults: {
|
|
541
|
+
...state.toolDefaults,
|
|
542
|
+
[subtype]: { ...state.toolDefaults[subtype], ...patch }
|
|
543
|
+
}
|
|
235
544
|
};
|
|
236
|
-
|
|
545
|
+
}
|
|
546
|
+
/* ───── create ───── */
|
|
547
|
+
case CREATE_ANNOTATION: {
|
|
548
|
+
const { pageIndex, localId, annotation } = action.payload;
|
|
549
|
+
const uid = makeUid(pageIndex, localId);
|
|
237
550
|
return {
|
|
238
551
|
...state,
|
|
239
|
-
|
|
552
|
+
pages: { ...state.pages, [pageIndex]: [...state.pages[pageIndex] ?? [], uid] },
|
|
553
|
+
byUid: {
|
|
554
|
+
...state.byUid,
|
|
555
|
+
[uid]: { localId, pdfId: void 0, commitState: "new", object: annotation }
|
|
556
|
+
},
|
|
557
|
+
hasPendingChanges: true
|
|
240
558
|
};
|
|
241
|
-
|
|
559
|
+
}
|
|
560
|
+
/* ───── delete ───── */
|
|
561
|
+
case DELETE_ANNOTATION: {
|
|
562
|
+
const { pageIndex, localId } = action.payload;
|
|
563
|
+
const uid = makeUid(pageIndex, localId);
|
|
564
|
+
if (!state.byUid[uid]) return state;
|
|
242
565
|
return {
|
|
243
566
|
...state,
|
|
244
|
-
|
|
567
|
+
pages: {
|
|
568
|
+
...state.pages,
|
|
569
|
+
[pageIndex]: (state.pages[pageIndex] ?? []).filter((u) => u !== uid)
|
|
570
|
+
},
|
|
571
|
+
byUid: {
|
|
572
|
+
...state.byUid,
|
|
573
|
+
[uid]: { ...state.byUid[uid], commitState: "deleted" }
|
|
574
|
+
},
|
|
575
|
+
hasPendingChanges: true
|
|
245
576
|
};
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
577
|
+
}
|
|
578
|
+
/* ───── field edits ───── */
|
|
579
|
+
case PATCH_ANNOTATION: {
|
|
580
|
+
const uid = makeUid(action.payload.pageIndex, action.payload.localId);
|
|
581
|
+
return patchAnno(state, uid, action.payload.patch);
|
|
582
|
+
}
|
|
583
|
+
/* ───── commit bookkeeping ───── */
|
|
584
|
+
case COMMIT_PENDING_CHANGES: {
|
|
585
|
+
const cleaned = {};
|
|
586
|
+
for (const [uid, ta] of Object.entries(state.byUid)) {
|
|
587
|
+
cleaned[uid] = {
|
|
588
|
+
...ta,
|
|
589
|
+
commitState: ta.commitState === "dirty" || ta.commitState === "new" ? "synced" : ta.commitState
|
|
590
|
+
};
|
|
251
591
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
592
|
+
return { ...state, byUid: cleaned, hasPendingChanges: false };
|
|
593
|
+
}
|
|
594
|
+
case REINDEX_PAGE_ANNOTATIONS: {
|
|
595
|
+
const { pageIndex } = action.payload;
|
|
596
|
+
const newByUid = { ...state.byUid };
|
|
597
|
+
const uidsOnPage = state.pages[pageIndex] || [];
|
|
598
|
+
const annosOnPage = uidsOnPage.map((uid) => state.byUid[uid]).filter((ta) => ta && ta.commitState !== "deleted");
|
|
599
|
+
annosOnPage.sort((a, b) => (a.pdfId ?? Infinity) - (b.pdfId ?? Infinity));
|
|
600
|
+
annosOnPage.forEach((ta, newPdfId) => {
|
|
601
|
+
const uid = makeUid(pageIndex, ta.localId);
|
|
602
|
+
newByUid[uid] = { ...newByUid[uid], pdfId: newPdfId };
|
|
262
603
|
});
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
if (
|
|
269
|
-
const updatedAnnotation = updatedAnnotations.find((a) => a.id === annotationId);
|
|
270
|
-
if (updatedAnnotation) {
|
|
271
|
-
newSelectedAnnotation = {
|
|
272
|
-
...newSelectedAnnotation,
|
|
273
|
-
annotation: updatedAnnotation
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
}
|
|
604
|
+
return { ...state, byUid: newByUid };
|
|
605
|
+
}
|
|
606
|
+
case STORE_PDF_ID: {
|
|
607
|
+
const { uid, pdfId } = action.payload;
|
|
608
|
+
const ta = state.byUid[uid];
|
|
609
|
+
if (!ta) return state;
|
|
277
610
|
return {
|
|
278
611
|
...state,
|
|
279
|
-
|
|
280
|
-
|
|
612
|
+
byUid: {
|
|
613
|
+
...state.byUid,
|
|
614
|
+
[uid]: { ...ta, pdfId, commitState: "synced" }
|
|
615
|
+
}
|
|
281
616
|
};
|
|
282
617
|
}
|
|
618
|
+
case PURGE_ANNOTATION: {
|
|
619
|
+
const { uid } = action.payload;
|
|
620
|
+
const { [uid]: _gone, ...rest } = state.byUid;
|
|
621
|
+
return { ...state, byUid: rest };
|
|
622
|
+
}
|
|
283
623
|
default:
|
|
284
624
|
return state;
|
|
285
625
|
}
|
|
@@ -288,15 +628,23 @@ var reducer = (state, action) => {
|
|
|
288
628
|
// src/lib/index.ts
|
|
289
629
|
var AnnotationPluginPackage = {
|
|
290
630
|
manifest,
|
|
291
|
-
create: (registry, engine) => new AnnotationPlugin(ANNOTATION_PLUGIN_ID, registry, engine),
|
|
631
|
+
create: (registry, engine, config) => new AnnotationPlugin(ANNOTATION_PLUGIN_ID, registry, engine, config),
|
|
292
632
|
reducer,
|
|
293
|
-
initialState
|
|
633
|
+
initialState: (_, config) => initialState(config)
|
|
294
634
|
};
|
|
295
635
|
// Annotate the CommonJS export names for ESM import in node:
|
|
296
636
|
0 && (module.exports = {
|
|
297
637
|
ANNOTATION_PLUGIN_ID,
|
|
298
638
|
AnnotationPlugin,
|
|
299
639
|
AnnotationPluginPackage,
|
|
640
|
+
getAnnotations,
|
|
641
|
+
getAnnotationsByPageIndex,
|
|
642
|
+
getSelectedAnnotation,
|
|
643
|
+
getSelectedAnnotationByPageIndex,
|
|
644
|
+
getSelectedAnnotationMode,
|
|
645
|
+
getSelectedAnnotationWithPageIndex,
|
|
646
|
+
isAnnotationSelected,
|
|
647
|
+
isInAnnotationMode,
|
|
300
648
|
manifest
|
|
301
649
|
});
|
|
302
650
|
//# sourceMappingURL=index.cjs.map
|