-
- {{pageNumber}}
-
+
diff --git a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.scss b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.scss
index 07cda4c1f..9b532d927 100644
--- a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.scss
+++ b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.scss
@@ -1,172 +1,179 @@
-@import "../../../../assets/styles/red-variables";
-@import "../../../../assets/styles/red-mixins";
+@import '../../../../assets/styles/red-variables';
+@import '../../../../assets/styles/red-mixins';
redaction-pdf-viewer {
- position: absolute;
- width: calc(100vw - #{$right-container-width});
- height: calc(100vh - 110px);
- top: 110px;
- z-index: 2;
+ position: absolute;
+ width: calc(100vw - #{$right-container-width});
+ height: calc(100vh - 110px);
+ top: 110px;
+ z-index: 2;
}
.actions-container {
- display: flex;
- justify-content: flex-end;
- align-items: center;
- gap: 10px;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ gap: 10px;
}
.filename {
- display: flex;
- justify-content: center;
+ display: flex;
+ justify-content: center;
}
.right-fixed-container {
- padding: 0;
- width: $right-container-width;
- box-sizing: border-box;
-
- .right-title {
- height: 70px;
- display: flex;
- border-bottom: 1px solid $separator;
- align-items: center;
- justify-content: space-between;
- padding: 0 24px;
-
- > div {
- position: relative;
-
- .dot {
- background: $primary;
- height: 10px;
- width: 10px;
- border-radius: 50%;
- position: absolute;
- top: 0;
- left: 0;
- }
- }
-
- .close-icon {
- height: 14px;
- width: 14px;
- cursor: pointer;
- }
- }
-
- .right-content {
- height: calc(100vh - 110px - 72px);
+ padding: 0;
+ width: $right-container-width;
box-sizing: border-box;
- display: flex;
- .pages, .annotations {
- overflow-y: scroll;
- @include no-scroll-bar();
- outline: none;
-
- &.activePanel {
- background-color: #FAFAFA;
- }
- }
-
- .pages {
- border-right: 1px solid $separator;
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 10px;
- padding: 16px;
- min-width: 28px;
- }
-
- .annotations {
- width: 100%;
-
- .page-separator {
- border-bottom: 1px solid $separator;
- height: 40px;
- box-sizing: border-box;
- padding: 8px 10px;
+ .right-title {
+ height: 70px;
display: flex;
- align-items: flex-end;
- background-color: $grey-6;
- }
-
- .annotation {
border-bottom: 1px solid $separator;
- padding: 10px;
- font-size: 12px;
- cursor: pointer;
- position: relative;
- display: flex;
- gap: 10px;
- border-left: 2px solid transparent;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 24px;
- redaction-annotation-icon {
- margin-top: 6px;
- }
+ > div {
+ position: relative;
- &:hover {
- background-color: #F9FAFB;
-
- .annotation-actions {
- background: linear-gradient(to right, transparent 0%, #F9FAFB, #F9FAFB, #F9FAFB);
- display: flex;
- align-items: center;
- justify-content: flex-end;
- width: 120px;
- padding-right: 16px;
-
- .confirm{
- color: $green-2;
+ .dot {
+ background: $primary;
+ height: 10px;
+ width: 10px;
+ border-radius: 50%;
+ position: absolute;
+ top: 0;
+ left: 0;
}
- }
}
+ .close-icon {
+ height: 14px;
+ width: 14px;
+ cursor: pointer;
+ }
+ }
+
+ .right-content {
+ height: calc(100vh - 110px - 72px);
+ box-sizing: border-box;
+ display: flex;
+
+ .pages,
+ .annotations {
+ overflow-y: scroll;
+ @include no-scroll-bar();
+ outline: none;
+
+ &.activePanel {
+ background-color: #fafafa;
+ }
+ }
+
+ .pages {
+ border-right: 1px solid $separator;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 10px;
+ padding: 16px;
+ min-width: 28px;
+ }
+
+ .annotations {
+ width: 100%;
+
+ .page-separator {
+ border-bottom: 1px solid $separator;
+ height: 40px;
+ box-sizing: border-box;
+ padding: 8px 10px;
+ display: flex;
+ align-items: flex-end;
+ background-color: $grey-6;
+ }
+
+ .annotation {
+ border-bottom: 1px solid $separator;
+ padding: 10px;
+ font-size: 12px;
+ cursor: pointer;
+ position: relative;
+ display: flex;
+ gap: 10px;
+ border-left: 2px solid transparent;
+
+ redaction-annotation-icon {
+ margin-top: 6px;
+ }
+
+ &:hover {
+ background-color: #f9fafb;
+
+ .annotation-actions {
+ background: linear-gradient(
+ to right,
+ transparent 0%,
+ #f9fafb,
+ #f9fafb,
+ #f9fafb
+ );
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ width: 120px;
+ padding-right: 16px;
+
+ .confirm {
+ color: $green-2;
+ }
+ }
+ }
+
+ &.active {
+ border-left: 2px solid $primary;
+ }
+
+ .annotation-actions {
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ display: none;
+ width: 40px;
+ }
+ }
+ }
+ }
+
+ .page-number {
+ border: 1px solid $separator;
+ padding: 5px 10px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 28px;
+ min-height: 28px;
+ min-width: 14px;
+ opacity: 0.7;
+ font-size: 11px;
+ line-height: 14px;
+
&.active {
- border-left: 2px solid $primary;
+ border: 1px solid $primary;
}
-
- .annotation-actions {
- position: absolute;
- right: 0;
- top: 0;
- bottom: 0;
- display: none;
- width: 40px;
- }
- }
}
- }
-
- .page-number {
- border: 1px solid $separator;
- padding: 5px 10px;
- display: flex;
- justify-content: center;
- align-items: center;
- height: 28px;
- min-height: 28px;
- min-width: 14px;
- opacity: 0.7;
- font-size: 11px;
- line-height: 14px;
-
- &.active {
- border: 1px solid $primary;
- }
- }
}
.filter-menu-header {
- display: flex;
- justify-content: space-between;
- padding: 7px 15px 15px;
- width: 350px;
-
- .actions {
display: flex;
- gap: 8px;
- }
+ justify-content: space-between;
+ padding: 7px 15px 15px;
+ width: 350px;
+
+ .actions {
+ display: flex;
+ gap: 8px;
+ }
}
diff --git a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts
index 651ef114e..032c18f01 100644
--- a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts
+++ b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts
@@ -1,4 +1,12 @@
-import { ChangeDetectorRef, Component, ElementRef, HostListener, NgZone, OnInit, ViewChild } from '@angular/core';
+import {
+ ChangeDetectorRef,
+ Component,
+ ElementRef,
+ HostListener,
+ NgZone,
+ OnInit,
+ ViewChild
+} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ManualRedactionEntry, ReanalysisControllerService } from '@redaction/red-ui-http';
import { AppStateService } from '../../../state/app-state.service';
@@ -17,393 +25,440 @@ import { DialogService } from '../../../dialogs/dialog.service';
import { MatDialogRef, MatDialogState } from '@angular/material/dialog';
@Component({
- selector: 'redaction-file-preview-screen',
- templateUrl: './file-preview-screen.component.html',
- styleUrls: ['./file-preview-screen.component.scss']
+ selector: 'redaction-file-preview-screen',
+ templateUrl: './file-preview-screen.component.html',
+ styleUrls: ['./file-preview-screen.component.scss']
})
export class FilePreviewScreenComponent implements OnInit {
+ private projectId: string;
+ private _activeViewer: 'ANNOTATED' | 'REDACTED' = 'ANNOTATED';
+ private instance: WebViewerInstance;
+ private _dialogRef: MatDialogRef
;
- private projectId: string;
- private _activeViewer: 'ANNOTATED' | 'REDACTED' = 'ANNOTATED';
- private instance: WebViewerInstance;
- private _dialogRef: MatDialogRef;
+ @ViewChild(PdfViewerComponent) private _viewerComponent: PdfViewerComponent;
+ @ViewChild('annotations') private _annotationsElement: ElementRef;
+ @ViewChild('quickNavigation') private _quickNavigationElement: ElementRef;
- @ViewChild(PdfViewerComponent) private _viewerComponent: PdfViewerComponent;
- @ViewChild('annotations') private _annotationsElement: ElementRef;
- @ViewChild('quickNavigation') private _quickNavigationElement: ElementRef;
+ public annotatedFileData: Blob;
+ public redactedFileData: Blob;
+ public fileId: string;
+ public annotations: Annotations.Annotation[] = [];
+ public displayedAnnotations: { [key: number]: { annotations: Annotations.Annotation[] } } = {};
+ public selectedAnnotation: Annotations.Annotation;
+ public filters: AnnotationFilters;
+ public expandedFilters: AnnotationFilters = { hint: false };
+ public pagesPanelActive = true;
- public annotatedFileData: Blob;
- public redactedFileData: Blob;
- public fileId: string;
- public annotations: Annotations.Annotation[] = [];
- public displayedAnnotations: { [key: number]: { annotations: Annotations.Annotation[] } } = {};
- public selectedAnnotation: Annotations.Annotation;
- public filters: AnnotationFilters;
- public expandedFilters: AnnotationFilters = { hint: false };
- public pagesPanelActive = true;
-
- constructor(
- public readonly appStateService: AppStateService,
- private readonly _changeDetectorRef: ChangeDetectorRef,
- private readonly _activatedRoute: ActivatedRoute,
- private readonly _dialogService: DialogService,
- private readonly _router: Router,
- private readonly _userService: UserService,
- private readonly _fileDownloadService: FileDownloadService,
- private readonly _reanalysisControllerService: ReanalysisControllerService,
- private readonly _filtersService: FiltersService,
- private ngZone: NgZone) {
- this._activatedRoute.params.subscribe(params => {
- this.projectId = params.projectId;
- this.fileId = params.fileId;
- this.appStateService.activateFile(this.projectId, this.fileId);
- });
- this.filters = _filtersService.filters;
- }
-
- public get user() {
- return this._userService.user;
- }
-
- public filterKeys(key?: string) {
- if (key) {
- return Object.keys(this.filters[key]);
+ constructor(
+ public readonly appStateService: AppStateService,
+ private readonly _changeDetectorRef: ChangeDetectorRef,
+ private readonly _activatedRoute: ActivatedRoute,
+ private readonly _dialogService: DialogService,
+ private readonly _router: Router,
+ private readonly _userService: UserService,
+ private readonly _fileDownloadService: FileDownloadService,
+ private readonly _reanalysisControllerService: ReanalysisControllerService,
+ private readonly _filtersService: FiltersService,
+ private ngZone: NgZone
+ ) {
+ this._activatedRoute.params.subscribe((params) => {
+ this.projectId = params.projectId;
+ this.fileId = params.fileId;
+ this.appStateService.activateFile(this.projectId, this.fileId);
+ });
+ this.filters = _filtersService.filters;
}
- return Object.keys(this.filters);
- }
+ public get user() {
+ return this._userService.user;
+ }
- public get redactedView() {
- return this._activeViewer === 'REDACTED';
- }
+ public filterKeys(key?: string) {
+ if (key) {
+ return Object.keys(this.filters[key]);
+ }
- public set redactedView(value: boolean) {
- this._activeViewer = value ? 'REDACTED' : 'ANNOTATED';
- }
+ return Object.keys(this.filters);
+ }
- public ngOnInit(): void {
- // PDFTRON cache fix
- localStorage.clear();
- this._reloadFiles();
- this.appStateService.fileStatusChanged.subscribe((fileStatus) => {
- if (fileStatus.fileId === this.fileId) {
- console.log(fileStatus);
+ public get redactedView() {
+ return this._activeViewer === 'REDACTED';
+ }
+
+ public set redactedView(value: boolean) {
+ this._activeViewer = value ? 'REDACTED' : 'ANNOTATED';
+ }
+
+ public ngOnInit(): void {
+ // PDFTRON cache fix
+ localStorage.clear();
this._reloadFiles();
- }
- });
- }
-
- private _reloadFiles() {
- this._fileDownloadService.loadFile('ANNOTATED', this.fileId, (data) => {
- this.annotatedFileData = data;
- }).subscribe(() => {
- });
- this._fileDownloadService.loadFile('REDACTED', this.fileId, (data) => {
- this.redactedFileData = data;
- }).subscribe(() => {
- });
- }
-
- public openFileDetailsDialog($event: MouseEvent) {
- this._dialogRef = this._dialogService.openFileDetailsDialog($event, this.appStateService.activeFile);
- }
-
- public reanalyseFile($event: MouseEvent) {
- $event.stopPropagation();
- this._reanalysisControllerService.reanalyzeFile(this.appStateService.activeProject.project.projectId, this.fileId).subscribe(async () => {
- await this.appStateService.reloadActiveProjectFiles();
- });
- }
-
- public openDeleteFileDialog($event: MouseEvent) {
- this._dialogRef = this._dialogService.openDeleteFileDialog($event, this.projectId, this.fileId, () => {
- this._router.navigate([`/ui/projects/${this.projectId}`]);
- });
- }
-
- public openAssignFileOwnerDialog($event: MouseEvent) {
- const file = this.appStateService.getFileById(this.projectId, this.fileId);
- this._dialogRef = this._dialogService.openAssignFileOwnerDialog($event, file);
- }
-
- public get activeViewer() {
- return this.instance;
- }
-
- public applyFilters() {
- this.displayedAnnotations = AnnotationUtils.parseAnnotations(this.annotations, this.filters);
- }
-
- public get displayedPages(): number[] {
- return Object.keys(this.displayedAnnotations).map(key => Number(key));
- }
-
- public handleAnnotationSelected(annotation: Annotations.Annotation) {
- this.selectedAnnotation = annotation;
- this.scrollToSelectedAnnotation();
- this._changeDetectorRef.detectChanges();
- }
-
- public selectAnnotation(annotation: Annotations.Annotation) {
- this._viewerComponent.selectAnnotation(annotation);
- }
-
- @debounce()
- private scrollToSelectedAnnotation() {
- if (!this.selectedAnnotation) {
- return;
+ this.appStateService.fileStatusChanged.subscribe((fileStatus) => {
+ if (fileStatus.fileId === this.fileId) {
+ console.log(fileStatus);
+ this._reloadFiles();
+ }
+ });
}
- const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(`div[annotation-id="${this.selectedAnnotation.Id}"].active`);
- this._scrollToFirstElement(elements);
- }
- public selectPage(pageNumber: number) {
- this._viewerComponent.navigateToPage(pageNumber);
- }
-
- public openManualRedactionDialog($event: ManualRedactionEntry) {
- this.ngZone.run(() => {
- this._dialogRef = this._dialogService.openManualRedactionDialog($event, () => {
- });
- });
-
- }
-
- get activeViewerPage() {
- return this.instance.docViewer.getCurrentPage();
- }
-
- @debounce()
- private _scrollViews() {
- this._scrollQuickNavigation();
- this._scrollAnnotations();
- }
-
- private _scrollQuickNavigation() {
- const elements: any[] = this._quickNavigationElement.nativeElement.querySelectorAll(`#quick-nav-page-${this.activeViewerPage}`);
- this._scrollToFirstElement(elements);
- }
-
- private _scrollAnnotations() {
- if (this.selectedAnnotation?.getPageNumber() === this.activeViewerPage) {
- return;
+ private _reloadFiles() {
+ this._fileDownloadService
+ .loadFile('ANNOTATED', this.fileId, (data) => {
+ this.annotatedFileData = data;
+ })
+ .subscribe(() => {});
+ this._fileDownloadService
+ .loadFile('REDACTED', this.fileId, (data) => {
+ this.redactedFileData = data;
+ })
+ .subscribe(() => {});
}
- const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(`div[anotation-page-header="${this.activeViewerPage}"]`);
- this._scrollToFirstElement(elements);
- }
- private _scrollToFirstElement(elements: HTMLElement[]) {
- if (elements.length > 0) {
- scrollIntoView(elements[0], {
- behavior: 'smooth',
- scrollMode: 'if-needed',
- block: 'start',
- inline: 'start'
- });
+ public openFileDetailsDialog($event: MouseEvent) {
+ this._dialogRef = this._dialogService.openFileDetailsDialog(
+ $event,
+ this.appStateService.activeFile
+ );
}
- }
- public getType(annotation: Annotations.Annotation): string {
- return AnnotationUtils.getType(annotation);
- }
+ public reanalyseFile($event: MouseEvent) {
+ $event.stopPropagation();
+ this._reanalysisControllerService
+ .reanalyzeFile(this.appStateService.activeProject.project.projectId, this.fileId)
+ .subscribe(async () => {
+ await this.appStateService.reloadActiveProjectFiles();
+ });
+ }
- public getDictionary(annotation: Annotations.Annotation): string {
- return AnnotationUtils.getDictionary(annotation);
- }
+ public openDeleteFileDialog($event: MouseEvent) {
+ this._dialogRef = this._dialogService.openDeleteFileDialog(
+ $event,
+ this.projectId,
+ this.fileId,
+ () => {
+ this._router.navigate([`/ui/projects/${this.projectId}`]);
+ }
+ );
+ }
- public acceptSuggestionAnnotation($event: MouseEvent, annotation: Annotations.Annotation) {
- this.ngZone.run(() => {
- this._dialogRef = this._dialogService.acceptSuggestionAnnotation($event, annotation, this.projectId, this.fileId);
- });
- }
+ public openAssignFileOwnerDialog($event: MouseEvent) {
+ const file = this.appStateService.getFileById(this.projectId, this.fileId);
+ this._dialogRef = this._dialogService.openAssignFileOwnerDialog($event, file);
+ }
- public suggestRemoveAnnotation($event: MouseEvent, annotation: Annotations.Annotation) {
- this.ngZone.run(() => {
- this._dialogRef = this._dialogService.suggestRemoveAnnotation($event, annotation, this.projectId, this.fileId);
- });
- }
+ public get activeViewer() {
+ return this.instance;
+ }
- public downloadFile(type: FileType | string) {
- this._fileDownloadService.loadFile(type, this.fileId).subscribe(data => {
- saveAs(data, this.appStateService.activeFile.filename);
- });
- }
+ public applyFilters() {
+ this.displayedAnnotations = AnnotationUtils.parseAnnotations(
+ this.annotations,
+ this.filters
+ );
+ }
- public setAllFilters(filter: AnnotationFilters, value: boolean, rootKey?: string) {
- if (rootKey) {
- this.filters[rootKey] = value;
- } else {
+ public get displayedPages(): number[] {
+ return Object.keys(this.displayedAnnotations).map((key) => Number(key));
+ }
- for (const key of Object.keys(filter)) {
- if (AnnotationUtils.hasSubsections(filter[key])) {
- this.setAllFilters(filter[key], value);
- } else {
- filter[key] = value;
+ public handleAnnotationSelected(annotation: Annotations.Annotation) {
+ this.selectedAnnotation = annotation;
+ this.scrollToSelectedAnnotation();
+ this._changeDetectorRef.detectChanges();
+ }
+
+ public selectAnnotation(annotation: Annotations.Annotation) {
+ this._viewerComponent.selectAnnotation(annotation);
+ }
+
+ @debounce()
+ private scrollToSelectedAnnotation() {
+ if (!this.selectedAnnotation) {
+ return;
}
- }
+ const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(
+ `div[annotation-id="${this.selectedAnnotation.Id}"].active`
+ );
+ this._scrollToFirstElement(elements);
}
- this.applyFilters();
- }
-
- public isChecked(key: string): boolean {
- return AnnotationUtils.isChecked(this.filters[key]);
- }
-
- public isIndeterminate(key: string): boolean {
- return AnnotationUtils.isIndeterminate(this.filters[key]);
- }
-
- public get hasActiveFilters(): boolean {
- return AnnotationUtils.hasActiveFilters(this.filters);
- }
-
- public hasSubsections(filter: AnnotationFilters | boolean) {
- return AnnotationUtils.hasSubsections(filter);
- }
-
- public setExpanded(key: string, value: boolean, $event: MouseEvent) {
- $event.stopPropagation();
- this.expandedFilters[key] = value;
- }
-
- public isManuallyAddedAnnotation(annotation: Annotations.Annotation) {
- return annotation.Id.indexOf('request:') >= 0;
- }
-
- @HostListener('window:keyup', ['$event'])
- handleKeyEvent($event: KeyboardEvent) {
- const keyArray = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
-
- if (!keyArray.includes($event.key) || this._dialogRef?.getState() === MatDialogState.OPEN) {
- return;
+ public selectPage(pageNumber: number) {
+ this._viewerComponent.navigateToPage(pageNumber);
}
- if ($event.key === 'ArrowLeft' || $event.key === 'ArrowRight') {
- this.pagesPanelActive = !this.pagesPanelActive;
- this._changeDetectorRef.detectChanges();
- return;
+ public openManualRedactionDialog($event: ManualRedactionEntry) {
+ this.ngZone.run(() => {
+ this._dialogRef = this._dialogService.openManualRedactionDialog($event, () => {});
+ });
}
- if (!this.pagesPanelActive) {
- this._navigateAnnotations($event);
- } else {
- this._navigatePages($event);
+ get activeViewerPage() {
+ return this.instance.docViewer.getCurrentPage();
}
- }
- private _navigateAnnotations($event: KeyboardEvent) {
- if (!this.selectedAnnotation || this.activeViewerPage !== this.selectedAnnotation.getPageNumber()) {
- const pageIdx = this.displayedPages.indexOf(this.activeViewerPage);
- if (pageIdx !== -1) { // Displayed page has annotations
- this.selectAnnotation(this.displayedAnnotations[this.activeViewerPage].annotations[0]);
- } else { // Displayed page doesn't have annotations
- if ($event.key === 'ArrowDown') {
- const nextPage = this._nextPageWithAnnotations();
- this.selectAnnotation(this.displayedAnnotations[nextPage].annotations[0]);
- } else {
- const prevPage = this._prevPageWithAnnotations();
- const prevPageAnnotations = this.displayedAnnotations[prevPage].annotations;
- this.selectAnnotation(prevPageAnnotations[prevPageAnnotations.length - 1]);
- }
- }
-
- } else {
- const page = this.selectedAnnotation.getPageNumber();
- const pageIdx = this.displayedPages.indexOf(page);
- const annotationsOnPage = this.displayedAnnotations[page].annotations;
- const idx = annotationsOnPage.indexOf(this.selectedAnnotation);
-
- if ($event.key === 'ArrowDown') {
- if (idx + 1 !== annotationsOnPage.length) { // If not last item in page
- this.selectAnnotation(annotationsOnPage[idx + 1]);
- } else if (pageIdx + 1 < this.displayedPages.length) { // If not last page
- const nextPageAnnotations = this.displayedAnnotations[this.displayedPages[pageIdx + 1]].annotations;
- this.selectAnnotation(nextPageAnnotations[0]);
- }
- } else {
- if (idx !== 0) { // If not first item in page
- this.selectAnnotation(annotationsOnPage[idx - 1]);
- } else if (pageIdx) { // If not first page
- const prevPageAnnotations = this.displayedAnnotations[this.displayedPages[pageIdx - 1]].annotations;
- this.selectAnnotation(prevPageAnnotations[prevPageAnnotations.length - 1]);
- }
- }
- }
- }
-
- private _navigatePages($event: KeyboardEvent) {
- const pageIdx = this.displayedPages.indexOf(this.activeViewerPage);
-
- if ($event.key === 'ArrowDown') {
- if (pageIdx !== -1) { // If active page has annotations
- if (pageIdx !== this.displayedPages.length - 1) {
- this.selectPage(this.displayedPages[pageIdx + 1]);
- }
- } else { // If active page doesn't have annotations
- const nextPage = this._nextPageWithAnnotations();
- if (nextPage) {
- this.selectPage(nextPage);
- }
- }
- } else {
- if (pageIdx !== -1) { // If active page has annotations
- if (pageIdx !== 0) {
- this.selectPage(this.displayedPages[pageIdx - 1]);
- }
- } else { // If active page doesn't have annotations
- const prevPage = this._prevPageWithAnnotations();
- if (prevPage) {
- this.selectPage(prevPage);
- }
- }
- }
- }
-
- private _nextPageWithAnnotations() {
- let idx = 0;
- for (const page of this.displayedPages) {
- if (page > this.activeViewerPage) {
- break;
- }
- ++idx;
- }
- return idx < this.displayedPages.length ? this.displayedPages[idx] : null;
- }
-
- private _prevPageWithAnnotations() {
- let idx = this.displayedPages.length - 1;
- for (const page of this.displayedPages.reverse()) {
- if (page < this.activeViewerPage) {
- this.selectPage(this.displayedPages[idx]);
+ @debounce()
+ private _scrollViews() {
+ this._scrollQuickNavigation();
this._scrollAnnotations();
- break;
- }
- --idx;
}
- return idx >= 0 ? this.displayedPages[idx] : null;
- }
- viewerPageChanged($event: number) {
- this._scrollViews();
- this._changeDetectorRef.detectChanges();
- }
+ private _scrollQuickNavigation() {
+ const elements: any[] = this._quickNavigationElement.nativeElement.querySelectorAll(
+ `#quick-nav-page-${this.activeViewerPage}`
+ );
+ this._scrollToFirstElement(elements);
+ }
- viewerReady($event: WebViewerInstance) {
- this.instance = $event;
- }
+ private _scrollAnnotations() {
+ if (this.selectedAnnotation?.getPageNumber() === this.activeViewerPage) {
+ return;
+ }
+ const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(
+ `div[anotation-page-header="${this.activeViewerPage}"]`
+ );
+ this._scrollToFirstElement(elements);
+ }
- handleAnnotationsAdded(annotations: Annotations.Annotation[]) {
+ private _scrollToFirstElement(elements: HTMLElement[]) {
+ if (elements.length > 0) {
+ scrollIntoView(elements[0], {
+ behavior: 'smooth',
+ scrollMode: 'if-needed',
+ block: 'start',
+ inline: 'start'
+ });
+ }
+ }
- // handle comments
- annotations.forEach(a => {
- a['comments'] = a['Mi'] ? a['Mi'].map(m => {
- return { value: m.eC };
- }) : [];
- });
+ public getType(annotation: Annotations.Annotation): string {
+ return AnnotationUtils.getType(annotation);
+ }
- AnnotationUtils.addAnnotations(this.annotations, annotations);
- this.applyFilters();
- this._changeDetectorRef.detectChanges();
- }
+ public getDictionary(annotation: Annotations.Annotation): string {
+ return AnnotationUtils.getDictionary(annotation);
+ }
+
+ public acceptSuggestionAnnotation($event: MouseEvent, annotation: Annotations.Annotation) {
+ this.ngZone.run(() => {
+ this._dialogRef = this._dialogService.acceptSuggestionAnnotation(
+ $event,
+ annotation,
+ this.projectId,
+ this.fileId
+ );
+ });
+ }
+
+ public suggestRemoveAnnotation($event: MouseEvent, annotation: Annotations.Annotation) {
+ this.ngZone.run(() => {
+ this._dialogRef = this._dialogService.suggestRemoveAnnotation(
+ $event,
+ annotation,
+ this.projectId,
+ this.fileId
+ );
+ });
+ }
+
+ public downloadFile(type: FileType | string) {
+ this._fileDownloadService.loadFile(type, this.fileId).subscribe((data) => {
+ saveAs(data, this.appStateService.activeFile.filename);
+ });
+ }
+
+ public setAllFilters(filter: AnnotationFilters, value: boolean, rootKey?: string) {
+ if (rootKey) {
+ this.filters[rootKey] = value;
+ } else {
+ for (const key of Object.keys(filter)) {
+ if (AnnotationUtils.hasSubsections(filter[key])) {
+ this.setAllFilters(filter[key], value);
+ } else {
+ filter[key] = value;
+ }
+ }
+ }
+
+ this.applyFilters();
+ }
+
+ public isChecked(key: string): boolean {
+ return AnnotationUtils.isChecked(this.filters[key]);
+ }
+
+ public isIndeterminate(key: string): boolean {
+ return AnnotationUtils.isIndeterminate(this.filters[key]);
+ }
+
+ public get hasActiveFilters(): boolean {
+ return AnnotationUtils.hasActiveFilters(this.filters);
+ }
+
+ public hasSubsections(filter: AnnotationFilters | boolean) {
+ return AnnotationUtils.hasSubsections(filter);
+ }
+
+ public setExpanded(key: string, value: boolean, $event: MouseEvent) {
+ $event.stopPropagation();
+ this.expandedFilters[key] = value;
+ }
+
+ public isManuallyAddedAnnotation(annotation: Annotations.Annotation) {
+ return annotation.Id.indexOf('request:') >= 0;
+ }
+
+ @HostListener('window:keyup', ['$event'])
+ handleKeyEvent($event: KeyboardEvent) {
+ const keyArray = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
+
+ if (!keyArray.includes($event.key) || this._dialogRef?.getState() === MatDialogState.OPEN) {
+ return;
+ }
+
+ if ($event.key === 'ArrowLeft' || $event.key === 'ArrowRight') {
+ this.pagesPanelActive = !this.pagesPanelActive;
+ this._changeDetectorRef.detectChanges();
+ return;
+ }
+
+ if (!this.pagesPanelActive) {
+ this._navigateAnnotations($event);
+ } else {
+ this._navigatePages($event);
+ }
+ }
+
+ private _navigateAnnotations($event: KeyboardEvent) {
+ if (
+ !this.selectedAnnotation ||
+ this.activeViewerPage !== this.selectedAnnotation.getPageNumber()
+ ) {
+ const pageIdx = this.displayedPages.indexOf(this.activeViewerPage);
+ if (pageIdx !== -1) {
+ // Displayed page has annotations
+ this.selectAnnotation(
+ this.displayedAnnotations[this.activeViewerPage].annotations[0]
+ );
+ } else {
+ // Displayed page doesn't have annotations
+ if ($event.key === 'ArrowDown') {
+ const nextPage = this._nextPageWithAnnotations();
+ this.selectAnnotation(this.displayedAnnotations[nextPage].annotations[0]);
+ } else {
+ const prevPage = this._prevPageWithAnnotations();
+ const prevPageAnnotations = this.displayedAnnotations[prevPage].annotations;
+ this.selectAnnotation(prevPageAnnotations[prevPageAnnotations.length - 1]);
+ }
+ }
+ } else {
+ const page = this.selectedAnnotation.getPageNumber();
+ const pageIdx = this.displayedPages.indexOf(page);
+ const annotationsOnPage = this.displayedAnnotations[page].annotations;
+ const idx = annotationsOnPage.indexOf(this.selectedAnnotation);
+
+ if ($event.key === 'ArrowDown') {
+ if (idx + 1 !== annotationsOnPage.length) {
+ // If not last item in page
+ this.selectAnnotation(annotationsOnPage[idx + 1]);
+ } else if (pageIdx + 1 < this.displayedPages.length) {
+ // If not last page
+ const nextPageAnnotations = this.displayedAnnotations[
+ this.displayedPages[pageIdx + 1]
+ ].annotations;
+ this.selectAnnotation(nextPageAnnotations[0]);
+ }
+ } else {
+ if (idx !== 0) {
+ // If not first item in page
+ this.selectAnnotation(annotationsOnPage[idx - 1]);
+ } else if (pageIdx) {
+ // If not first page
+ const prevPageAnnotations = this.displayedAnnotations[
+ this.displayedPages[pageIdx - 1]
+ ].annotations;
+ this.selectAnnotation(prevPageAnnotations[prevPageAnnotations.length - 1]);
+ }
+ }
+ }
+ }
+
+ private _navigatePages($event: KeyboardEvent) {
+ const pageIdx = this.displayedPages.indexOf(this.activeViewerPage);
+
+ if ($event.key === 'ArrowDown') {
+ if (pageIdx !== -1) {
+ // If active page has annotations
+ if (pageIdx !== this.displayedPages.length - 1) {
+ this.selectPage(this.displayedPages[pageIdx + 1]);
+ }
+ } else {
+ // If active page doesn't have annotations
+ const nextPage = this._nextPageWithAnnotations();
+ if (nextPage) {
+ this.selectPage(nextPage);
+ }
+ }
+ } else {
+ if (pageIdx !== -1) {
+ // If active page has annotations
+ if (pageIdx !== 0) {
+ this.selectPage(this.displayedPages[pageIdx - 1]);
+ }
+ } else {
+ // If active page doesn't have annotations
+ const prevPage = this._prevPageWithAnnotations();
+ if (prevPage) {
+ this.selectPage(prevPage);
+ }
+ }
+ }
+ }
+
+ private _nextPageWithAnnotations() {
+ let idx = 0;
+ for (const page of this.displayedPages) {
+ if (page > this.activeViewerPage) {
+ break;
+ }
+ ++idx;
+ }
+ return idx < this.displayedPages.length ? this.displayedPages[idx] : null;
+ }
+
+ private _prevPageWithAnnotations() {
+ let idx = this.displayedPages.length - 1;
+ for (const page of this.displayedPages.reverse()) {
+ if (page < this.activeViewerPage) {
+ this.selectPage(this.displayedPages[idx]);
+ this._scrollAnnotations();
+ break;
+ }
+ --idx;
+ }
+ return idx >= 0 ? this.displayedPages[idx] : null;
+ }
+
+ viewerPageChanged($event: number) {
+ this._scrollViews();
+ this._changeDetectorRef.detectChanges();
+ }
+
+ viewerReady($event: WebViewerInstance) {
+ this.instance = $event;
+ }
+
+ handleAnnotationsAdded(annotations: Annotations.Annotation[]) {
+ // handle comments
+ annotations.forEach((a) => {
+ a['comments'] = a['Mi']
+ ? a['Mi'].map((m) => {
+ return { value: m.eC };
+ })
+ : [];
+ });
+
+ AnnotationUtils.addAnnotations(this.annotations, annotations);
+ this.applyFilters();
+ this._changeDetectorRef.detectChanges();
+ }
}
diff --git a/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts b/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts
index 981d94634..b98ca230c 100644
--- a/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts
+++ b/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts
@@ -1,252 +1,249 @@
import {
- AfterViewInit,
- Component,
- ElementRef,
- EventEmitter,
- Input,
- OnChanges,
- OnInit,
- Output,
- SimpleChanges,
- ViewChild
+ AfterViewInit,
+ Component,
+ ElementRef,
+ EventEmitter,
+ Input,
+ OnChanges,
+ OnInit,
+ Output,
+ SimpleChanges,
+ ViewChild
} from '@angular/core';
-import {AppConfigKey, AppConfigService} from '../../../app-config/app-config.service';
-import {FileStatus, ManualRedactionEntry, Rectangle} from '@redaction/red-ui-http';
-import WebViewer, {Annotations, WebViewerInstance} from '@pdftron/webviewer';
-import {TranslateService} from '@ngx-translate/core';
-import {FileDownloadService} from '../service/file-download.service';
+import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.service';
+import { FileStatus, ManualRedactionEntry, Rectangle } from '@redaction/red-ui-http';
+import WebViewer, { Annotations, WebViewerInstance } from '@pdftron/webviewer';
+import { TranslateService } from '@ngx-translate/core';
+import { FileDownloadService } from '../service/file-download.service';
export interface ViewerState {
-
- displayMode?: any;
- layoutMode?: any;
- pageNumber?: any;
- scrollTop?: any;
- scrollLeft?: any;
- zoom?: any;
- leftPanelState?: any;
-
+ displayMode?: any;
+ layoutMode?: any;
+ pageNumber?: any;
+ scrollTop?: any;
+ scrollLeft?: any;
+ zoom?: any;
+ leftPanelState?: any;
}
@Component({
- selector: 'redaction-pdf-viewer',
- templateUrl: './pdf-viewer.component.html',
- styleUrls: ['./pdf-viewer.component.scss']
+ selector: 'redaction-pdf-viewer',
+ templateUrl: './pdf-viewer.component.html',
+ styleUrls: ['./pdf-viewer.component.scss']
})
export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
+ private _viewerState: ViewerState = null; // no initial state
- private _viewerState: ViewerState = null; // no initial state
+ @Input() fileData: Blob;
+ @Input() fileStatus: FileStatus;
- @Input() fileData: Blob;
- @Input() fileStatus: FileStatus;
+ @Output() fileReady = new EventEmitter();
+ @Output() annotationsAdded = new EventEmitter();
+ @Output() annotationSelected = new EventEmitter();
+ @Output() manualAnnotationRequested = new EventEmitter();
+ @Output() pageChanged = new EventEmitter();
+ @Output() keyUp = new EventEmitter();
+ @Output() viewerReady = new EventEmitter();
- @Output() fileReady = new EventEmitter();
- @Output() annotationsAdded = new EventEmitter();
- @Output() annotationSelected = new EventEmitter();
- @Output() manualAnnotationRequested = new EventEmitter();
- @Output() pageChanged = new EventEmitter();
- @Output() keyUp = new EventEmitter();
+ @Input() flag = false;
- @Output() viewerReady = new EventEmitter();
+ @ViewChild('viewer', { static: true }) viewer: ElementRef;
+ instance: WebViewerInstance;
- @Input() flag = false;
+ constructor(
+ private readonly _translateService: TranslateService,
+ private readonly _fileDownloadService: FileDownloadService,
+ private readonly _appConfigService: AppConfigService
+ ) {}
- @ViewChild('viewer', {static: true}) viewer: ElementRef;
- instance: WebViewerInstance;
-
- constructor(private readonly _translateService: TranslateService,
- private readonly _fileDownloadService: FileDownloadService,
- private readonly _appConfigService: AppConfigService) {
- }
-
- ngOnInit() {
- this._restoreViewerState = this._restoreViewerState.bind(this);
- }
-
- ngOnChanges(changes: SimpleChanges): void {
- if (changes.fileData && !changes.fileData.firstChange) {
- this._changeDocument();
+ ngOnInit() {
+ this._restoreViewerState = this._restoreViewerState.bind(this);
}
- }
- ngAfterViewInit(): void {
- this._loadViewer(this.fileData);
- }
-
- private _loadViewer(pdfBlob: any) {
- const license = this._appConfigService.getConfig(AppConfigKey.PDFTRON_LICENSE);
- WebViewer({
- licenseKey: license,
- isReadOnly: true,
- path: '/assets/wv-resources'
- }, this.viewer.nativeElement).then(instance => {
- this.instance = instance;
- this._disableElements();
- this._configureTextPopup();
- this._configureHeader();
- instance.annotManager.on('annotationChanged', (annotations, action) => {
- if (action === 'add') {
- this.annotationsAdded.emit(annotations);
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes.fileData && !changes.fileData.firstChange) {
+ this._changeDocument();
}
- });
+ }
- instance.annotManager.on('annotationSelected', ((annotationList, action) => {
- if (action === 'deselected') {
- this.annotationSelected.emit(null);
+ ngAfterViewInit(): void {
+ this._loadViewer(this.fileData);
+ }
+
+ private _loadViewer(pdfBlob: any) {
+ const license = this._appConfigService.getConfig(AppConfigKey.PDFTRON_LICENSE);
+ WebViewer(
+ {
+ licenseKey: license,
+ isReadOnly: true,
+ path: '/assets/wv-resources'
+ },
+ this.viewer.nativeElement
+ ).then((instance) => {
+ this.instance = instance;
+ this._disableElements();
+ this._configureTextPopup();
+ this._configureHeader();
+ instance.annotManager.on('annotationChanged', (annotations, action) => {
+ if (action === 'add') {
+ this.annotationsAdded.emit(annotations);
+ }
+ });
+
+ instance.annotManager.on('annotationSelected', (annotationList, action) => {
+ if (action === 'deselected') {
+ this.annotationSelected.emit(null);
+ } else {
+ this.annotationSelected.emit(annotationList[0]);
+ }
+ });
+
+ instance.docViewer.on('pageComplete', (p) => {
+ this.pageChanged.emit(p);
+ });
+
+ instance.docViewer.on('documentLoaded', this._restoreViewerState);
+
+ instance.docViewer.on('keyDown', ($event) => {
+ if ($event.key.startsWith('Arrow')) {
+ $event.preventDefault();
+ }
+ });
+
+ instance.docViewer.on('keyUp', ($event) => {
+ if ($event.key.startsWith('Arrow')) {
+ this.keyUp.emit($event);
+ }
+ });
+
+ instance.loadDocument(pdfBlob, {
+ filename: this.fileStatus ? this.fileStatus.filename : 'document.pdf'
+ });
+
+ this.viewerReady.emit(instance);
+ });
+ }
+
+ private _disableElements() {
+ this.instance.disableElements([
+ 'textHighlightToolButton',
+ 'textUnderlineToolButton',
+ 'textSquigglyToolButton',
+ 'textStrikeoutToolButton',
+ 'linkButton',
+ 'toggleNotesButton',
+ 'notesPanel',
+ 'thumbnailControl',
+ 'documentControl',
+ 'ribbons',
+ 'rotateClockwiseButton',
+ 'rotateCounterClockwiseButton'
+ ]);
+ }
+
+ private _configureTextPopup() {
+ this.instance.textPopup.add({
+ type: 'actionButton',
+ img: '/assets/icons/general/add-redaction.svg',
+ title: this._translateService.instant(
+ 'pdf-viewer.text-popup.actions.suggestion-redaction.label'
+ ),
+ onClick: () => {
+ const selectedQuads = this.instance.docViewer.getSelectedTextQuads();
+ const text = this.instance.docViewer.getSelectedText();
+ const entry: ManualRedactionEntry = { positions: [] };
+ for (const key of Object.keys(selectedQuads)) {
+ for (const quad of selectedQuads[key]) {
+ entry.positions.push(this.toPosition(parseInt(key, 10), quad));
+ }
+ }
+ entry.value = text;
+ this.manualAnnotationRequested.emit(entry);
+ }
+ });
+ }
+
+ private toPosition(page: number, selectedQuad: any): Rectangle {
+ const pageHeight = this.instance.docViewer.getPageHeight(page);
+ const height = selectedQuad.y2 - selectedQuad.y4;
+ return {
+ page: page,
+ topLeft: {
+ x: selectedQuad.x4,
+ y: pageHeight - (selectedQuad.y4 + height)
+ },
+ height: height,
+ width: selectedQuad.x3 - selectedQuad.x4
+ };
+ }
+
+ private _configureHeader() {
+ this.instance.setToolbarGroup('toolbarGroup-View');
+ }
+
+ public selectAnnotation(annotation: Annotations.Annotation) {
+ this.instance.annotManager.deselectAllAnnotations();
+ this.instance.annotManager.selectAnnotation(annotation);
+ this.navigateToPage(annotation.getPageNumber());
+ }
+
+ public navigateToPage(pageNumber: number) {
+ const activePage = this.instance.docViewer.getCurrentPage();
+ if (activePage !== pageNumber) {
+ this.instance.docViewer.displayPageLocation(pageNumber, 0, 0);
+ }
+ }
+
+ private _changeDocument() {
+ // sync layout and display mode
+
+ const instance = this.instance;
+ const docViewer = this.instance.docViewer;
+
+ const lastScrolledViewerScrollElement = docViewer.getScrollViewElement();
+
+ const viewerState: ViewerState = {
+ displayMode: docViewer.getDisplayModeManager().getDisplayMode().mode,
+ layoutMode: instance.getLayoutMode(),
+ pageNumber: instance.docViewer.getCurrentPage(),
+ scrollLeft: lastScrolledViewerScrollElement.scrollLeft,
+ scrollTop: lastScrolledViewerScrollElement.scrollTop,
+ zoom: docViewer.getZoom(),
+ leftPanelState: instance.isElementOpen('leftPanel')
+ };
+
+ this.instance.loadDocument(this.fileData, {
+ filename: this.fileStatus ? this.fileStatus.filename : 'document.pdf'
+ });
+
+ this._viewerState = viewerState;
+ }
+
+ private _restoreViewerState() {
+ this._restoreState(this._viewerState, this.instance);
+ }
+
+ private _restoreState(viewerState: ViewerState, instance: WebViewerInstance) {
+ if (this._viewerState) {
+ instance.docViewer.setCurrentPage(viewerState.pageNumber);
+ instance.setLayoutMode(viewerState.layoutMode);
+ const instanceDisplayMode = instance.docViewer.getDisplayModeManager().getDisplayMode();
+ instanceDisplayMode.mode = viewerState.displayMode;
+ instance.docViewer.getDisplayModeManager().setDisplayMode(instanceDisplayMode);
+ // Synchronize zoom - needs to be done before scrolling
+ instance.docViewer.zoomTo(viewerState.zoom);
+ const viewerScrollElement = instance.docViewer.getScrollViewElement();
+ viewerScrollElement.scrollTo(viewerState.scrollLeft, viewerState.scrollTop);
+
+ if (viewerState.leftPanelState) {
+ instance.openElements(['leftPanel']);
+ } else {
+ instance.closeElements(['leftPanel']);
+ }
} else {
- this.annotationSelected.emit(annotationList[0]);
+ // viewer init
+ this.instance.setFitMode('FitPage');
}
- }));
-
- instance.docViewer.on('pageComplete', (p) => {
- this.pageChanged.emit(p);
- });
-
- instance.docViewer.on('documentLoaded', this._restoreViewerState);
-
- instance.docViewer.on('keyDown', ($event) => {
- if ($event.key.startsWith('Arrow')) {
- $event.preventDefault();
- }
- })
-
- instance.docViewer.on('keyUp', ($event) => {
- if ($event.key.startsWith('Arrow')) {
- this.keyUp.emit($event);
- }
- })
-
- instance.loadDocument(pdfBlob, {filename: this.fileStatus ? this.fileStatus.filename : 'document.pdf'});
-
- this.viewerReady.emit(instance);
- });
- }
-
-
- private _disableElements() {
- this.instance.disableElements([
- 'textHighlightToolButton',
- 'textUnderlineToolButton',
- 'textSquigglyToolButton',
- 'textStrikeoutToolButton',
- 'linkButton',
- 'toggleNotesButton',
- 'notesPanel',
- 'thumbnailControl',
- 'documentControl',
- 'ribbons',
- 'rotateClockwiseButton',
- 'rotateCounterClockwiseButton'
- ]);
- }
-
- private _configureTextPopup() {
- this.instance.textPopup.add({
- type: 'actionButton',
- img: '/assets/icons/general/add-redaction.svg',
- title: this._translateService.instant('pdf-viewer.text-popup.actions.suggestion-redaction.label'),
- onClick: () => {
- const selectedQuads = this.instance.docViewer.getSelectedTextQuads();
- const text = this.instance.docViewer.getSelectedText();
- const entry: ManualRedactionEntry = {positions: []};
- for (const key of Object.keys(selectedQuads)) {
- for (const quad of selectedQuads[key]) {
- entry.positions.push(this.toPosition(parseInt(key, 10), quad));
- }
- }
- entry.value = text;
- this.manualAnnotationRequested.emit(entry);
- }
- });
- }
-
- private toPosition(page: number, selectedQuad: any): Rectangle {
-
- const pageHeight = this.instance.docViewer.getPageHeight(page);
- const height = selectedQuad.y2 - selectedQuad.y4;
- return {
- page: page,
- topLeft: {
- x: selectedQuad.x4,
- y: pageHeight - (selectedQuad.y4 + height)
- },
- height: height,
- width: selectedQuad.x3 - selectedQuad.x4
- };
- }
-
- private _configureHeader() {
- this.instance.setToolbarGroup('toolbarGroup-View');
- }
-
-
- public selectAnnotation(annotation: Annotations.Annotation) {
- this.instance.annotManager.deselectAllAnnotations();
- this.instance.annotManager.selectAnnotation(annotation);
- this.navigateToPage(annotation.getPageNumber());
- }
-
- public navigateToPage(pageNumber: number) {
- const activePage = this.instance.docViewer.getCurrentPage();
- if (activePage !== pageNumber) {
- this.instance.docViewer.displayPageLocation(pageNumber, 0, 0);
}
- }
-
-
- private _changeDocument() {
- // sync layout and display mode
-
-
- const instance = this.instance;
- const docViewer = this.instance.docViewer;
-
- const lastScrolledViewerScrollElement = docViewer.getScrollViewElement();
-
- const viewerState: ViewerState = {
- displayMode: docViewer.getDisplayModeManager().getDisplayMode().mode,
- layoutMode: instance.getLayoutMode(),
- pageNumber: instance.docViewer.getCurrentPage(),
- scrollLeft: lastScrolledViewerScrollElement.scrollLeft,
- scrollTop: lastScrolledViewerScrollElement.scrollTop,
- zoom: docViewer.getZoom(),
- leftPanelState: instance.isElementOpen('leftPanel')
- }
-
- this.instance.loadDocument(this.fileData, {filename: this.fileStatus ? this.fileStatus.filename : 'document.pdf'});
-
- this._viewerState = viewerState;
-
- }
-
- private _restoreViewerState() {
- this._restoreState(this._viewerState, this.instance);
- }
-
- private _restoreState(viewerState: ViewerState, instance: WebViewerInstance) {
- if (this._viewerState) {
- instance.docViewer.setCurrentPage(viewerState.pageNumber);
- instance.setLayoutMode(viewerState.layoutMode);
- const instanceDisplayMode = instance.docViewer.getDisplayModeManager().getDisplayMode();
- instanceDisplayMode.mode = viewerState.displayMode;
- instance.docViewer.getDisplayModeManager().setDisplayMode(instanceDisplayMode);
- // Synchronize zoom - needs to be done before scrolling
- instance.docViewer.zoomTo(viewerState.zoom);
- const viewerScrollElement = instance.docViewer.getScrollViewElement();
- viewerScrollElement.scrollTo(viewerState.scrollLeft, viewerState.scrollTop);
-
- if (viewerState.leftPanelState) {
- instance.openElements(['leftPanel']);
- } else {
- instance.closeElements(['leftPanel']);
- }
- } else {
- // viewer init
- this.instance.setFitMode('FitPage');
- }
- }
-
-
}
-
diff --git a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html
index 91ddf98ae..895fd5ba6 100644
--- a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html
+++ b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html
@@ -1,151 +1,188 @@