@embedpdf/plugin-redaction 1.5.0 → 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 +573 -207
- package/dist/index.js.map +1 -1
- package/dist/lib/actions.d.ts +48 -13
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/redaction-plugin.d.ts +22 -8
- package/dist/lib/reducer.d.ts +4 -2
- package/dist/lib/selectors.d.ts +5 -3
- package/dist/lib/types.d.ts +68 -20
- package/dist/preact/index.cjs +1 -1
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.js +86 -37
- 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 +86 -37
- package/dist/react/index.js.map +1 -1
- package/dist/shared/components/marquee-redact.d.ts +4 -2
- package/dist/shared/components/pending-redactions.d.ts +4 -3
- package/dist/shared/components/redaction-layer.d.ts +11 -5
- package/dist/shared/components/selection-redact.d.ts +2 -1
- package/dist/shared/components/types.d.ts +6 -7
- package/dist/shared/hooks/use-redaction.d.ts +4 -4
- package/dist/shared-preact/components/marquee-redact.d.ts +4 -2
- package/dist/shared-preact/components/pending-redactions.d.ts +4 -3
- package/dist/shared-preact/components/redaction-layer.d.ts +11 -5
- package/dist/shared-preact/components/selection-redact.d.ts +2 -1
- package/dist/shared-preact/components/types.d.ts +6 -7
- package/dist/shared-preact/hooks/use-redaction.d.ts +4 -4
- package/dist/shared-react/components/marquee-redact.d.ts +4 -2
- package/dist/shared-react/components/pending-redactions.d.ts +4 -3
- package/dist/shared-react/components/redaction-layer.d.ts +11 -5
- package/dist/shared-react/components/selection-redact.d.ts +2 -1
- package/dist/shared-react/components/types.d.ts +6 -7
- package/dist/shared-react/hooks/use-redaction.d.ts +4 -4
- package/dist/svelte/components/highlight.svelte.d.ts +14 -0
- package/dist/svelte/components/index.d.ts +5 -0
- package/dist/svelte/components/marquee-redact.svelte.d.ts +16 -0
- package/dist/svelte/components/pending-redactions.svelte.d.ts +15 -0
- package/dist/svelte/components/redaction-layer.svelte.d.ts +20 -0
- package/dist/svelte/components/selection-redact.svelte.d.ts +8 -0
- package/dist/svelte/hooks/index.d.ts +1 -0
- package/dist/svelte/hooks/use-redaction.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 +554 -0
- package/dist/svelte/index.js.map +1 -0
- package/dist/svelte/types.d.ts +10 -0
- package/dist/vue/components/highlight.vue.d.ts +2 -1
- package/dist/vue/components/marquee-redact.vue.d.ts +5 -2
- package/dist/vue/components/pending-redactions.vue.d.ts +18 -13
- package/dist/vue/components/redaction-layer.vue.d.ts +13 -4
- package/dist/vue/components/selection-redact.vue.d.ts +3 -1
- package/dist/vue/components/types.d.ts +9 -0
- package/dist/vue/hooks/use-redaction.d.ts +9 -102
- 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 +219 -125
- package/dist/vue/index.js.map +1 -1
- package/package.json +18 -10
package/dist/index.js
CHANGED
|
@@ -5,6 +5,9 @@ var RedactionMode = /* @__PURE__ */ ((RedactionMode2) => {
|
|
|
5
5
|
RedactionMode2["RedactSelection"] = "redactSelection";
|
|
6
6
|
return RedactionMode2;
|
|
7
7
|
})(RedactionMode || {});
|
|
8
|
+
const INIT_REDACTION_STATE = "REDACTION/INIT_STATE";
|
|
9
|
+
const CLEANUP_REDACTION_STATE = "REDACTION/CLEANUP_STATE";
|
|
10
|
+
const SET_ACTIVE_DOCUMENT = "REDACTION/SET_ACTIVE_DOCUMENT";
|
|
8
11
|
const START_REDACTION = "START_REDACTION";
|
|
9
12
|
const END_REDACTION = "END_REDACTION";
|
|
10
13
|
const SET_ACTIVE_TYPE = "SET_ACTIVE_TYPE";
|
|
@@ -13,25 +16,40 @@ const REMOVE_PENDING = "REMOVE_PENDING";
|
|
|
13
16
|
const CLEAR_PENDING = "CLEAR_PENDING";
|
|
14
17
|
const SELECT_PENDING = "SELECT_PENDING";
|
|
15
18
|
const DESELECT_PENDING = "DESELECT_PENDING";
|
|
16
|
-
|
|
19
|
+
function initRedactionState(documentId, state) {
|
|
20
|
+
return { type: INIT_REDACTION_STATE, payload: { documentId, state } };
|
|
21
|
+
}
|
|
22
|
+
function cleanupRedactionState(documentId) {
|
|
23
|
+
return { type: CLEANUP_REDACTION_STATE, payload: documentId };
|
|
24
|
+
}
|
|
25
|
+
const addPending = (documentId, items) => ({
|
|
17
26
|
type: ADD_PENDING,
|
|
18
|
-
payload: items
|
|
27
|
+
payload: { documentId, items }
|
|
19
28
|
});
|
|
20
|
-
const removePending = (page, id) => ({
|
|
29
|
+
const removePending = (documentId, page, id) => ({
|
|
21
30
|
type: REMOVE_PENDING,
|
|
22
|
-
payload: { page, id }
|
|
31
|
+
payload: { documentId, page, id }
|
|
32
|
+
});
|
|
33
|
+
const clearPending = (documentId) => ({
|
|
34
|
+
type: CLEAR_PENDING,
|
|
35
|
+
payload: documentId
|
|
23
36
|
});
|
|
24
|
-
const
|
|
25
|
-
const startRedaction = (mode) => ({
|
|
37
|
+
const startRedaction = (documentId, mode) => ({
|
|
26
38
|
type: START_REDACTION,
|
|
27
|
-
payload: mode
|
|
39
|
+
payload: { documentId, mode }
|
|
28
40
|
});
|
|
29
|
-
const endRedaction = () => ({
|
|
30
|
-
|
|
41
|
+
const endRedaction = (documentId) => ({
|
|
42
|
+
type: END_REDACTION,
|
|
43
|
+
payload: documentId
|
|
44
|
+
});
|
|
45
|
+
const selectPending = (documentId, page, id) => ({
|
|
31
46
|
type: SELECT_PENDING,
|
|
32
|
-
payload: { page, id }
|
|
47
|
+
payload: { documentId, page, id }
|
|
48
|
+
});
|
|
49
|
+
const deselectPending = (documentId) => ({
|
|
50
|
+
type: DESELECT_PENDING,
|
|
51
|
+
payload: documentId
|
|
33
52
|
});
|
|
34
|
-
const deselectPending = () => ({ type: DESELECT_PENDING });
|
|
35
53
|
function createMarqueeHandler(opts) {
|
|
36
54
|
const { pageSize, scale, minDragPx = 5, onPreview, onCommit } = opts;
|
|
37
55
|
let start = null;
|
|
@@ -74,15 +92,201 @@ function createMarqueeHandler(opts) {
|
|
|
74
92
|
}
|
|
75
93
|
};
|
|
76
94
|
}
|
|
95
|
+
const calculatePendingCount = (pending) => {
|
|
96
|
+
return Object.values(pending).reduce((total, items) => total + items.length, 0);
|
|
97
|
+
};
|
|
98
|
+
const initialDocumentState = {
|
|
99
|
+
isRedacting: false,
|
|
100
|
+
activeType: null,
|
|
101
|
+
pending: {},
|
|
102
|
+
pendingCount: 0,
|
|
103
|
+
selected: null
|
|
104
|
+
};
|
|
105
|
+
const initialState = {
|
|
106
|
+
documents: {},
|
|
107
|
+
activeDocumentId: null
|
|
108
|
+
};
|
|
109
|
+
const redactionReducer = (state = initialState, action) => {
|
|
110
|
+
switch (action.type) {
|
|
111
|
+
case INIT_REDACTION_STATE: {
|
|
112
|
+
const { documentId, state: docState } = action.payload;
|
|
113
|
+
return {
|
|
114
|
+
...state,
|
|
115
|
+
documents: {
|
|
116
|
+
...state.documents,
|
|
117
|
+
[documentId]: docState
|
|
118
|
+
},
|
|
119
|
+
// Set as active if no active document
|
|
120
|
+
activeDocumentId: state.activeDocumentId ?? documentId
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
case CLEANUP_REDACTION_STATE: {
|
|
124
|
+
const documentId = action.payload;
|
|
125
|
+
const { [documentId]: removed, ...remainingDocs } = state.documents;
|
|
126
|
+
return {
|
|
127
|
+
...state,
|
|
128
|
+
documents: remainingDocs,
|
|
129
|
+
activeDocumentId: state.activeDocumentId === documentId ? null : state.activeDocumentId
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
case SET_ACTIVE_DOCUMENT: {
|
|
133
|
+
return {
|
|
134
|
+
...state,
|
|
135
|
+
activeDocumentId: action.payload
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
case ADD_PENDING: {
|
|
139
|
+
const { documentId, items } = action.payload;
|
|
140
|
+
const docState = state.documents[documentId];
|
|
141
|
+
if (!docState) return state;
|
|
142
|
+
const next = { ...docState.pending };
|
|
143
|
+
for (const item of items) {
|
|
144
|
+
next[item.page] = (next[item.page] ?? []).concat(item);
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
...state,
|
|
148
|
+
documents: {
|
|
149
|
+
...state.documents,
|
|
150
|
+
[documentId]: {
|
|
151
|
+
...docState,
|
|
152
|
+
pending: next,
|
|
153
|
+
pendingCount: calculatePendingCount(next)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
case REMOVE_PENDING: {
|
|
159
|
+
const { documentId, page, id } = action.payload;
|
|
160
|
+
const docState = state.documents[documentId];
|
|
161
|
+
if (!docState) return state;
|
|
162
|
+
const list = docState.pending[page] ?? [];
|
|
163
|
+
const filtered = list.filter((it) => it.id !== id);
|
|
164
|
+
const next = { ...docState.pending, [page]: filtered };
|
|
165
|
+
const stillSelected = docState.selected && !(docState.selected.page === page && docState.selected.id === id);
|
|
166
|
+
return {
|
|
167
|
+
...state,
|
|
168
|
+
documents: {
|
|
169
|
+
...state.documents,
|
|
170
|
+
[documentId]: {
|
|
171
|
+
...docState,
|
|
172
|
+
pending: next,
|
|
173
|
+
pendingCount: calculatePendingCount(next),
|
|
174
|
+
selected: stillSelected ? docState.selected : null
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
case CLEAR_PENDING: {
|
|
180
|
+
const documentId = action.payload;
|
|
181
|
+
const docState = state.documents[documentId];
|
|
182
|
+
if (!docState) return state;
|
|
183
|
+
return {
|
|
184
|
+
...state,
|
|
185
|
+
documents: {
|
|
186
|
+
...state.documents,
|
|
187
|
+
[documentId]: {
|
|
188
|
+
...docState,
|
|
189
|
+
pending: {},
|
|
190
|
+
pendingCount: 0,
|
|
191
|
+
selected: null
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
case SELECT_PENDING: {
|
|
197
|
+
const { documentId, page, id } = action.payload;
|
|
198
|
+
const docState = state.documents[documentId];
|
|
199
|
+
if (!docState) return state;
|
|
200
|
+
return {
|
|
201
|
+
...state,
|
|
202
|
+
documents: {
|
|
203
|
+
...state.documents,
|
|
204
|
+
[documentId]: {
|
|
205
|
+
...docState,
|
|
206
|
+
selected: { page, id }
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
case DESELECT_PENDING: {
|
|
212
|
+
const documentId = action.payload;
|
|
213
|
+
const docState = state.documents[documentId];
|
|
214
|
+
if (!docState) return state;
|
|
215
|
+
return {
|
|
216
|
+
...state,
|
|
217
|
+
documents: {
|
|
218
|
+
...state.documents,
|
|
219
|
+
[documentId]: {
|
|
220
|
+
...docState,
|
|
221
|
+
selected: null
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
case START_REDACTION: {
|
|
227
|
+
const { documentId, mode } = action.payload;
|
|
228
|
+
const docState = state.documents[documentId];
|
|
229
|
+
if (!docState) return state;
|
|
230
|
+
return {
|
|
231
|
+
...state,
|
|
232
|
+
documents: {
|
|
233
|
+
...state.documents,
|
|
234
|
+
[documentId]: {
|
|
235
|
+
...docState,
|
|
236
|
+
isRedacting: true,
|
|
237
|
+
activeType: mode
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
case END_REDACTION: {
|
|
243
|
+
const documentId = action.payload;
|
|
244
|
+
const docState = state.documents[documentId];
|
|
245
|
+
if (!docState) return state;
|
|
246
|
+
return {
|
|
247
|
+
...state,
|
|
248
|
+
documents: {
|
|
249
|
+
...state.documents,
|
|
250
|
+
[documentId]: {
|
|
251
|
+
...docState,
|
|
252
|
+
pending: {},
|
|
253
|
+
pendingCount: 0,
|
|
254
|
+
selected: null,
|
|
255
|
+
isRedacting: false,
|
|
256
|
+
activeType: null
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
case SET_ACTIVE_TYPE: {
|
|
262
|
+
const { documentId, mode } = action.payload;
|
|
263
|
+
const docState = state.documents[documentId];
|
|
264
|
+
if (!docState) return state;
|
|
265
|
+
return {
|
|
266
|
+
...state,
|
|
267
|
+
documents: {
|
|
268
|
+
...state.documents,
|
|
269
|
+
[documentId]: {
|
|
270
|
+
...docState,
|
|
271
|
+
activeType: mode
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
default:
|
|
277
|
+
return state;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
77
280
|
const _RedactionPlugin = class _RedactionPlugin extends BasePlugin {
|
|
78
281
|
constructor(id, registry, config) {
|
|
79
|
-
var _a, _b, _c
|
|
282
|
+
var _a, _b, _c;
|
|
80
283
|
super(id, registry);
|
|
81
|
-
this.redactionSelection$ =
|
|
284
|
+
this.redactionSelection$ = /* @__PURE__ */ new Map();
|
|
82
285
|
this.pending$ = createBehaviorEmitter();
|
|
83
286
|
this.selected$ = createBehaviorEmitter();
|
|
84
287
|
this.state$ = createBehaviorEmitter();
|
|
85
288
|
this.events$ = createBehaviorEmitter();
|
|
289
|
+
this.documentUnsubscribers = /* @__PURE__ */ new Map();
|
|
86
290
|
this.config = config;
|
|
87
291
|
this.selectionCapability = (_a = this.registry.getPlugin("selection")) == null ? void 0 : _a.provides();
|
|
88
292
|
this.interactionManagerCapability = (_b = this.registry.getPlugin("interaction-manager")) == null ? void 0 : _b.provides();
|
|
@@ -93,134 +297,277 @@ const _RedactionPlugin = class _RedactionPlugin extends BasePlugin {
|
|
|
93
297
|
exclusive: true,
|
|
94
298
|
cursor: "crosshair"
|
|
95
299
|
});
|
|
96
|
-
}
|
|
97
|
-
if (this.interactionManagerCapability && this.selectionCapability) {
|
|
98
300
|
this.interactionManagerCapability.registerMode({
|
|
99
301
|
id: RedactionMode.RedactSelection,
|
|
100
302
|
scope: "page",
|
|
101
303
|
exclusive: false
|
|
102
304
|
});
|
|
103
|
-
this.selectionCapability.enableForMode(RedactionMode.RedactSelection);
|
|
104
305
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
306
|
+
(_c = this.interactionManagerCapability) == null ? void 0 : _c.onModeChange((modeState) => {
|
|
307
|
+
const documentId = modeState.documentId;
|
|
308
|
+
if (modeState.activeMode === RedactionMode.RedactSelection) {
|
|
309
|
+
this.dispatch(startRedaction(documentId, RedactionMode.RedactSelection));
|
|
310
|
+
} else if (modeState.activeMode === RedactionMode.MarqueeRedact) {
|
|
311
|
+
this.dispatch(startRedaction(documentId, RedactionMode.MarqueeRedact));
|
|
110
312
|
} else {
|
|
111
|
-
this.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (!this.selectionCapability) return;
|
|
116
|
-
if (!this.state.isRedacting) return;
|
|
117
|
-
const formattedSelection = this.selectionCapability.getFormattedSelection();
|
|
118
|
-
this.redactionSelection$.emit(formattedSelection);
|
|
119
|
-
});
|
|
120
|
-
this.unsubscribeEndSelection = (_e = this.selectionCapability) == null ? void 0 : _e.onEndSelection(() => {
|
|
121
|
-
if (!this.selectionCapability) return;
|
|
122
|
-
if (!this.state.isRedacting) return;
|
|
123
|
-
const formattedSelection = this.selectionCapability.getFormattedSelection();
|
|
124
|
-
const items = formattedSelection.map((s) => ({
|
|
125
|
-
id: uuidV4(),
|
|
126
|
-
kind: "text",
|
|
127
|
-
page: s.pageIndex,
|
|
128
|
-
rect: s.rect,
|
|
129
|
-
rects: s.segmentRects
|
|
130
|
-
}));
|
|
131
|
-
this.dispatch(addPending(items));
|
|
132
|
-
this.redactionSelection$.emit([]);
|
|
133
|
-
this.selectionCapability.clear();
|
|
134
|
-
this.pending$.emit(this.state.pending);
|
|
135
|
-
if (items.length) {
|
|
136
|
-
this.selectPending(items[items.length - 1].page, items[items.length - 1].id);
|
|
313
|
+
const docState = this.getDocumentState(documentId);
|
|
314
|
+
if (docState == null ? void 0 : docState.isRedacting) {
|
|
315
|
+
this.dispatch(endRedaction(documentId));
|
|
316
|
+
}
|
|
137
317
|
}
|
|
138
318
|
});
|
|
139
319
|
}
|
|
320
|
+
// ─────────────────────────────────────────────────────────
|
|
321
|
+
// Document Lifecycle Hooks (from BasePlugin)
|
|
322
|
+
// ─────────────────────────────────────────────────────────
|
|
323
|
+
onDocumentLoadingStarted(documentId) {
|
|
324
|
+
this.dispatch(
|
|
325
|
+
initRedactionState(documentId, {
|
|
326
|
+
...initialDocumentState
|
|
327
|
+
})
|
|
328
|
+
);
|
|
329
|
+
this.redactionSelection$.set(documentId, createBehaviorEmitter());
|
|
330
|
+
const unsubscribers = [];
|
|
331
|
+
if (this.selectionCapability) {
|
|
332
|
+
const selectionScope = this.selectionCapability.forDocument(documentId);
|
|
333
|
+
const unsubSelection = selectionScope.onSelectionChange(() => {
|
|
334
|
+
const docState = this.getDocumentState(documentId);
|
|
335
|
+
if (!(docState == null ? void 0 : docState.isRedacting)) return;
|
|
336
|
+
const formattedSelection = selectionScope.getFormattedSelection();
|
|
337
|
+
const emitter = this.redactionSelection$.get(documentId);
|
|
338
|
+
emitter == null ? void 0 : emitter.emit(formattedSelection);
|
|
339
|
+
});
|
|
340
|
+
const unsubEndSelection = selectionScope.onEndSelection(() => {
|
|
341
|
+
const docState = this.getDocumentState(documentId);
|
|
342
|
+
if (!(docState == null ? void 0 : docState.isRedacting)) return;
|
|
343
|
+
const formattedSelection = selectionScope.getFormattedSelection();
|
|
344
|
+
const items = formattedSelection.map((s) => ({
|
|
345
|
+
id: uuidV4(),
|
|
346
|
+
kind: "text",
|
|
347
|
+
page: s.pageIndex,
|
|
348
|
+
rect: s.rect,
|
|
349
|
+
rects: s.segmentRects
|
|
350
|
+
}));
|
|
351
|
+
this.dispatch(addPending(documentId, items));
|
|
352
|
+
const emitter = this.redactionSelection$.get(documentId);
|
|
353
|
+
emitter == null ? void 0 : emitter.emit([]);
|
|
354
|
+
selectionScope.clear();
|
|
355
|
+
this.emitPendingChange(documentId);
|
|
356
|
+
if (items.length) {
|
|
357
|
+
this.selectPending(items[items.length - 1].page, items[items.length - 1].id, documentId);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
unsubscribers.push(unsubSelection, unsubEndSelection);
|
|
361
|
+
}
|
|
362
|
+
this.documentUnsubscribers.set(documentId, unsubscribers);
|
|
363
|
+
this.logger.debug(
|
|
364
|
+
"RedactionPlugin",
|
|
365
|
+
"DocumentOpened",
|
|
366
|
+
`Initialized redaction state for document: ${documentId}`
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
onDocumentLoaded(documentId) {
|
|
370
|
+
var _a;
|
|
371
|
+
(_a = this.selectionCapability) == null ? void 0 : _a.enableForMode(RedactionMode.RedactSelection, documentId);
|
|
372
|
+
}
|
|
373
|
+
onDocumentClosed(documentId) {
|
|
374
|
+
this.dispatch(cleanupRedactionState(documentId));
|
|
375
|
+
const emitter = this.redactionSelection$.get(documentId);
|
|
376
|
+
emitter == null ? void 0 : emitter.clear();
|
|
377
|
+
this.redactionSelection$.delete(documentId);
|
|
378
|
+
const unsubscribers = this.documentUnsubscribers.get(documentId);
|
|
379
|
+
if (unsubscribers) {
|
|
380
|
+
unsubscribers.forEach((unsub) => unsub());
|
|
381
|
+
this.documentUnsubscribers.delete(documentId);
|
|
382
|
+
}
|
|
383
|
+
this.logger.debug(
|
|
384
|
+
"RedactionPlugin",
|
|
385
|
+
"DocumentClosed",
|
|
386
|
+
`Cleaned up redaction state for document: ${documentId}`
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
// ─────────────────────────────────────────────────────────
|
|
390
|
+
// Capability
|
|
391
|
+
// ─────────────────────────────────────────────────────────
|
|
140
392
|
async initialize(_config) {
|
|
393
|
+
this.logger.info("RedactionPlugin", "Initialize", "Redaction plugin initialized");
|
|
141
394
|
}
|
|
142
395
|
buildCapability() {
|
|
143
396
|
return {
|
|
397
|
+
// Active document operations
|
|
144
398
|
queueCurrentSelectionAsPending: () => this.queueCurrentSelectionAsPending(),
|
|
145
399
|
enableMarqueeRedact: () => this.enableMarqueeRedact(),
|
|
146
400
|
toggleMarqueeRedact: () => this.toggleMarqueeRedact(),
|
|
147
|
-
isMarqueeRedactActive: () =>
|
|
148
|
-
var _a;
|
|
149
|
-
return ((_a = this.interactionManagerCapability) == null ? void 0 : _a.getActiveMode()) === RedactionMode.MarqueeRedact;
|
|
150
|
-
},
|
|
401
|
+
isMarqueeRedactActive: () => this.isMarqueeRedactActive(),
|
|
151
402
|
enableRedactSelection: () => this.enableRedactSelection(),
|
|
152
403
|
toggleRedactSelection: () => this.toggleRedactSelection(),
|
|
153
|
-
isRedactSelectionActive: () =>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
addPending: (items) => {
|
|
158
|
-
this.dispatch(addPending(items));
|
|
159
|
-
this.pending$.emit(this.state.pending);
|
|
160
|
-
this.events$.emit({ type: "add", items });
|
|
161
|
-
},
|
|
162
|
-
removePending: (page, id) => {
|
|
163
|
-
this.dispatch(removePending(page, id));
|
|
164
|
-
this.pending$.emit(this.state.pending);
|
|
165
|
-
this.events$.emit({ type: "remove", page, id });
|
|
166
|
-
},
|
|
167
|
-
clearPending: () => {
|
|
168
|
-
this.dispatch(clearPending());
|
|
169
|
-
this.pending$.emit(this.state.pending);
|
|
170
|
-
this.events$.emit({ type: "clear" });
|
|
171
|
-
},
|
|
404
|
+
isRedactSelectionActive: () => this.isRedactSelectionActive(),
|
|
405
|
+
addPending: (items) => this.addPendingItems(items),
|
|
406
|
+
removePending: (page, id) => this.removePendingItem(page, id),
|
|
407
|
+
clearPending: () => this.clearPendingItems(),
|
|
172
408
|
commitAllPending: () => this.commitAllPending(),
|
|
173
409
|
commitPending: (page, id) => this.commitPendingOne(page, id),
|
|
174
|
-
endRedaction: () => this.
|
|
175
|
-
startRedaction: () => this.
|
|
410
|
+
endRedaction: () => this.endRedactionMode(),
|
|
411
|
+
startRedaction: () => this.startRedactionMode(),
|
|
176
412
|
selectPending: (page, id) => this.selectPending(page, id),
|
|
413
|
+
getSelectedPending: () => this.getSelectedPending(),
|
|
177
414
|
deselectPending: () => this.deselectPending(),
|
|
415
|
+
getState: () => this.getDocumentStateOrThrow(),
|
|
416
|
+
// Document-scoped operations
|
|
417
|
+
forDocument: (documentId) => this.createRedactionScope(documentId),
|
|
418
|
+
// Events
|
|
419
|
+
onPendingChange: this.pending$.on,
|
|
178
420
|
onSelectedChange: this.selected$.on,
|
|
179
421
|
onRedactionEvent: this.events$.on,
|
|
180
|
-
onStateChange: this.state$.on
|
|
181
|
-
|
|
422
|
+
onStateChange: this.state$.on
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
// ─────────────────────────────────────────────────────────
|
|
426
|
+
// Document Scoping
|
|
427
|
+
// ─────────────────────────────────────────────────────────
|
|
428
|
+
createRedactionScope(documentId) {
|
|
429
|
+
return {
|
|
430
|
+
queueCurrentSelectionAsPending: () => this.queueCurrentSelectionAsPending(documentId),
|
|
431
|
+
enableMarqueeRedact: () => this.enableMarqueeRedact(documentId),
|
|
432
|
+
toggleMarqueeRedact: () => this.toggleMarqueeRedact(documentId),
|
|
433
|
+
isMarqueeRedactActive: () => this.isMarqueeRedactActive(documentId),
|
|
434
|
+
enableRedactSelection: () => this.enableRedactSelection(documentId),
|
|
435
|
+
toggleRedactSelection: () => this.toggleRedactSelection(documentId),
|
|
436
|
+
isRedactSelectionActive: () => this.isRedactSelectionActive(documentId),
|
|
437
|
+
addPending: (items) => this.addPendingItems(items, documentId),
|
|
438
|
+
removePending: (page, id) => this.removePendingItem(page, id, documentId),
|
|
439
|
+
clearPending: () => this.clearPendingItems(documentId),
|
|
440
|
+
commitAllPending: () => this.commitAllPending(documentId),
|
|
441
|
+
commitPending: (page, id) => this.commitPendingOne(page, id, documentId),
|
|
442
|
+
endRedaction: () => this.endRedactionMode(documentId),
|
|
443
|
+
startRedaction: () => this.startRedactionMode(documentId),
|
|
444
|
+
selectPending: (page, id) => this.selectPending(page, id, documentId),
|
|
445
|
+
getSelectedPending: () => this.getSelectedPending(documentId),
|
|
446
|
+
deselectPending: () => this.deselectPending(documentId),
|
|
447
|
+
getState: () => this.getDocumentStateOrThrow(documentId),
|
|
448
|
+
onPendingChange: (listener) => this.pending$.on((event) => {
|
|
449
|
+
if (event.documentId === documentId) listener(event.pending);
|
|
450
|
+
}),
|
|
451
|
+
onSelectedChange: (listener) => this.selected$.on((event) => {
|
|
452
|
+
if (event.documentId === documentId) listener(event.selected);
|
|
453
|
+
}),
|
|
454
|
+
onRedactionEvent: (listener) => this.events$.on((event) => {
|
|
455
|
+
if (event.documentId === documentId) listener(event);
|
|
456
|
+
}),
|
|
457
|
+
onStateChange: (listener) => this.state$.on((event) => {
|
|
458
|
+
if (event.documentId === documentId) listener(event.state);
|
|
459
|
+
})
|
|
182
460
|
};
|
|
183
461
|
}
|
|
184
|
-
|
|
185
|
-
|
|
462
|
+
// ─────────────────────────────────────────────────────────
|
|
463
|
+
// State Helpers
|
|
464
|
+
// ─────────────────────────────────────────────────────────
|
|
465
|
+
getDocumentState(documentId) {
|
|
466
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
467
|
+
return this.state.documents[id] ?? null;
|
|
186
468
|
}
|
|
187
|
-
|
|
469
|
+
getDocumentStateOrThrow(documentId) {
|
|
470
|
+
const state = this.getDocumentState(documentId);
|
|
471
|
+
if (!state) {
|
|
472
|
+
throw new Error(`Redaction state not found for document: ${documentId ?? "active"}`);
|
|
473
|
+
}
|
|
474
|
+
return state;
|
|
475
|
+
}
|
|
476
|
+
// ─────────────────────────────────────────────────────────
|
|
477
|
+
// Core Operations
|
|
478
|
+
// ─────────────────────────────────────────────────────────
|
|
479
|
+
addPendingItems(items, documentId) {
|
|
480
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
481
|
+
this.dispatch(addPending(id, items));
|
|
482
|
+
this.emitPendingChange(id);
|
|
483
|
+
this.events$.emit({ type: "add", documentId: id, items });
|
|
484
|
+
}
|
|
485
|
+
removePendingItem(page, itemId, documentId) {
|
|
486
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
487
|
+
this.dispatch(removePending(id, page, itemId));
|
|
488
|
+
this.emitPendingChange(id);
|
|
489
|
+
this.events$.emit({ type: "remove", documentId: id, page, id: itemId });
|
|
490
|
+
}
|
|
491
|
+
clearPendingItems(documentId) {
|
|
492
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
493
|
+
this.dispatch(clearPending(id));
|
|
494
|
+
this.emitPendingChange(id);
|
|
495
|
+
this.events$.emit({ type: "clear", documentId: id });
|
|
496
|
+
}
|
|
497
|
+
selectPending(page, itemId, documentId) {
|
|
188
498
|
var _a;
|
|
189
|
-
this.
|
|
190
|
-
|
|
191
|
-
|
|
499
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
500
|
+
this.dispatch(selectPending(id, page, itemId));
|
|
501
|
+
(_a = this.selectionCapability) == null ? void 0 : _a.forDocument(id).clear();
|
|
502
|
+
this.emitSelectedChange(id);
|
|
192
503
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
this.
|
|
504
|
+
getSelectedPending(documentId) {
|
|
505
|
+
var _a;
|
|
506
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
507
|
+
return ((_a = this.getDocumentState(id)) == null ? void 0 : _a.selected) ?? null;
|
|
196
508
|
}
|
|
197
|
-
|
|
509
|
+
deselectPending(documentId) {
|
|
510
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
511
|
+
this.dispatch(deselectPending(id));
|
|
512
|
+
this.emitSelectedChange(id);
|
|
513
|
+
}
|
|
514
|
+
enableRedactSelection(documentId) {
|
|
198
515
|
var _a;
|
|
199
|
-
|
|
516
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
517
|
+
(_a = this.interactionManagerCapability) == null ? void 0 : _a.forDocument(id).activate(RedactionMode.RedactSelection);
|
|
200
518
|
}
|
|
201
|
-
toggleRedactSelection() {
|
|
202
|
-
var _a
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
519
|
+
toggleRedactSelection(documentId) {
|
|
520
|
+
var _a;
|
|
521
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
522
|
+
const scope = (_a = this.interactionManagerCapability) == null ? void 0 : _a.forDocument(id);
|
|
523
|
+
if ((scope == null ? void 0 : scope.getActiveMode()) === RedactionMode.RedactSelection) {
|
|
524
|
+
scope.activateDefaultMode();
|
|
525
|
+
} else {
|
|
526
|
+
scope == null ? void 0 : scope.activate(RedactionMode.RedactSelection);
|
|
527
|
+
}
|
|
206
528
|
}
|
|
207
|
-
|
|
529
|
+
isRedactSelectionActive(documentId) {
|
|
208
530
|
var _a;
|
|
209
|
-
|
|
531
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
532
|
+
return ((_a = this.interactionManagerCapability) == null ? void 0 : _a.forDocument(id).getActiveMode()) === RedactionMode.RedactSelection;
|
|
210
533
|
}
|
|
211
|
-
|
|
212
|
-
var _a
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
534
|
+
enableMarqueeRedact(documentId) {
|
|
535
|
+
var _a;
|
|
536
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
537
|
+
(_a = this.interactionManagerCapability) == null ? void 0 : _a.forDocument(id).activate(RedactionMode.MarqueeRedact);
|
|
538
|
+
}
|
|
539
|
+
toggleMarqueeRedact(documentId) {
|
|
540
|
+
var _a;
|
|
541
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
542
|
+
const scope = (_a = this.interactionManagerCapability) == null ? void 0 : _a.forDocument(id);
|
|
543
|
+
if ((scope == null ? void 0 : scope.getActiveMode()) === RedactionMode.MarqueeRedact) {
|
|
544
|
+
scope.activateDefaultMode();
|
|
545
|
+
} else {
|
|
546
|
+
scope == null ? void 0 : scope.activate(RedactionMode.MarqueeRedact);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
isMarqueeRedactActive(documentId) {
|
|
550
|
+
var _a;
|
|
551
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
552
|
+
return ((_a = this.interactionManagerCapability) == null ? void 0 : _a.forDocument(id).getActiveMode()) === RedactionMode.MarqueeRedact;
|
|
216
553
|
}
|
|
217
|
-
|
|
554
|
+
startRedactionMode(documentId) {
|
|
218
555
|
var _a;
|
|
219
|
-
|
|
556
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
557
|
+
(_a = this.interactionManagerCapability) == null ? void 0 : _a.forDocument(id).activate(RedactionMode.RedactSelection);
|
|
220
558
|
}
|
|
221
|
-
|
|
559
|
+
endRedactionMode(documentId) {
|
|
222
560
|
var _a;
|
|
223
|
-
|
|
561
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
562
|
+
(_a = this.interactionManagerCapability) == null ? void 0 : _a.forDocument(id).activateDefaultMode();
|
|
563
|
+
}
|
|
564
|
+
// ─────────────────────────────────────────────────────────
|
|
565
|
+
// Public Methods
|
|
566
|
+
// ─────────────────────────────────────────────────────────
|
|
567
|
+
onRedactionSelectionChange(documentId, callback) {
|
|
568
|
+
const emitter = this.redactionSelection$.get(documentId);
|
|
569
|
+
return (emitter == null ? void 0 : emitter.on(callback)) ?? (() => {
|
|
570
|
+
});
|
|
224
571
|
}
|
|
225
572
|
registerMarqueeOnPage(opts) {
|
|
226
573
|
if (!this.interactionManagerCapability) {
|
|
@@ -232,13 +579,13 @@ const _RedactionPlugin = class _RedactionPlugin extends BasePlugin {
|
|
|
232
579
|
return () => {
|
|
233
580
|
};
|
|
234
581
|
}
|
|
235
|
-
const
|
|
236
|
-
if (!document) {
|
|
582
|
+
const coreDoc = this.coreState.core.documents[opts.documentId];
|
|
583
|
+
if (!(coreDoc == null ? void 0 : coreDoc.document)) {
|
|
237
584
|
this.logger.warn("RedactionPlugin", "DocumentNotFound", "Document not found");
|
|
238
585
|
return () => {
|
|
239
586
|
};
|
|
240
587
|
}
|
|
241
|
-
const page = document.pages[opts.pageIndex];
|
|
588
|
+
const page = coreDoc.document.pages[opts.pageIndex];
|
|
242
589
|
if (!page) {
|
|
243
590
|
this.logger.warn("RedactionPlugin", "PageNotFound", `Page ${opts.pageIndex} not found`);
|
|
244
591
|
return () => {
|
|
@@ -256,27 +603,29 @@ const _RedactionPlugin = class _RedactionPlugin extends BasePlugin {
|
|
|
256
603
|
page: opts.pageIndex,
|
|
257
604
|
rect: r
|
|
258
605
|
};
|
|
259
|
-
this.dispatch(addPending([item]));
|
|
260
|
-
this.
|
|
606
|
+
this.dispatch(addPending(opts.documentId, [item]));
|
|
607
|
+
this.emitPendingChange(opts.documentId);
|
|
261
608
|
(_b = (_a = opts.callback).onCommit) == null ? void 0 : _b.call(_a, r);
|
|
262
|
-
this.enableRedactSelection();
|
|
263
|
-
this.selectPending(opts.pageIndex, item.id);
|
|
609
|
+
this.enableRedactSelection(opts.documentId);
|
|
610
|
+
this.selectPending(opts.pageIndex, item.id, opts.documentId);
|
|
264
611
|
}
|
|
265
612
|
});
|
|
266
613
|
const off = this.interactionManagerCapability.registerAlways({
|
|
267
614
|
handlers: {
|
|
268
615
|
onPointerDown: (_, evt) => {
|
|
269
616
|
if (evt.target === evt.currentTarget) {
|
|
270
|
-
this.deselectPending();
|
|
617
|
+
this.deselectPending(opts.documentId);
|
|
271
618
|
}
|
|
272
619
|
}
|
|
273
620
|
},
|
|
274
621
|
scope: {
|
|
275
622
|
type: "page",
|
|
623
|
+
documentId: opts.documentId,
|
|
276
624
|
pageIndex: opts.pageIndex
|
|
277
625
|
}
|
|
278
626
|
});
|
|
279
627
|
const off2 = this.interactionManagerCapability.registerHandlers({
|
|
628
|
+
documentId: opts.documentId,
|
|
280
629
|
modeId: RedactionMode.MarqueeRedact,
|
|
281
630
|
handlers,
|
|
282
631
|
pageIndex: opts.pageIndex
|
|
@@ -286,69 +635,92 @@ const _RedactionPlugin = class _RedactionPlugin extends BasePlugin {
|
|
|
286
635
|
off2();
|
|
287
636
|
};
|
|
288
637
|
}
|
|
289
|
-
queueCurrentSelectionAsPending() {
|
|
290
|
-
|
|
638
|
+
queueCurrentSelectionAsPending(documentId) {
|
|
639
|
+
const id = documentId ?? this.getActiveDocumentId();
|
|
291
640
|
if (!this.selectionCapability)
|
|
292
641
|
return PdfTaskHelper.reject({
|
|
293
642
|
code: PdfErrorCode.NotFound,
|
|
294
643
|
message: "[RedactionPlugin] selection plugin required"
|
|
295
644
|
});
|
|
296
|
-
const
|
|
297
|
-
if (!
|
|
645
|
+
const coreDoc = this.coreState.core.documents[id];
|
|
646
|
+
if (!(coreDoc == null ? void 0 : coreDoc.document))
|
|
298
647
|
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
299
|
-
const
|
|
648
|
+
const selectionScope = this.selectionCapability.forDocument(id);
|
|
649
|
+
const formatted = selectionScope.getFormattedSelection();
|
|
300
650
|
if (!formatted.length) return PdfTaskHelper.resolve(true);
|
|
301
|
-
const
|
|
651
|
+
const uniqueId = uuidV4();
|
|
302
652
|
const items = formatted.map((s) => ({
|
|
303
|
-
id,
|
|
653
|
+
id: uniqueId,
|
|
304
654
|
kind: "text",
|
|
305
655
|
page: s.pageIndex,
|
|
306
656
|
rect: s.rect,
|
|
307
657
|
rects: s.segmentRects
|
|
308
658
|
}));
|
|
309
|
-
this.enableRedactSelection();
|
|
310
|
-
this.dispatch(addPending(items));
|
|
311
|
-
this.
|
|
659
|
+
this.enableRedactSelection(id);
|
|
660
|
+
this.dispatch(addPending(id, items));
|
|
661
|
+
this.emitPendingChange(id);
|
|
312
662
|
const last = items[items.length - 1];
|
|
313
|
-
this.selectPending(last.page, last.id);
|
|
314
|
-
this.redactionSelection$.
|
|
315
|
-
|
|
663
|
+
this.selectPending(last.page, last.id, id);
|
|
664
|
+
const emitter = this.redactionSelection$.get(id);
|
|
665
|
+
emitter == null ? void 0 : emitter.emit([]);
|
|
666
|
+
selectionScope.clear();
|
|
316
667
|
return PdfTaskHelper.resolve(true);
|
|
317
668
|
}
|
|
318
|
-
commitPendingOne(page, id) {
|
|
319
|
-
const
|
|
320
|
-
|
|
669
|
+
commitPendingOne(page, id, documentId) {
|
|
670
|
+
const docId = documentId ?? this.getActiveDocumentId();
|
|
671
|
+
const coreDoc = this.coreState.core.documents[docId];
|
|
672
|
+
if (!(coreDoc == null ? void 0 : coreDoc.document))
|
|
321
673
|
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
322
|
-
const
|
|
674
|
+
const docState = this.getDocumentState(docId);
|
|
675
|
+
if (!docState) {
|
|
676
|
+
return PdfTaskHelper.reject({
|
|
677
|
+
code: PdfErrorCode.NotFound,
|
|
678
|
+
message: "Document state not found"
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
const item = (docState.pending[page] ?? []).find((it) => it.id === id);
|
|
323
682
|
if (!item) return PdfTaskHelper.resolve(true);
|
|
324
683
|
const rects = item.kind === "text" ? item.rects : [item.rect];
|
|
325
|
-
const pdfPage =
|
|
684
|
+
const pdfPage = coreDoc.document.pages[page];
|
|
326
685
|
if (!pdfPage)
|
|
327
686
|
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Page not found" });
|
|
328
687
|
const task = new Task();
|
|
329
|
-
this.engine.redactTextInRects(
|
|
688
|
+
this.engine.redactTextInRects(coreDoc.document, pdfPage, rects, {
|
|
330
689
|
drawBlackBoxes: this.config.drawBlackBoxes
|
|
331
690
|
}).wait(
|
|
332
691
|
() => {
|
|
333
|
-
this.dispatch(removePending(page, id));
|
|
334
|
-
this.
|
|
335
|
-
this.dispatchCoreAction(refreshPages([page]));
|
|
336
|
-
this.events$.emit({ type: "commit", success: true });
|
|
692
|
+
this.dispatch(removePending(docId, page, id));
|
|
693
|
+
this.emitPendingChange(docId);
|
|
694
|
+
this.dispatchCoreAction(refreshPages(docId, [page]));
|
|
695
|
+
this.events$.emit({ type: "commit", documentId: docId, success: true });
|
|
337
696
|
task.resolve(true);
|
|
338
697
|
},
|
|
339
698
|
(error) => {
|
|
340
|
-
this.events$.emit({
|
|
699
|
+
this.events$.emit({
|
|
700
|
+
type: "commit",
|
|
701
|
+
documentId: docId,
|
|
702
|
+
success: false,
|
|
703
|
+
error: error.reason
|
|
704
|
+
});
|
|
341
705
|
task.reject({ code: PdfErrorCode.Unknown, message: "Failed to commit redactions" });
|
|
342
706
|
}
|
|
343
707
|
);
|
|
344
708
|
return task;
|
|
345
709
|
}
|
|
346
|
-
commitAllPending() {
|
|
347
|
-
const
|
|
348
|
-
|
|
710
|
+
commitAllPending(documentId) {
|
|
711
|
+
const docId = documentId ?? this.getActiveDocumentId();
|
|
712
|
+
const coreDoc = this.coreState.core.documents[docId];
|
|
713
|
+
if (!(coreDoc == null ? void 0 : coreDoc.document))
|
|
349
714
|
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
715
|
+
const docState = this.getDocumentState(docId);
|
|
716
|
+
if (!docState) {
|
|
717
|
+
return PdfTaskHelper.reject({
|
|
718
|
+
code: PdfErrorCode.NotFound,
|
|
719
|
+
message: "Document state not found"
|
|
720
|
+
});
|
|
721
|
+
}
|
|
350
722
|
const perPage = /* @__PURE__ */ new Map();
|
|
351
|
-
for (const [page, items] of Object.entries(
|
|
723
|
+
for (const [page, items] of Object.entries(docState.pending)) {
|
|
352
724
|
const p = Number(page);
|
|
353
725
|
const list = perPage.get(p) ?? [];
|
|
354
726
|
for (const it of items) {
|
|
@@ -360,11 +732,11 @@ const _RedactionPlugin = class _RedactionPlugin extends BasePlugin {
|
|
|
360
732
|
const pagesToRefresh = Array.from(perPage.entries()).filter(([_, rects]) => rects.length > 0).map(([pageIndex]) => pageIndex);
|
|
361
733
|
const tasks = [];
|
|
362
734
|
for (const [pageIndex, rects] of perPage) {
|
|
363
|
-
const page =
|
|
735
|
+
const page = coreDoc.document.pages[pageIndex];
|
|
364
736
|
if (!page) continue;
|
|
365
737
|
if (!rects.length) continue;
|
|
366
738
|
tasks.push(
|
|
367
|
-
this.engine.redactTextInRects(
|
|
739
|
+
this.engine.redactTextInRects(coreDoc.document, page, rects, {
|
|
368
740
|
drawBlackBoxes: this.config.drawBlackBoxes
|
|
369
741
|
})
|
|
370
742
|
);
|
|
@@ -372,33 +744,72 @@ const _RedactionPlugin = class _RedactionPlugin extends BasePlugin {
|
|
|
372
744
|
const task = new Task();
|
|
373
745
|
Task.all(tasks).wait(
|
|
374
746
|
() => {
|
|
375
|
-
this.dispatch(clearPending());
|
|
376
|
-
this.dispatchCoreAction(refreshPages(pagesToRefresh));
|
|
377
|
-
this.
|
|
378
|
-
this.events$.emit({ type: "commit", success: true });
|
|
747
|
+
this.dispatch(clearPending(docId));
|
|
748
|
+
this.dispatchCoreAction(refreshPages(docId, pagesToRefresh));
|
|
749
|
+
this.emitPendingChange(docId);
|
|
750
|
+
this.events$.emit({ type: "commit", documentId: docId, success: true });
|
|
379
751
|
task.resolve(true);
|
|
380
752
|
},
|
|
381
753
|
(error) => {
|
|
382
|
-
this.events$.emit({
|
|
754
|
+
this.events$.emit({
|
|
755
|
+
type: "commit",
|
|
756
|
+
documentId: docId,
|
|
757
|
+
success: false,
|
|
758
|
+
error: error.reason
|
|
759
|
+
});
|
|
383
760
|
task.reject({ code: PdfErrorCode.Unknown, message: "Failed to commit redactions" });
|
|
384
761
|
}
|
|
385
762
|
);
|
|
386
763
|
return task;
|
|
387
764
|
}
|
|
765
|
+
// ─────────────────────────────────────────────────────────
|
|
766
|
+
// Event Emission Helpers
|
|
767
|
+
// ─────────────────────────────────────────────────────────
|
|
768
|
+
emitPendingChange(documentId) {
|
|
769
|
+
const docState = this.getDocumentState(documentId);
|
|
770
|
+
if (docState) {
|
|
771
|
+
this.pending$.emit({ documentId, pending: docState.pending });
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
emitSelectedChange(documentId) {
|
|
775
|
+
const docState = this.getDocumentState(documentId);
|
|
776
|
+
if (docState) {
|
|
777
|
+
this.selected$.emit({ documentId, selected: docState.selected });
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
emitStateChange(documentId) {
|
|
781
|
+
const docState = this.getDocumentState(documentId);
|
|
782
|
+
if (docState) {
|
|
783
|
+
this.state$.emit({ documentId, state: docState });
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
// ─────────────────────────────────────────────────────────
|
|
787
|
+
// Store Update Handlers
|
|
788
|
+
// ─────────────────────────────────────────────────────────
|
|
388
789
|
onStoreUpdated(_, newState) {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
790
|
+
for (const documentId in newState.documents) {
|
|
791
|
+
const docState = newState.documents[documentId];
|
|
792
|
+
if (docState) {
|
|
793
|
+
this.emitPendingChange(documentId);
|
|
794
|
+
this.emitSelectedChange(documentId);
|
|
795
|
+
this.emitStateChange(documentId);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
392
798
|
}
|
|
799
|
+
// ─────────────────────────────────────────────────────────
|
|
800
|
+
// Lifecycle
|
|
801
|
+
// ─────────────────────────────────────────────────────────
|
|
393
802
|
async destroy() {
|
|
394
|
-
var _a, _b, _c;
|
|
395
|
-
this.redactionSelection$.clear();
|
|
396
803
|
this.pending$.clear();
|
|
804
|
+
this.selected$.clear();
|
|
397
805
|
this.state$.clear();
|
|
398
806
|
this.events$.clear();
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
807
|
+
this.redactionSelection$.forEach((emitter) => emitter.clear());
|
|
808
|
+
this.redactionSelection$.clear();
|
|
809
|
+
this.documentUnsubscribers.forEach((unsubscribers) => {
|
|
810
|
+
unsubscribers.forEach((unsub) => unsub());
|
|
811
|
+
});
|
|
812
|
+
this.documentUnsubscribers.clear();
|
|
402
813
|
await super.destroy();
|
|
403
814
|
}
|
|
404
815
|
};
|
|
@@ -417,63 +828,15 @@ const manifest = {
|
|
|
417
828
|
drawBlackBoxes: true
|
|
418
829
|
}
|
|
419
830
|
};
|
|
420
|
-
const
|
|
421
|
-
|
|
831
|
+
const getPendingRedactionsCount = (s) => s.pendingCount;
|
|
832
|
+
const hasPendingRedactions = (s) => s.pendingCount > 0;
|
|
833
|
+
const getDocumentPendingCount = (state, documentId) => {
|
|
834
|
+
var _a;
|
|
835
|
+
return ((_a = state.documents[documentId]) == null ? void 0 : _a.pendingCount) ?? 0;
|
|
422
836
|
};
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
activeType: null,
|
|
426
|
-
pending: {},
|
|
427
|
-
pendingCount: 0,
|
|
428
|
-
selected: null
|
|
429
|
-
};
|
|
430
|
-
const redactionReducer = (state = initialState, action) => {
|
|
431
|
-
switch (action.type) {
|
|
432
|
-
case ADD_PENDING: {
|
|
433
|
-
const next = { ...state.pending };
|
|
434
|
-
for (const item of action.payload) {
|
|
435
|
-
next[item.page] = (next[item.page] ?? []).concat(item);
|
|
436
|
-
}
|
|
437
|
-
return { ...state, pending: next, pendingCount: calculatePendingCount(next) };
|
|
438
|
-
}
|
|
439
|
-
case REMOVE_PENDING: {
|
|
440
|
-
const { page, id } = action.payload;
|
|
441
|
-
const list = state.pending[page] ?? [];
|
|
442
|
-
const filtered = list.filter((it) => it.id !== id);
|
|
443
|
-
const next = { ...state.pending, [page]: filtered };
|
|
444
|
-
const stillSelected = state.selected && !(state.selected.page === page && state.selected.id === id);
|
|
445
|
-
return {
|
|
446
|
-
...state,
|
|
447
|
-
pending: next,
|
|
448
|
-
pendingCount: calculatePendingCount(next),
|
|
449
|
-
selected: stillSelected ? state.selected : null
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
case CLEAR_PENDING:
|
|
453
|
-
return { ...state, pending: {}, pendingCount: 0, selected: null };
|
|
454
|
-
case SELECT_PENDING:
|
|
455
|
-
return { ...state, selected: { page: action.payload.page, id: action.payload.id } };
|
|
456
|
-
case DESELECT_PENDING:
|
|
457
|
-
return { ...state, selected: null };
|
|
458
|
-
case START_REDACTION:
|
|
459
|
-
return { ...state, isRedacting: true, activeType: action.payload };
|
|
460
|
-
case END_REDACTION:
|
|
461
|
-
return {
|
|
462
|
-
...state,
|
|
463
|
-
pending: {},
|
|
464
|
-
pendingCount: 0,
|
|
465
|
-
selected: null,
|
|
466
|
-
isRedacting: false,
|
|
467
|
-
activeType: null
|
|
468
|
-
};
|
|
469
|
-
case SET_ACTIVE_TYPE:
|
|
470
|
-
return { ...state, activeType: action.payload };
|
|
471
|
-
default:
|
|
472
|
-
return state;
|
|
473
|
-
}
|
|
837
|
+
const getTotalPendingCount = (state) => {
|
|
838
|
+
return Object.values(state.documents).reduce((sum, doc) => sum + doc.pendingCount, 0);
|
|
474
839
|
};
|
|
475
|
-
const getPendingRedactionsCount = (s) => Object.values(s.pending).reduce((sum, list) => sum + ((list == null ? void 0 : list.length) ?? 0), 0);
|
|
476
|
-
const hasPendingRedactions = (s) => Object.values(s.pending).some((list) => ((list == null ? void 0 : list.length) ?? 0) > 0);
|
|
477
840
|
const RedactionPluginPackage = {
|
|
478
841
|
manifest,
|
|
479
842
|
create: (registry, config) => new RedactionPlugin(REDACTION_PLUGIN_ID, registry, config),
|
|
@@ -485,8 +848,11 @@ export {
|
|
|
485
848
|
RedactionMode,
|
|
486
849
|
RedactionPlugin,
|
|
487
850
|
RedactionPluginPackage,
|
|
851
|
+
getDocumentPendingCount,
|
|
488
852
|
getPendingRedactionsCount,
|
|
853
|
+
getTotalPendingCount,
|
|
489
854
|
hasPendingRedactions,
|
|
855
|
+
initialDocumentState,
|
|
490
856
|
initialState,
|
|
491
857
|
manifest
|
|
492
858
|
};
|