@embedpdf/plugin-redaction 1.0.18
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/LICENSE +21 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +418 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/actions.d.ts +47 -0
- package/dist/lib/handlers/index.d.ts +1 -0
- package/dist/lib/handlers/marquee-redact.handler.d.ts +9 -0
- package/dist/lib/index.d.ts +9 -0
- package/dist/lib/manifest.d.ts +4 -0
- package/dist/lib/redaction-plugin.d.ts +33 -0
- package/dist/lib/reducer.d.ts +4 -0
- package/dist/lib/selectors.d.ts +3 -0
- package/dist/lib/types.d.ts +57 -0
- package/dist/preact/adapter.d.ts +10 -0
- package/dist/preact/core.d.ts +1 -0
- package/dist/preact/index.cjs +2 -0
- package/dist/preact/index.cjs.map +1 -0
- package/dist/preact/index.d.ts +1 -0
- package/dist/preact/index.js +265 -0
- package/dist/preact/index.js.map +1 -0
- package/dist/react/adapter.d.ts +2 -0
- package/dist/react/core.d.ts +1 -0
- package/dist/react/index.cjs +2 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +264 -0
- package/dist/react/index.js.map +1 -0
- package/dist/shared-preact/components/highlight.d.ts +14 -0
- package/dist/shared-preact/components/index.d.ts +1 -0
- package/dist/shared-preact/components/marquee-redact.d.ts +13 -0
- package/dist/shared-preact/components/pending-redactions.d.ts +11 -0
- package/dist/shared-preact/components/redaction-layer.d.ts +10 -0
- package/dist/shared-preact/components/selection-redact.d.ts +6 -0
- package/dist/shared-preact/components/types.d.ts +10 -0
- package/dist/shared-preact/hooks/index.d.ts +1 -0
- package/dist/shared-preact/hooks/use-redaction.d.ts +11 -0
- package/dist/shared-preact/index.d.ts +2 -0
- package/dist/shared-react/components/highlight.d.ts +14 -0
- package/dist/shared-react/components/index.d.ts +1 -0
- package/dist/shared-react/components/marquee-redact.d.ts +13 -0
- package/dist/shared-react/components/pending-redactions.d.ts +11 -0
- package/dist/shared-react/components/redaction-layer.d.ts +10 -0
- package/dist/shared-react/components/selection-redact.d.ts +6 -0
- package/dist/shared-react/components/types.d.ts +10 -0
- package/dist/shared-react/hooks/index.d.ts +1 -0
- package/dist/shared-react/hooks/use-redaction.d.ts +11 -0
- package/dist/shared-react/index.d.ts +2 -0
- package/dist/vue/hooks/index.d.ts +1 -0
- package/dist/vue/hooks/use-redaction.d.ts +3 -0
- package/dist/vue/index.cjs +2 -0
- package/dist/vue/index.cjs.map +1 -0
- package/dist/vue/index.d.ts +1 -0
- package/dist/vue/index.js +9 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 CloudPDF
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/models"),i="START_REDACTION",n="END_REDACTION",a="ADD_PENDING",s="REMOVE_PENDING",r="CLEAR_PENDING",o="SELECT_PENDING",c="DESELECT_PENDING",l=e=>({type:a,payload:e}),d=(e,t)=>({type:s,payload:{page:e,id:t}}),g=()=>({type:r});const u=class extends e.BasePlugin{constructor(a,s,r,o){var c,d,g,u,h;super(a,s),this.redactionSelection$=e.createBehaviorEmitter(),this.pending$=e.createBehaviorEmitter(),this.selected$=e.createBehaviorEmitter(),this.engine=r,this.config=o,this.selectionCapability=null==(c=this.registry.getPlugin("selection"))?void 0:c.provides(),this.interactionManagerCapability=null==(d=this.registry.getPlugin("interaction-manager"))?void 0:d.provides(),this.interactionManagerCapability&&this.interactionManagerCapability.registerMode({id:"marqueeRedact",scope:"page",exclusive:!0,cursor:"crosshair"}),this.interactionManagerCapability&&this.selectionCapability&&(this.interactionManagerCapability.registerMode({id:"redactSelection",scope:"page",exclusive:!1}),this.selectionCapability.enableForMode("redactSelection")),this.unsubscribeModeChange=null==(g=this.interactionManagerCapability)?void 0:g.onModeChange((e=>{"redactSelection"===e.activeMode||"marqueeRedact"===e.activeMode?this.dispatch({type:i}):this.dispatch({type:n})})),this.unsubscribeSelectionChange=null==(u=this.selectionCapability)?void 0:u.onSelectionChange((()=>{if(!this.selectionCapability)return;if(!this.state.isRedacting)return;const e=this.selectionCapability.getFormattedSelection();this.redactionSelection$.emit(e)})),this.unsubscribeEndSelection=null==(h=this.selectionCapability)?void 0:h.onEndSelection((()=>{if(!this.selectionCapability)return;if(!this.state.isRedacting)return;const e=this.selectionCapability.getFormattedSelection().map((e=>({id:t.uuidV4(),kind:"text",page:e.pageIndex,boundingRect:e.rect,rects:e.segmentRects})));this.dispatch(l(e)),this.redactionSelection$.emit([]),this.selectionCapability.clear(),this.pending$.emit(this.state.pending),e.length&&this.selectPending(e[e.length-1].page,e[e.length-1].id)}))}async initialize(e){}buildCapability(){return{onRedactionSelectionChange:this.redactionSelection$.on,queueCurrentSelectionAsPending:()=>this.queueCurrentSelectionAsPending(),enableMarqueeRedact:()=>this.enableMarqueeRedact(),toggleMarqueeRedact:()=>this.toggleMarqueeRedact(),isMarqueeRedactActive:()=>{var e;return"marqueeRedact"===(null==(e=this.interactionManagerCapability)?void 0:e.getActiveMode())},enableRedactSelection:()=>this.enableRedactSelection(),toggleRedactSelection:()=>this.toggleRedactSelection(),isRedactSelectionActive:()=>{var e;return"redactSelection"===(null==(e=this.interactionManagerCapability)?void 0:e.getActiveMode())},onPendingChange:this.pending$.on,removePending:(e,t)=>{this.dispatch(d(e,t)),this.pending$.emit(this.state.pending)},clearPending:()=>{this.dispatch(g()),this.pending$.emit(this.state.pending)},commitAllPending:()=>this.commitAllPending(),commitPending:(e,t)=>this.commitPendingOne(e,t),endRedaction:()=>this.endRedaction(),startRedaction:()=>this.startRedaction(),onSelectionChange:this.selected$.on,selectPending:(e,t)=>this.selectPending(e,t),deselectPending:()=>this.deselectPending(),registerMarqueeOnPage:e=>this.registerMarqueeOnPage(e)}}selectPending(e,t){var i;this.dispatch(((e,t)=>({type:o,payload:{page:e,id:t}}))(e,t)),null==(i=this.selectionCapability)||i.clear(),this.selected$.emit(this.state.selected)}deselectPending(){this.dispatch({type:c}),this.selected$.emit(this.state.selected)}enableRedactSelection(){var e;null==(e=this.interactionManagerCapability)||e.activate("redactSelection")}toggleRedactSelection(){var e,t,i;"redactSelection"===(null==(e=this.interactionManagerCapability)?void 0:e.getActiveMode())?null==(t=this.interactionManagerCapability)||t.activateDefaultMode():null==(i=this.interactionManagerCapability)||i.activate("redactSelection")}enableMarqueeRedact(){var e;null==(e=this.interactionManagerCapability)||e.activate("marqueeRedact")}toggleMarqueeRedact(){var e,t,i;"marqueeRedact"===(null==(e=this.interactionManagerCapability)?void 0:e.getActiveMode())?null==(t=this.interactionManagerCapability)||t.activateDefaultMode():null==(i=this.interactionManagerCapability)||i.activate("marqueeRedact")}startRedaction(){var e;null==(e=this.interactionManagerCapability)||e.activate("redactSelection")}endRedaction(){var e;null==(e=this.interactionManagerCapability)||e.activateDefaultMode()}registerMarqueeOnPage(i){if(!this.interactionManagerCapability)throw new Error("[RedactionPlugin] Make sure the interaction-manager plugin is loaded, if you want to use marquee redaction");const n=this.coreState.core.document;if(!n)throw new Error("[RedactionPlugin] Document not found");const a=n.pages[i.pageIndex];if(!a)throw new Error("[RedactionPlugin] Page not found");const s=function(t){const{pageSize:i,scale:n,minDragPx:a=5,onPreview:s,onCommit:r}=t;let o=null,c=null;return{onPointerDown:(e,t)=>{var i;o=e,c={origin:{x:e.x,y:e.y},size:{width:0,height:0}},null==s||s(c),null==(i=t.setPointerCapture)||i.call(t)},onPointerMove:t=>{if(!o)return;const n=e.clamp(t.x,0,i.width),a=e.clamp(t.y,0,i.height);c={origin:{x:Math.min(o.x,n),y:Math.min(o.y,a)},size:{width:Math.abs(n-o.x),height:Math.abs(a-o.y)}},null==s||s(c)},onPointerUp:(e,t)=>{var i;c&&Math.max(c.size.width,c.size.height)*n>a&&(null==r||r(c)),o=null,c=null,null==s||s(null),null==(i=t.releasePointerCapture)||i.call(t)},onPointerCancel:(e,t)=>{var i;o=null,c=null,null==s||s(null),null==(i=t.releasePointerCapture)||i.call(t)}}}({pageSize:a.size,scale:i.scale,onPreview:i.callback.onPreview,onCommit:e=>{var n,a;const s={id:t.uuidV4(),kind:"area",page:i.pageIndex,rect:e};this.dispatch(l([s])),this.pending$.emit(this.state.pending),null==(a=(n=i.callback).onCommit)||a.call(n,e),this.enableRedactSelection(),this.selectPending(i.pageIndex,s.id)}}),r=this.interactionManagerCapability.registerAlways({handlers:{onPointerDown:(e,t)=>{t.target===t.currentTarget&&this.deselectPending()}},scope:{type:"page",pageIndex:i.pageIndex}}),o=this.interactionManagerCapability.registerHandlers({modeId:"marqueeRedact",handlers:s,pageIndex:i.pageIndex});return()=>{r(),o()}}queueCurrentSelectionAsPending(){var e;if(!this.selectionCapability)return t.PdfTaskHelper.reject({code:t.PdfErrorCode.NotFound,message:"[RedactionPlugin] selection plugin required"});if(!this.coreState.core.document)return t.PdfTaskHelper.reject({code:t.PdfErrorCode.NotFound,message:"Document not found"});const i=this.selectionCapability.getFormattedSelection();if(!i.length)return t.PdfTaskHelper.resolve(!0);const n=t.uuidV4(),a=i.map((e=>({id:n,kind:"text",page:e.pageIndex,boundingRect:e.rect,rects:e.segmentRects})));this.enableRedactSelection(),this.dispatch(l(a)),this.pending$.emit(this.state.pending);const s=a[a.length-1];return this.selectPending(s.page,s.id),this.redactionSelection$.emit([]),null==(e=this.selectionCapability)||e.clear(),t.PdfTaskHelper.resolve(!0)}commitPendingOne(i,n){const a=this.coreState.core.document;if(!a)return t.PdfTaskHelper.reject({code:t.PdfErrorCode.NotFound,message:"Document not found"});const s=(this.state.pending[i]??[]).find((e=>e.id===n));if(!s)return t.PdfTaskHelper.resolve(!0);const r="text"===s.kind?s.rects:[s.rect],o=a.pages[i];if(!o)return t.PdfTaskHelper.reject({code:t.PdfErrorCode.NotFound,message:"Page not found"});const c=new t.Task;return this.engine.redactTextInRects(a,o,r,!1,this.config.blackbox).wait((()=>{this.dispatch(d(i,n)),this.pending$.emit(this.state.pending),this.dispatchCoreAction(e.refreshPages([i])),c.resolve(!0)}),(()=>c.reject({code:t.PdfErrorCode.Unknown,message:"Failed to commit redactions"}))),c}commitAllPending(){const i=this.coreState.core.document;if(!i)return t.PdfTaskHelper.reject({code:t.PdfErrorCode.NotFound,message:"Document not found"});const n=new Map;for(const[e,t]of Object.entries(this.state.pending)){const i=Number(e),a=n.get(i)??[];for(const e of t)"text"===e.kind?a.push(...e.rects):a.push(e.rect);n.set(i,a)}const a=Array.from(n.entries()).filter((([e,t])=>t.length>0)).map((([e])=>e)),s=[];for(const[e,t]of n){const n=i.pages[e];n&&(t.length&&s.push(this.engine.redactTextInRects(i,n,t,!1,this.config.blackbox)))}const r=new t.Task;return t.Task.all(s).wait((()=>{this.dispatch(g()),this.dispatchCoreAction(e.refreshPages(a)),this.pending$.emit(this.state.pending),r.resolve(!0)}),(()=>r.reject({code:t.PdfErrorCode.Unknown,message:"Failed to commit redactions"}))),r}onStoreUpdated(e,t){this.pending$.emit(t.pending),this.selected$.emit(t.selected)}async destroy(){var e,t,i;this.redactionSelection$.clear(),this.pending$.clear(),null==(e=this.unsubscribeSelectionChange)||e.call(this),null==(t=this.unsubscribeEndSelection)||t.call(this),null==(i=this.unsubscribeModeChange)||i.call(this),await super.destroy()}};u.id="redaction";let h=u;const p="redaction",m={id:p,name:"Redaction Plugin",version:"1.0.0",provides:["redaction"],requires:[],optional:["interaction-manager","selection"],defaultConfig:{enabled:!0,blackbox:!0}},b={isRedacting:!1,pending:{},selected:null},P={manifest:m,create:(e,t,i)=>new h(p,e,t,i),reducer:(e=b,t)=>{switch(t.type){case a:{const i={...e.pending};for(const e of t.payload)i[e.page]=(i[e.page]??[]).concat(e);return{...e,pending:i}}case s:{const{page:i,id:n}=t.payload,a=(e.pending[i]??[]).filter((e=>e.id!==n)),s={...e.pending,[i]:a},r=e.selected&&!(e.selected.page===i&&e.selected.id===n);return{...e,pending:s,selected:r?e.selected:null}}case r:return{...e,pending:{},selected:null};case o:return{...e,selected:{page:t.payload.page,id:t.payload.id}};case c:return{...e,selected:null};case i:return{...e,isRedacting:!0};case n:return{...e,pending:{},selected:null,isRedacting:!1};default:return e}},initialState:b};exports.REDACTION_PLUGIN_ID=p,exports.RedactionPlugin=h,exports.RedactionPluginPackage=P,exports.getPendingRedactionsCount=e=>Object.values(e.pending).reduce(((e,t)=>e+((null==t?void 0:t.length)??0)),0),exports.hasPendingRedactions=e=>Object.values(e.pending).some((e=>((null==e?void 0:e.length)??0)>0)),exports.manifest=m;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/lib/actions.ts","../src/lib/redaction-plugin.ts","../src/lib/handlers/marquee-redact.handler.ts","../src/lib/manifest.ts","../src/lib/reducer.ts","../src/lib/index.ts","../src/lib/selectors.ts"],"sourcesContent":["import { Action } from '@embedpdf/core';\nimport { RedactionItem } from './types';\n\nexport const START_REDACTION = 'START_REDACTION';\nexport const END_REDACTION = 'END_REDACTION';\n\nexport const ADD_PENDING = 'ADD_PENDING';\nexport const REMOVE_PENDING = 'REMOVE_PENDING';\nexport const CLEAR_PENDING = 'CLEAR_PENDING';\n\nexport const SELECT_PENDING = 'SELECT_PENDING';\nexport const DESELECT_PENDING = 'DESELECT_PENDING';\n\nexport interface StartRedactionAction extends Action {\n type: typeof START_REDACTION;\n}\nexport interface EndRedactionAction extends Action {\n type: typeof END_REDACTION;\n}\n\nexport interface AddPendingAction extends Action {\n type: typeof ADD_PENDING;\n payload: RedactionItem[];\n}\nexport interface RemovePendingAction extends Action {\n type: typeof REMOVE_PENDING;\n payload: { page: number; id: string };\n}\nexport interface ClearPendingAction extends Action {\n type: typeof CLEAR_PENDING;\n}\n\nexport interface SelectPendingAction extends Action {\n type: typeof SELECT_PENDING;\n payload: { page: number; id: string };\n}\nexport interface DeselectPendingAction extends Action {\n type: typeof DESELECT_PENDING;\n}\n\nexport type RedactionAction =\n | StartRedactionAction\n | EndRedactionAction\n | AddPendingAction\n | RemovePendingAction\n | ClearPendingAction\n | SelectPendingAction\n | DeselectPendingAction;\n\nexport const addPending = (items: RedactionItem[]): AddPendingAction => ({\n type: ADD_PENDING,\n payload: items,\n});\nexport const removePending = (page: number, id: string): RemovePendingAction => ({\n type: REMOVE_PENDING,\n payload: { page, id },\n});\nexport const clearPending = (): ClearPendingAction => ({ type: CLEAR_PENDING });\n\nexport const startRedaction = (): StartRedactionAction => ({ type: START_REDACTION });\nexport const endRedaction = (): EndRedactionAction => ({ type: END_REDACTION });\n\nexport const selectPending = (page: number, id: string): SelectPendingAction => ({\n type: SELECT_PENDING,\n payload: { page, id },\n});\nexport const deselectPending = (): DeselectPendingAction => ({ type: DESELECT_PENDING });\n","import {\n RedactionPluginConfig,\n RedactionCapability,\n RedactionState,\n RegisterMarqueeOnPageOptions,\n RedactionItem,\n SelectedRedaction,\n} from './types';\nimport {\n BasePlugin,\n createBehaviorEmitter,\n PluginRegistry,\n refreshDocument,\n refreshPages,\n Unsubscribe,\n} from '@embedpdf/core';\nimport {\n ignore,\n PdfEngine,\n PdfErrorCode,\n PdfErrorReason,\n PdfTask,\n PdfTaskHelper,\n Rect,\n Task,\n uuidV4,\n} from '@embedpdf/models';\nimport {\n FormattedSelection,\n SelectionCapability,\n SelectionPlugin,\n} from '@embedpdf/plugin-selection';\nimport {\n InteractionManagerCapability,\n InteractionManagerPlugin,\n} from '@embedpdf/plugin-interaction-manager';\nimport {\n addPending,\n clearPending,\n deselectPending,\n endRedaction,\n removePending,\n selectPending,\n startRedaction,\n} from './actions';\nimport { createMarqueeHandler } from './handlers';\n\nexport class RedactionPlugin extends BasePlugin<\n RedactionPluginConfig,\n RedactionCapability,\n RedactionState\n> {\n static readonly id = 'redaction' as const;\n private engine: PdfEngine;\n private config: RedactionPluginConfig;\n\n private selectionCapability: SelectionCapability | undefined;\n private interactionManagerCapability: InteractionManagerCapability | undefined;\n\n private readonly redactionSelection$ = createBehaviorEmitter<FormattedSelection[]>();\n private readonly pending$ = createBehaviorEmitter<Record<number, RedactionItem[]>>();\n private readonly selected$ = createBehaviorEmitter<SelectedRedaction | null>();\n\n private readonly unsubscribeSelectionChange: Unsubscribe | undefined;\n private readonly unsubscribeEndSelection: Unsubscribe | undefined;\n private readonly unsubscribeModeChange: Unsubscribe | undefined;\n\n constructor(\n id: string,\n registry: PluginRegistry,\n engine: PdfEngine,\n config: RedactionPluginConfig,\n ) {\n super(id, registry);\n this.engine = engine;\n this.config = config;\n\n this.selectionCapability = this.registry.getPlugin<SelectionPlugin>('selection')?.provides();\n this.interactionManagerCapability = this.registry\n .getPlugin<InteractionManagerPlugin>('interaction-manager')\n ?.provides();\n\n if (this.interactionManagerCapability) {\n this.interactionManagerCapability.registerMode({\n id: 'marqueeRedact',\n scope: 'page',\n exclusive: true,\n cursor: 'crosshair',\n });\n }\n\n if (this.interactionManagerCapability && this.selectionCapability) {\n this.interactionManagerCapability.registerMode({\n id: 'redactSelection',\n scope: 'page',\n exclusive: false,\n });\n this.selectionCapability.enableForMode('redactSelection');\n }\n\n this.unsubscribeModeChange = this.interactionManagerCapability?.onModeChange((state) => {\n if (state.activeMode === 'redactSelection' || state.activeMode === 'marqueeRedact')\n this.dispatch(startRedaction());\n else this.dispatch(endRedaction());\n });\n\n this.unsubscribeSelectionChange = this.selectionCapability?.onSelectionChange(() => {\n if (!this.selectionCapability) return;\n if (!this.state.isRedacting) return;\n const formattedSelection = this.selectionCapability.getFormattedSelection();\n this.redactionSelection$.emit(formattedSelection);\n });\n\n this.unsubscribeEndSelection = this.selectionCapability?.onEndSelection(() => {\n if (!this.selectionCapability) return;\n if (!this.state.isRedacting) return;\n\n const formattedSelection = this.selectionCapability.getFormattedSelection();\n\n const items: RedactionItem[] = formattedSelection.map((s) => ({\n id: uuidV4(),\n kind: 'text',\n page: s.pageIndex,\n boundingRect: s.rect,\n rects: s.segmentRects,\n }));\n\n this.dispatch(addPending(items));\n this.redactionSelection$.emit([]);\n this.selectionCapability.clear();\n this.pending$.emit(this.state.pending);\n if (items.length) {\n this.selectPending(items[items.length - 1].page, items[items.length - 1].id);\n }\n });\n }\n\n async initialize(_config: RedactionPluginConfig): Promise<void> {}\n\n protected buildCapability(): RedactionCapability {\n return {\n onRedactionSelectionChange: this.redactionSelection$.on,\n\n queueCurrentSelectionAsPending: () => this.queueCurrentSelectionAsPending(),\n\n enableMarqueeRedact: () => this.enableMarqueeRedact(),\n toggleMarqueeRedact: () => this.toggleMarqueeRedact(),\n isMarqueeRedactActive: () =>\n this.interactionManagerCapability?.getActiveMode() === 'marqueeRedact',\n\n enableRedactSelection: () => this.enableRedactSelection(),\n toggleRedactSelection: () => this.toggleRedactSelection(),\n isRedactSelectionActive: () =>\n this.interactionManagerCapability?.getActiveMode() === 'redactSelection',\n\n onPendingChange: this.pending$.on,\n removePending: (page, id) => {\n this.dispatch(removePending(page, id));\n this.pending$.emit(this.state.pending);\n },\n clearPending: () => {\n this.dispatch(clearPending());\n this.pending$.emit(this.state.pending);\n },\n commitAllPending: () => this.commitAllPending(),\n commitPending: (page, id) => this.commitPendingOne(page, id),\n\n endRedaction: () => this.endRedaction(),\n startRedaction: () => this.startRedaction(),\n\n onSelectionChange: this.selected$.on,\n selectPending: (page, id) => this.selectPending(page, id),\n deselectPending: () => this.deselectPending(),\n\n registerMarqueeOnPage: (opts) => this.registerMarqueeOnPage(opts),\n };\n }\n\n private selectPending(page: number, id: string) {\n this.dispatch(selectPending(page, id));\n this.selectionCapability?.clear();\n this.selected$.emit(this.state.selected);\n }\n private deselectPending() {\n this.dispatch(deselectPending());\n this.selected$.emit(this.state.selected);\n }\n\n private enableRedactSelection() {\n this.interactionManagerCapability?.activate('redactSelection');\n }\n private toggleRedactSelection() {\n if (this.interactionManagerCapability?.getActiveMode() === 'redactSelection')\n this.interactionManagerCapability?.activateDefaultMode();\n else this.interactionManagerCapability?.activate('redactSelection');\n }\n\n private enableMarqueeRedact() {\n this.interactionManagerCapability?.activate('marqueeRedact');\n }\n private toggleMarqueeRedact() {\n if (this.interactionManagerCapability?.getActiveMode() === 'marqueeRedact')\n this.interactionManagerCapability?.activateDefaultMode();\n else this.interactionManagerCapability?.activate('marqueeRedact');\n }\n\n private startRedaction() {\n this.interactionManagerCapability?.activate('redactSelection');\n }\n private endRedaction() {\n this.interactionManagerCapability?.activateDefaultMode();\n }\n\n public registerMarqueeOnPage(opts: RegisterMarqueeOnPageOptions) {\n if (!this.interactionManagerCapability)\n throw new Error(\n '[RedactionPlugin] Make sure the interaction-manager plugin is loaded, if you want to use marquee redaction',\n );\n\n const document = this.coreState.core.document;\n if (!document) throw new Error('[RedactionPlugin] Document not found');\n\n const page = document.pages[opts.pageIndex];\n if (!page) throw new Error('[RedactionPlugin] Page not found');\n\n const handlers = createMarqueeHandler({\n pageSize: page.size,\n scale: opts.scale,\n onPreview: opts.callback.onPreview,\n onCommit: (r) => {\n const item: RedactionItem = {\n id: uuidV4(),\n kind: 'area',\n page: opts.pageIndex,\n rect: r,\n };\n this.dispatch(addPending([item]));\n this.pending$.emit(this.state.pending);\n opts.callback.onCommit?.(r);\n this.enableRedactSelection();\n this.selectPending(opts.pageIndex, item.id);\n },\n });\n\n const off = this.interactionManagerCapability.registerAlways({\n handlers: {\n onPointerDown: (_, evt) => {\n if (evt.target === evt.currentTarget) {\n this.deselectPending();\n }\n },\n },\n scope: {\n type: 'page',\n pageIndex: opts.pageIndex,\n },\n });\n\n const off2 = this.interactionManagerCapability.registerHandlers({\n modeId: 'marqueeRedact',\n handlers,\n pageIndex: opts.pageIndex,\n });\n\n return () => {\n off();\n off2();\n };\n }\n\n private queueCurrentSelectionAsPending(): Task<boolean, PdfErrorReason> {\n if (!this.selectionCapability)\n return PdfTaskHelper.reject({\n code: PdfErrorCode.NotFound,\n message: '[RedactionPlugin] selection plugin required',\n });\n\n const doc = this.coreState.core.document;\n if (!doc)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Document not found' });\n\n const formatted = this.selectionCapability.getFormattedSelection();\n if (!formatted.length) return PdfTaskHelper.resolve(true);\n\n const id = uuidV4();\n\n const items: RedactionItem[] = formatted.map((s) => ({\n id,\n kind: 'text',\n page: s.pageIndex,\n boundingRect: s.rect,\n rects: s.segmentRects,\n }));\n\n this.enableRedactSelection();\n this.dispatch(addPending(items));\n this.pending$.emit(this.state.pending);\n // optional: auto-select the last one added\n const last = items[items.length - 1];\n this.selectPending(last.page, last.id);\n\n // clear live UI selection\n this.redactionSelection$.emit([]);\n this.selectionCapability?.clear();\n\n return PdfTaskHelper.resolve(true);\n }\n\n private commitPendingOne(page: number, id: string): Task<boolean, PdfErrorReason> {\n const doc = this.coreState.core.document;\n if (!doc)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Document not found' });\n\n const item = (this.state.pending[page] ?? []).find((it) => it.id === id);\n if (!item) return PdfTaskHelper.resolve(true);\n\n const rects: Rect[] = item.kind === 'text' ? item.rects : [item.rect];\n const pdfPage = doc.pages[page];\n if (!pdfPage)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Page not found' });\n\n const task = new Task<boolean, PdfErrorReason>();\n this.engine.redactTextInRects(doc, pdfPage, rects, false, this.config.blackbox).wait(\n () => {\n this.dispatch(removePending(page, id));\n this.pending$.emit(this.state.pending);\n this.dispatchCoreAction(refreshPages([page]));\n task.resolve(true);\n },\n () => task.reject({ code: PdfErrorCode.Unknown, message: 'Failed to commit redactions' }),\n );\n\n return task;\n }\n\n private commitAllPending(): Task<boolean, PdfErrorReason> {\n const doc = this.coreState.core.document;\n if (!doc)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Document not found' });\n\n // group rects per page\n const perPage = new Map<number, Rect[]>();\n for (const [page, items] of Object.entries(this.state.pending)) {\n const p = Number(page);\n const list = perPage.get(p) ?? [];\n for (const it of items) {\n if (it.kind === 'text') list.push(...it.rects);\n else list.push(it.rect);\n }\n perPage.set(p, list);\n }\n\n const pagesToRefresh = Array.from(perPage.entries())\n .filter(([_, rects]) => rects.length > 0)\n .map(([pageIndex]) => pageIndex);\n\n const tasks: PdfTask<boolean>[] = [];\n for (const [pageIndex, rects] of perPage) {\n const page = doc.pages[pageIndex];\n if (!page) continue;\n if (!rects.length) continue;\n tasks.push(this.engine.redactTextInRects(doc, page, rects, false, this.config.blackbox));\n }\n\n const task = new Task<boolean, PdfErrorReason>();\n Task.all(tasks).wait(\n () => {\n this.dispatch(clearPending());\n this.dispatchCoreAction(refreshPages(pagesToRefresh));\n this.pending$.emit(this.state.pending);\n task.resolve(true);\n },\n () => task.reject({ code: PdfErrorCode.Unknown, message: 'Failed to commit redactions' }),\n );\n\n return task;\n }\n\n override onStoreUpdated(_: RedactionState, newState: RedactionState): void {\n // keep external listeners in sync\n this.pending$.emit(newState.pending);\n this.selected$.emit(newState.selected);\n }\n\n async destroy(): Promise<void> {\n this.redactionSelection$.clear();\n this.pending$.clear();\n\n this.unsubscribeSelectionChange?.();\n this.unsubscribeEndSelection?.();\n this.unsubscribeModeChange?.();\n\n await super.destroy();\n }\n}\n","import { Position, Rect, Size } from '@embedpdf/models';\nimport { clamp } from '@embedpdf/core';\nimport {\n EmbedPdfPointerEvent,\n PointerEventHandlersWithLifecycle,\n} from '@embedpdf/plugin-interaction-manager';\n\nexport function createMarqueeHandler(opts: {\n pageSize: Size;\n scale: number;\n minDragPx?: number;\n onPreview?: (rect: Rect | null) => void;\n onCommit?: (rect: Rect) => void;\n}): PointerEventHandlersWithLifecycle<EmbedPdfPointerEvent> {\n const { pageSize, scale, minDragPx = 5, onPreview, onCommit } = opts;\n\n let start: Position | null = null;\n let last: Rect | null = null;\n\n return {\n onPointerDown: (pos, evt) => {\n start = pos;\n last = { origin: { x: pos.x, y: pos.y }, size: { width: 0, height: 0 } };\n onPreview?.(last);\n evt.setPointerCapture?.();\n },\n onPointerMove: (pos) => {\n if (!start) return;\n const x = clamp(pos.x, 0, pageSize.width);\n const y = clamp(pos.y, 0, pageSize.height);\n last = {\n origin: { x: Math.min(start.x, x), y: Math.min(start.y, y) },\n size: { width: Math.abs(x - start.x), height: Math.abs(y - start.y) },\n };\n onPreview?.(last);\n },\n onPointerUp: (_pos, evt) => {\n if (last) {\n const dragPx = Math.max(last.size.width, last.size.height) * scale;\n if (dragPx > minDragPx) onCommit?.(last);\n }\n start = null;\n last = null;\n onPreview?.(null);\n evt.releasePointerCapture?.();\n },\n onPointerCancel: (_pos, evt) => {\n start = null;\n last = null;\n onPreview?.(null);\n evt.releasePointerCapture?.();\n },\n };\n}\n","import { PluginManifest } from '@embedpdf/core';\nimport { RedactionPluginConfig } from './types';\n\nexport const REDACTION_PLUGIN_ID = 'redaction';\n\nexport const manifest: PluginManifest<RedactionPluginConfig> = {\n id: REDACTION_PLUGIN_ID,\n name: 'Redaction Plugin',\n version: '1.0.0',\n provides: ['redaction'],\n requires: [],\n optional: ['interaction-manager', 'selection'],\n defaultConfig: {\n enabled: true,\n blackbox: true,\n },\n};\n","import { RedactionState } from './types';\nimport {\n RedactionAction,\n ADD_PENDING,\n CLEAR_PENDING,\n END_REDACTION,\n REMOVE_PENDING,\n START_REDACTION,\n SELECT_PENDING,\n DESELECT_PENDING,\n} from './actions';\n\nexport const initialState: RedactionState = {\n isRedacting: false,\n pending: {},\n selected: null,\n};\n\nexport const redactionReducer = (state = initialState, action: RedactionAction): RedactionState => {\n switch (action.type) {\n case ADD_PENDING: {\n const next = { ...state.pending };\n for (const item of action.payload) {\n next[item.page] = (next[item.page] ?? []).concat(item);\n }\n return { ...state, pending: next };\n }\n\n case REMOVE_PENDING: {\n const { page, id } = action.payload;\n const list = state.pending[page] ?? [];\n const filtered = list.filter((it) => it.id !== id);\n const next = { ...state.pending, [page]: filtered };\n\n // if the removed one was selected → clear selection\n const stillSelected =\n state.selected && !(state.selected.page === page && state.selected.id === id);\n\n return { ...state, pending: next, selected: stillSelected ? state.selected : null };\n }\n\n case CLEAR_PENDING:\n return { ...state, pending: {}, selected: null };\n\n case SELECT_PENDING:\n return { ...state, selected: { page: action.payload.page, id: action.payload.id } };\n\n case DESELECT_PENDING:\n return { ...state, selected: null };\n\n case START_REDACTION:\n return { ...state, isRedacting: true };\n case END_REDACTION:\n return { ...state, pending: {}, selected: null, isRedacting: false };\n default:\n return state;\n }\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { RedactionPluginConfig, RedactionState } from './types';\nimport { RedactionPlugin } from './redaction-plugin';\nimport { manifest, REDACTION_PLUGIN_ID } from './manifest';\nimport { RedactionAction } from './actions';\nimport { initialState, redactionReducer } from './reducer';\n\nexport const RedactionPluginPackage: PluginPackage<\n RedactionPlugin,\n RedactionPluginConfig,\n RedactionState,\n RedactionAction\n> = {\n manifest,\n create: (registry, engine, config) =>\n new RedactionPlugin(REDACTION_PLUGIN_ID, registry, engine, config),\n reducer: redactionReducer,\n initialState: initialState,\n};\n\nexport * from './redaction-plugin';\nexport * from './types';\nexport * from './manifest';\nexport * from './selectors';\n","import { RedactionState } from './types';\n\nexport const getPendingRedactionsCount = (s: RedactionState) =>\n Object.values(s.pending).reduce((sum, list) => sum + (list?.length ?? 0), 0);\n\nexport const hasPendingRedactions = (s: RedactionState) =>\n Object.values(s.pending).some((list) => (list?.length ?? 0) > 0);\n"],"names":["START_REDACTION","END_REDACTION","ADD_PENDING","REMOVE_PENDING","CLEAR_PENDING","SELECT_PENDING","DESELECT_PENDING","addPending","items","type","payload","removePending","page","id","clearPending","_RedactionPlugin","BasePlugin","constructor","registry","engine","config","super","this","redactionSelection$","createBehaviorEmitter","pending$","selected$","selectionCapability","_a","getPlugin","provides","interactionManagerCapability","_b","registerMode","scope","exclusive","cursor","enableForMode","unsubscribeModeChange","_c","onModeChange","state","activeMode","dispatch","unsubscribeSelectionChange","_d","onSelectionChange","isRedacting","formattedSelection","getFormattedSelection","emit","unsubscribeEndSelection","_e","onEndSelection","map","s","uuidV4","kind","pageIndex","boundingRect","rect","rects","segmentRects","clear","pending","length","selectPending","initialize","_config","buildCapability","onRedactionSelectionChange","on","queueCurrentSelectionAsPending","enableMarqueeRedact","toggleMarqueeRedact","isMarqueeRedactActive","getActiveMode","enableRedactSelection","toggleRedactSelection","isRedactSelectionActive","onPendingChange","commitAllPending","commitPending","commitPendingOne","endRedaction","startRedaction","deselectPending","registerMarqueeOnPage","opts","selected","activate","activateDefaultMode","Error","document","coreState","core","pages","handlers","pageSize","scale","minDragPx","onPreview","onCommit","start","last","onPointerDown","pos","evt","origin","x","y","size","width","height","setPointerCapture","call","onPointerMove","clamp","Math","min","abs","onPointerUp","_pos","max","releasePointerCapture","onPointerCancel","createMarqueeHandler","callback","r","item","off","registerAlways","_","target","currentTarget","off2","registerHandlers","modeId","PdfTaskHelper","reject","code","PdfErrorCode","NotFound","message","formatted","resolve","doc","find","it","pdfPage","task","Task","redactTextInRects","blackbox","wait","dispatchCoreAction","refreshPages","Unknown","perPage","Map","Object","entries","p","Number","list","get","push","set","pagesToRefresh","Array","from","filter","tasks","all","onStoreUpdated","newState","destroy","RedactionPlugin","REDACTION_PLUGIN_ID","manifest","name","version","requires","optional","defaultConfig","enabled","initialState","RedactionPluginPackage","create","reducer","action","next","concat","filtered","stillSelected","values","reduce","sum","some"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lib';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { clamp, BasePlugin, createBehaviorEmitter, refreshPages } from "@embedpdf/core";
|
|
2
|
+
import { uuidV4, PdfTaskHelper, PdfErrorCode, Task } from "@embedpdf/models";
|
|
3
|
+
const START_REDACTION = "START_REDACTION";
|
|
4
|
+
const END_REDACTION = "END_REDACTION";
|
|
5
|
+
const ADD_PENDING = "ADD_PENDING";
|
|
6
|
+
const REMOVE_PENDING = "REMOVE_PENDING";
|
|
7
|
+
const CLEAR_PENDING = "CLEAR_PENDING";
|
|
8
|
+
const SELECT_PENDING = "SELECT_PENDING";
|
|
9
|
+
const DESELECT_PENDING = "DESELECT_PENDING";
|
|
10
|
+
const addPending = (items) => ({
|
|
11
|
+
type: ADD_PENDING,
|
|
12
|
+
payload: items
|
|
13
|
+
});
|
|
14
|
+
const removePending = (page, id) => ({
|
|
15
|
+
type: REMOVE_PENDING,
|
|
16
|
+
payload: { page, id }
|
|
17
|
+
});
|
|
18
|
+
const clearPending = () => ({ type: CLEAR_PENDING });
|
|
19
|
+
const startRedaction = () => ({ type: START_REDACTION });
|
|
20
|
+
const endRedaction = () => ({ type: END_REDACTION });
|
|
21
|
+
const selectPending = (page, id) => ({
|
|
22
|
+
type: SELECT_PENDING,
|
|
23
|
+
payload: { page, id }
|
|
24
|
+
});
|
|
25
|
+
const deselectPending = () => ({ type: DESELECT_PENDING });
|
|
26
|
+
function createMarqueeHandler(opts) {
|
|
27
|
+
const { pageSize, scale, minDragPx = 5, onPreview, onCommit } = opts;
|
|
28
|
+
let start = null;
|
|
29
|
+
let last = null;
|
|
30
|
+
return {
|
|
31
|
+
onPointerDown: (pos, evt) => {
|
|
32
|
+
var _a;
|
|
33
|
+
start = pos;
|
|
34
|
+
last = { origin: { x: pos.x, y: pos.y }, size: { width: 0, height: 0 } };
|
|
35
|
+
onPreview == null ? void 0 : onPreview(last);
|
|
36
|
+
(_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
|
|
37
|
+
},
|
|
38
|
+
onPointerMove: (pos) => {
|
|
39
|
+
if (!start) return;
|
|
40
|
+
const x = clamp(pos.x, 0, pageSize.width);
|
|
41
|
+
const y = clamp(pos.y, 0, pageSize.height);
|
|
42
|
+
last = {
|
|
43
|
+
origin: { x: Math.min(start.x, x), y: Math.min(start.y, y) },
|
|
44
|
+
size: { width: Math.abs(x - start.x), height: Math.abs(y - start.y) }
|
|
45
|
+
};
|
|
46
|
+
onPreview == null ? void 0 : onPreview(last);
|
|
47
|
+
},
|
|
48
|
+
onPointerUp: (_pos, evt) => {
|
|
49
|
+
var _a;
|
|
50
|
+
if (last) {
|
|
51
|
+
const dragPx = Math.max(last.size.width, last.size.height) * scale;
|
|
52
|
+
if (dragPx > minDragPx) onCommit == null ? void 0 : onCommit(last);
|
|
53
|
+
}
|
|
54
|
+
start = null;
|
|
55
|
+
last = null;
|
|
56
|
+
onPreview == null ? void 0 : onPreview(null);
|
|
57
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
58
|
+
},
|
|
59
|
+
onPointerCancel: (_pos, evt) => {
|
|
60
|
+
var _a;
|
|
61
|
+
start = null;
|
|
62
|
+
last = null;
|
|
63
|
+
onPreview == null ? void 0 : onPreview(null);
|
|
64
|
+
(_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const _RedactionPlugin = class _RedactionPlugin extends BasePlugin {
|
|
69
|
+
constructor(id, registry, engine, config) {
|
|
70
|
+
var _a, _b, _c, _d, _e;
|
|
71
|
+
super(id, registry);
|
|
72
|
+
this.redactionSelection$ = createBehaviorEmitter();
|
|
73
|
+
this.pending$ = createBehaviorEmitter();
|
|
74
|
+
this.selected$ = createBehaviorEmitter();
|
|
75
|
+
this.engine = engine;
|
|
76
|
+
this.config = config;
|
|
77
|
+
this.selectionCapability = (_a = this.registry.getPlugin("selection")) == null ? void 0 : _a.provides();
|
|
78
|
+
this.interactionManagerCapability = (_b = this.registry.getPlugin("interaction-manager")) == null ? void 0 : _b.provides();
|
|
79
|
+
if (this.interactionManagerCapability) {
|
|
80
|
+
this.interactionManagerCapability.registerMode({
|
|
81
|
+
id: "marqueeRedact",
|
|
82
|
+
scope: "page",
|
|
83
|
+
exclusive: true,
|
|
84
|
+
cursor: "crosshair"
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (this.interactionManagerCapability && this.selectionCapability) {
|
|
88
|
+
this.interactionManagerCapability.registerMode({
|
|
89
|
+
id: "redactSelection",
|
|
90
|
+
scope: "page",
|
|
91
|
+
exclusive: false
|
|
92
|
+
});
|
|
93
|
+
this.selectionCapability.enableForMode("redactSelection");
|
|
94
|
+
}
|
|
95
|
+
this.unsubscribeModeChange = (_c = this.interactionManagerCapability) == null ? void 0 : _c.onModeChange((state) => {
|
|
96
|
+
if (state.activeMode === "redactSelection" || state.activeMode === "marqueeRedact")
|
|
97
|
+
this.dispatch(startRedaction());
|
|
98
|
+
else this.dispatch(endRedaction());
|
|
99
|
+
});
|
|
100
|
+
this.unsubscribeSelectionChange = (_d = this.selectionCapability) == null ? void 0 : _d.onSelectionChange(() => {
|
|
101
|
+
if (!this.selectionCapability) return;
|
|
102
|
+
if (!this.state.isRedacting) return;
|
|
103
|
+
const formattedSelection = this.selectionCapability.getFormattedSelection();
|
|
104
|
+
this.redactionSelection$.emit(formattedSelection);
|
|
105
|
+
});
|
|
106
|
+
this.unsubscribeEndSelection = (_e = this.selectionCapability) == null ? void 0 : _e.onEndSelection(() => {
|
|
107
|
+
if (!this.selectionCapability) return;
|
|
108
|
+
if (!this.state.isRedacting) return;
|
|
109
|
+
const formattedSelection = this.selectionCapability.getFormattedSelection();
|
|
110
|
+
const items = formattedSelection.map((s) => ({
|
|
111
|
+
id: uuidV4(),
|
|
112
|
+
kind: "text",
|
|
113
|
+
page: s.pageIndex,
|
|
114
|
+
boundingRect: s.rect,
|
|
115
|
+
rects: s.segmentRects
|
|
116
|
+
}));
|
|
117
|
+
this.dispatch(addPending(items));
|
|
118
|
+
this.redactionSelection$.emit([]);
|
|
119
|
+
this.selectionCapability.clear();
|
|
120
|
+
this.pending$.emit(this.state.pending);
|
|
121
|
+
if (items.length) {
|
|
122
|
+
this.selectPending(items[items.length - 1].page, items[items.length - 1].id);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async initialize(_config) {
|
|
127
|
+
}
|
|
128
|
+
buildCapability() {
|
|
129
|
+
return {
|
|
130
|
+
onRedactionSelectionChange: this.redactionSelection$.on,
|
|
131
|
+
queueCurrentSelectionAsPending: () => this.queueCurrentSelectionAsPending(),
|
|
132
|
+
enableMarqueeRedact: () => this.enableMarqueeRedact(),
|
|
133
|
+
toggleMarqueeRedact: () => this.toggleMarqueeRedact(),
|
|
134
|
+
isMarqueeRedactActive: () => {
|
|
135
|
+
var _a;
|
|
136
|
+
return ((_a = this.interactionManagerCapability) == null ? void 0 : _a.getActiveMode()) === "marqueeRedact";
|
|
137
|
+
},
|
|
138
|
+
enableRedactSelection: () => this.enableRedactSelection(),
|
|
139
|
+
toggleRedactSelection: () => this.toggleRedactSelection(),
|
|
140
|
+
isRedactSelectionActive: () => {
|
|
141
|
+
var _a;
|
|
142
|
+
return ((_a = this.interactionManagerCapability) == null ? void 0 : _a.getActiveMode()) === "redactSelection";
|
|
143
|
+
},
|
|
144
|
+
onPendingChange: this.pending$.on,
|
|
145
|
+
removePending: (page, id) => {
|
|
146
|
+
this.dispatch(removePending(page, id));
|
|
147
|
+
this.pending$.emit(this.state.pending);
|
|
148
|
+
},
|
|
149
|
+
clearPending: () => {
|
|
150
|
+
this.dispatch(clearPending());
|
|
151
|
+
this.pending$.emit(this.state.pending);
|
|
152
|
+
},
|
|
153
|
+
commitAllPending: () => this.commitAllPending(),
|
|
154
|
+
commitPending: (page, id) => this.commitPendingOne(page, id),
|
|
155
|
+
endRedaction: () => this.endRedaction(),
|
|
156
|
+
startRedaction: () => this.startRedaction(),
|
|
157
|
+
onSelectionChange: this.selected$.on,
|
|
158
|
+
selectPending: (page, id) => this.selectPending(page, id),
|
|
159
|
+
deselectPending: () => this.deselectPending(),
|
|
160
|
+
registerMarqueeOnPage: (opts) => this.registerMarqueeOnPage(opts)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
selectPending(page, id) {
|
|
164
|
+
var _a;
|
|
165
|
+
this.dispatch(selectPending(page, id));
|
|
166
|
+
(_a = this.selectionCapability) == null ? void 0 : _a.clear();
|
|
167
|
+
this.selected$.emit(this.state.selected);
|
|
168
|
+
}
|
|
169
|
+
deselectPending() {
|
|
170
|
+
this.dispatch(deselectPending());
|
|
171
|
+
this.selected$.emit(this.state.selected);
|
|
172
|
+
}
|
|
173
|
+
enableRedactSelection() {
|
|
174
|
+
var _a;
|
|
175
|
+
(_a = this.interactionManagerCapability) == null ? void 0 : _a.activate("redactSelection");
|
|
176
|
+
}
|
|
177
|
+
toggleRedactSelection() {
|
|
178
|
+
var _a, _b, _c;
|
|
179
|
+
if (((_a = this.interactionManagerCapability) == null ? void 0 : _a.getActiveMode()) === "redactSelection")
|
|
180
|
+
(_b = this.interactionManagerCapability) == null ? void 0 : _b.activateDefaultMode();
|
|
181
|
+
else (_c = this.interactionManagerCapability) == null ? void 0 : _c.activate("redactSelection");
|
|
182
|
+
}
|
|
183
|
+
enableMarqueeRedact() {
|
|
184
|
+
var _a;
|
|
185
|
+
(_a = this.interactionManagerCapability) == null ? void 0 : _a.activate("marqueeRedact");
|
|
186
|
+
}
|
|
187
|
+
toggleMarqueeRedact() {
|
|
188
|
+
var _a, _b, _c;
|
|
189
|
+
if (((_a = this.interactionManagerCapability) == null ? void 0 : _a.getActiveMode()) === "marqueeRedact")
|
|
190
|
+
(_b = this.interactionManagerCapability) == null ? void 0 : _b.activateDefaultMode();
|
|
191
|
+
else (_c = this.interactionManagerCapability) == null ? void 0 : _c.activate("marqueeRedact");
|
|
192
|
+
}
|
|
193
|
+
startRedaction() {
|
|
194
|
+
var _a;
|
|
195
|
+
(_a = this.interactionManagerCapability) == null ? void 0 : _a.activate("redactSelection");
|
|
196
|
+
}
|
|
197
|
+
endRedaction() {
|
|
198
|
+
var _a;
|
|
199
|
+
(_a = this.interactionManagerCapability) == null ? void 0 : _a.activateDefaultMode();
|
|
200
|
+
}
|
|
201
|
+
registerMarqueeOnPage(opts) {
|
|
202
|
+
if (!this.interactionManagerCapability)
|
|
203
|
+
throw new Error(
|
|
204
|
+
"[RedactionPlugin] Make sure the interaction-manager plugin is loaded, if you want to use marquee redaction"
|
|
205
|
+
);
|
|
206
|
+
const document = this.coreState.core.document;
|
|
207
|
+
if (!document) throw new Error("[RedactionPlugin] Document not found");
|
|
208
|
+
const page = document.pages[opts.pageIndex];
|
|
209
|
+
if (!page) throw new Error("[RedactionPlugin] Page not found");
|
|
210
|
+
const handlers = createMarqueeHandler({
|
|
211
|
+
pageSize: page.size,
|
|
212
|
+
scale: opts.scale,
|
|
213
|
+
onPreview: opts.callback.onPreview,
|
|
214
|
+
onCommit: (r) => {
|
|
215
|
+
var _a, _b;
|
|
216
|
+
const item = {
|
|
217
|
+
id: uuidV4(),
|
|
218
|
+
kind: "area",
|
|
219
|
+
page: opts.pageIndex,
|
|
220
|
+
rect: r
|
|
221
|
+
};
|
|
222
|
+
this.dispatch(addPending([item]));
|
|
223
|
+
this.pending$.emit(this.state.pending);
|
|
224
|
+
(_b = (_a = opts.callback).onCommit) == null ? void 0 : _b.call(_a, r);
|
|
225
|
+
this.enableRedactSelection();
|
|
226
|
+
this.selectPending(opts.pageIndex, item.id);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
const off = this.interactionManagerCapability.registerAlways({
|
|
230
|
+
handlers: {
|
|
231
|
+
onPointerDown: (_, evt) => {
|
|
232
|
+
if (evt.target === evt.currentTarget) {
|
|
233
|
+
this.deselectPending();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
scope: {
|
|
238
|
+
type: "page",
|
|
239
|
+
pageIndex: opts.pageIndex
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
const off2 = this.interactionManagerCapability.registerHandlers({
|
|
243
|
+
modeId: "marqueeRedact",
|
|
244
|
+
handlers,
|
|
245
|
+
pageIndex: opts.pageIndex
|
|
246
|
+
});
|
|
247
|
+
return () => {
|
|
248
|
+
off();
|
|
249
|
+
off2();
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
queueCurrentSelectionAsPending() {
|
|
253
|
+
var _a;
|
|
254
|
+
if (!this.selectionCapability)
|
|
255
|
+
return PdfTaskHelper.reject({
|
|
256
|
+
code: PdfErrorCode.NotFound,
|
|
257
|
+
message: "[RedactionPlugin] selection plugin required"
|
|
258
|
+
});
|
|
259
|
+
const doc = this.coreState.core.document;
|
|
260
|
+
if (!doc)
|
|
261
|
+
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
262
|
+
const formatted = this.selectionCapability.getFormattedSelection();
|
|
263
|
+
if (!formatted.length) return PdfTaskHelper.resolve(true);
|
|
264
|
+
const id = uuidV4();
|
|
265
|
+
const items = formatted.map((s) => ({
|
|
266
|
+
id,
|
|
267
|
+
kind: "text",
|
|
268
|
+
page: s.pageIndex,
|
|
269
|
+
boundingRect: s.rect,
|
|
270
|
+
rects: s.segmentRects
|
|
271
|
+
}));
|
|
272
|
+
this.enableRedactSelection();
|
|
273
|
+
this.dispatch(addPending(items));
|
|
274
|
+
this.pending$.emit(this.state.pending);
|
|
275
|
+
const last = items[items.length - 1];
|
|
276
|
+
this.selectPending(last.page, last.id);
|
|
277
|
+
this.redactionSelection$.emit([]);
|
|
278
|
+
(_a = this.selectionCapability) == null ? void 0 : _a.clear();
|
|
279
|
+
return PdfTaskHelper.resolve(true);
|
|
280
|
+
}
|
|
281
|
+
commitPendingOne(page, id) {
|
|
282
|
+
const doc = this.coreState.core.document;
|
|
283
|
+
if (!doc)
|
|
284
|
+
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
285
|
+
const item = (this.state.pending[page] ?? []).find((it) => it.id === id);
|
|
286
|
+
if (!item) return PdfTaskHelper.resolve(true);
|
|
287
|
+
const rects = item.kind === "text" ? item.rects : [item.rect];
|
|
288
|
+
const pdfPage = doc.pages[page];
|
|
289
|
+
if (!pdfPage)
|
|
290
|
+
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Page not found" });
|
|
291
|
+
const task = new Task();
|
|
292
|
+
this.engine.redactTextInRects(doc, pdfPage, rects, false, this.config.blackbox).wait(
|
|
293
|
+
() => {
|
|
294
|
+
this.dispatch(removePending(page, id));
|
|
295
|
+
this.pending$.emit(this.state.pending);
|
|
296
|
+
this.dispatchCoreAction(refreshPages([page]));
|
|
297
|
+
task.resolve(true);
|
|
298
|
+
},
|
|
299
|
+
() => task.reject({ code: PdfErrorCode.Unknown, message: "Failed to commit redactions" })
|
|
300
|
+
);
|
|
301
|
+
return task;
|
|
302
|
+
}
|
|
303
|
+
commitAllPending() {
|
|
304
|
+
const doc = this.coreState.core.document;
|
|
305
|
+
if (!doc)
|
|
306
|
+
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
|
|
307
|
+
const perPage = /* @__PURE__ */ new Map();
|
|
308
|
+
for (const [page, items] of Object.entries(this.state.pending)) {
|
|
309
|
+
const p = Number(page);
|
|
310
|
+
const list = perPage.get(p) ?? [];
|
|
311
|
+
for (const it of items) {
|
|
312
|
+
if (it.kind === "text") list.push(...it.rects);
|
|
313
|
+
else list.push(it.rect);
|
|
314
|
+
}
|
|
315
|
+
perPage.set(p, list);
|
|
316
|
+
}
|
|
317
|
+
const pagesToRefresh = Array.from(perPage.entries()).filter(([_, rects]) => rects.length > 0).map(([pageIndex]) => pageIndex);
|
|
318
|
+
const tasks = [];
|
|
319
|
+
for (const [pageIndex, rects] of perPage) {
|
|
320
|
+
const page = doc.pages[pageIndex];
|
|
321
|
+
if (!page) continue;
|
|
322
|
+
if (!rects.length) continue;
|
|
323
|
+
tasks.push(this.engine.redactTextInRects(doc, page, rects, false, this.config.blackbox));
|
|
324
|
+
}
|
|
325
|
+
const task = new Task();
|
|
326
|
+
Task.all(tasks).wait(
|
|
327
|
+
() => {
|
|
328
|
+
this.dispatch(clearPending());
|
|
329
|
+
this.dispatchCoreAction(refreshPages(pagesToRefresh));
|
|
330
|
+
this.pending$.emit(this.state.pending);
|
|
331
|
+
task.resolve(true);
|
|
332
|
+
},
|
|
333
|
+
() => task.reject({ code: PdfErrorCode.Unknown, message: "Failed to commit redactions" })
|
|
334
|
+
);
|
|
335
|
+
return task;
|
|
336
|
+
}
|
|
337
|
+
onStoreUpdated(_, newState) {
|
|
338
|
+
this.pending$.emit(newState.pending);
|
|
339
|
+
this.selected$.emit(newState.selected);
|
|
340
|
+
}
|
|
341
|
+
async destroy() {
|
|
342
|
+
var _a, _b, _c;
|
|
343
|
+
this.redactionSelection$.clear();
|
|
344
|
+
this.pending$.clear();
|
|
345
|
+
(_a = this.unsubscribeSelectionChange) == null ? void 0 : _a.call(this);
|
|
346
|
+
(_b = this.unsubscribeEndSelection) == null ? void 0 : _b.call(this);
|
|
347
|
+
(_c = this.unsubscribeModeChange) == null ? void 0 : _c.call(this);
|
|
348
|
+
await super.destroy();
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
_RedactionPlugin.id = "redaction";
|
|
352
|
+
let RedactionPlugin = _RedactionPlugin;
|
|
353
|
+
const REDACTION_PLUGIN_ID = "redaction";
|
|
354
|
+
const manifest = {
|
|
355
|
+
id: REDACTION_PLUGIN_ID,
|
|
356
|
+
name: "Redaction Plugin",
|
|
357
|
+
version: "1.0.0",
|
|
358
|
+
provides: ["redaction"],
|
|
359
|
+
requires: [],
|
|
360
|
+
optional: ["interaction-manager", "selection"],
|
|
361
|
+
defaultConfig: {
|
|
362
|
+
enabled: true,
|
|
363
|
+
blackbox: true
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
const initialState = {
|
|
367
|
+
isRedacting: false,
|
|
368
|
+
pending: {},
|
|
369
|
+
selected: null
|
|
370
|
+
};
|
|
371
|
+
const redactionReducer = (state = initialState, action) => {
|
|
372
|
+
switch (action.type) {
|
|
373
|
+
case ADD_PENDING: {
|
|
374
|
+
const next = { ...state.pending };
|
|
375
|
+
for (const item of action.payload) {
|
|
376
|
+
next[item.page] = (next[item.page] ?? []).concat(item);
|
|
377
|
+
}
|
|
378
|
+
return { ...state, pending: next };
|
|
379
|
+
}
|
|
380
|
+
case REMOVE_PENDING: {
|
|
381
|
+
const { page, id } = action.payload;
|
|
382
|
+
const list = state.pending[page] ?? [];
|
|
383
|
+
const filtered = list.filter((it) => it.id !== id);
|
|
384
|
+
const next = { ...state.pending, [page]: filtered };
|
|
385
|
+
const stillSelected = state.selected && !(state.selected.page === page && state.selected.id === id);
|
|
386
|
+
return { ...state, pending: next, selected: stillSelected ? state.selected : null };
|
|
387
|
+
}
|
|
388
|
+
case CLEAR_PENDING:
|
|
389
|
+
return { ...state, pending: {}, selected: null };
|
|
390
|
+
case SELECT_PENDING:
|
|
391
|
+
return { ...state, selected: { page: action.payload.page, id: action.payload.id } };
|
|
392
|
+
case DESELECT_PENDING:
|
|
393
|
+
return { ...state, selected: null };
|
|
394
|
+
case START_REDACTION:
|
|
395
|
+
return { ...state, isRedacting: true };
|
|
396
|
+
case END_REDACTION:
|
|
397
|
+
return { ...state, pending: {}, selected: null, isRedacting: false };
|
|
398
|
+
default:
|
|
399
|
+
return state;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
const getPendingRedactionsCount = (s) => Object.values(s.pending).reduce((sum, list) => sum + ((list == null ? void 0 : list.length) ?? 0), 0);
|
|
403
|
+
const hasPendingRedactions = (s) => Object.values(s.pending).some((list) => ((list == null ? void 0 : list.length) ?? 0) > 0);
|
|
404
|
+
const RedactionPluginPackage = {
|
|
405
|
+
manifest,
|
|
406
|
+
create: (registry, engine, config) => new RedactionPlugin(REDACTION_PLUGIN_ID, registry, engine, config),
|
|
407
|
+
reducer: redactionReducer,
|
|
408
|
+
initialState
|
|
409
|
+
};
|
|
410
|
+
export {
|
|
411
|
+
REDACTION_PLUGIN_ID,
|
|
412
|
+
RedactionPlugin,
|
|
413
|
+
RedactionPluginPackage,
|
|
414
|
+
getPendingRedactionsCount,
|
|
415
|
+
hasPendingRedactions,
|
|
416
|
+
manifest
|
|
417
|
+
};
|
|
418
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/lib/actions.ts","../src/lib/handlers/marquee-redact.handler.ts","../src/lib/redaction-plugin.ts","../src/lib/manifest.ts","../src/lib/reducer.ts","../src/lib/selectors.ts","../src/lib/index.ts"],"sourcesContent":["import { Action } from '@embedpdf/core';\nimport { RedactionItem } from './types';\n\nexport const START_REDACTION = 'START_REDACTION';\nexport const END_REDACTION = 'END_REDACTION';\n\nexport const ADD_PENDING = 'ADD_PENDING';\nexport const REMOVE_PENDING = 'REMOVE_PENDING';\nexport const CLEAR_PENDING = 'CLEAR_PENDING';\n\nexport const SELECT_PENDING = 'SELECT_PENDING';\nexport const DESELECT_PENDING = 'DESELECT_PENDING';\n\nexport interface StartRedactionAction extends Action {\n type: typeof START_REDACTION;\n}\nexport interface EndRedactionAction extends Action {\n type: typeof END_REDACTION;\n}\n\nexport interface AddPendingAction extends Action {\n type: typeof ADD_PENDING;\n payload: RedactionItem[];\n}\nexport interface RemovePendingAction extends Action {\n type: typeof REMOVE_PENDING;\n payload: { page: number; id: string };\n}\nexport interface ClearPendingAction extends Action {\n type: typeof CLEAR_PENDING;\n}\n\nexport interface SelectPendingAction extends Action {\n type: typeof SELECT_PENDING;\n payload: { page: number; id: string };\n}\nexport interface DeselectPendingAction extends Action {\n type: typeof DESELECT_PENDING;\n}\n\nexport type RedactionAction =\n | StartRedactionAction\n | EndRedactionAction\n | AddPendingAction\n | RemovePendingAction\n | ClearPendingAction\n | SelectPendingAction\n | DeselectPendingAction;\n\nexport const addPending = (items: RedactionItem[]): AddPendingAction => ({\n type: ADD_PENDING,\n payload: items,\n});\nexport const removePending = (page: number, id: string): RemovePendingAction => ({\n type: REMOVE_PENDING,\n payload: { page, id },\n});\nexport const clearPending = (): ClearPendingAction => ({ type: CLEAR_PENDING });\n\nexport const startRedaction = (): StartRedactionAction => ({ type: START_REDACTION });\nexport const endRedaction = (): EndRedactionAction => ({ type: END_REDACTION });\n\nexport const selectPending = (page: number, id: string): SelectPendingAction => ({\n type: SELECT_PENDING,\n payload: { page, id },\n});\nexport const deselectPending = (): DeselectPendingAction => ({ type: DESELECT_PENDING });\n","import { Position, Rect, Size } from '@embedpdf/models';\nimport { clamp } from '@embedpdf/core';\nimport {\n EmbedPdfPointerEvent,\n PointerEventHandlersWithLifecycle,\n} from '@embedpdf/plugin-interaction-manager';\n\nexport function createMarqueeHandler(opts: {\n pageSize: Size;\n scale: number;\n minDragPx?: number;\n onPreview?: (rect: Rect | null) => void;\n onCommit?: (rect: Rect) => void;\n}): PointerEventHandlersWithLifecycle<EmbedPdfPointerEvent> {\n const { pageSize, scale, minDragPx = 5, onPreview, onCommit } = opts;\n\n let start: Position | null = null;\n let last: Rect | null = null;\n\n return {\n onPointerDown: (pos, evt) => {\n start = pos;\n last = { origin: { x: pos.x, y: pos.y }, size: { width: 0, height: 0 } };\n onPreview?.(last);\n evt.setPointerCapture?.();\n },\n onPointerMove: (pos) => {\n if (!start) return;\n const x = clamp(pos.x, 0, pageSize.width);\n const y = clamp(pos.y, 0, pageSize.height);\n last = {\n origin: { x: Math.min(start.x, x), y: Math.min(start.y, y) },\n size: { width: Math.abs(x - start.x), height: Math.abs(y - start.y) },\n };\n onPreview?.(last);\n },\n onPointerUp: (_pos, evt) => {\n if (last) {\n const dragPx = Math.max(last.size.width, last.size.height) * scale;\n if (dragPx > minDragPx) onCommit?.(last);\n }\n start = null;\n last = null;\n onPreview?.(null);\n evt.releasePointerCapture?.();\n },\n onPointerCancel: (_pos, evt) => {\n start = null;\n last = null;\n onPreview?.(null);\n evt.releasePointerCapture?.();\n },\n };\n}\n","import {\n RedactionPluginConfig,\n RedactionCapability,\n RedactionState,\n RegisterMarqueeOnPageOptions,\n RedactionItem,\n SelectedRedaction,\n} from './types';\nimport {\n BasePlugin,\n createBehaviorEmitter,\n PluginRegistry,\n refreshDocument,\n refreshPages,\n Unsubscribe,\n} from '@embedpdf/core';\nimport {\n ignore,\n PdfEngine,\n PdfErrorCode,\n PdfErrorReason,\n PdfTask,\n PdfTaskHelper,\n Rect,\n Task,\n uuidV4,\n} from '@embedpdf/models';\nimport {\n FormattedSelection,\n SelectionCapability,\n SelectionPlugin,\n} from '@embedpdf/plugin-selection';\nimport {\n InteractionManagerCapability,\n InteractionManagerPlugin,\n} from '@embedpdf/plugin-interaction-manager';\nimport {\n addPending,\n clearPending,\n deselectPending,\n endRedaction,\n removePending,\n selectPending,\n startRedaction,\n} from './actions';\nimport { createMarqueeHandler } from './handlers';\n\nexport class RedactionPlugin extends BasePlugin<\n RedactionPluginConfig,\n RedactionCapability,\n RedactionState\n> {\n static readonly id = 'redaction' as const;\n private engine: PdfEngine;\n private config: RedactionPluginConfig;\n\n private selectionCapability: SelectionCapability | undefined;\n private interactionManagerCapability: InteractionManagerCapability | undefined;\n\n private readonly redactionSelection$ = createBehaviorEmitter<FormattedSelection[]>();\n private readonly pending$ = createBehaviorEmitter<Record<number, RedactionItem[]>>();\n private readonly selected$ = createBehaviorEmitter<SelectedRedaction | null>();\n\n private readonly unsubscribeSelectionChange: Unsubscribe | undefined;\n private readonly unsubscribeEndSelection: Unsubscribe | undefined;\n private readonly unsubscribeModeChange: Unsubscribe | undefined;\n\n constructor(\n id: string,\n registry: PluginRegistry,\n engine: PdfEngine,\n config: RedactionPluginConfig,\n ) {\n super(id, registry);\n this.engine = engine;\n this.config = config;\n\n this.selectionCapability = this.registry.getPlugin<SelectionPlugin>('selection')?.provides();\n this.interactionManagerCapability = this.registry\n .getPlugin<InteractionManagerPlugin>('interaction-manager')\n ?.provides();\n\n if (this.interactionManagerCapability) {\n this.interactionManagerCapability.registerMode({\n id: 'marqueeRedact',\n scope: 'page',\n exclusive: true,\n cursor: 'crosshair',\n });\n }\n\n if (this.interactionManagerCapability && this.selectionCapability) {\n this.interactionManagerCapability.registerMode({\n id: 'redactSelection',\n scope: 'page',\n exclusive: false,\n });\n this.selectionCapability.enableForMode('redactSelection');\n }\n\n this.unsubscribeModeChange = this.interactionManagerCapability?.onModeChange((state) => {\n if (state.activeMode === 'redactSelection' || state.activeMode === 'marqueeRedact')\n this.dispatch(startRedaction());\n else this.dispatch(endRedaction());\n });\n\n this.unsubscribeSelectionChange = this.selectionCapability?.onSelectionChange(() => {\n if (!this.selectionCapability) return;\n if (!this.state.isRedacting) return;\n const formattedSelection = this.selectionCapability.getFormattedSelection();\n this.redactionSelection$.emit(formattedSelection);\n });\n\n this.unsubscribeEndSelection = this.selectionCapability?.onEndSelection(() => {\n if (!this.selectionCapability) return;\n if (!this.state.isRedacting) return;\n\n const formattedSelection = this.selectionCapability.getFormattedSelection();\n\n const items: RedactionItem[] = formattedSelection.map((s) => ({\n id: uuidV4(),\n kind: 'text',\n page: s.pageIndex,\n boundingRect: s.rect,\n rects: s.segmentRects,\n }));\n\n this.dispatch(addPending(items));\n this.redactionSelection$.emit([]);\n this.selectionCapability.clear();\n this.pending$.emit(this.state.pending);\n if (items.length) {\n this.selectPending(items[items.length - 1].page, items[items.length - 1].id);\n }\n });\n }\n\n async initialize(_config: RedactionPluginConfig): Promise<void> {}\n\n protected buildCapability(): RedactionCapability {\n return {\n onRedactionSelectionChange: this.redactionSelection$.on,\n\n queueCurrentSelectionAsPending: () => this.queueCurrentSelectionAsPending(),\n\n enableMarqueeRedact: () => this.enableMarqueeRedact(),\n toggleMarqueeRedact: () => this.toggleMarqueeRedact(),\n isMarqueeRedactActive: () =>\n this.interactionManagerCapability?.getActiveMode() === 'marqueeRedact',\n\n enableRedactSelection: () => this.enableRedactSelection(),\n toggleRedactSelection: () => this.toggleRedactSelection(),\n isRedactSelectionActive: () =>\n this.interactionManagerCapability?.getActiveMode() === 'redactSelection',\n\n onPendingChange: this.pending$.on,\n removePending: (page, id) => {\n this.dispatch(removePending(page, id));\n this.pending$.emit(this.state.pending);\n },\n clearPending: () => {\n this.dispatch(clearPending());\n this.pending$.emit(this.state.pending);\n },\n commitAllPending: () => this.commitAllPending(),\n commitPending: (page, id) => this.commitPendingOne(page, id),\n\n endRedaction: () => this.endRedaction(),\n startRedaction: () => this.startRedaction(),\n\n onSelectionChange: this.selected$.on,\n selectPending: (page, id) => this.selectPending(page, id),\n deselectPending: () => this.deselectPending(),\n\n registerMarqueeOnPage: (opts) => this.registerMarqueeOnPage(opts),\n };\n }\n\n private selectPending(page: number, id: string) {\n this.dispatch(selectPending(page, id));\n this.selectionCapability?.clear();\n this.selected$.emit(this.state.selected);\n }\n private deselectPending() {\n this.dispatch(deselectPending());\n this.selected$.emit(this.state.selected);\n }\n\n private enableRedactSelection() {\n this.interactionManagerCapability?.activate('redactSelection');\n }\n private toggleRedactSelection() {\n if (this.interactionManagerCapability?.getActiveMode() === 'redactSelection')\n this.interactionManagerCapability?.activateDefaultMode();\n else this.interactionManagerCapability?.activate('redactSelection');\n }\n\n private enableMarqueeRedact() {\n this.interactionManagerCapability?.activate('marqueeRedact');\n }\n private toggleMarqueeRedact() {\n if (this.interactionManagerCapability?.getActiveMode() === 'marqueeRedact')\n this.interactionManagerCapability?.activateDefaultMode();\n else this.interactionManagerCapability?.activate('marqueeRedact');\n }\n\n private startRedaction() {\n this.interactionManagerCapability?.activate('redactSelection');\n }\n private endRedaction() {\n this.interactionManagerCapability?.activateDefaultMode();\n }\n\n public registerMarqueeOnPage(opts: RegisterMarqueeOnPageOptions) {\n if (!this.interactionManagerCapability)\n throw new Error(\n '[RedactionPlugin] Make sure the interaction-manager plugin is loaded, if you want to use marquee redaction',\n );\n\n const document = this.coreState.core.document;\n if (!document) throw new Error('[RedactionPlugin] Document not found');\n\n const page = document.pages[opts.pageIndex];\n if (!page) throw new Error('[RedactionPlugin] Page not found');\n\n const handlers = createMarqueeHandler({\n pageSize: page.size,\n scale: opts.scale,\n onPreview: opts.callback.onPreview,\n onCommit: (r) => {\n const item: RedactionItem = {\n id: uuidV4(),\n kind: 'area',\n page: opts.pageIndex,\n rect: r,\n };\n this.dispatch(addPending([item]));\n this.pending$.emit(this.state.pending);\n opts.callback.onCommit?.(r);\n this.enableRedactSelection();\n this.selectPending(opts.pageIndex, item.id);\n },\n });\n\n const off = this.interactionManagerCapability.registerAlways({\n handlers: {\n onPointerDown: (_, evt) => {\n if (evt.target === evt.currentTarget) {\n this.deselectPending();\n }\n },\n },\n scope: {\n type: 'page',\n pageIndex: opts.pageIndex,\n },\n });\n\n const off2 = this.interactionManagerCapability.registerHandlers({\n modeId: 'marqueeRedact',\n handlers,\n pageIndex: opts.pageIndex,\n });\n\n return () => {\n off();\n off2();\n };\n }\n\n private queueCurrentSelectionAsPending(): Task<boolean, PdfErrorReason> {\n if (!this.selectionCapability)\n return PdfTaskHelper.reject({\n code: PdfErrorCode.NotFound,\n message: '[RedactionPlugin] selection plugin required',\n });\n\n const doc = this.coreState.core.document;\n if (!doc)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Document not found' });\n\n const formatted = this.selectionCapability.getFormattedSelection();\n if (!formatted.length) return PdfTaskHelper.resolve(true);\n\n const id = uuidV4();\n\n const items: RedactionItem[] = formatted.map((s) => ({\n id,\n kind: 'text',\n page: s.pageIndex,\n boundingRect: s.rect,\n rects: s.segmentRects,\n }));\n\n this.enableRedactSelection();\n this.dispatch(addPending(items));\n this.pending$.emit(this.state.pending);\n // optional: auto-select the last one added\n const last = items[items.length - 1];\n this.selectPending(last.page, last.id);\n\n // clear live UI selection\n this.redactionSelection$.emit([]);\n this.selectionCapability?.clear();\n\n return PdfTaskHelper.resolve(true);\n }\n\n private commitPendingOne(page: number, id: string): Task<boolean, PdfErrorReason> {\n const doc = this.coreState.core.document;\n if (!doc)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Document not found' });\n\n const item = (this.state.pending[page] ?? []).find((it) => it.id === id);\n if (!item) return PdfTaskHelper.resolve(true);\n\n const rects: Rect[] = item.kind === 'text' ? item.rects : [item.rect];\n const pdfPage = doc.pages[page];\n if (!pdfPage)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Page not found' });\n\n const task = new Task<boolean, PdfErrorReason>();\n this.engine.redactTextInRects(doc, pdfPage, rects, false, this.config.blackbox).wait(\n () => {\n this.dispatch(removePending(page, id));\n this.pending$.emit(this.state.pending);\n this.dispatchCoreAction(refreshPages([page]));\n task.resolve(true);\n },\n () => task.reject({ code: PdfErrorCode.Unknown, message: 'Failed to commit redactions' }),\n );\n\n return task;\n }\n\n private commitAllPending(): Task<boolean, PdfErrorReason> {\n const doc = this.coreState.core.document;\n if (!doc)\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Document not found' });\n\n // group rects per page\n const perPage = new Map<number, Rect[]>();\n for (const [page, items] of Object.entries(this.state.pending)) {\n const p = Number(page);\n const list = perPage.get(p) ?? [];\n for (const it of items) {\n if (it.kind === 'text') list.push(...it.rects);\n else list.push(it.rect);\n }\n perPage.set(p, list);\n }\n\n const pagesToRefresh = Array.from(perPage.entries())\n .filter(([_, rects]) => rects.length > 0)\n .map(([pageIndex]) => pageIndex);\n\n const tasks: PdfTask<boolean>[] = [];\n for (const [pageIndex, rects] of perPage) {\n const page = doc.pages[pageIndex];\n if (!page) continue;\n if (!rects.length) continue;\n tasks.push(this.engine.redactTextInRects(doc, page, rects, false, this.config.blackbox));\n }\n\n const task = new Task<boolean, PdfErrorReason>();\n Task.all(tasks).wait(\n () => {\n this.dispatch(clearPending());\n this.dispatchCoreAction(refreshPages(pagesToRefresh));\n this.pending$.emit(this.state.pending);\n task.resolve(true);\n },\n () => task.reject({ code: PdfErrorCode.Unknown, message: 'Failed to commit redactions' }),\n );\n\n return task;\n }\n\n override onStoreUpdated(_: RedactionState, newState: RedactionState): void {\n // keep external listeners in sync\n this.pending$.emit(newState.pending);\n this.selected$.emit(newState.selected);\n }\n\n async destroy(): Promise<void> {\n this.redactionSelection$.clear();\n this.pending$.clear();\n\n this.unsubscribeSelectionChange?.();\n this.unsubscribeEndSelection?.();\n this.unsubscribeModeChange?.();\n\n await super.destroy();\n }\n}\n","import { PluginManifest } from '@embedpdf/core';\nimport { RedactionPluginConfig } from './types';\n\nexport const REDACTION_PLUGIN_ID = 'redaction';\n\nexport const manifest: PluginManifest<RedactionPluginConfig> = {\n id: REDACTION_PLUGIN_ID,\n name: 'Redaction Plugin',\n version: '1.0.0',\n provides: ['redaction'],\n requires: [],\n optional: ['interaction-manager', 'selection'],\n defaultConfig: {\n enabled: true,\n blackbox: true,\n },\n};\n","import { RedactionState } from './types';\nimport {\n RedactionAction,\n ADD_PENDING,\n CLEAR_PENDING,\n END_REDACTION,\n REMOVE_PENDING,\n START_REDACTION,\n SELECT_PENDING,\n DESELECT_PENDING,\n} from './actions';\n\nexport const initialState: RedactionState = {\n isRedacting: false,\n pending: {},\n selected: null,\n};\n\nexport const redactionReducer = (state = initialState, action: RedactionAction): RedactionState => {\n switch (action.type) {\n case ADD_PENDING: {\n const next = { ...state.pending };\n for (const item of action.payload) {\n next[item.page] = (next[item.page] ?? []).concat(item);\n }\n return { ...state, pending: next };\n }\n\n case REMOVE_PENDING: {\n const { page, id } = action.payload;\n const list = state.pending[page] ?? [];\n const filtered = list.filter((it) => it.id !== id);\n const next = { ...state.pending, [page]: filtered };\n\n // if the removed one was selected → clear selection\n const stillSelected =\n state.selected && !(state.selected.page === page && state.selected.id === id);\n\n return { ...state, pending: next, selected: stillSelected ? state.selected : null };\n }\n\n case CLEAR_PENDING:\n return { ...state, pending: {}, selected: null };\n\n case SELECT_PENDING:\n return { ...state, selected: { page: action.payload.page, id: action.payload.id } };\n\n case DESELECT_PENDING:\n return { ...state, selected: null };\n\n case START_REDACTION:\n return { ...state, isRedacting: true };\n case END_REDACTION:\n return { ...state, pending: {}, selected: null, isRedacting: false };\n default:\n return state;\n }\n};\n","import { RedactionState } from './types';\n\nexport const getPendingRedactionsCount = (s: RedactionState) =>\n Object.values(s.pending).reduce((sum, list) => sum + (list?.length ?? 0), 0);\n\nexport const hasPendingRedactions = (s: RedactionState) =>\n Object.values(s.pending).some((list) => (list?.length ?? 0) > 0);\n","import { PluginPackage } from '@embedpdf/core';\nimport { RedactionPluginConfig, RedactionState } from './types';\nimport { RedactionPlugin } from './redaction-plugin';\nimport { manifest, REDACTION_PLUGIN_ID } from './manifest';\nimport { RedactionAction } from './actions';\nimport { initialState, redactionReducer } from './reducer';\n\nexport const RedactionPluginPackage: PluginPackage<\n RedactionPlugin,\n RedactionPluginConfig,\n RedactionState,\n RedactionAction\n> = {\n manifest,\n create: (registry, engine, config) =>\n new RedactionPlugin(REDACTION_PLUGIN_ID, registry, engine, config),\n reducer: redactionReducer,\n initialState: initialState,\n};\n\nexport * from './redaction-plugin';\nexport * from './types';\nexport * from './manifest';\nexport * from './selectors';\n"],"names":[],"mappings":"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"}
|