@hmcts/annotation-ui-lib
Version:
PDF Viewer and ability to highlight text with and comment tracking
1,556 lines (1,542 loc) • 96.2 kB
JavaScript
import { v4 } from 'uuid';
import { isPlatformServer, CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { __awaiter } from 'tslib';
import { WINDOW, NgtUniversalModule } from '@ng-toolkit/universal';
import { Injectable, Inject, PLATFORM_ID, Component, ViewChildren, Input, Output, EventEmitter, ViewChild, ChangeDetectorRef, Renderer2, ComponentFactoryResolver, Injector, ApplicationRef, Directive, ViewContainerRef, NgModule, defineInjectable, inject } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpClientModule } from '@angular/common/http';
import { BehaviorSubject, Subject, of, throwError } from 'rxjs';
import { TransferState, makeStateKey } from '@angular/platform-browser';
import { tap, catchError, map } from 'rxjs/operators';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class Comment {
/**
* @param {?} id
* @param {?} annotationId
* @param {?} createdBy
* @param {?} createdByDetails
* @param {?} createdDate
* @param {?} lastModifiedBy
* @param {?} lastModifiedByDetails
* @param {?} lastModifiedDate
* @param {?} content
*/
constructor(id, annotationId, createdBy, createdByDetails, createdDate, lastModifiedBy, lastModifiedByDetails, lastModifiedDate, content) {
this.id = id;
this.annotationId = annotationId;
this.createdBy = createdBy;
this.createdByDetails = createdByDetails;
this.createdDate = createdDate;
this.lastModifiedBy = lastModifiedBy;
this.lastModifiedByDetails = lastModifiedByDetails;
this.lastModifiedDate = lastModifiedDate;
this.content = content;
}
}
class Annotation {
/**
* @param {?=} id
* @param {?=} annotationSetId
* @param {?=} createdBy
* @param {?=} createdDate
* @param {?=} createdByDetails
* @param {?=} lastModifiedBy
* @param {?=} lastModifiedByDetails
* @param {?=} lastModifiedDate
* @param {?=} documentId
* @param {?=} page
* @param {?=} color
* @param {?=} comments
* @param {?=} rectangles
* @param {?=} type
*/
constructor(id, annotationSetId, createdBy, createdDate, createdByDetails, lastModifiedBy, lastModifiedByDetails, lastModifiedDate, documentId, page, color, comments, rectangles, type) {
this.id = id;
this.annotationSetId = annotationSetId;
this.createdBy = createdBy;
this.createdDate = createdDate;
this.createdByDetails = createdByDetails;
this.lastModifiedBy = lastModifiedBy;
this.lastModifiedByDetails = lastModifiedByDetails;
this.lastModifiedDate = lastModifiedDate;
this.documentId = documentId;
this.page = page;
this.color = color;
this.comments = comments;
this.rectangles = rectangles;
this.type = type;
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class PdfAnnotateWrapper {
/**
* @param {?} pageNumber
* @return {?}
*/
createPage(pageNumber) {
return PDFAnnotate.UI.createPage(pageNumber);
}
/**
* @param {?} pageNumber
* @param {?} RENDER_OPTIONS
* @return {?}
*/
renderPage(pageNumber, RENDER_OPTIONS) {
return PDFAnnotate.UI.renderPage(pageNumber, RENDER_OPTIONS);
}
/**
* @param {?} type
* @return {?}
*/
enableRect(type) {
PDFAnnotate.UI.enableRect(type);
}
/**
* @return {?}
*/
disableRect() {
PDFAnnotate.UI.disableRect();
}
/**
* @param {?=} storeAdapter
* @return {?}
*/
setStoreAdapter(storeAdapter) {
if (storeAdapter) {
PDFAnnotate.setStoreAdapter(storeAdapter);
}
else {
PDFAnnotate.setStoreAdapter(new PDFAnnotate.LocalStoreAdapter());
}
}
/**
* @return {?}
*/
getStoreAdapter() {
return PDFAnnotate.getStoreAdapter();
}
/**
* @return {?}
*/
getUi() {
return PDFAnnotate.UI;
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class EmLoggerService {
/**
* @param {?} loggingClass
* @return {?}
*/
setClass(loggingClass) {
this.loggingClass = loggingClass;
}
/**
* @param {?} message
* @return {?}
*/
error(message) {
this.buildLog('error-' + JSON.stringify(message));
}
/**
* @param {?} message
* @return {?}
*/
info(message) {
this.buildLog('info-' + JSON.stringify(message));
}
/**
* @param {?} message
* @return {?}
*/
buildLog(message) {
console.log(`${this.loggingClass}-${message}`);
}
}
EmLoggerService.decorators = [
{ type: Injectable }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class PdfService {
/**
* @param {?} log
* @param {?} pdfAnnotateWrapper
*/
constructor(log, pdfAnnotateWrapper) {
this.log = log;
this.pdfAnnotateWrapper = pdfAnnotateWrapper;
log.setClass('PdfService');
}
/**
* @return {?}
*/
preRun() {
this.pageNumber = new BehaviorSubject(1);
}
/**
* @return {?}
*/
getAnnotationWrapper() {
return this.annotationWrapper;
}
/**
* @param {?} annotationWrapper
* @return {?}
*/
setAnnotationWrapper(annotationWrapper) {
this.annotationWrapper = annotationWrapper;
}
/**
* @return {?}
*/
getPageNumber() {
return this.pageNumber;
}
/**
* @param {?} pageNumber
* @return {?}
*/
setPageNumber(pageNumber) {
this.pageNumber.next(pageNumber);
}
/**
* @return {?}
*/
setHighlightTool() {
this.log.info('Highlight cursor is enabled');
this.pdfAnnotateWrapper.enableRect('highlight');
}
/**
* @return {?}
*/
setCursorTool() {
this.pdfAnnotateWrapper.disableRect();
}
}
PdfService.decorators = [
{ type: Injectable }
];
PdfService.ctorParameters = () => [
{ type: EmLoggerService },
{ type: PdfAnnotateWrapper }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class Utils {
/**
* @param {?} rectangles
* @return {?}
*/
buildLineRectangle(rectangles) {
this.sortByY(rectangles);
/** @type {?} */
const lowestY = rectangles[0].y;
/** @type {?} */
const lineHeight = rectangles[0].height;
this.sortByX(rectangles);
/** @type {?} */
const lowestX = rectangles[0].x;
/** @type {?} */
const upperX = rectangles[rectangles.length - 1].x;
/** @type {?} */
const width = rectangles[rectangles.length - 1].width;
/** @type {?} */
const rectangle = {
y: lowestY,
x: lowestX,
width: (upperX - lowestX) + width,
height: lineHeight
};
return rectangle;
}
/**
* @param {?} annotationRectangles
* @param {?} generatedRectangles
* @return {?}
*/
generateRectanglePerLine(annotationRectangles, generatedRectangles) {
this.sortByY(annotationRectangles);
/** @type {?} */
const highestY = annotationRectangles[annotationRectangles.length - 1].y;
/** @type {?} */
const lowestY = annotationRectangles[0].y;
/** @type {?} */
const lineHeight = this.getAnnotationLineHeight(annotationRectangles);
if (this.difference(highestY, lowestY) > lineHeight) {
/** @type {?} */
const currentLineRectangles = annotationRectangles.filter(rectangle => rectangle.y <= (lowestY + lineHeight));
/** @type {?} */
const nextLineRectangles = annotationRectangles.filter(rectangle => rectangle.y > (lowestY + lineHeight));
generatedRectangles.push(this.buildLineRectangle(currentLineRectangles));
this.generateRectanglePerLine(nextLineRectangles, generatedRectangles);
}
else {
generatedRectangles.push(this.buildLineRectangle(annotationRectangles));
}
}
/**
* @param {?} rectangles
* @return {?}
*/
getAnnotationLineHeight(rectangles) {
return rectangles[0].height;
}
/**
* @param {?} rectangles
* @param {?=} lowest
* @return {?}
*/
sortByY(rectangles, lowest = true) {
rectangles.sort(function (a, b) {
/** @type {?} */
const keyA = a.y;
/** @type {?} */
const keyB = b.y;
if (keyA < keyB) {
return lowest ? -1 : 1;
}
if (keyA > keyB) {
return lowest ? 1 : -1;
}
return 0;
});
}
/**
* @param {?} rectangles
* @param {?=} lowest
* @return {?}
*/
sortByX(rectangles, lowest = true) {
rectangles.sort(function (a, b) {
/** @type {?} */
const keyA = a.x;
/** @type {?} */
const keyB = b.x;
if (keyA < keyB) {
return lowest ? -1 : 1;
}
if (keyA > keyB) {
return lowest ? 1 : -1;
}
return 0;
});
}
/**
* @param {?} a
* @param {?} b
* @return {?}
*/
sortByLinePosition(a, b) {
this.sortByX(a);
this.sortByX(b);
return (a[0].x > b[0].x) ? 1 : -1;
}
/**
* @param {?} a
* @param {?} b
* @return {?}
*/
difference(a, b) { return Math.abs(a - b); }
/**
* @param {?} event
* @return {?}
*/
clickIsHighlight(event) {
/** @type {?} */
const target = (/** @type {?} */ (event.target));
/** @type {?} */
const isHighlight = target.firstElementChild;
if (isHighlight == null) {
return false;
}
else if (isHighlight.id.includes('pdf-annotate-screenreader')) {
return true;
}
else {
return false;
}
}
/**
* @param {?} event
* @return {?}
*/
getClickedPage(event) {
/** @type {?} */
let currentParent = event.target;
for (let step = 0; step < 5; step++) {
if (currentParent.parentNode != null) {
/** @type {?} */
const pageNumber = currentParent.parentNode.getAttribute('data-page-number');
if (pageNumber != null) {
return parseInt(pageNumber, null);
}
currentParent = currentParent.parentNode;
}
}
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class PdfAdapter {
/**
* @param {?} log
* @param {?} utils
* @param {?} window
*/
constructor(log, utils, window) {
this.log = log;
this.utils = utils;
this.window = window;
this.annotationChangeSubject = new Subject();
log.setClass('PdfAdapter');
}
/**
* @return {?}
*/
getAnnotationChangeSubject() {
return this.annotationChangeSubject;
}
/**
* @param {?} annotationSet
* @return {?}
*/
setStoreData(annotationSet) {
this.annotationSet = annotationSet;
this.annotations = annotationSet.annotations;
this.commentData = [];
this.annotations.forEach((annotation) => {
annotation.comments.forEach((comment) => {
this.commentData.push(comment);
});
});
this.annotationSetId = annotationSet.id;
}
/**
* @param {?} comment
* @return {?}
*/
editComment(comment) {
this.annotations.forEach((annotation) => {
annotation.comments
.filter(storeComment => storeComment.id === comment.id)
.map(storeComment => {
this.log.info('Editing comment:' + comment.id);
storeComment.content = comment.content;
this.annotationChangeSubject.next({ 'type': 'editComment', 'annotation': annotation });
});
});
}
/**
* @param {?} documentId
* @param {?} comment
* @return {?}
*/
updateComments(documentId, comment) {
this.commentData.push(comment);
}
/**
* @param {?} documentId
* @return {?}
*/
_getAnnotations(documentId) {
return this.annotations || [];
}
/**
* @param {?} documentId
* @return {?}
*/
_getComments(documentId) {
return this.commentData || [];
}
/**
* @return {?}
*/
clearSelection() {
/** @type {?} */
const sel = this.window.getSelection();
if (sel) {
if (sel.removeAllRanges) {
sel.removeAllRanges();
}
else if (sel.empty) {
sel.empty();
}
}
}
/**
* @param {?} comment
* @return {?}
*/
isDraftComment(comment) {
return (comment.content === null || comment.content === '');
}
/**
* @return {?}
*/
getStoreAdapter() {
/** @type {?} */
const getAnnotations = (documentId, pageNumber) => {
return new Promise((resolve, reject) => {
/** @type {?} */
const annotations = this._getAnnotations(documentId).filter(function (i) {
return i.page === pageNumber;
});
resolve({
documentId: documentId,
pageNumber: pageNumber,
annotations: annotations
});
});
};
/** @type {?} */
const getComments = (documentId, annotationId) => {
return new Promise((resolve, reject) => {
resolve(this._getComments(documentId).filter(function (i) {
return i.annotationId === annotationId;
}));
});
};
/** @type {?} */
const getAnnotation = (documentId, annotationId) => {
return new Promise((resolve, reject) => {
/** @type {?} */
const annotation = this._getAnnotations(documentId).find(function (i) {
return i.id === annotationId;
});
resolve(annotation);
});
};
/** @type {?} */
const addAnnotation = (documentId, pageNumber, annotation) => {
return new Promise((resolve, reject) => {
this.clearSelection();
/** @type {?} */
const persistAnnotation = new Annotation();
persistAnnotation.id = v4();
persistAnnotation.page = pageNumber;
persistAnnotation.color = annotation.color;
persistAnnotation.type = annotation.type;
persistAnnotation.comments = [];
persistAnnotation.annotationSetId = this.annotationSetId;
/** @type {?} */
const rectangles = [];
this.log.info('Generating efficient rectangles for new annotation:' + persistAnnotation.id);
this.utils.generateRectanglePerLine(annotation.rectangles, rectangles);
rectangles.forEach((rectangle) => {
rectangle.id = v4();
});
persistAnnotation.rectangles = rectangles;
/** @type {?} */
const annotations = this._getAnnotations(documentId);
annotations.push(persistAnnotation);
this.log.info('Added annotation:' + annotation.id);
this.annotationChangeSubject.next({ 'type': 'addAnnotation', 'annotation': persistAnnotation });
resolve(persistAnnotation);
});
};
/** @type {?} */
const deleteAnnotation = (documentId, annotationId) => {
return new Promise((resolve, reject) => {
/** @type {?} */
const annotation = this.findById(this.annotations, annotationId);
this.remove(this.annotations, annotationId);
this.log.info('Deleted annotation:' + annotationId);
this.annotationChangeSubject.next({ 'type': 'deleteAnnotation', 'annotation': annotation });
resolve(this.annotations);
});
};
/** @type {?} */
const addComment = (documentId, annotationId, content) => {
return new Promise((resolve, reject) => {
/** @type {?} */
const comment = new Comment(v4(), annotationId, null, null, new Date(), null, null, null, content);
this.updateComments(documentId, comment);
/** @type {?} */
const annotation = this.findById(this.annotations, annotationId);
this.log.info('Comment:' + comment.id + ' has been added to annotation:' + annotationId);
annotation.comments.push(comment);
if (this.isDraftComment(comment)) {
this.log.info('Removing comment box because no content exists');
resolve(comment);
}
else {
this.log.info('Add comment:' + comment.id + '-' + 'annotationId:' + annotation.id);
this.annotationChangeSubject.next({ 'type': 'addComment', 'annotation': annotation });
resolve(comment);
}
});
};
/** @type {?} */
const deleteComment = (documentId, commentId) => {
return new Promise((resolve, reject) => {
/** @type {?} */
const comment = this.findById(this.commentData, commentId);
/** @type {?} */
const annotation = this.findById(this.annotations, comment.annotationId);
this.remove(this.commentData, commentId);
this.remove(annotation.comments, commentId);
if (this.isDraftComment(comment)) {
this.log.info('Removing comment box because no content exists');
resolve(comment);
}
else {
this.log.info('Deleted comment:' + commentId + '-' + 'annotationId:' + annotation.id);
this.annotationChangeSubject.next({ 'type': 'deleteComment', 'annotation': annotation });
resolve(this.annotations);
}
});
};
// Unused
/** @type {?} */
const editAnnotation = (documentId, pageNumber, annotation) => {
return new Promise((resolve, reject) => {
this.annotationChangeSubject.next({ 'type': 'editAnnotation', 'annotation': annotation });
resolve(this.commentData);
});
};
return {
getAnnotations,
getComments,
getAnnotation,
addAnnotation,
editAnnotation,
deleteAnnotation,
addComment,
deleteComment
};
}
/**
* @param {?} array
* @param {?} id
* @return {?}
*/
findById(array, id) {
return array.find(e => e.id === id);
}
/**
* @param {?} array
* @param {?} id
* @return {?}
*/
remove(array, id) {
return array.splice(array.findIndex(e => e.id === id), 1);
}
}
PdfAdapter.decorators = [
{ type: Injectable }
];
PdfAdapter.ctorParameters = () => [
{ type: EmLoggerService },
{ type: Utils },
{ type: undefined, decorators: [{ type: Inject, args: [WINDOW,] }] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class ApiHttpService {
/**
* @param {?} log
* @param {?} httpClient
* @param {?} platformId
* @param {?} transferState
*/
constructor(log, httpClient, platformId, transferState) {
this.log = log;
this.httpClient = httpClient;
this.platformId = platformId;
this.transferState = transferState;
log.setClass('ApiHttpService');
}
/**
* @param {?} baseUrl
* @return {?}
*/
setBaseUrl(baseUrl) {
this.baseUrl = baseUrl;
}
/**
* @return {?}
*/
getBaseUrl() {
return this.baseUrl;
}
/**
* @param {?} baseUrl
* @param {?} body
* @return {?}
*/
createAnnotationSet(baseUrl, body) {
return this.httpClient.post(`${baseUrl}/em-anno/annotation-sets`, body, { observe: 'response' });
}
/**
* @param {?} baseUrl
* @param {?} dmDocumentId
* @return {?}
*/
fetch(baseUrl, dmDocumentId) {
/** @type {?} */
const STATE_KEY = makeStateKey('annotationSet-' + dmDocumentId);
if (this.transferState.hasKey(STATE_KEY)) {
/** @type {?} */
const annotationSet = this.transferState.get(STATE_KEY, null);
this.transferState.remove(STATE_KEY);
return of(annotationSet);
}
else {
/** @type {?} */
const url = `${baseUrl}/em-anno/annotation-sets/${dmDocumentId}`;
return this.httpClient.get(url, { observe: 'response' })
.pipe(tap(annotationSet => {
if (isPlatformServer(this.platformId)) {
this.transferState.set(STATE_KEY, annotationSet);
}
}));
}
}
/**
* @param {?} dmDocumentId
* @param {?} outputDmDocumentId
* @param {?} baseUrl
* @return {?}
*/
documentTask(dmDocumentId, outputDmDocumentId, baseUrl) {
/** @type {?} */
const url = `${baseUrl}/api/em-npa/document-tasks`;
/** @type {?} */
const documentTasks = {
inputDocumentId: dmDocumentId,
outputDocumentId: outputDmDocumentId
};
this.log.info('Calling NPA service-' + dmDocumentId);
return this.httpClient.post(url, documentTasks, { observe: 'response' });
}
/**
* @param {?} annotation
* @return {?}
*/
deleteAnnotation(annotation) {
/** @type {?} */
const url = `${this.baseUrl}/em-anno/annotations/${annotation.id}`;
return this.httpClient.delete(url, { observe: 'response' });
}
/**
* @param {?} annotation
* @return {?}
*/
saveAnnotation(annotation) {
/** @type {?} */
const url = `${this.baseUrl}/em-anno/annotations`;
return this.httpClient.post(url, annotation, { observe: 'response' });
}
}
ApiHttpService.decorators = [
{ type: Injectable }
];
ApiHttpService.ctorParameters = () => [
{ type: EmLoggerService },
{ type: HttpClient },
{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] },
{ type: TransferState }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class PdfWrapper {
/**
* @param {?} documentId
* @return {?}
*/
getDocument(documentId) {
return PDFJS.getDocument(documentId);
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class RotationModel {
/**
* @param {?} pageNumber
* @param {?} pageDom
*/
constructor(pageNumber, pageDom) {
this.pageNumber = pageNumber;
this.pageDom = pageDom;
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class PdfRenderService {
/**
* @param {?} pdfWrapper
* @param {?} log
* @param {?} pdfAnnotateWrapper
*/
constructor(pdfWrapper, log, pdfAnnotateWrapper) {
this.pdfWrapper = pdfWrapper;
this.log = log;
this.pdfAnnotateWrapper = pdfAnnotateWrapper;
this.listPages = [];
this.log.setClass('PdfRenderService');
this.dataLoadedSubject = new BehaviorSubject(false);
this.listPagesSubject = new Subject();
}
/**
* @return {?}
*/
getDataLoadedSub() {
return this.dataLoadedSubject;
}
/**
* @param {?} isLoaded
* @return {?}
*/
dataLoadedUpdate(isLoaded) {
this.dataLoadedSubject.next(isLoaded);
}
/**
* @return {?}
*/
getRenderOptions() {
return Object.assign({}, this.RENDER_OPTIONS);
}
/**
* @param {?} RENDER_OPTIONS
* @return {?}
*/
setRenderOptions(RENDER_OPTIONS) {
this.RENDER_OPTIONS = RENDER_OPTIONS;
}
/**
* @return {?}
*/
getViewerElementRef() {
return this.viewerElementRef;
}
/**
* @return {?}
*/
getPdfPages() {
return this.pdfPages;
}
/**
* @param {?=} viewerElementRef
* @return {?}
*/
render(viewerElementRef) {
if (viewerElementRef != null) {
this.viewerElementRef = viewerElementRef;
}
/** @type {?} */
const renderOptions = this.getRenderOptions();
this.pdfWrapper.getDocument(renderOptions.documentId)
.then(pdf => {
renderOptions.pdfDocument = pdf;
/** @type {?} */
const viewer = this.viewerElementRef.nativeElement;
viewer.innerHTML = '';
this.pdfPages = pdf.pdfInfo.numPages;
this.listPages = [];
for (let i = 1; i < this.pdfPages + 1; i++) {
/** @type {?} */
const pageDom = this.pdfAnnotateWrapper.createPage(i);
// Create a copy of the render options for each page.
/** @type {?} */
const pageOptions = Object.assign({}, renderOptions);
viewer.appendChild(pageDom);
this.addDomPage(pageDom, i);
pdf.getPage(i).then((pdfPage) => {
// Get current page rotation from page rotation objects
pageOptions.rotate = this.addPageRotation(renderOptions, pageOptions, pdfPage);
setTimeout(() => {
this.pdfAnnotateWrapper.renderPage(i, pageOptions).then(() => {
if (i === this.pdfPages) {
this.setRenderOptions(renderOptions);
this.dataLoadedUpdate(true);
this.listPagesSubject.next(this.listPages);
}
});
});
});
}
}).catch((error) => {
/** @type {?} */
const errorMessage = new Error('Unable to render your supplied PDF. ' +
renderOptions.documentId + '. Error is: ' + error);
this.log.error('Encountered error while rendering the PDF:' + errorMessage);
});
}
/**
* @param {?} pageDom
* @param {?} pageNumber
* @return {?}
*/
addDomPage(pageDom, pageNumber) {
/** @type {?} */
const pagedetails = new RotationModel(pageNumber, pageDom);
/** @type {?} */
const index = this.listPages.findIndex(pageElement => pageElement.pageNumber === pageNumber);
if (index > 0) {
this.listPages[index] = pagedetails;
}
else {
this.listPages.push(pagedetails);
}
}
/**
* @param {?} renderOptions
* @param {?} pageOptions
* @param {?} pdfPage
* @return {?}
*/
addPageRotation(renderOptions, pageOptions, pdfPage) {
/** @type {?} */
let rotation = this.getPageRotation(pageOptions, pdfPage);
if (!rotation) {
renderOptions.rotationPages.push({ page: pdfPage.pageNumber, rotate: pdfPage.rotate });
rotation = pdfPage.rotate;
}
return rotation;
}
/**
* @param {?} pageOptions
* @param {?} pdfPage
* @return {?}
*/
getPageRotation(pageOptions, pdfPage) {
return pageOptions.rotationPages
.filter(rotateObj => rotateObj.page === pdfPage.pageNumber)
.map(rotateObj => rotateObj.rotate)[0];
}
}
PdfRenderService.decorators = [
{ type: Injectable }
];
PdfRenderService.ctorParameters = () => [
{ type: PdfWrapper },
{ type: EmLoggerService },
{ type: PdfAnnotateWrapper }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class AnnotationStoreService {
/**
* @param {?} log
* @param {?} pdfAdapter
* @param {?} apiHttpService
* @param {?} pdfService
* @param {?} pdfAnnotateWrapper
* @param {?} pdfRenderService
*/
constructor(log, pdfAdapter, apiHttpService, pdfService, pdfAnnotateWrapper, pdfRenderService) {
this.log = log;
this.pdfAdapter = pdfAdapter;
this.apiHttpService = apiHttpService;
this.pdfService = pdfService;
this.pdfAnnotateWrapper = pdfAnnotateWrapper;
this.pdfRenderService = pdfRenderService;
log.setClass('AnnotationStoreService');
this.commentBtnSubject = new Subject();
this.commentFocusSubject = new BehaviorSubject({ annotation: new Annotation(null, null, null, null, null, null, null, null, null, null, null, null) });
this.contextualToolBarOptions = new Subject();
this.annotationFocusSubject = new Subject();
this.annotationChangeSubscription = this.pdfAdapter.getAnnotationChangeSubject().subscribe((e) => this.handleAnnotationEvent(e));
}
/**
* @return {?}
*/
getAnnotationFocusSubject() {
return this.annotationFocusSubject;
}
/**
* @param {?} annotation
* @return {?}
*/
setAnnotationFocusSubject(annotation) {
this.annotationFocusSubject.next(annotation);
}
/**
* @return {?}
*/
getCommentFocusSubject() {
return this.commentFocusSubject;
}
/**
* @param {?} annotation
* @param {?=} showButton
* @return {?}
*/
setCommentFocusSubject(annotation, showButton) {
this.commentFocusSubject.next({ annotation, showButton });
}
/**
* @return {?}
*/
getCommentBtnSubject() {
return this.commentBtnSubject;
}
/**
* @param {?} commentId
* @return {?}
*/
setCommentBtnSubject(commentId) {
this.commentBtnSubject.next(commentId);
}
/**
* @param {?} annotation
* @param {?=} showDelete
* @return {?}
*/
setToolBarUpdate(annotation, showDelete) {
/** @type {?} */
const contextualOptions = {
annotation,
showDelete
};
this.contextualToolBarOptions.next(contextualOptions);
}
/**
* @return {?}
*/
getToolbarUpdate() {
return this.contextualToolBarOptions;
}
/**
* @param {?} annotationData
* @return {?}
*/
preLoad(annotationData) {
if (annotationData != null) {
this.pdfAdapter.setStoreData(annotationData);
this.pdfAnnotateWrapper.setStoreAdapter(this.pdfAdapter.getStoreAdapter());
this.pdfService.setHighlightTool();
}
else {
this.pdfService.setCursorTool();
this.pdfAnnotateWrapper.setStoreAdapter();
}
}
/**
* @param {?} e
* @return {?}
*/
handleAnnotationEvent(e) {
switch (e.type) {
case 'addAnnotation': {
this.saveAnnotation(e.annotation);
break;
}
case 'addComment': {
this.saveAnnotation(e.annotation, e.type);
break;
}
case 'editComment': {
this.saveAnnotation(e.annotation, e.type);
break;
}
case 'deleteComment': {
this.saveAnnotation(e.annotation);
break;
}
case 'editAnnotation': {
this.saveAnnotation(e.annotation);
break;
}
case 'deleteAnnotation': {
this.deleteAnnotation(e.annotation);
break;
}
}
}
/**
* @param {?} baseUrl
* @param {?} dmDocumentId
* @return {?}
*/
getAnnotationSet(baseUrl, dmDocumentId) {
return this.apiHttpService.fetch(baseUrl, dmDocumentId).pipe(catchError((err) => {
if (err instanceof HttpErrorResponse) {
switch (err.status) {
case 400: {
this.log.error('Bad request: ' + err.error);
return throwError(err.error);
}
case 404: {
/** @type {?} */
const body = {
documentId: dmDocumentId,
id: v4()
};
this.log.info('Creating new annotation set for document id:' + dmDocumentId);
return this.apiHttpService.createAnnotationSet(baseUrl, body);
}
case 500: {
this.log.error('Internal server error: ' + err);
return throwError('Internal server error: ' + err);
}
}
}
}));
}
/**
* @return {?}
*/
saveData() {
/** @type {?} */
let loadedData;
/** @type {?} */
let toKeepAnnotations;
/** @type {?} */
let toRemoveAnnotations;
loadedData = this.pdfAdapter.annotationSet;
toKeepAnnotations = this.pdfAdapter.annotations;
toRemoveAnnotations = this.pdfAdapter.annotationSet.annotations
.filter((annotation) => !this.pdfAdapter.annotations.map(a => a.id).includes(annotation.id));
toKeepAnnotations.forEach((annotation) => {
this.apiHttpService.saveAnnotation(annotation).subscribe(response => this.log.info('Successfully saved annotation:' + response), error => this.log.error('There has been a problem saving the annotation:' + annotation.id + '-' + error));
});
toRemoveAnnotations.forEach((annotation) => {
this.apiHttpService.deleteAnnotation(annotation).subscribe(response => this.log.info('Successfully deleted annotation:' + response), error => this.log.error('There has been a problem deleting annotation:' + annotation.id + '-' + error));
});
loadedData.annotations.splice(0, loadedData.annotations.length);
loadedData.annotations.concat(toKeepAnnotations);
this.pdfAdapter.annotationSet = loadedData;
}
/**
* @param {?} annotation
* @param {?=} type
* @return {?}
*/
saveAnnotation(annotation, type) {
this.apiHttpService.saveAnnotation(annotation).subscribe(response => {
if (type === 'addComment' || type === 'editComment') {
this.pdfAdapter.annotationSet.annotations[this.pdfAdapter.annotationSet.annotations
.findIndex(x => x.id === annotation.id)] = response.body;
}
this.log.info('Successfully saved annotation:' + response);
}, error => this.log.error('There has been a problem saving the annotation:' + annotation.id + '-' + error));
}
/**
* @param {?} annotation
* @return {?}
*/
deleteAnnotation(annotation) {
this.apiHttpService.deleteAnnotation(annotation).subscribe(response => {
this.log.info('Successfully deleted annotation:' + annotation.id + '-' + response);
}, error => this.log.error('There has been a problem deleting annotation:' + annotation.id + '-' + error));
}
/**
* @param {?} comment
* @return {?}
*/
editComment(comment) {
this.pdfAdapter.editComment(comment);
}
/**
* @param {?} annotationId
* @return {?}
*/
getAnnotationById(annotationId) {
return new Promise((resolve) => {
this.getAnnotation(annotationId, annotation => {
resolve(annotation);
});
});
}
/**
* @param {?} pageNumber
* @return {?}
*/
getAnnotationsForPage(pageNumber) {
return new Promise((resolve) => {
this.getAnnotations(pageNumber, pageData => {
resolve(pageData);
});
});
}
/**
* @param {?} annotationId
* @return {?}
*/
getCommentsForAnnotation(annotationId) {
return new Promise((resolve) => {
this.getComments(annotationId, comments => {
resolve(comments);
});
});
}
/**
* @param {?} annotationId
* @param {?} callback
* @return {?}
*/
getAnnotation(annotationId, callback) {
this.pdfAnnotateWrapper.getStoreAdapter()
.getAnnotation(this.pdfRenderService.getRenderOptions().documentId, annotationId)
.then(callback);
}
/**
* @param {?} annotationId
* @param {?} callback
* @return {?}
*/
getComments(annotationId, callback) {
this.pdfAnnotateWrapper.getStoreAdapter()
.getComments(this.pdfRenderService.getRenderOptions().documentId, annotationId)
.then(callback);
}
/**
* @param {?} comment
* @return {?}
*/
addComment(comment) {
this.pdfAnnotateWrapper.getStoreAdapter()
.addComment(this.pdfRenderService.getRenderOptions().documentId, comment.annotationId, comment.content)
.then();
}
/**
* @param {?} pageNumber
* @param {?} callback
* @return {?}
*/
getAnnotations(pageNumber, callback) {
this.pdfAnnotateWrapper.getStoreAdapter()
.getAnnotations(this.pdfRenderService.getRenderOptions().documentId, pageNumber)
.then(callback);
}
/**
* @param {?} commentId
* @return {?}
*/
deleteComment(commentId) {
this.pdfAnnotateWrapper.getStoreAdapter()
.deleteComment(this.pdfRenderService.getRenderOptions().documentId, commentId)
.then();
}
/**
* @param {?} annotationId
* @param {?} pageNumber
* @return {?}
*/
deleteAnnotationById(annotationId, pageNumber) {
return __awaiter(this, void 0, void 0, function* () {
/** @type {?} */
const renderOptions = this.pdfRenderService.getRenderOptions();
yield this.pdfAnnotateWrapper.getStoreAdapter()
.deleteAnnotation(renderOptions.documentId, annotationId);
this.renderPage(renderOptions, pageNumber);
});
}
/**
* @param {?} renderOptions
* @param {?} pageNumber
* @return {?}
*/
renderPage(renderOptions, pageNumber) {
renderOptions.rotate = this.pdfRenderService.getPageRotation(renderOptions, { pageNumber: pageNumber });
this.pdfAnnotateWrapper.renderPage(pageNumber, renderOptions);
}
/**
* @return {?}
*/
ngOnDestroy() {
if (this.annotationChangeSubscription) {
this.annotationChangeSubscription.unsubscribe();
}
}
}
AnnotationStoreService.decorators = [
{ type: Injectable }
];
AnnotationStoreService.ctorParameters = () => [
{ type: EmLoggerService },
{ type: PdfAdapter },
{ type: ApiHttpService },
{ type: PdfService },
{ type: PdfAnnotateWrapper },
{ type: PdfRenderService }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class CommentsComponent {
/**
* @param {?} annotationStoreService
* @param {?} pdfService
* @param {?} utils
* @param {?} pdfRenderService
* @param {?} log
*/
constructor(annotationStoreService, pdfService, utils, pdfRenderService, log) {
this.annotationStoreService = annotationStoreService;
this.pdfService = pdfService;
this.utils = utils;
this.pdfRenderService = pdfRenderService;
this.log = log;
this.log.setClass('CommentsComponent');
}
/**
* @return {?}
*/
ngOnInit() {
this.dataLoadedSub = this.pdfRenderService.getDataLoadedSub()
.subscribe(isDataLoaded => {
if (isDataLoaded) {
this.showAllComments();
this.preRun();
}
});
}
/**
* @return {?}
*/
redrawCommentItemComponents() {
setTimeout(() => {
/** @type {?} */
let previousCommentItem;
this.sortCommentItemComponents().forEach((commentItem) => {
previousCommentItem = this.isOverlapping(commentItem, previousCommentItem);
});
});
}
/**
* @return {?}
*/
sortCommentItemComponents() {
return this.commentItems.map((commentItem) => commentItem)
.sort((a, b) => {
return this.processSort(a, b);
});
}
/**
* @param {?} a
* @param {?} b
* @return {?}
*/
processSort(a, b) {
if (this.isAnnotationOnSameLine(a, b)) {
if (a.annotationLeftPos < b.annotationLeftPos) {
return -1;
}
if (a.annotationLeftPos >= b.annotationLeftPos) {
return 1;
}
}
if (a.annotationTopPos < b.annotationTopPos) {
return -1;
}
if (a.annotationTopPos >= b.annotationTopPos) {
return 1;
}
return 0;
}
/**
* @param {?} a
* @param {?} b
* @return {?}
*/
isAnnotationOnSameLine(a, b) {
/** @type {?} */
const delta = (a.annotationHeight >= b.annotationHeight) ? a.annotationHeight : b.annotationHeight;
if (this.utils.difference(a.annotationTopPos, b.annotationTopPos) > delta) {
return false;
}
return true;
}
/**
* @param {?} commentItem
* @param {?} previousCommentItem
* @return {?}
*/
isOverlapping(commentItem, previousCommentItem) {
commentItem.commentTopPos = commentItem.annotationTopPos;
if (previousCommentItem) {
/** @type {?} */
const endOfPreviousCommentItem = (previousCommentItem.commentTopPos + previousCommentItem.commentHeight);
if (commentItem.commentTopPos <= endOfPreviousCommentItem) {
commentItem.commentTopPos = endOfPreviousCommentItem;
}
}
return commentItem;
}
/**
* @return {?}
*/
ngOnDestroy() {
if (this.pageNumSub) {
this.pageNumSub.unsubscribe();
}
if (this.dataLoadedSub) {
this.dataLoadedSub.unsubscribe();
}
}
/**
* @return {?}
*/
preRun() {
this.pageNumSub = this.pdfService.getPageNumber().subscribe(pageNumber => {
this.pageNumber = pageNumber;
});
}
/**
* @return {?}
*/
showAllComments() {
// todo - refactor this out of component
this.annotations = [];
for (let i = 0; i < this.pdfRenderService.getPdfPages() + 1; i++) {
this.annotationStoreService.getAnnotationsForPage(i)
.then((pageData) => {
this.annotations = this.annotations.concat(pageData.annotations.slice());
});
}
}
/**
* @return {?}
*/
handleAnnotationBlur() {
this.showAllComments();
}
/**
* @param {?} event
* @return {?}
*/
handleAnnotationClick(event) {
/** @type {?} */
const annotationId = event.getAttribute('data-pdf-annotate-id');
this.annotationStoreService.getAnnotationById(annotationId)
.then((annotation) => {
this.annotationStoreService.setAnnotationFocusSubject(annotation);
this.annotationStoreService.setCommentFocusSubject(annotation);
this.annotationStoreService.setToolBarUpdate(annotation, true);
});
}
}
CommentsComponent.decorators = [
{ type: Component, args: [{
selector: 'app-comments',
template: "<div *ngIf=\"pageNumber\" id=\"comment-wrapper\">\n <div class=\"comment-list-container\">\n\n <div *ngFor=\"let annotation of annotations\" class=\"highlight-group\">\n <app-comment-item #commentItem\n *ngFor=\"let comment of annotation.comments\"\n [annotation]=\"annotation\"\n [comment]=\"comment\"\n (commentSubmitted)='showAllComments()'\n (commentRendered)='redrawCommentItemComponents()'\n ></app-comment-item>\n </div>\n </div>\n</div>\n",
styles: ["#comment-wrapper{position:absolute;height:100%;width:380px;right:0;overflow:hidden;z-index:0;font-family:nta,Arial,sans-serif;-webkit-font-smoothing:antialiased;font-size:12px}#comment-wrapper .comment-list{font-size:12px;position:absolute;top:38px;left:0;right:0;bottom:0}#comment-wrapper .comment-list-container{position:absolute;top:0;left:0;right:0;bottom:47px;overflow-x:hidden;overflow-y:auto}"]
}] }
];
CommentsComponent.ctorParameters = () => [
{ type: AnnotationStoreService },
{ type: PdfService },
{ type: Utils },
{ type: PdfRenderService },
{ type: EmLoggerService }
];
CommentsComponent.propDecorators = {
commentItems: [{ type: ViewChildren, args: ['commentItem',] }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class CommentItemComponent {
/**
* @param {?} annotationStoreService
* @param {?} pdfService
* @param {?} pdfRenderService
* @param {?} ref
* @param {?} renderer
* @param {?} utils
* @param {?} log
*/
constructor(annotationStoreService, pdfService, pdfRenderService, ref, renderer, utils, log) {
this.annotationStoreService = annotationStoreService;
this.pdfService = pdfService;
this.pdfRenderService = pdfRenderService;
this.ref = ref;
this.renderer = renderer;
this.utils = utils;
this.log = log;
this.commentSubmitted = new EventEmitter();
this.commentRendered = new EventEmitter();
this.model = new Comment(null, null, null, null, null, null, null, null, null);
this.log.setClass('CommentItemComponent');
}
/**
* @return {?}
*/
ngOnInit() {
this.hideButton = true;
this.focused = false;
this.sliceComment = this.comment.content;
this.commentFocusSub = this.annotationStoreService.getCommentFocusSubject()
.subscribe((options) => {
if (options.annotation.id === this.comment.annotationId) {
if (options.showButton) {
this.onEdit();
}
else {
this.handleShowBtn();
}
this.ref.detectChanges();
}
else {
this.onBlur();
}
});
this.commentBtnSub = this.annotationStoreService.getCommentBtnSubject()
.subscribe((commentId) => {
(commentId === this.comment.id) ? this.handleShowBtn() : this.handleHideBtn();
});
this.dataLoadedSub = this.pdfRenderService.getDataLoadedSub()
.subscribe((dataLoaded) => {
if (dataLoaded) {
this.annotationTopPos = this.getRelativePosition(this.comment.annotationId);
this.commentTopPos = this.annotationTopPos;
this.utils.sortByX(this.annotation.rectangles, true);
this.annotationHeight = this.utils.getAnnotationLineHeight(this.annotation.rectangles);
this.annotationLeftPos = this.annotation.rectangles[0].x;
this.commentRendered.emit(true);
this.collapseComment();
}
});
this.commentItem.statusChanges.subscribe(() => {
if (this.focused) {
this.expandComment();
}
});
}
/**
* @return {?}
*/
setHeight() {
this.renderer.setStyle(this.commentArea.nativeElement, 'height', 'fit-content');
this.renderer.setStyle(this.commentArea.nativeElement, 'height', (this.commentArea.nativeElement.scrollHeight) + 'px');
this.commentHeight = this.commentSelector.nativeElement.getBoundingClientRect().height;
this.commentRendered.emit(true);
if (!this.ref['destroyed']) {
this.ref.detectChanges();
}
}
/**
* @return {?}
*/
ngOnDestroy() {
if (this.commentFocusSub) {