RED-3988: remove old pdf viewer stuff

This commit is contained in:
Dan Percic 2022-05-20 13:26:01 +03:00
parent fe37a78488
commit 1edab7c304
23 changed files with 242 additions and 265 deletions

View File

@ -1,8 +1,6 @@
<router-outlet></router-outlet>
<redaction-reusable-pdf-viewer
[style.visibility]="(reusablePdfViewer.documentLoaded$ | async) ? 'visible' : 'hidden'"
></redaction-reusable-pdf-viewer>
<redaction-pdf-viewer [style.visibility]="(pdf.loaded$ | async) ? 'visible' : 'hidden'"></redaction-pdf-viewer>
<iqser-full-page-loading-indicator></iqser-full-page-loading-indicator>
<iqser-connection-status></iqser-connection-status>

View File

@ -1,7 +1,7 @@
import { Component, ViewContainerRef } from '@angular/core';
import { RouterHistoryService } from '@services/router-history.service';
import { UserService } from '@services/user.service';
import { ReusablePdfViewer } from './modules/shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { PdfViewer } from '@shared/components/reusable-pdf-viewer/pdf-viewer.service';
@Component({
selector: 'redaction-root',
@ -15,6 +15,6 @@ export class AppComponent {
public viewContainerRef: ViewContainerRef,
private readonly _routerHistoryService: RouterHistoryService,
private readonly _userService: UserService,
readonly reusablePdfViewer: ReusablePdfViewer,
readonly pdf: PdfViewer,
) {}
}

View File

@ -52,7 +52,7 @@ import { LoggerModule, NgxLoggerLevel, TOKEN_LOGGER_CONFIG, TOKEN_LOGGER_RULES_S
import { LoggerRulesService } from '@services/logger-rules.service';
import { ILoggerConfig } from '@red/domain';
import { SystemPreferencesService } from '@services/system-preferences.service';
import { ReusablePdfViewerComponent } from './modules/shared/components/reusable-pdf-viewer/reusable-pdf-viewer.component';
import { PdfViewerComponent } from '@shared/components/reusable-pdf-viewer/pdf-viewer.component';
export function httpLoaderFactory(httpClient: HttpClient, configService: ConfigService): PruningTranslationLoader {
return new PruningTranslationLoader(httpClient, '/assets/i18n/', `.json?version=${configService.values.FRONTEND_APP_VERSION}`);
@ -72,7 +72,7 @@ const screens = [BaseScreenComponent, DownloadsListScreenComponent];
const components = [
AppComponent,
ReusablePdfViewerComponent,
PdfViewerComponent,
AuthErrorComponent,
NotificationsComponent,
SpotlightSearchComponent,

View File

@ -10,15 +10,15 @@ import {
TemplateRef,
} from '@angular/core';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { FilterService, HasScrollbarDirective, IqserEventTarget, ListingService } from '@iqser/common-ui';
import { FilterService, HasScrollbarDirective, IqserEventTarget } from '@iqser/common-ui';
import { MultiSelectService } from '../../services/multi-select.service';
import { AnnotationReferencesService } from '../../services/annotation-references.service';
import { UserPreferenceService } from '@services/user-preference.service';
import { ViewModeService } from '../../services/view-mode.service';
import { BehaviorSubject } from 'rxjs';
import { TextHighlightsGroup } from '@red/domain';
import { PdfViewer } from '../../services/pdf-viewer.service';
import { REDAnnotationManager } from '../../../shared/components/reusable-pdf-viewer/annotation-manager.service';
import { AnnotationsListingService } from '../../services/annotations-listing.service';
@Component({
selector: 'redaction-annotations-list',
@ -41,9 +41,8 @@ export class AnnotationsListComponent extends HasScrollbarDirective implements O
private readonly _filterService: FilterService,
private readonly _userPreferenceService: UserPreferenceService,
private readonly _viewModeService: ViewModeService,
private readonly _pdf: PdfViewer,
private readonly _annotationManager: REDAnnotationManager,
private readonly _listingService: ListingService<AnnotationWrapper>,
private readonly _listingService: AnnotationsListingService,
readonly annotationReferencesService: AnnotationReferencesService,
) {
super(_elementRef, _changeDetector);
@ -77,7 +76,7 @@ export class AnnotationsListComponent extends HasScrollbarDirective implements O
if (canMultiSelect && ($event?.ctrlKey || $event?.metaKey) && this._listingService.selected.length > 0) {
this._multiSelectService.activate();
}
this._pdf.selectAnnotations([annotation]);
this._listingService.selectAnnotations([annotation]);
}
}

View File

@ -21,7 +21,6 @@ import {
IconButtonTypes,
INestedFilter,
IqserEventTarget,
ListingService,
shareDistinctLast,
shareLast,
} from '@iqser/common-ui';
@ -36,9 +35,9 @@ import { FilePreviewStateService } from '../../services/file-preview-state.servi
import { ViewModeService } from '../../services/view-mode.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FileDataService } from '../../services/file-data.service';
import { PdfViewer } from '../../services/pdf-viewer.service';
import { ReusablePdfViewer } from '../../../shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { PdfViewer } from '../../../shared/components/reusable-pdf-viewer/pdf-viewer.service';
import { REDAnnotationManager } from '../../../shared/components/reusable-pdf-viewer/annotation-manager.service';
import { AnnotationsListingService } from '../../services/annotations-listing.service';
const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape'];
const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
@ -73,19 +72,18 @@ export class FileWorkloadComponent {
readonly filterService: FilterService,
readonly skippedService: SkippedService,
readonly state: FilePreviewStateService,
readonly multiSelectService: MultiSelectService,
readonly documentInfoService: DocumentInfoService,
readonly excludedPagesService: ExcludedPagesService,
readonly pdf: PdfViewer,
readonly fileDataService: FileDataService,
readonly viewModeService: ViewModeService,
readonly listingService: ListingService<AnnotationWrapper>,
readonly pdf: PdfViewer,
readonly reusablePdf: ReusablePdfViewer,
readonly multiSelectService: MultiSelectService,
readonly annotationManager: REDAnnotationManager,
readonly documentInfoService: DocumentInfoService,
readonly listingService: AnnotationsListingService,
readonly excludedPagesService: ExcludedPagesService,
private readonly _changeDetectorRef: ChangeDetectorRef,
private readonly _annotationProcessingService: AnnotationProcessingService,
) {
this.reusablePdf.currentPage$.pipe(takeWhile(() => !!this)).subscribe(pageNumber => {
this.pdf.currentPage$.pipe(takeWhile(() => !!this)).subscribe(pageNumber => {
this._scrollViews();
this.scrollAnnotationsToPage(pageNumber, 'always');
});
@ -183,7 +181,7 @@ export class FileWorkloadComponent {
}
selectAllOnActivePage() {
this.pdf.selectAnnotations(this.activeAnnotations);
this.listingService.selectAnnotations(this.activeAnnotations);
}
deselectAllOnActivePage(): void {
@ -295,19 +293,19 @@ export class FileWorkloadComponent {
if (!this._firstSelectedAnnotation || this.activeViewerPage !== this._firstSelectedAnnotation.pageNumber) {
if (this.displayedPages.indexOf(this.activeViewerPage) !== -1) {
// Displayed page has annotations
return this.pdf.selectAnnotations(this.activeAnnotations ? [this.activeAnnotations[0]] : null);
return this.listingService.selectAnnotations(this.activeAnnotations ? [this.activeAnnotations[0]] : null);
}
// Displayed page doesn't have annotations
if ($event.key === 'ArrowDown') {
const nextPage = this._nextPageWithAnnotations();
return this.pdf.selectAnnotations([this.displayedAnnotations.get(nextPage)[0]]);
return this.listingService.selectAnnotations([this.displayedAnnotations.get(nextPage)[0]]);
}
const prevPage = this._prevPageWithAnnotations();
const prevPageAnnotations = this.displayedAnnotations.get(prevPage);
return this.pdf.selectAnnotations([prevPageAnnotations[prevPageAnnotations.length - 1]]);
return this.listingService.selectAnnotations([prevPageAnnotations[prevPageAnnotations.length - 1]]);
}
const page = this._firstSelectedAnnotation.pageNumber;
@ -320,13 +318,13 @@ export class FileWorkloadComponent {
if ($event.key === 'ArrowDown') {
if (idx + 1 !== annotationsOnPage.length) {
// If not last item in page
this.pdf.selectAnnotations([annotationsOnPage[idx + 1]]);
this.listingService.selectAnnotations([annotationsOnPage[idx + 1]]);
} else if (nextPageIdx < this.displayedPages.length) {
// If not last page
for (let i = nextPageIdx; i < this.displayedPages.length; i++) {
const nextPageAnnotations = this.displayedAnnotations.get(this.displayedPages[i]);
if (nextPageAnnotations) {
this.pdf.selectAnnotations([nextPageAnnotations[0]]);
this.listingService.selectAnnotations([nextPageAnnotations[0]]);
break;
}
}
@ -336,7 +334,7 @@ export class FileWorkloadComponent {
if (idx !== 0) {
// If not first item in page
return this.pdf.selectAnnotations([annotationsOnPage[idx - 1]]);
return this.listingService.selectAnnotations([annotationsOnPage[idx - 1]]);
}
if (pageIdx) {
@ -344,7 +342,7 @@ export class FileWorkloadComponent {
for (let i = previousPageIdx; i >= 0; i--) {
const prevPageAnnotations = this.displayedAnnotations.get(this.displayedPages[i]);
if (prevPageAnnotations) {
this.pdf.selectAnnotations([prevPageAnnotations[prevPageAnnotations.length - 1]]);
this.listingService.selectAnnotations([prevPageAnnotations[prevPageAnnotations.length - 1]]);
break;
}
}
@ -398,7 +396,7 @@ export class FileWorkloadComponent {
this.displayedPages.indexOf(this.activeViewerPage) >= 0 &&
this.activeAnnotations.length > 0
) {
this.pdf.selectAnnotations([this.activeAnnotations[0]]);
this.listingService.selectAnnotations([this.activeAnnotations[0]]);
}
}

View File

@ -1,16 +1,16 @@
<input #compareFileInput (change)="uploadFile($event.target['files'])" accept="application/pdf" class="file-upload-input" type="file" />
<div *ngIf="reusablePdf.documentLoaded$ | async" class="pagination noselect">
<div (click)="pdfViewer.navigatePreviousPage()">
<div *ngIf="pdf.loaded$ | async" class="pagination noselect">
<div (click)="pdf.navigatePreviousPage()">
<mat-icon class="chevron-icon" svgIcon="red:nav-prev"></mat-icon>
</div>
<div>
<input
#pageInput
(change)="pdfViewer.navigateToPage(pageInput.value)"
[max]="reusablePdf.totalPages$ | async"
[value]="reusablePdf.currentPage$ | async"
(change)="pdf.navigateTo(pageInput.value)"
[max]="pdf.totalPages$ | async"
[value]="pdf.currentPage$ | async"
class="page-number-input"
min="1"
type="number"
@ -20,10 +20,10 @@
<div class="separator">/</div>
<div>
{{ reusablePdf.totalPages$ | async }}
{{ pdf.totalPages$ | async }}
</div>
<div (click)="pdfViewer.navigateNextPage()">
<div (click)="pdf.navigateNextPage()">
<mat-icon class="chevron-icon" svgIcon="red:nav-next"></mat-icon>
</div>
</div>

View File

@ -27,7 +27,6 @@ import { UserPreferenceService } from '@services/user-preference.service';
import { BASE_HREF } from '../../../../tokens';
import { ConfigService } from '@services/config.service';
import { AutoUnsubscribe, ConfirmationDialogInput, ErrorService, LoadingService, log } from '@iqser/common-ui';
import { PdfViewer } from '../../services/pdf-viewer.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { toPosition } from '../../utils/pdf-calculation.utils';
import { MultiSelectService } from '../../services/multi-select.service';
@ -42,16 +41,17 @@ import { FileDataService } from '../../services/file-data.service';
import { ViewerHeaderConfigService } from '../../services/viewer-header-config.service';
import { TooltipsService } from '../../services/tooltips.service';
import { ManualRedactionService } from '../../services/manual-redaction.service';
import { ReusablePdfViewer } from '../../../shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { PdfViewer } from '../../../shared/components/reusable-pdf-viewer/pdf-viewer.service';
import { REDAnnotationManager } from '../../../shared/components/reusable-pdf-viewer/annotation-manager.service';
import { translateQuads } from '../../../../utils';
import Annotation = Core.Annotations.Annotation;
@Component({
selector: 'redaction-pdf-viewer',
templateUrl: './pdf-viewer.component.html',
styleUrls: ['./pdf-viewer.component.scss'],
templateUrl: './pdf-paginator.component.html',
styleUrls: ['./pdf-paginator.component.scss'],
})
export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnChanges {
export class PdfPaginatorComponent extends AutoUnsubscribe implements OnInit, OnChanges {
@Input() dossier: Dossier;
@Input() canPerformActions = false;
@Output() readonly annotationSelected = new EventEmitter<string[]>();
@ -81,10 +81,9 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
private readonly _tooltipsService: TooltipsService,
private readonly _errorService: ErrorService,
private readonly _annotationManager: REDAnnotationManager,
readonly reusablePdf: ReusablePdfViewer,
readonly pdf: PdfViewer,
readonly stateService: FilePreviewStateService,
readonly multiSelectService: MultiSelectService,
readonly pdfViewer: PdfViewer,
) {
super();
}
@ -96,10 +95,10 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
this.addActiveScreenSubscription = this.stateService.blob$
.pipe(
log('Reload blob'),
switchMap(blob => from(this.reusablePdf.lockDocument()).pipe(map(() => blob))),
switchMap(blob => from(this.pdf.lockDocument()).pipe(map(() => blob))),
withLatestFrom(this.stateService.file$),
tap(() => this._errorService.clear()),
tap(([blob, file]) => this.reusablePdf.loadDocument(blob, file)),
tap(([blob, file]) => this.pdf.loadDocument(blob, file)),
tap(() => this._pageRotationService.clearRotationsHideActions()),
)
.subscribe();
@ -141,10 +140,10 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
this.instance,
file,
() => {
this.reusablePdf.openCompareMode();
this.pdf.openCompareMode();
},
() => {
this.pdfViewer.navigateToPage(1);
this.pdf.navigateTo(1);
},
this.instance.Core.PDFNet,
);
@ -180,9 +179,9 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
}
private _loadViewer() {
this.instance = this.reusablePdf.instance;
this.documentViewer = this.reusablePdf.documentViewer;
this.annotationManager = this.reusablePdf.annotationManager;
this.instance = this.pdf.instance;
this.documentViewer = this.pdf.documentViewer;
this.annotationManager = this.pdf.annotationManager;
this._configureElements();
this._configureTextPopup();
@ -254,13 +253,14 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
const file = this.stateService.file;
if (this.reusablePdf.isCompare && pageNumber % 2 === 0) {
if (this.pdf.isCompare && pageNumber % 2 === 0) {
this.instance.UI.disableElements(['textPopup']);
} else {
this.instance.UI.enableElements(['textPopup']);
}
if (selectedText.length > 2 && this.canPerformActions && !this.pdfViewer.isCurrentPageExcluded(file)) {
const isCurrentPageExcluded = file.isPageExcluded(this.pdf.currentPage);
if (selectedText.length > 2 && this.canPerformActions && !isCurrentPageExcluded) {
this.instance.UI.enableElements(textActions);
} else {
this.instance.UI.disableElements(textActions);
@ -283,7 +283,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
private _setInitialDisplayMode() {
this.instance.UI.setFitMode('FitPage');
const instanceDisplayMode = this.documentViewer.getDisplayModeManager().getDisplayMode();
instanceDisplayMode.mode = this.reusablePdf.isCompare ? 'Facing' : 'Single';
instanceDisplayMode.mode = this.pdf.isCompare ? 'Facing' : 'Single';
this.documentViewer.getDisplayModeManager().setDisplayMode(instanceDisplayMode);
}
@ -360,7 +360,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
}
private _configureRectangleAnnotationPopup(annotation: Annotation) {
if (!this.reusablePdf.isCompare || annotation.getPageNumber() % 2 === 1) {
if (!this.pdf.isCompare || annotation.getPageNumber() % 2 === 1) {
this.instance.UI.annotationPopup.add([
{
type: 'actionButton',
@ -459,7 +459,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
HeaderElements.ROTATE_RIGHT_BUTTON,
];
const isCurrentPageExcluded = this.pdfViewer.isCurrentPageExcluded(this.stateService.file);
const isCurrentPageExcluded = this.stateService.file.isPageExcluded(this.pdf.currentPage);
if (this.canPerformActions && !isCurrentPageExcluded) {
try {
@ -507,7 +507,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
for (const quad of quads[key]) {
const page = parseInt(key, 10);
const pageHeight = this.documentViewer.getPageHeight(page);
entry.positions.push(toPosition(page, pageHeight, convertQuads ? this.pdfViewer.translateQuad(page, quad) : quad));
entry.positions.push(toPosition(page, pageHeight, convertQuads ? this.#translateQuad(page, quad) : quad));
}
}
@ -516,6 +516,11 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
return entry;
}
#translateQuad(page: number, quad: Core.Math.Quad) {
const rotation = this.pdf.documentViewer.getCompleteRotation(page);
return translateQuads(page, rotation, quad);
}
private _setReadyAndInitialState() {
this._ngZone.run(() => {
this._setInitialDisplayMode();

View File

@ -12,7 +12,6 @@ import { EntitiesService, FilterService, ListingService, SearchService } from '@
import { AnnotationProcessingService } from './services/annotation-processing.service';
import { dossiersServiceProvider } from '@services/entity-services/dossiers.service.provider';
import { PageRotationService } from './services/page-rotation.service';
import { PdfViewer } from './services/pdf-viewer.service';
import { FileDataService } from './services/file-data.service';
import { ViewerHeaderConfigService } from './services/viewer-header-config.service';
import { TooltipsService } from './services/tooltips.service';
@ -32,14 +31,14 @@ export const filePreviewScreenProviders = [
FilePreviewStateService,
AnnotationReferencesService,
PageRotationService,
PdfViewer,
AnnotationProcessingService,
FileDataService,
{ provide: EntitiesService, useExisting: FileDataService },
dossiersServiceProvider,
ViewerHeaderConfigService,
TooltipsService,
{ provide: ListingService, useClass: AnnotationsListingService },
AnnotationsListingService,
{ provide: ListingService, useExisting: AnnotationsListingService },
SearchService,
StampService,
];

View File

@ -86,7 +86,7 @@
<redaction-file-workload
(selectPage)="selectPage($event)"
*ngIf="!file.excluded"
[activeViewerPage]="reusablePdf.currentPage$ | async"
[activeViewerPage]="pdf.currentPage$ | async"
[annotationActionsTemplate]="annotationActionsTemplate"
[dialogRef]="dialogRef"
[file]="file"

View File

@ -45,13 +45,12 @@ import { ManualRedactionService } from './services/manual-redaction.service';
import { DossiersService } from '@services/dossiers/dossiers.service';
import { PageRotationService } from './services/page-rotation.service';
import { ComponentCanDeactivate } from '@guards/can-deactivate.guard';
import { PdfViewer } from './services/pdf-viewer.service';
import { FilePreviewDialogService } from './services/file-preview-dialog.service';
import { FileDataService } from './services/file-data.service';
import { ActionsHelpModeKeys, ALL_HOTKEYS } from './utils/constants';
import { NGXLogger } from 'ngx-logger';
import { StampService } from './services/stamp.service';
import { ReusablePdfViewer } from '../shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { PdfViewer } from '../shared/components/reusable-pdf-viewer/pdf-viewer.service';
import { REDAnnotationManager } from '../shared/components/reusable-pdf-viewer/annotation-manager.service';
import Annotation = Core.Annotations.Annotation;
@ -79,7 +78,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
constructor(
readonly pdf: PdfViewer,
readonly reusablePdf: ReusablePdfViewer,
readonly documentInfoService: DocumentInfoService,
readonly state: FilePreviewStateService,
readonly listingService: ListingService<AnnotationWrapper>,
@ -129,7 +127,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
private get _canPerformAnnotationActions$() {
const viewMode$ = this._viewModeService.viewMode$.pipe(tap(() => this.#deactivateMultiSelect()));
return combineLatest([this.state.file$, this.state.dossier$, viewMode$, this.reusablePdf.compareMode$]).pipe(
return combineLatest([this.state.file$, this.state.dossier$, viewMode$, this.pdf.compareMode$]).pipe(
map(
([file, dossier, viewMode]) =>
this.permissionsService.canPerformAnnotationActions(file, dossier) && viewMode === 'STANDARD',
@ -194,7 +192,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
ngOnDetach(): void {
this._pageRotationService.clearRotations();
this.reusablePdf.closeDocument();
this.pdf.closeDocument();
super.ngOnDetach();
this._changeDetectorRef.markForCheck();
}
@ -237,7 +235,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
selectPage(pageNumber: number) {
this.pdf.navigateToPage(pageNumber);
this.pdf.navigateTo(pageNumber);
this._lastPage = pageNumber.toString();
}
@ -348,11 +346,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
loadAnnotations() {
const documentLoaded$ = this.reusablePdf.documentLoaded$.pipe(
const documentLoaded$ = this.pdf.loaded$.pipe(
filter(s => s),
tap(() => this.viewerReady()),
);
const currentPageAnnotations$ = combineLatest([this.reusablePdf.currentPage$, this._fileDataService.annotations$]).pipe(
const currentPageAnnotations$ = combineLatest([this.pdf.currentPage$, this._fileDataService.annotations$]).pipe(
map(([page, annotations]) => annotations.filter(annotation => annotation.pageNumber === page)),
);
let start;
@ -480,10 +478,12 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
private _setExcludedPageStyles() {
const file = this._filesMapService.get(this.dossierId, this.fileId);
setTimeout(() => {
const iframeDoc = this.reusablePdf.instance.UI.iframeWindow.document;
const pageContainer = iframeDoc.getElementById(`pageWidgetContainer${this.pdf.currentPage}`);
const iframeDoc = this.pdf.instance.UI.iframeWindow.document;
const currentPage = this.pdf.currentPage;
const elementId = `pageWidgetContainer${currentPage}`;
const pageContainer = iframeDoc.getElementById(elementId);
if (pageContainer) {
if (file.excludedPages.includes(this.pdf.currentPage)) {
if (file.excludedPages.includes(currentPage)) {
pageContainer.classList.add('excluded-page');
} else {
pageContainer.classList.remove('excluded-page');
@ -515,7 +515,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
)
.subscribe();
this.addActiveScreenSubscription = this.reusablePdf.pageComplete$.subscribe(() => {
this.addActiveScreenSubscription = this.pdf.pageComplete$.subscribe(() => {
this._setExcludedPageStyles();
});
}

View File

@ -11,7 +11,7 @@ import { AnnotationDetailsComponent } from './components/annotation-details/anno
import { AnnotationsListComponent } from './components/annotations-list/annotations-list.component';
import { PageIndicatorComponent } from './components/page-indicator/page-indicator.component';
import { PageExclusionComponent } from './components/page-exclusion/page-exclusion.component';
import { PdfViewerComponent } from './components/pdf-viewer/pdf-viewer.component';
import { PdfPaginatorComponent } from './components/pdf-paginator/pdf-paginator.component';
import { AnnotationActionsComponent } from './components/annotation-actions/annotation-actions.component';
import { CommentsComponent } from './components/comments/comments.component';
import { DocumentInfoComponent } from './components/document-info/document-info.component';
@ -70,7 +70,7 @@ const components = [
AnnotationsListComponent,
PageIndicatorComponent,
PageExclusionComponent,
PdfViewerComponent,
PdfPaginatorComponent,
AnnotationActionsComponent,
CommentsComponent,
DocumentInfoComponent,

View File

@ -31,11 +31,10 @@ import { defaultDialogConfig, List, ListingService } from '@iqser/common-ui';
import { filter } from 'rxjs/operators';
import { MatDialog } from '@angular/material/dialog';
import { FilePreviewStateService } from './file-preview-state.service';
import { PdfViewer } from './pdf-viewer.service';
import { FilePreviewDialogService } from './file-preview-dialog.service';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { FileDataService } from './file-data.service';
import { ReusablePdfViewer } from '../../shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { PdfViewer } from '../../shared/components/reusable-pdf-viewer/pdf-viewer.service';
import { REDAnnotationManager } from '../../shared/components/reusable-pdf-viewer/annotation-manager.service';
import Quad = Core.Math.Quad;
@ -51,7 +50,6 @@ export class AnnotationActionsService {
private readonly _dialogService: FilePreviewDialogService,
private readonly _dialog: MatDialog,
private readonly _pdf: PdfViewer,
private readonly _reusablePdf: ReusablePdfViewer,
private readonly _annotationManager: REDAnnotationManager,
private readonly _annotationDrawService: AnnotationDrawService,
private readonly _activeDossiersService: ActiveDossiersService,
@ -403,17 +401,17 @@ export class AnnotationActionsService {
if (annotationWrapper.rectangle || annotationWrapper.imported || annotationWrapper.isImage) {
this._annotationManager.deleteAnnotation(annotationWrapper);
const rectangleAnnotation = this.#generateRectangle(annotationWrapper);
this._reusablePdf.annotationManager.addAnnotation(rectangleAnnotation, { imported: true });
await this._reusablePdf.annotationManager.drawAnnotationsFromList([rectangleAnnotation]);
this._reusablePdf.annotationManager.selectAnnotation(rectangleAnnotation);
this._pdf.annotationManager.addAnnotation(rectangleAnnotation, { imported: true });
await this._pdf.annotationManager.drawAnnotationsFromList([rectangleAnnotation]);
this._pdf.annotationManager.selectAnnotation(rectangleAnnotation);
return;
}
viewerAnnotation.ReadOnly = false;
viewerAnnotation.Hidden = false;
viewerAnnotation.disableRotationControl();
this._reusablePdf.annotationManager.redrawAnnotation(viewerAnnotation);
this._reusablePdf.annotationManager.selectAnnotation(viewerAnnotation);
this._pdf.annotationManager.redrawAnnotation(viewerAnnotation);
this._pdf.annotationManager.selectAnnotation(viewerAnnotation);
}
async acceptResize($event: MouseEvent, annotation: AnnotationWrapper): Promise<void> {
@ -465,8 +463,8 @@ export class AnnotationActionsService {
}
#generateRectangle(annotationWrapper: AnnotationWrapper) {
const annotation = this._reusablePdf.rectangle();
const pageHeight = this._reusablePdf.documentViewer.getPageHeight(annotationWrapper.pageNumber);
const annotation = this._pdf.rectangle();
const pageHeight = this._pdf.documentViewer.getPageHeight(annotationWrapper.pageNumber);
const rectangle: IRectangle = annotationWrapper.positions[0];
annotation.PageNumber = annotationWrapper.pageNumber;
annotation.X = rectangle.topLeft.x;
@ -533,15 +531,15 @@ export class AnnotationActionsService {
private async _extractTextAndPositions(annotationId: string) {
const viewerAnnotation = this._annotationManager.getAnnotation(annotationId);
const document = await this._reusablePdf.PDFDoc;
const document = await this._pdf.PDFDoc;
const page = await document.getPage(viewerAnnotation.getPageNumber());
if (this._reusablePdf.isTextHighlight(viewerAnnotation)) {
if (this._pdf.isTextHighlight(viewerAnnotation)) {
const words = [];
const rectangles: IRectangle[] = [];
for (const quad of viewerAnnotation.Quads) {
const rect = toPosition(
viewerAnnotation.getPageNumber(),
this._reusablePdf.getPageHeight(viewerAnnotation.getPageNumber()),
this._pdf.getPageHeight(viewerAnnotation.getPageNumber()),
this._translateQuads(viewerAnnotation.getPageNumber(), quad),
);
rectangles.push(rect);
@ -552,7 +550,7 @@ export class AnnotationActionsService {
*/
const percentHeightOffset = rect.height / 10;
const pdfNetRect = new this._reusablePdf.PDFNet.Rect(
const pdfNetRect = new this._pdf.PDFNet.Rect(
rect.topLeft.x,
rect.topLeft.y + percentHeightOffset,
rect.topLeft.x + rect.width,
@ -569,7 +567,7 @@ export class AnnotationActionsService {
} else {
const rect = toPosition(
viewerAnnotation.getPageNumber(),
this._reusablePdf.documentViewer.getPageHeight(viewerAnnotation.getPageNumber()),
this._pdf.documentViewer.getPageHeight(viewerAnnotation.getPageNumber()),
this._annotationDrawService.annotationToQuads(viewerAnnotation),
);
return {
@ -580,12 +578,12 @@ export class AnnotationActionsService {
}
private _translateQuads(page: number, quad: Quad): Quad {
const rotation = this._reusablePdf.documentViewer.getCompleteRotation(page);
const rotation = this._pdf.documentViewer.getCompleteRotation(page);
return translateQuads(page, rotation, quad);
}
private async _extractTextFromRect(page: Core.PDFNet.Page, rect: Core.PDFNet.Rect) {
const txt = await this._reusablePdf.PDFNet.TextExtractor.create();
const txt = await this._pdf.PDFNet.TextExtractor.create();
await txt.begin(page, rect); // Read the page.
const words: string[] = [];

View File

@ -10,11 +10,10 @@ import { IRectangle, ISectionGrid, ISectionRectangle } from '@red/domain';
import { SkippedService } from './skipped.service';
import { firstValueFrom } from 'rxjs';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { PdfViewer } from './pdf-viewer.service';
import { FilePreviewStateService } from './file-preview-state.service';
import { FileDataService } from './file-data.service';
import { SuperTypes } from '@models/file/super-types';
import { ReusablePdfViewer } from '../../shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { PdfViewer } from '../../shared/components/reusable-pdf-viewer/pdf-viewer.service';
import Annotation = Core.Annotations.Annotation;
import Quad = Core.Math.Quad;
@ -29,14 +28,13 @@ export class AnnotationDrawService {
private readonly _userPreferenceService: UserPreferenceService,
private readonly _skippedService: SkippedService,
private readonly _pdf: PdfViewer,
private readonly _reusablePdf: ReusablePdfViewer,
private readonly _state: FilePreviewStateService,
private readonly _fileDataService: FileDataService,
) {}
draw(annotations: readonly AnnotationWrapper[]) {
const licenseKey = environment.licenseKey ? atob(environment.licenseKey) : null;
return this._reusablePdf.PDFNet.runWithCleanup(() => this._draw(annotations), licenseKey);
return this._pdf.PDFNet.runWithCleanup(() => this._draw(annotations), licenseKey);
}
getColor(superType: string, dictionary?: string) {
@ -64,7 +62,7 @@ export class AnnotationDrawService {
}
convertColor(hexColor: string) {
return this._reusablePdf.color(hexToRgb(hexColor));
return this._pdf.color(hexToRgb(hexColor));
}
annotationToQuads(annotation: Annotation) {
@ -80,13 +78,13 @@ export class AnnotationDrawService {
const x4 = annotation.getRect().x1;
const y4 = annotation.getRect().y1;
return this._reusablePdf.quad(x1, y1, x2, y2, x3, y3, x4, y4);
return this._pdf.quad(x1, y1, x2, y2, x3, y3, x4, y4);
}
private async _draw(annotationWrappers: readonly AnnotationWrapper[]) {
const annotations = annotationWrappers.map(annotation => this._computeAnnotation(annotation)).filter(a => !!a);
this._reusablePdf.annotationManager.addAnnotations(annotations, { imported: true });
await this._reusablePdf.annotationManager.drawAnnotationsFromList(annotations);
this._pdf.annotationManager.addAnnotations(annotations, { imported: true });
await this._pdf.annotationManager.drawAnnotationsFromList(annotations);
if (this._userPreferenceService.areDevFeaturesEnabled) {
const { dossierId, fileId } = this._state;
@ -107,13 +105,13 @@ export class AnnotationDrawService {
// })
});
}
this._reusablePdf.annotationManager.addAnnotations(sections, { imported: true });
await this._reusablePdf.annotationManager.drawAnnotationsFromList(sections);
this._pdf.annotationManager.addAnnotations(sections, { imported: true });
await this._pdf.annotationManager.drawAnnotationsFromList(sections);
}
private _computeSection(pageNumber: number, sectionRectangle: ISectionRectangle) {
const rectangleAnnot = this._reusablePdf.rectangle();
const pageHeight = this._reusablePdf.getPageHeight(pageNumber);
const rectangleAnnot = this._pdf.rectangle();
const pageHeight = this._pdf.getPageHeight(pageNumber);
const rectangle: IRectangle = {
topLeft: sectionRectangle.topLeft,
page: pageNumber,
@ -133,15 +131,15 @@ export class AnnotationDrawService {
}
private _computeAnnotation(annotationWrapper: AnnotationWrapper) {
const pageNumber = this._reusablePdf.isCompare ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber;
if (pageNumber > this._reusablePdf.pageCount) {
const pageNumber = this._pdf.isCompare ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber;
if (pageNumber > this._pdf.pageCount) {
// skip imported annotations from files that have more pages than the current one
return;
}
if (annotationWrapper.superType === SuperTypes.TextHighlight) {
const rectangleAnnot = this._reusablePdf.rectangle();
const pageHeight = this._reusablePdf.getPageHeight(pageNumber);
const rectangleAnnot = this._pdf.rectangle();
const pageHeight = this._pdf.getPageHeight(pageNumber);
const rectangle: IRectangle = annotationWrapper.positions[0];
rectangleAnnot.PageNumber = pageNumber;
rectangleAnnot.X = rectangle.topLeft.x;
@ -156,7 +154,7 @@ export class AnnotationDrawService {
return rectangleAnnot;
}
const annotation = this._reusablePdf.textHighlight();
const annotation = this._pdf.textHighlight();
annotation.Quads = this._rectanglesToQuads(annotationWrapper.positions, pageNumber);
annotation.Opacity = annotationWrapper.isChangeLogRemoved ? DEFAULT_REMOVED_ANNOTATION_OPACITY : DEFAULT_TEXT_ANNOTATION_OPACITY;
annotation.setContents(annotationWrapper.content);
@ -183,7 +181,7 @@ export class AnnotationDrawService {
}
private _rectanglesToQuads(positions: IRectangle[], pageNumber: number): Quad[] {
const pageHeight = this._reusablePdf.getPageHeight(pageNumber);
const pageHeight = this._pdf.getPageHeight(pageNumber);
return positions.map(p => this._rectangleToQuad(p, pageHeight));
}
@ -200,6 +198,6 @@ export class AnnotationDrawService {
const x4 = rectangle.topLeft.x;
const y4 = pageHeight - rectangle.topLeft.y;
return this._reusablePdf.quad(x1, y1, x2, y2, x3, y3, x4, y4);
return this._pdf.quad(x1, y1, x2, y2, x3, y3, x4, y4);
}
}

View File

@ -3,6 +3,8 @@ import { Injectable } from '@angular/core';
import { EntitiesService, FilterService, ListingService, SearchService } from '@iqser/common-ui';
import { filter, tap } from 'rxjs/operators';
import { MultiSelectService } from './multi-select.service';
import { PdfViewer } from '../../shared/components/reusable-pdf-viewer/pdf-viewer.service';
import { REDAnnotationManager } from '../../shared/components/reusable-pdf-viewer/annotation-manager.service';
@Injectable()
export class AnnotationsListingService extends ListingService<AnnotationWrapper> {
@ -11,6 +13,8 @@ export class AnnotationsListingService extends ListingService<AnnotationWrapper>
protected readonly _searchService: SearchService<AnnotationWrapper>,
protected readonly _entitiesService: EntitiesService<AnnotationWrapper>,
private readonly _multiSelectService: MultiSelectService,
private readonly _pdf: PdfViewer,
private readonly _annotationManager: REDAnnotationManager,
) {
super(_filterService, _searchService, _entitiesService);
@ -21,4 +25,42 @@ export class AnnotationsListingService extends ListingService<AnnotationWrapper>
)
.subscribe();
}
selectAnnotations(annotations?: AnnotationWrapper[]) {
if (!annotations) {
return this._annotationManager.deselectAnnotations();
}
const annotationsToSelect = this._multiSelectService.isActive ? [...this.selected, ...annotations] : annotations;
this.#selectAnnotations(annotationsToSelect);
}
#selectAnnotations(annotations: AnnotationWrapper[] = []) {
const filteredAnnotationsIds = annotations.filter(a => !!a).map(a => a.id);
if (!filteredAnnotationsIds.length) {
return;
}
if (!this._multiSelectService.isActive) {
this._annotationManager.deselectAnnotations();
}
const pageNumber = annotations[0].pageNumber;
if (pageNumber === this._pdf.currentPage) {
return this.#jumpAndSelectAnnotations(filteredAnnotationsIds);
}
this._pdf.navigateTo(pageNumber);
// wait for page to be loaded and to draw annotations
setTimeout(() => this.#jumpAndSelectAnnotations(filteredAnnotationsIds), 300);
}
#jumpAndSelectAnnotations(annotationIds: readonly string[]) {
const annotationsFromViewer = this._annotationManager.getAnnotations(annotationIds);
this._pdf.annotationManager.jumpToAnnotation(annotationsFromViewer[0]);
this._pdf.annotationManager.selectAnnotations(annotationsFromViewer);
}
}

View File

@ -4,7 +4,6 @@ import { RotationType, RotationTypes } from '@red/domain';
import { FileManagementService } from '@services/files/file-management.service';
import { FilePreviewStateService } from './file-preview-state.service';
import { distinctUntilChanged, map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { PdfViewer } from './pdf-viewer.service';
import { HeaderElements } from '../utils/constants';
import {
ConfirmationDialogComponent,
@ -17,7 +16,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { MatDialog } from '@angular/material/dialog';
import { ViewerHeaderConfigService } from './viewer-header-config.service';
import { FilesService } from '@services/files/files.service';
import { ReusablePdfViewer } from '../../shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { PdfViewer } from '../../shared/components/reusable-pdf-viewer/pdf-viewer.service';
const ACTION_BUTTONS = [HeaderElements.APPLY_ROTATION, HeaderElements.DISCARD_ROTATION];
const ONE_ROTATION_DEGREE = 90;
@ -28,7 +27,6 @@ export class PageRotationService {
constructor(
private readonly _pdf: PdfViewer,
private readonly _reusablePdf: ReusablePdfViewer,
private readonly _dialog: MatDialog,
private readonly _loadingService: LoadingService,
private readonly _screenState: FilePreviewStateService,
@ -70,7 +68,7 @@ export class PageRotationService {
for (const page of Object.keys(rotations)) {
const times = rotations[page] / ONE_ROTATION_DEGREE;
for (let i = 1; i <= times; i++) {
this._reusablePdf.documentViewer.rotateCounterClockwise(Number(page));
this._pdf.documentViewer.rotateCounterClockwise(Number(page));
}
}
@ -85,9 +83,9 @@ export class PageRotationService {
this.#rotations$.next({ ...this.#rotations$.value, [pageNumber]: rotationValue });
if (rotation === RotationTypes.LEFT) {
this._reusablePdf.documentViewer.rotateCounterClockwise(pageNumber);
this._pdf.documentViewer.rotateCounterClockwise(pageNumber);
} else {
this._reusablePdf.documentViewer.rotateClockwise(pageNumber);
this._pdf.documentViewer.rotateClockwise(pageNumber);
}
if (this.hasRotations()) {

View File

@ -1,103 +0,0 @@
import { translateQuads } from '../../../utils';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { Core } from '@pdftron/webviewer';
import { File } from '@red/domain';
import { Injectable } from '@angular/core';
import { ListingService } from '@iqser/common-ui';
import { MultiSelectService } from './multi-select.service';
import { ReusablePdfViewer } from '../../shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { REDAnnotationManager } from '../../shared/components/reusable-pdf-viewer/annotation-manager.service';
@Injectable()
export class PdfViewer {
constructor(
private readonly _multiSelectService: MultiSelectService,
private readonly _reusablePdf: ReusablePdfViewer,
private readonly _annotationManager: REDAnnotationManager,
private readonly _listingService: ListingService<AnnotationWrapper>,
) {}
get paginationOffset() {
return this._reusablePdf.isCompare ? 2 : 1;
}
get currentPage() {
return this._reusablePdf.isCompare ? Math.ceil(this._currentInternalPage / 2) : this._currentInternalPage;
}
private get _currentInternalPage() {
return this._reusablePdf.documentViewer?.getCurrentPage() ?? 1;
}
isCurrentPageExcluded(file: File) {
const currentPage = this.currentPage;
return !!file?.excludedPages?.includes(currentPage);
}
navigateToPage(pageNumber: string | number) {
const parsedNumber = typeof pageNumber === 'string' ? parseInt(pageNumber, 10) : pageNumber;
this._navigateToPage(this.paginationOffset === 2 ? parsedNumber * this.paginationOffset - 1 : parsedNumber);
}
navigatePreviousPage() {
if (this._currentInternalPage > 1) {
this._navigateToPage(Math.max(this._currentInternalPage - this.paginationOffset, 1));
}
}
navigateNextPage() {
const pageCount = this._reusablePdf.pageCount;
if (this._currentInternalPage < pageCount) {
this._navigateToPage(Math.min(this._currentInternalPage + this.paginationOffset, pageCount));
}
}
translateQuad(page: number, quad: Core.Math.Quad) {
const rotation = this._reusablePdf.documentViewer.getCompleteRotation(page);
return translateQuads(page, rotation, quad);
}
selectAnnotations(annotations?: AnnotationWrapper[]) {
if (!annotations) {
return this._annotationManager.deselectAnnotations();
}
const annotationsToSelect = this._multiSelectService.isActive ? [...this._listingService.selected, ...annotations] : annotations;
this.#selectAnnotations(annotationsToSelect);
}
#selectAnnotations(annotations: AnnotationWrapper[] = []) {
const filteredAnnotationsIds = annotations.filter(a => !!a).map(a => a.id);
if (!filteredAnnotationsIds.length) {
return;
}
if (!this._multiSelectService.isActive) {
this._annotationManager.deselectAnnotations();
}
const pageNumber = annotations[0].pageNumber;
if (pageNumber === this.currentPage) {
return this.#jumpAndSelectAnnotations(filteredAnnotationsIds);
}
this.navigateToPage(pageNumber);
// wait for page to be loaded and to draw annotations
setTimeout(() => this.#jumpAndSelectAnnotations(filteredAnnotationsIds), 300);
}
#jumpAndSelectAnnotations(annotationIds: readonly string[]) {
const annotationsFromViewer = this._annotationManager.getAnnotations(annotationIds);
this._reusablePdf.annotationManager.jumpToAnnotation(annotationsFromViewer[0]);
this._reusablePdf.annotationManager.selectAnnotations(annotationsFromViewer);
}
private _navigateToPage(pageNumber: number) {
if (this._currentInternalPage !== pageNumber) {
this._reusablePdf.documentViewer.displayPageLocation(pageNumber, 0, 0);
}
}
}

View File

@ -1,6 +1,5 @@
import { Injectable } from '@angular/core';
import { clearStamps, stampPDFPage } from '../../../utils';
import { PdfViewer } from './pdf-viewer.service';
import { FilePreviewStateService } from './file-preview-state.service';
import { NGXLogger } from 'ngx-logger';
import { ViewModeService } from './view-mode.service';
@ -8,14 +7,13 @@ import { TranslateService } from '@ngx-translate/core';
import { Core } from '@pdftron/webviewer';
import { firstValueFrom } from 'rxjs';
import { WatermarkService } from '@services/entity-services/watermark.service';
import { ReusablePdfViewer } from '../../shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { PdfViewer } from '../../shared/components/reusable-pdf-viewer/pdf-viewer.service';
import PDFNet = Core.PDFNet;
@Injectable()
export class StampService {
constructor(
private readonly _pdf: PdfViewer,
private readonly _reusablePdf: ReusablePdfViewer,
private readonly _state: FilePreviewStateService,
private readonly _logger: NGXLogger,
private readonly _viewModeService: ViewModeService,
@ -24,7 +22,7 @@ export class StampService {
) {}
async stampPDF(): Promise<void> {
const pdfDoc = await this._reusablePdf.PDFDoc;
const pdfDoc = await this._pdf.PDFDoc;
if (!pdfDoc) {
return;
}
@ -33,7 +31,7 @@ export class StampService {
const allPages = [...Array(file.numberOfPages).keys()].map(page => page + 1);
try {
await clearStamps(pdfDoc, this._reusablePdf.PDFNet, allPages);
await clearStamps(pdfDoc, this._pdf.PDFNet, allPages);
} catch (e) {
console.error('Error clearing stamps: ', e);
return;
@ -48,15 +46,16 @@ export class StampService {
await this._stampExcludedPages(pdfDoc, file.excludedPages);
}
this._reusablePdf.documentViewer.refreshAll();
this._reusablePdf.documentViewer.updateView([this._pdf.currentPage], this._pdf.currentPage);
this._pdf.documentViewer.refreshAll();
const currentPage = this._pdf.currentPage;
this._pdf.documentViewer.updateView([currentPage], currentPage);
}
private async _stampExcludedPages(document: PDFNet.PDFDoc, excludedPages: number[]): Promise<void> {
if (excludedPages && excludedPages.length > 0) {
await stampPDFPage(
document,
this._reusablePdf.PDFNet,
this._pdf.PDFNet,
this._translateService.instant('file-preview.excluded-from-redaction') as string,
17,
'courier',
@ -72,7 +71,7 @@ export class StampService {
const watermark = await firstValueFrom(this._watermarkService.getWatermark(dossierTemplateId));
await stampPDFPage(
document,
this._reusablePdf.PDFNet,
this._pdf.PDFNet,
watermark.text,
watermark.fontSize,
watermark.fontType,

View File

@ -4,13 +4,13 @@ import { HeaderElements } from '../utils/constants';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { TranslateService } from '@ngx-translate/core';
import { BASE_HREF } from '../../../tokens';
import { ReusablePdfViewer } from '../../shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { PdfViewer } from '../../shared/components/reusable-pdf-viewer/pdf-viewer.service';
@Injectable()
export class TooltipsService {
constructor(
@Inject(BASE_HREF) private readonly _baseHref: string,
private readonly _pdfViewer: ReusablePdfViewer,
private readonly _pdf: PdfViewer,
private readonly _userPreferenceService: UserPreferenceService,
private readonly _translateService: TranslateService,
) {}
@ -31,13 +31,13 @@ export class TooltipsService {
updateTooltipsVisibility(): void {
const current = this._userPreferenceService.getFilePreviewTooltipsPreference();
this._pdfViewer.instance.UI.setAnnotationContentOverlayHandler(() => (current ? undefined : false));
this._pdf.instance.UI.setAnnotationContentOverlayHandler(() => (current ? undefined : false));
}
async toggleTooltips(): Promise<void> {
await this._userPreferenceService.toggleFilePreviewTooltipsPreference();
this.updateTooltipsVisibility();
this._pdfViewer.instance.UI.updateElement(HeaderElements.TOGGLE_TOOLTIPS, {
this._pdf.instance.UI.updateElement(HeaderElements.TOGGLE_TOOLTIPS, {
title: this.toggleTooltipsBtnTitle,
img: this.toggleTooltipsBtnIcon,
});

View File

@ -3,12 +3,11 @@ import { IHeaderElement, RotationTypes } from '@red/domain';
import { HeaderElements, HeaderElementType } from '../utils/constants';
import { TranslateService } from '@ngx-translate/core';
import { BASE_HREF } from '../../../tokens';
import { PdfViewer } from './pdf-viewer.service';
import { TooltipsService } from './tooltips.service';
import { environment } from '@environments/environment';
import { FilePreviewStateService } from './file-preview-state.service';
import { PageRotationService } from './page-rotation.service';
import { ReusablePdfViewer } from '../../shared/components/reusable-pdf-viewer/reusable-pdf-viewer.service';
import { PdfViewer } from '../../shared/components/reusable-pdf-viewer/pdf-viewer.service';
@Injectable()
export class ViewerHeaderConfigService {
@ -32,8 +31,7 @@ export class ViewerHeaderConfigService {
@Inject(BASE_HREF) private readonly _baseHref: string,
private readonly _injector: Injector,
private readonly _translateService: TranslateService,
private readonly _pdfViewer: PdfViewer,
private readonly _reusablePdf: ReusablePdfViewer,
private readonly _pdf: PdfViewer,
private readonly _tooltipsService: TooltipsService,
private readonly _stateService: FilePreviewStateService,
) {}
@ -162,19 +160,19 @@ export class ViewerHeaderConfigService {
}
private async _closeCompareMode() {
this._reusablePdf.closeCompareMode();
const pdfNet = this._reusablePdf.PDFNet;
this._pdf.closeCompareMode();
const pdfNet = this._pdf.PDFNet;
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
const blob = await this._stateService.blob;
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await blob.arrayBuffer());
const filename = this._stateService.file.filename ?? 'document.pdf';
this._reusablePdf.instance.UI.loadDocument(currentDocument, { filename });
this._pdf.instance.UI.loadDocument(currentDocument, { filename });
this.disable([HeaderElements.CLOSE_COMPARE_BUTTON]);
this.enable([HeaderElements.COMPARE_BUTTON]);
this._pdfViewer.navigateToPage(1);
this._pdf.navigateTo(1);
}
private _compare(compareFileInput: ElementRef): IHeaderElement {
@ -197,7 +195,7 @@ export class ViewerHeaderConfigService {
}
private _updateElements(): void {
this._reusablePdf.instance.UI.setHeaderItems(header => {
this._pdf.instance.UI.setHeaderItems(header => {
const enabledItems: IHeaderElement[] = [];
const groups: HeaderElementType[][] = [
[HeaderElements.COMPARE_BUTTON, HeaderElements.CLOSE_COMPARE_BUTTON],

View File

@ -1,9 +1,9 @@
import { Component, ElementRef, ViewChild } from '@angular/core';
import { ReusablePdfViewer } from './reusable-pdf-viewer.service';
import { PdfViewer } from './pdf-viewer.service';
import { REDAnnotationManager } from '@shared/components/reusable-pdf-viewer/annotation-manager.service';
@Component({
selector: 'redaction-reusable-pdf-viewer',
selector: 'redaction-pdf-viewer',
template: ' <div #viewer></div>',
styles: [
`
@ -17,10 +17,10 @@ import { REDAnnotationManager } from '@shared/components/reusable-pdf-viewer/ann
`,
],
})
export class ReusablePdfViewerComponent {
export class PdfViewerComponent {
#viewer: ElementRef;
constructor(readonly reusablePdfViewer: ReusablePdfViewer, private readonly _annotationManager: REDAnnotationManager) {}
constructor(private readonly _pdf: PdfViewer, private readonly _annotationManager: REDAnnotationManager) {}
@ViewChild('viewer', { static: true })
set viewer(value: ElementRef) {
@ -29,7 +29,7 @@ export class ReusablePdfViewerComponent {
}
this.#viewer = value;
const pdfInit = this.reusablePdfViewer.init(value.nativeElement as HTMLElement);
const pdfInit = this._pdf.init(value.nativeElement as HTMLElement);
pdfInit.then(instance => this._annotationManager.init(instance.Core.annotationManager));
}
}

View File

@ -1,11 +1,11 @@
import { Inject, Injectable, Injector } from '@angular/core';
import { Injectable, Injector } from '@angular/core';
import WebViewer, { Core, WebViewerInstance, WebViewerOptions } from '@pdftron/webviewer';
import { environment } from '@environments/environment';
import { BASE_HREF_FN, BaseHrefFn } from '../../../../tokens';
import { BASE_HREF_FN } from '../../../../tokens';
import { File } from '@red/domain';
import { ErrorService, log, shareDistinctLast, shareLast } from '@iqser/common-ui';
import { ErrorService, shareDistinctLast, shareLast } from '@iqser/common-ui';
import { ActivatedRoute } from '@angular/router';
import { debounceTime, map, tap } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, map, tap } from 'rxjs/operators';
import { BehaviorSubject, combineLatest, fromEvent, merge, Observable } from 'rxjs';
import { ConfigService } from '@services/config.service';
import { NGXLogger } from 'ngx-logger';
@ -20,15 +20,18 @@ import DocumentViewer = Core.DocumentViewer;
@Injectable({
providedIn: 'root',
})
export class ReusablePdfViewer {
export class PdfViewer {
readonly currentPage$ = this._activatedRoute.queryParamMap.pipe(
map(params => Number(params.get('page') ?? '1')),
shareDistinctLast(),
);
documentViewer: DocumentViewer;
/**
* @deprecated Use REDAnnotationManager service instead
*/
annotationManager: AnnotationManager;
documentLoaded$: Observable<boolean>;
loaded$: Observable<boolean>;
pageComplete$: Observable<unknown>;
compareMode$: Observable<boolean>;
totalPages$: Observable<number>;
@ -37,8 +40,6 @@ export class ReusablePdfViewer {
readonly #compareMode$ = new BehaviorSubject(false);
constructor(
@Inject(BASE_HREF_FN) private readonly _convertPath: BaseHrefFn,
private readonly _errorService: ErrorService,
private readonly _logger: NGXLogger,
private readonly _activatedRoute: ActivatedRoute,
private readonly _injector: Injector,
@ -73,10 +74,19 @@ export class ReusablePdfViewer {
}
}
get currentPage() {
const currentInternalPage = this.#currentInternalPage;
return this.isCompare ? Math.ceil(currentInternalPage / 2) : currentInternalPage;
}
get #totalPages$() {
const layoutChanged$ = fromEvent(this.documentViewer, 'layoutChanged');
const pageCount$ = layoutChanged$.pipe(map(() => this.pageCount));
const docChanged$ = combineLatest([pageCount$, this.compareMode$]).pipe(log('total pages'));
const pageCount$ = layoutChanged$.pipe(
map(() => this.pageCount),
distinctUntilChanged(),
);
const docChanged$ = combineLatest([pageCount$, this.compareMode$]);
return docChanged$.pipe(map(([pageCount, isCompare]) => (isCompare ? Math.ceil(pageCount / 2) : pageCount)));
}
@ -84,6 +94,10 @@ export class ReusablePdfViewer {
return fromEvent(this.documentViewer, 'pageComplete').pipe(debounceTime(300));
}
get #paginationOffset() {
return this.isCompare ? 2 : 1;
}
get #documentLoaded$() {
const event$ = fromEvent(this.documentViewer, 'documentLoaded');
const toBool$ = event$.pipe(map(() => true));
@ -99,6 +113,29 @@ export class ReusablePdfViewer {
return toBool$.pipe(tap(() => this._logger.info('[PDF] Document unloaded')));
}
get #currentInternalPage() {
return this.documentViewer.getCurrentPage();
}
navigateTo(page: string | number) {
const parsedNumber = typeof page === 'string' ? parseInt(page, 10) : page;
const paginationOffset = this.#paginationOffset;
this.#navigateTo(paginationOffset === 2 ? parsedNumber * paginationOffset - 1 : parsedNumber);
}
navigatePreviousPage() {
if (this.#currentInternalPage > 1) {
this.#navigateTo(Math.max(this.#currentInternalPage - this.#paginationOffset, 1));
}
}
navigateNextPage() {
const pageCount = this.pageCount;
if (this.#currentInternalPage < pageCount) {
this.#navigateTo(Math.min(this.#currentInternalPage + this.#paginationOffset, pageCount));
}
}
async init(htmlElement: HTMLElement) {
this.#instance = await this.#getInstance(htmlElement);
this._logger.info('[PDF] Initialized');
@ -106,10 +143,10 @@ export class ReusablePdfViewer {
this.documentViewer = this.#instance.Core.documentViewer;
this.annotationManager = this.#instance.Core.annotationManager;
this.documentLoaded$ = merge(this.#documentUnloaded$, this.#documentLoaded$).pipe(shareLast());
this.loaded$ = merge(this.#documentUnloaded$, this.#documentLoaded$).pipe(shareLast());
this.compareMode$ = this.#compareMode$.asObservable();
this.pageComplete$ = this.#pageComplete$.pipe(shareLast());
this.totalPages$ = this.#totalPages$.pipe(shareLast());
this.totalPages$ = this.#totalPages$.pipe(shareDistinctLast());
this.#setSelectionMode();
this.#configureElements();
this.#disableHotkeys();
@ -154,13 +191,13 @@ export class ReusablePdfViewer {
async loadDocument(blob: Blob, file: File) {
this._logger.info('[PDF] Loading document', blob, file);
const onError = () => {
this._errorService.set(DOCUMENT_LOADING_ERROR);
this._injector.get(ErrorService).set(DOCUMENT_LOADING_ERROR);
this._logger.error('[PDF] Error while loading document');
// this.stateService.reloadBlob();
};
const pdfNet = this.#instance.Core.PDFNet;
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
await pdfNet.initialize(environment.licenseKey ? window.atob(environment.licenseKey) : null);
const document = await pdfNet.PDFDoc.createFromBuffer(await blob.arrayBuffer());
await document.flattenAnnotations(false);
@ -187,6 +224,12 @@ export class ReusablePdfViewer {
return annotation instanceof this.#instance.Core.Annotations.TextHighlightAnnotation;
}
#navigateTo(pageNumber: number) {
if (this.#currentInternalPage !== pageNumber) {
this.documentViewer.displayPageLocation(pageNumber, 0, 0);
}
}
#disableHotkeys(): void {
DISABLED_HOTKEYS.forEach(key => this.#instance.UI.hotkeys.off(key));
}
@ -202,11 +245,12 @@ export class ReusablePdfViewer {
}
#getInstance(htmlElement: HTMLElement) {
const convertPath = this._injector.get(BASE_HREF_FN);
const options: WebViewerOptions = {
licenseKey: environment.licenseKey ? atob(environment.licenseKey) : null,
licenseKey: environment.licenseKey ? window.atob(environment.licenseKey) : null,
fullAPI: true,
path: this._convertPath('/assets/wv-resources'),
css: this._convertPath('/assets/pdftron/stylesheet.css'),
path: convertPath('/assets/wv-resources'),
css: convertPath('/assets/pdftron/stylesheet.css'),
backendType: 'ems',
};

View File

@ -154,4 +154,8 @@ export class File extends Entity<IFile> implements IFile {
const routerPath = this.dossierArchived ? ARCHIVE_ROUTE : DOSSIERS_ROUTE;
return this.canBeOpened ? `/main/${this.dossierTemplateId}/${routerPath}/${this.dossierId}/file/${this.fileId}` : undefined;
}
isPageExcluded(page: number): boolean {
return this.excludedPages.includes(page);
}
}