- {{annotation.Id+ ' '+annotation.getPageNumber() + ' content: ' + annotation.getContents() + 'status: '+annotation.getStatus()}}
+
+
+
{{annotation.Id}}
+
Page {{annotation.getPageNumber()}}
+
{{annotation.getContents()}}
+
{{annotation.getStatus()}}
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 4d3c0137c..8b1faef8f 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
@@ -17,6 +17,8 @@ redaction-pdf-viewer {
.tabs-title-row {
border-bottom: 1px solid rgba(226,228,233,0.9);
+ box-sizing: border-box;
+ height: 45px;
.tab {
font-size: 13px;
@@ -40,8 +42,12 @@ redaction-pdf-viewer {
.actions-row {
margin: $right-container-padding $right-container-padding 0;
}
+
.tab-content {
padding: $right-container-padding;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ height: calc(100vh - 110px - 40px - 45px - 3*#{$right-container-padding});
}
.stats-subtitle {
@@ -55,4 +61,15 @@ redaction-pdf-viewer {
margin-left: 12px;
}
+
+ .annotation {
+ border: 1px solid $grey-2;
+ padding: 14px;
+ font-size: 12px;
+ cursor: pointer;
+
+ &.active {
+ border-left: 2px solid $red-1;
+ }
+ }
}
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 00bc316ce..63d69cece 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,13 +1,15 @@
-import {ChangeDetectorRef, Component, OnInit} from '@angular/core';
-import {ActivatedRoute, Router} from '@angular/router';
-import {FileUploadControllerService, ProjectControllerService, StatusControllerService} from '@redaction/red-ui-http';
-import {TranslateService} from '@ngx-translate/core';
-import {NotificationService} from '../../../notification/notification.service';
-import {MatDialog} from '@angular/material/dialog';
-import {AppStateService} from '../../../state/app-state.service';
-import {FileDetailsDialogComponent} from './file-details-dialog/file-details-dialog.component';
-import {ViewerSyncService} from '../service/viwer-sync.service';
-import {Annotations} from "@pdftron/webviewer";
+import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { FileUploadControllerService, ProjectControllerService, StatusControllerService } from '@redaction/red-ui-http';
+import { TranslateService } from '@ngx-translate/core';
+import { NotificationService } from '../../../notification/notification.service';
+import { MatDialog } from '@angular/material/dialog';
+import { AppStateService } from '../../../state/app-state.service';
+import { FileDetailsDialogComponent } from './file-details-dialog/file-details-dialog.component';
+import { ViewerSyncService } from '../service/viwer-sync.service';
+import { Annotations } from '@pdftron/webviewer';
+import { PdfViewerComponent } from '../pdf-viewer/pdf-viewer.component';
+import { AnnotationUtils } from '../../../utils/annotation-utils';
@Component({
selector: 'redaction-file-preview-screen',
@@ -15,12 +17,20 @@ import {Annotations} from "@pdftron/webviewer";
styleUrls: ['./file-preview-screen.component.scss']
})
export class FilePreviewScreenComponent implements OnInit {
-
- projectId: string;
- fileId: string;
- annotations: Annotations.Annotation[] = [];
- public selectedTab: 'ANNOTATIONS' | 'INFO' = 'ANNOTATIONS';
private _readyViewers: string[] = [];
+ private _clickedAnnotationInSidebar = false;
+ private projectId: string;
+
+ @ViewChild(PdfViewerComponent)
+ private _viewerComponent: PdfViewerComponent;
+
+ @ViewChild('annotationsContainer')
+ private _annotationsContainer: ElementRef;
+
+ public fileId: string;
+ public annotations: Annotations.Annotation[] = [];
+ public selectedTab: 'ANNOTATIONS' | 'INFO' = 'ANNOTATIONS';
+ public selectedAnnotation: Annotations.Annotation;
constructor(
public readonly appStateService: AppStateService,
@@ -77,10 +87,44 @@ export class FilePreviewScreenComponent implements OnInit {
handleAnnotationsAdded(annotations: Annotations.Annotation[]) {
this._changeDetectorRef.detectChanges();
- for(let annotation of annotations){
- if(annotation.Id.indexOf(':')>=0){
+ for (const annotation of annotations) {
+ if (annotation.Id.indexOf(':') >= 0) {
this.annotations.push(annotation);
}
}
+ this.annotations = AnnotationUtils.sortAnnotations(this.annotations);
+ }
+
+ public handleAnnotationSelected(annotation: Annotations.Annotation) {
+ this.selectedAnnotation = annotation;
+ this.scrollToAnnotation(annotation);
+ }
+
+ public selectAnnotation(annotation: Annotations.Annotation) {
+ this._clickedAnnotationInSidebar = true;
+ setTimeout(() => {
+ this._clickedAnnotationInSidebar = false;
+ }, 100);
+ this._viewerComponent.selectAnnotation(annotation);
+ }
+
+ private scrollToAnnotation(annotation: Annotations.Annotation) {
+ if (!annotation || this._clickedAnnotationInSidebar) {
+ return;
+ }
+ const el = document.getElementById('ann-' + annotation.Id);
+
+ if (!el) {
+ console.error(`Annotation with id ${annotation.Id} does not exist!`);
+ return;
+ }
+
+ const { top, height } = el.getBoundingClientRect();
+ const headerHeight = window.innerHeight - this._annotationsContainer.nativeElement.getBoundingClientRect().height;
+
+ if (top < headerHeight || top > window.innerHeight - height - 30) {
+ const scrollTop = this._annotationsContainer.nativeElement.scrollTop - 30;
+ this._annotationsContainer.nativeElement.scroll({ top: scrollTop + top - headerHeight, behavior: 'smooth' });
+ }
}
}
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 1894c09c8..bb24d6db8 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
@@ -16,6 +16,7 @@ import {tap} from "rxjs/operators";
import WebViewer, {Annotations, WebViewerInstance} from "@pdftron/webviewer";
import {TranslateService} from "@ngx-translate/core";
import {ViewerSyncService} from "../service/viwer-sync.service";
+import { AnnotationUtils } from '../../../utils/annotation-utils';
@@ -37,6 +38,7 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnDestroy {
@Input() fileStatus: FileStatus;
@Output() fileReady = new EventEmitter();
@Output() annotationsAdded = new EventEmitter
();
+ @Output() annotationSelected = new EventEmitter();
@ViewChild('viewer', {static: true}) viewer: ElementRef;
wvInstance: WebViewerInstance;
@@ -81,12 +83,20 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnDestroy {
this._viewerSyncService.registerViewer(this.fileType, this.wvInstance);
this._configureTextPopup();
this._configureHeader();
- instance.annotManager.on('annotationChanged', (annotations,b,c) => {
- if(b === 'add'){
+ 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('documentLoaded', this.wvDocumentLoadedHandler)
instance.loadDocument(pdfBlob, {filename: this.fileStatus ? this.fileStatus.filename : 'file.pdf'});
});
@@ -123,8 +133,8 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnDestroy {
'textSquigglyToolButton',
'textStrikeoutToolButton',
'linkButton',
- // 'toggleNotesButton',
- // 'notesPanel'
+ 'toggleNotesButton',
+ 'notesPanel'
]);
this.wvInstance.textPopup.add({
@@ -147,5 +157,13 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnDestroy {
this._viewerSyncService.deregisterInstance(this.fileType);
}
+ public selectAnnotation(annotation: Annotations.Annotation) {
+ this.wvInstance.annotManager.deselectAllAnnotations();
+ this.wvInstance.annotManager.selectAnnotation(annotation);
+ this.wvInstance.docViewer.displayPageLocation(
+ annotation.getPageNumber(),
+ 0,
+ annotation.getY() - 100);
+ }
}
diff --git a/apps/red-ui/src/app/utils/annotation-utils.ts b/apps/red-ui/src/app/utils/annotation-utils.ts
new file mode 100644
index 000000000..d12a5bf59
--- /dev/null
+++ b/apps/red-ui/src/app/utils/annotation-utils.ts
@@ -0,0 +1,18 @@
+import { Annotations } from '@pdftron/webviewer';
+
+export class AnnotationUtils {
+ public static sortAnnotations(annotations: Annotations.Annotation[]): Annotations.Annotation[] {
+ return annotations.sort((ann1, ann2) => {
+ if (ann1.getPageNumber() === ann2.getPageNumber()) {
+ if (ann1.getY() === ann2.getY()) {
+ if (ann1.getX() === ann2.getY()) {
+ return 0;
+ }
+ return ann1.getX() < ann2.getX() ? -1 : 1;
+ }
+ return ann1.getY() < ann2.getY() ? -1 : 1;
+ }
+ return ann1.getPageNumber() < ann2.getPageNumber() ? -1 : 1;
+ });
+ }
+}
diff --git a/apps/red-ui/src/assets/styles/red-page-layout.scss b/apps/red-ui/src/assets/styles/red-page-layout.scss
index e1d6ad22e..c3b586e7b 100644
--- a/apps/red-ui/src/assets/styles/red-page-layout.scss
+++ b/apps/red-ui/src/assets/styles/red-page-layout.scss
@@ -38,6 +38,7 @@ html, body {
.actions-row {
display: flex;
+ height: 40px;
> div {
padding: 10px;