little refactor for pdf viewer

This commit is contained in:
Dan Percic 2021-11-06 02:04:46 +02:00
parent 0e90411f51
commit a3e2f1d498
3 changed files with 301 additions and 247 deletions

View File

@ -1,10 +1,18 @@
import { IManualRedactionEntry } from '@red/domain';
export const ManualRedactionEntryTypes = {
DICTIONARY: 'DICTIONARY',
REDACTION: 'REDACTION',
FALSE_POSITIVE: 'FALSE_POSITIVE',
} as const;
export type ManualRedactionEntryType = keyof typeof ManualRedactionEntryTypes;
export class ManualRedactionEntryWrapper {
constructor(
readonly quads: any,
readonly manualRedactionEntry: IManualRedactionEntry,
readonly type: 'DICTIONARY' | 'REDACTION' | 'FALSE_POSITIVE',
readonly type: ManualRedactionEntryType,
readonly annotationType: 'TEXT' | 'RECTANGLE' = 'TEXT',
readonly rectId?: string,
) {}

View File

@ -14,7 +14,11 @@ import {
import { File, IManualRedactionEntry, ViewMode } from '@red/domain';
import WebViewer, { Core, WebViewerInstance } from '@pdftron/webviewer';
import { TranslateService } from '@ngx-translate/core';
import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
import {
ManualRedactionEntryType,
ManualRedactionEntryTypes,
ManualRedactionEntryWrapper,
} from '@models/file/manual-redaction-entry.wrapper';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { ManualAnnotationService } from '../../services/manual-annotation.service';
import { environment } from '@environments/environment';
@ -33,7 +37,19 @@ import Tools = Core.Tools;
import TextTool = Tools.TextTool;
import Annotation = Core.Annotations.Annotation;
const allowedKeyboardShortcuts = ['+', '-', 'p', 'r', 'Escape'];
const ALLOWED_KEYBOARD_SHORTCUTS = ['+', '-', 'p', 'r', 'Escape'] as const;
const dataElements = {
ADD_REDACTION: 'add-redaction',
ADD_DICTIONARY: 'add-dictionary',
ADD_RECTANGLE: 'add-rectangle',
ADD_FALSE_POSITIVE: 'add-false-positive',
SHAPE_TOOL_GROUP_BUTTON: 'shapeToolGroupButton',
RECTANGLE_TOOL_DIVIDER: 'rectangleToolDivider',
ANNOTATION_POPUP: 'annotationPopup',
COMPARE_BUTTON: 'compareButton',
CLOSE_COMPARE_BUTTON: 'closeCompareButton',
COMPARE_TOOL_DIVIDER: 'compareToolDivider',
} as const;
@Component({
selector: 'redaction-pdf-viewer',
@ -57,6 +73,8 @@ export class PdfViewerComponent implements OnInit, OnChanges {
@ViewChild('viewer', { static: true }) viewer: ElementRef;
@ViewChild('compareFileInput', { static: true }) compareFileInput: ElementRef;
instance: WebViewerInstance;
documentViewer: Core.DocumentViewer;
annotationManager: Core.AnnotationManager;
utils: PdfViewerUtils;
private _selectedText = '';
private _firstPageChange = true;
@ -87,96 +105,90 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
async ngOnInit() {
this._documentLoaded = this._documentLoaded.bind(this);
this._setReadyAndInitialState = this._setReadyAndInitialState.bind(this);
await this._loadViewer();
}
ngOnChanges(changes: SimpleChanges): void {
if (this.instance) {
if (changes.fileData) {
this._loadDocument();
}
if (changes.canPerformActions) {
this._handleCustomActions();
}
if (changes.multiSelectActive) {
this.utils.multiSelectActive = this.multiSelectActive;
}
if (!this.instance) {
return;
}
}
setInitialViewerState() {
// viewer init
this.instance.UI.setFitMode('FitPage');
if (changes.fileData) {
this._loadDocument();
}
const instanceDisplayMode = this.instance.Core.documentViewer.getDisplayModeManager().getDisplayMode();
instanceDisplayMode.mode = this.viewMode === 'STANDARD' ? 'Single' : 'Facing';
this.instance.Core.documentViewer.getDisplayModeManager().setDisplayMode(instanceDisplayMode);
if (changes.canPerformActions) {
this._handleCustomActions();
}
if (changes.multiSelectActive) {
this.utils.multiSelectActive = this.multiSelectActive;
}
}
uploadFile(files: any) {
const fileToCompare = files[0];
this.compareFileInput.nativeElement.value = null;
const fileReader = new FileReader();
if (fileToCompare) {
fileReader.onload = async () => {
const pdfData = fileReader.result;
const pdfNet = this.instance.Core.PDFNet;
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
const mergedDocument = await pdfNet.PDFDoc.create();
const compareDocument = await pdfNet.PDFDoc.createFromBuffer(<any>pdfData);
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this.fileData.arrayBuffer());
const currentDocumentPageCount = await currentDocument.getPageCount();
const compareDocumentPageCount = await compareDocument.getPageCount();
const loadCompareDocument = async () => {
this._loadingService.start();
this.utils.ready = false;
await loadCompareDocumentWrapper(
currentDocumentPageCount,
compareDocumentPageCount,
currentDocument,
compareDocument,
mergedDocument,
this.instance,
this.file,
() => {
this.viewMode = 'COMPARE';
},
() => {
this.utils.navigateToPage(1);
},
this.instance.Core.PDFNet,
);
this._loadingService.stop();
};
if (currentDocumentPageCount !== compareDocumentPageCount) {
this._dialogService.openDialog(
'confirm',
null,
new ConfirmationDialogInput({
title: _('confirmation-dialog.compare-file.title'),
question: _('confirmation-dialog.compare-file.question'),
translateParams: {
fileName: fileToCompare.name,
currentDocumentPageCount,
compareDocumentPageCount,
},
}),
loadCompareDocument,
);
} else {
await loadCompareDocument();
}
};
if (!fileToCompare) {
console.error('No file to compare!');
return;
}
const fileReader = new FileReader();
fileReader.onload = async () => {
const pdfNet = this.instance.Core.PDFNet;
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
const compareDocument = await pdfNet.PDFDoc.createFromBuffer(fileReader.result as ArrayBuffer);
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this.fileData.arrayBuffer());
const loadCompareDocument = async () => {
this._loadingService.start();
this.utils.ready = false;
const mergedDocument = await pdfNet.PDFDoc.create();
await loadCompareDocumentWrapper(
currentDocument,
compareDocument,
mergedDocument,
this.instance,
this.file,
() => {
this.viewMode = 'COMPARE';
},
() => {
this.utils.navigateToPage(1);
},
this.instance.Core.PDFNet,
);
this._loadingService.stop();
};
const currentDocumentPageCount = await currentDocument.getPageCount();
const compareDocumentPageCount = await compareDocument.getPageCount();
if (currentDocumentPageCount !== compareDocumentPageCount) {
this._dialogService.openDialog(
'confirm',
null,
new ConfirmationDialogInput({
title: _('confirmation-dialog.compare-file.title'),
question: _('confirmation-dialog.compare-file.question'),
translateParams: {
fileName: fileToCompare.name,
currentDocumentPageCount,
compareDocumentPageCount,
},
}),
loadCompareDocument,
);
} else {
await loadCompareDocument();
}
};
fileReader.readAsArrayBuffer(fileToCompare);
}
@ -188,11 +200,18 @@ export class PdfViewerComponent implements OnInit, OnChanges {
this.instance.UI.loadDocument(currentDocument, {
filename: this.file ? this.file.filename : 'document.pdf',
});
this.instance.UI.disableElements(['closeCompareButton']);
this.instance.UI.enableElements(['compareButton']);
this.instance.UI.disableElements([dataElements.CLOSE_COMPARE_BUTTON]);
this.instance.UI.enableElements([dataElements.COMPARE_BUTTON]);
this.utils.navigateToPage(1);
}
private _setInitialDisplayMode() {
this.instance.UI.setFitMode('FitPage');
const instanceDisplayMode = this.documentViewer.getDisplayModeManager().getDisplayMode();
instanceDisplayMode.mode = this.viewMode === 'STANDARD' ? 'Single' : 'Facing';
this.documentViewer.getDisplayModeManager().setDisplayMode(instanceDisplayMode);
}
private _convertPath(path: string): string {
return this._baseHref + path;
}
@ -209,6 +228,8 @@ export class PdfViewerComponent implements OnInit, OnChanges {
this.viewer.nativeElement,
);
this.documentViewer = this.instance.Core.documentViewer;
this.annotationManager = this.instance.Core.annotationManager;
this.utils = new PdfViewerUtils(this.instance, this.viewMode, this.multiSelectActive);
this._setSelectionMode();
@ -216,8 +237,8 @@ export class PdfViewerComponent implements OnInit, OnChanges {
this.utils.disableHotkeys();
this._configureTextPopup();
this.instance.Core.annotationManager.on('annotationSelected', (annotations, action) => {
this.annotationSelected.emit(this.instance.Core.annotationManager.getSelectedAnnotations().map(ann => ann.Id));
this.annotationManager.on('annotationSelected', (annotations, action) => {
this.annotationSelected.emit(this.annotationManager.getSelectedAnnotations().map(ann => ann.Id));
if (action === 'deselected') {
this._toggleRectangleAnnotationAction(true);
} else {
@ -226,16 +247,16 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
});
this.instance.Core.annotationManager.on('annotationChanged', annotations => {
this.annotationManager.on('annotationChanged', annotations => {
// when a rectangle is drawn,
// it returns one annotation with tool name 'AnnotationCreateRectangle;
// this will auto select rectangle after drawing
if (annotations.length === 1 && annotations[0].ToolName === 'AnnotationCreateRectangle') {
this.instance.Core.annotationManager.selectAnnotations(annotations);
this.annotationManager.selectAnnotations(annotations);
}
});
this.instance.Core.documentViewer.on('pageNumberUpdated', pageNumber => {
this.documentViewer.on('pageNumberUpdated', pageNumber => {
if (this.shouldDeselectAnnotationsOnPageChange) {
this.utils.deselectAllAnnotations();
}
@ -251,9 +272,9 @@ export class PdfViewerComponent implements OnInit, OnChanges {
this._handleCustomActions();
});
this.instance.Core.documentViewer.on('documentLoaded', this._documentLoaded);
this.documentViewer.on('documentLoaded', this._setReadyAndInitialState);
this.instance.Core.documentViewer.on('keyUp', $event => {
this.documentViewer.on('keyUp', $event => {
// arrows and full-screen
if ($event.target?.tagName?.toLowerCase() !== 'input') {
if ($event.key.startsWith('Arrow') || $event.key === 'f') {
@ -265,18 +286,20 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
}
if (allowedKeyboardShortcuts.indexOf($event.key) < 0) {
if (ALLOWED_KEYBOARD_SHORTCUTS.indexOf($event.key) < 0) {
$event.preventDefault();
$event.stopPropagation();
}
});
this.instance.Core.documentViewer.on('textSelected', (quads, selectedText) => {
this.documentViewer.on('textSelected', (quads, selectedText) => {
this._selectedText = selectedText;
if (selectedText.length > 2 && this.canPerformActions) {
this.instance.UI.enableElements(['add-dictionary', 'add-false-positive']);
const textActions = [dataElements.ADD_DICTIONARY, dataElements.ADD_FALSE_POSITIVE];
if (selectedText.length > 2 && this.canPerformActions && !this.utils.isCurrentPageExcluded) {
this.instance.UI.enableElements(textActions);
} else {
this.instance.UI.disableElements(['add-dictionary', 'add-false-positive']);
this.instance.UI.disableElements(textActions);
}
});
@ -287,7 +310,7 @@ export class PdfViewerComponent implements OnInit, OnChanges {
inputElement.value = '';
}, 0);
if (!event.detail.isVisible) {
this.instance.Core.documentViewer.clearSearchResults();
this.documentViewer.clearSearchResults();
}
}
});
@ -296,15 +319,15 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
private _setSelectionMode(): void {
const textTool = (<unknown> this.instance.Core.Tools.TextTool) as TextTool;
const textTool = this.instance.Core.Tools.TextTool as unknown as TextTool;
textTool.SELECTION_MODE = this._configService.values.SELECTION_MODE;
}
private _toggleRectangleAnnotationAction(readonly: boolean) {
if (!readonly) {
this.instance.UI.enableElements(['add-rectangle']);
this.instance.UI.enableElements([dataElements.ADD_RECTANGLE]);
} else {
this.instance.UI.disableElements(['add-rectangle']);
this.instance.UI.disableElements([dataElements.ADD_RECTANGLE]);
}
}
@ -332,50 +355,59 @@ export class PdfViewerComponent implements OnInit, OnChanges {
'annotationGroupButton',
]);
this.instance.UI.setHeaderItems(header => {
const originalHeaderItems = header.getItems();
originalHeaderItems.splice(8, 0, {
const headerItems = [
{
type: 'divider',
dataElement: 'rectangleToolDivider',
});
originalHeaderItems.splice(9, 0, {
dataElement: dataElements.RECTANGLE_TOOL_DIVIDER,
},
{
type: 'toolGroupButton',
toolGroup: 'rectangleTools',
dataElement: 'shapeToolGroupButton',
dataElement: dataElements.SHAPE_TOOL_GROUP_BUTTON,
img: this._convertPath('/assets/icons/general/rectangle.svg'),
title: 'annotation.rectangle',
});
},
];
this.instance.UI.setHeaderItems(header => {
const originalHeaderItems = header.getItems();
originalHeaderItems.splice(8, 0, ...headerItems);
if (this._userPreferenceService.areDevFeaturesEnabled) {
originalHeaderItems.splice(11, 0, {
type: 'actionButton',
element: 'compare',
dataElement: 'compareButton',
img: this._convertPath('/assets/icons/general/pdftron-action-compare.svg'),
title: 'Compare',
onClick: () => {
this.compareFileInput.nativeElement.click();
const devHeaderItems = [
{
type: 'actionButton',
element: 'compare',
dataElement: dataElements.COMPARE_BUTTON,
img: this._convertPath('/assets/icons/general/pdftron-action-compare.svg'),
title: 'Compare',
onClick: () => {
this.compareFileInput.nativeElement.click();
},
},
});
originalHeaderItems.splice(11, 0, {
type: 'actionButton',
element: 'closeCompare',
dataElement: 'closeCompareButton',
img: this._convertPath('/assets/icons/general/pdftron-action-close-compare.svg'),
title: 'Leave Compare Mode',
onClick: () => {
this.closeCompareMode();
{
type: 'actionButton',
element: 'closeCompare',
dataElement: dataElements.CLOSE_COMPARE_BUTTON,
img: this._convertPath('/assets/icons/general/pdftron-action-close-compare.svg'),
title: 'Leave Compare Mode',
onClick: async () => {
await this.closeCompareMode();
},
},
});
originalHeaderItems.splice(13, 0, {
type: 'divider',
dataElement: 'compareToolDivider',
});
{
type: 'divider',
dataElement: dataElements.COMPARE_TOOL_DIVIDER,
},
];
originalHeaderItems.splice(11, 0, ...devHeaderItems);
}
});
this.instance.UI.disableElements(['closeCompareButton']);
this.instance.UI.disableElements([dataElements.CLOSE_COMPARE_BUTTON]);
this.instance.Core.documentViewer.getTool('AnnotationCreateRectangle').setStyles(() => ({
this.documentViewer.getTool('AnnotationCreateRectangle').setStyles(() => ({
StrokeThickness: 2,
StrokeColor: this._annotationDrawService.getColor(this.instance, 'manual'),
FillColor: this._annotationDrawService.getColor(this.instance, 'manual'),
@ -411,11 +443,11 @@ export class PdfViewerComponent implements OnInit, OnChanges {
onClick: () => {
this._ngZone.run(() => {
if (allAreVisible) {
this.instance.Core.annotationManager.hideAnnotations(viewerAnnotations);
this.annotationManager.hideAnnotations(viewerAnnotations);
} else {
this.instance.Core.annotationManager.showAnnotations(viewerAnnotations);
this.annotationManager.showAnnotations(viewerAnnotations);
}
this.instance.Core.annotationManager.deselectAllAnnotations();
this.annotationManager.deselectAllAnnotations();
this._annotationActionsService.updateHiddenAnnotation(this.annotations, viewerAnnotations, allAreVisible);
});
},
@ -429,38 +461,43 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
private _configureRectangleAnnotationPopup() {
this.instance.UI.annotationPopup.add(<any>{
type: 'actionButton',
dataElement: 'add-rectangle',
img: this._convertPath('/assets/icons/general/pdftron-action-add-redaction.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle('REDACTION')),
onClick: () => {
const selectedAnnotations = this.instance.Core.annotationManager.getSelectedAnnotations();
const activeAnnotation = selectedAnnotations[0];
const activePage = selectedAnnotations[0].getPageNumber();
const quad = this._annotationDrawService.annotationToQuads(activeAnnotation, this.instance);
const quadsObject = {};
quadsObject[activePage] = [quad];
const mre = this._getManualRedactionEntry(quadsObject, 'Rectangle');
// cleanup selection and button state
this.utils.deselectAllAnnotations();
this.instance.UI.disableElements(['shapeToolGroupButton', 'rectangleToolDivider']);
this.instance.UI.enableElements(['shapeToolGroupButton', 'rectangleToolDivider']);
// dispatch event
this.manualAnnotationRequested.emit(
new ManualRedactionEntryWrapper([quad], mre, 'REDACTION', 'RECTANGLE', activeAnnotation.Id),
);
this.instance.UI.annotationPopup.add([
{
type: 'actionButton',
dataElement: dataElements.ADD_RECTANGLE,
img: this._convertPath('/assets/icons/general/pdftron-action-add-redaction.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle('REDACTION')),
onClick: () => this._addRectangleManualRedaction(),
},
});
]);
}
private _addRectangleManualRedaction() {
const activeAnnotation = this.annotationManager.getSelectedAnnotations()[0];
const activePage = activeAnnotation.getPageNumber();
const quads = [this._annotationDrawService.annotationToQuads(activeAnnotation, this.instance)];
const manualRedaction = this._getManualRedaction({ [activePage]: quads }, 'Rectangle');
this._cleanUpSelectionAndButtonState();
this.manualAnnotationRequested.emit(
new ManualRedactionEntryWrapper(quads, manualRedaction, 'REDACTION', 'RECTANGLE', activeAnnotation.Id),
);
}
private _cleanUpSelectionAndButtonState() {
const rectangleElements = [dataElements.SHAPE_TOOL_GROUP_BUTTON, dataElements.RECTANGLE_TOOL_DIVIDER];
this.utils.deselectAllAnnotations();
this.instance.UI.disableElements(rectangleElements);
this.instance.UI.enableElements(rectangleElements);
}
private _configureTextPopup() {
this.instance.UI.textPopup.add(<any>{
const searchButton = {
type: 'actionButton',
img: this._convertPath('/assets/icons/general/pdftron-action-search.svg'),
title: this._translateService.instant('pdf-viewer.text-popup.actions.search'),
onClick: () => {
const text = this.instance.Core.documentViewer.getSelectedText();
const text = this.documentViewer.getSelectedText();
const searchOptions = {
caseSensitive: true, // match case
wholeWord: true, // match whole words only
@ -470,117 +507,118 @@ export class PdfViewerComponent implements OnInit, OnChanges {
ambientString: true, // return ambient string as part of the result
};
this.instance.UI.openElements(['searchPanel']);
setTimeout(() => {
this.instance.UI.searchTextFull(text, searchOptions);
}, 250);
setTimeout(() => this.instance.UI.searchTextFull(text, searchOptions), 250);
},
});
};
this.instance.UI.textPopup.add([searchButton]);
// Adding directly to the false-positive dict is only available in dev-mode
if (this._userPreferenceService.areDevFeaturesEnabled) {
this.instance.UI.textPopup.add(<any>{
type: 'actionButton',
dataElement: 'add-false-positive',
img: this._convertPath('/assets/icons/general/pdftron-action-false-positive.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle('FALSE_POSITIVE')),
onClick: () => {
const selectedQuads = this.instance.Core.documentViewer.getSelectedTextQuads();
const text = this.instance.Core.documentViewer.getSelectedText();
const mre = this._getManualRedactionEntry(selectedQuads, text, true);
this.manualAnnotationRequested.emit(
new ManualRedactionEntryWrapper(this.instance.Core.documentViewer.getSelectedTextQuads(), mre, 'FALSE_POSITIVE'),
);
this.instance.UI.textPopup.add([
{
type: 'actionButton',
dataElement: 'add-false-positive',
img: this._convertPath('/assets/icons/general/pdftron-action-false-positive.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle(ManualRedactionEntryTypes.FALSE_POSITIVE)),
onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.FALSE_POSITIVE),
},
});
]);
}
this.instance.UI.textPopup.add(<any>{
type: 'actionButton',
dataElement: 'add-dictionary',
img: this._convertPath('/assets/icons/general/pdftron-action-add-dict.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle('DICTIONARY')),
onClick: () => {
const selectedQuads = this.instance.Core.documentViewer.getSelectedTextQuads();
const text = this.instance.Core.documentViewer.getSelectedText();
const mre = this._getManualRedactionEntry(selectedQuads, text, true);
this.manualAnnotationRequested.emit(
new ManualRedactionEntryWrapper(this.instance.Core.documentViewer.getSelectedTextQuads(), mre, 'DICTIONARY'),
);
this.instance.UI.textPopup.add([
{
type: 'actionButton',
dataElement: 'add-redaction',
img: this._convertPath('/assets/icons/general/pdftron-action-add-redaction.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle(ManualRedactionEntryTypes.REDACTION)),
onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.REDACTION),
},
});
{
type: 'actionButton',
dataElement: 'add-dictionary',
img: this._convertPath('/assets/icons/general/pdftron-action-add-dict.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle(ManualRedactionEntryTypes.DICTIONARY)),
onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.DICTIONARY),
},
]);
this.instance.UI.textPopup.add(<any>{
type: 'actionButton',
dataElement: 'add-redaction',
img: this._convertPath('/assets/icons/general/pdftron-action-add-redaction.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle('REDACTION')),
onClick: () => {
const selectedQuads = this.instance.Core.documentViewer.getSelectedTextQuads();
const text = this.instance.Core.documentViewer.getSelectedText();
const mre = this._getManualRedactionEntry(selectedQuads, text, true);
this.manualAnnotationRequested.emit(
new ManualRedactionEntryWrapper(this.instance.Core.documentViewer.getSelectedTextQuads(), mre, 'REDACTION'),
);
},
});
this._handleCustomActions();
}
private _addManualRedactionOfType(type: ManualRedactionEntryType) {
const selectedQuads = this.documentViewer.getSelectedTextQuads();
const text = this.documentViewer.getSelectedText();
const manualRedaction = this._getManualRedaction(selectedQuads, text, true);
this.manualAnnotationRequested.emit(new ManualRedactionEntryWrapper(selectedQuads, manualRedaction, type));
}
private _handleCustomActions() {
this.instance.UI.setToolMode('AnnotationEdit');
const elements = [
'add-redaction',
'add-rectangle',
'add-false-positive',
'shapeToolGroupButton',
'rectangleToolDivider',
'annotationPopup',
];
if (this.canPerformActions && !this.utils.isCurrentPageExcluded) {
this.instance.UI.enableTools(['AnnotationCreateRectangle']);
this.instance.UI.enableElements([
'add-redaction',
'add-rectangle',
'add-false-positive',
'shapeToolGroupButton',
'rectangleToolDivider',
'annotationPopup',
]);
this.instance.UI.enableElements(elements);
if (this._selectedText.length > 2) {
this.instance.UI.enableElements(['add-dictionary', 'add-false-positive']);
this.instance.UI.enableElements([dataElements.ADD_DICTIONARY, dataElements.ADD_FALSE_POSITIVE]);
}
} else {
this.instance.UI.disableTools(['AnnotationCreateRectangle']);
this.instance.UI.disableElements([
'add-redaction',
'add-dictionary',
'add-false-positive',
'add-rectangle',
'shapeToolGroupButton',
'rectangleToolDivider',
'annotationPopup',
]);
return;
}
const elementsToDisable = [...elements, dataElements.ADD_RECTANGLE];
if (this.utils.isCurrentPageExcluded) {
elementsToDisable.splice(elementsToDisable.indexOf(dataElements.ADD_REDACTION), 1);
elementsToDisable.splice(elementsToDisable.indexOf(dataElements.SHAPE_TOOL_GROUP_BUTTON), 1);
}
this.instance.UI.disableTools(['AnnotationCreateRectangle']);
this.instance.UI.disableElements(elementsToDisable);
}
private _getManualRedactionEntry(quads: any, text: string, convertQuads: boolean = false): IManualRedactionEntry {
private _getManualRedaction(
quads: Readonly<Record<string, Core.Math.Quad[]>>,
text: string,
convertQuads = false,
): IManualRedactionEntry {
const entry: IManualRedactionEntry = { positions: [] };
for (const key of Object.keys(quads)) {
for (const quad of quads[key]) {
const page = parseInt(key, 10);
entry.positions.push(this.utils.toPosition(page, convertQuads ? this.utils.translateQuads(page, quad) : quad));
}
}
entry.value = text;
return entry;
}
private _loadDocument() {
if (this.fileData) {
this.instance.UI.loadDocument(this.fileData, {
filename: this.file ? this.file.filename : 'document.pdf',
});
if (!this.fileData) {
return;
}
this.instance.UI.loadDocument(this.fileData, {
filename: this.file ? this.file.filename : 'document.pdf',
});
}
private _documentLoaded(): void {
private _setReadyAndInitialState(): void {
this._ngZone.run(() => {
this.utils.ready = true;
this._firstPageChange = true;
this.viewerReady.emit(this.instance);
this.setInitialViewerState();
this._setInitialDisplayMode();
});
}
}

View File

@ -1,34 +1,42 @@
import { stampPDFPage } from '@utils/page-stamper';
import { Core, WebViewerInstance } from '@pdftron/webviewer';
import { File } from '@red/domain';
const processPage = async (pageNumber, document1, document2, mergedDocument, pdfNet) => {
const processPage = async (
pageNumber: number,
document1: Core.PDFNet.PDFDoc,
document2: Core.PDFNet.PDFDoc,
mergedDocument: Core.PDFNet.PDFDoc,
pdfNet: typeof Core.PDFNet,
) => {
const document1PageCount = await document1.getPageCount();
if (document1PageCount >= pageNumber) {
await mergedDocument.insertPages(pageNumber * 2, document1, pageNumber, pageNumber, pdfNet.PDFDoc.InsertFlag.e_none);
} else {
const pageToCopy = await document2.getPage(pageNumber);
const blankPage = await mergedDocument.pageCreate(await pageToCopy.getCropBox());
await blankPage.setRotation(await pageToCopy.getRotation());
await mergedDocument.pagePushBack(blankPage);
await stampPDFPage(mergedDocument, pdfNet, '<< Compare Placeholder Page >>', 20, 'courier', 'DIAGONAL', 33, '#ffb83b', [
await mergedDocument.getPageCount(),
]);
return;
}
const pageToCopy = await document2.getPage(pageNumber);
const blankPage = await mergedDocument.pageCreate(await pageToCopy.getCropBox());
await blankPage.setRotation(await pageToCopy.getRotation());
await mergedDocument.pagePushBack(blankPage);
await stampPDFPage(mergedDocument, pdfNet, '<< Compare Placeholder Page >>', 20, 'courier', 'DIAGONAL', 33, '#ffb83b', [
await mergedDocument.getPageCount(),
]);
};
export const loadCompareDocumentWrapper = async (
currentDocumentPageCount,
compareDocumentPageCount,
currentDocument,
compareDocument,
mergedDocument,
instance,
file,
currentDocument: Core.PDFNet.PDFDoc,
compareDocument: Core.PDFNet.PDFDoc,
mergedDocument: Core.PDFNet.PDFDoc,
instance: WebViewerInstance,
file: File,
setCompareViewMode: () => void,
navigateToPage: () => void,
pdfNet: any,
pdfNet: typeof Core.PDFNet,
) => {
try {
const maxPageCount = Math.max(currentDocumentPageCount, compareDocumentPageCount);
const maxPageCount = Math.max(await currentDocument.getPageCount(), await compareDocument.getPageCount());
for (let idx = 1; idx <= maxPageCount; idx++) {
await processPage(idx, currentDocument, compareDocument, mergedDocument, pdfNet);
@ -43,11 +51,11 @@ export const loadCompareDocumentWrapper = async (
setCompareViewMode();
instance.loadDocument(mergedDocumentBuffer, {
instance.UI.loadDocument(mergedDocumentBuffer, {
filename: file?.filename ?? 'document.pdf',
});
instance.disableElements(['compareButton']);
instance.enableElements(['closeCompareButton']);
instance.UI.disableElements(['compareButton']);
instance.UI.enableElements(['closeCompareButton']);
navigateToPage();
} catch (e) {