UNPKG

@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
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) {