diff --git a/src/app/pdf-viewer/pdf-viewer.component.ts b/src/app/pdf-viewer/pdf-viewer.component.ts index 440059b04..f8d2af60f 100644 --- a/src/app/pdf-viewer/pdf-viewer.component.ts +++ b/src/app/pdf-viewer/pdf-viewer.component.ts @@ -15,7 +15,7 @@ import { ViewChild, AfterViewChecked } from '@angular/core'; -import { from, Subject } from 'rxjs'; +import { from, fromEvent, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { PDFDocumentProxy, @@ -91,6 +91,7 @@ export class PdfViewerComponent private pageScrollTimeout: NodeJS.Timer; private isInitialized = false; private loadingTask: any; + private destroy$ = new Subject(); @Output('after-load-complete') afterLoadComplete = new EventEmitter(); @Output('page-rendered') pageRendered = new EventEmitter(); @@ -215,8 +216,6 @@ export class PdfViewerComponent return null; } - private destroy$ = new Subject(); - constructor(private element: ElementRef) { if (isSSR()) { return; @@ -405,30 +404,38 @@ export class PdfViewerComponent private setupMultiPageViewer() { assign(PDFJS, "disableTextLayer", !this._renderText); - const eventBus = createEventBus(PDFJSViewer); + const eventBus = createEventBus(PDFJSViewer, this.destroy$); - eventBus.on('pagerendered', e => { - this.pageRendered.emit(e); - }); + fromEvent(eventBus, 'pagerendered') + .pipe(takeUntil(this.destroy$)) + .subscribe((event) => { + this.pageRendered.emit(event); + }); - eventBus.on('pagesinit', e => { - this.pageInitialized.emit(e); - }); + fromEvent(eventBus, 'pagesinit') + .pipe(takeUntil(this.destroy$)) + .subscribe((event) => { + this.pageInitialized.emit(event); + }); - eventBus.on('pagechanging', e => { - if (this.pageScrollTimeout) { - clearTimeout(this.pageScrollTimeout); - } + fromEvent(eventBus, 'pagechanging') + .pipe(takeUntil(this.destroy$)) + .subscribe(({ pageNumber }) => { + if (this.pageScrollTimeout) { + clearTimeout(this.pageScrollTimeout); + } - this.pageScrollTimeout = setTimeout(() => { - this._latestScrolledPage = e.pageNumber; - this.pageChange.emit(e.pageNumber); - }, 100); - }); + this.pageScrollTimeout = setTimeout(() => { + this._latestScrolledPage = pageNumber; + this.pageChange.emit(pageNumber); + }, 100); + }); - eventBus.on('textlayerrendered', e => { - this.textLayerRendered.emit(e); - }); + fromEvent(eventBus, 'textlayerrendered') + .pipe(takeUntil(this.destroy$)) + .subscribe((event) => { + this.textLayerRendered.emit(event); + }); this.pdfMultiPageLinkService = new PDFJSViewer.PDFLinkService({ eventBus, ...this.getPDFLinkServiceConfig() @@ -457,25 +464,33 @@ export class PdfViewerComponent private setupSinglePageViewer() { assign(PDFJS, "disableTextLayer", !this._renderText); - const eventBus = createEventBus(PDFJSViewer); + const eventBus = createEventBus(PDFJSViewer, this.destroy$); - eventBus.on('pagechanging', e => { - if (e.pageNumber !== this._page) { - this.page = e.pageNumber; - } - }); + fromEvent(eventBus, 'pagechanging') + .pipe(takeUntil(this.destroy$)) + .subscribe(({ pageNumber }) => { + if (pageNumber !== this._page) { + this.page = pageNumber; + } + }); - eventBus.on('pagerendered', e => { - this.pageRendered.emit(e); - }); + fromEvent(eventBus, 'pagerendered') + .pipe(takeUntil(this.destroy$)) + .subscribe((event) => { + this.pageRendered.emit(event); + }); - eventBus.on('pagesinit', e => { - this.pageInitialized.emit(e); - }); + fromEvent(eventBus, 'pagesinit') + .pipe(takeUntil(this.destroy$)) + .subscribe((event) => { + this.pageInitialized.emit(event); + }); - eventBus.on('textlayerrendered', e => { - this.textLayerRendered.emit(e); - }); + fromEvent(eventBus, 'textlayerrendered') + .pipe(takeUntil(this.destroy$)) + .subscribe((event) => { + this.textLayerRendered.emit(event); + }); this.pdfSinglePageLinkService = new PDFJSViewer.PDFLinkService({ eventBus, ...this.getPDFLinkServiceConfig() diff --git a/src/app/utils/event-bus-utils.ts b/src/app/utils/event-bus-utils.ts index 6331525c0..5aa15bac2 100644 --- a/src/app/utils/event-bus-utils.ts +++ b/src/app/utils/event-bus-utils.ts @@ -1,122 +1,172 @@ -export function _createEventBus(pdfJsViewer: any): any { - const globalEventBus = new pdfJsViewer.EventBus(true); - attachDOMEventsToEventBus(globalEventBus); +import { fromEvent, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +interface EventBus { + on(eventName: string, listener: Function): void; + off(eventName: string, listener: Function): void; +} + +export function createEventBus(pdfJsViewer: any, destroy$: Subject) { + const globalEventBus: EventBus = new pdfJsViewer.EventBus(); + attachDOMEventsToEventBus(globalEventBus, destroy$); return globalEventBus; } -function attachDOMEventsToEventBus(eventBus: any) { - eventBus.on('documentload', () => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('documentload', true, true, {}); - window.dispatchEvent(event); - }); - eventBus.on('pagerendered', evt => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('pagerendered', true, true, { - pageNumber: evt.pageNumber, - cssTransform: evt.cssTransform +function attachDOMEventsToEventBus( + eventBus: EventBus, + destroy$: Subject +): void { + fromEvent(eventBus, 'documentload') + .pipe(takeUntil(destroy$)) + .subscribe(() => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('documentload', true, true, {}); + window.dispatchEvent(event); }); - evt.source.div.dispatchEvent(event); - }); - eventBus.on('textlayerrendered', evt => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('textlayerrendered', true, true, { - pageNumber: evt.pageNumber + + fromEvent(eventBus, 'pagerendered') + .pipe(takeUntil(destroy$)) + .subscribe(({ pageNumber, cssTransform, source }) => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagerendered', true, true, { + pageNumber, + cssTransform, + }); + source.div.dispatchEvent(event); }); - evt.source.textLayerDiv.dispatchEvent(event); - }); - eventBus.on('pagechanging', evt => { - const event = document.createEvent('UIEvents'); - event.initEvent('pagechanging', true, true); - /* tslint:disable:no-string-literal */ - event['pageNumber'] = evt.pageNumber; - evt.source.container.dispatchEvent(event); - }); - eventBus.on('pagesinit', evt => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('pagesinit', true, true, null); - evt.source.container.dispatchEvent(event); - }); - eventBus.on('pagesloaded', evt => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('pagesloaded', true, true, { - pagesCount: evt.pagesCount + + fromEvent(eventBus, 'textlayerrendered') + .pipe(takeUntil(destroy$)) + .subscribe(({ pageNumber, source }) => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('textlayerrendered', true, true, { pageNumber }); + source.textLayerDiv.dispatchEvent(event); }); - evt.source.container.dispatchEvent(event); - }); - eventBus.on('scalechange', evt => { - const event = document.createEvent('UIEvents'); - event.initEvent('scalechange', true, true); - /* tslint:disable:no-string-literal */ - event['scale'] = evt.scale; - /* tslint:disable:no-string-literal */ - event['presetValue'] = evt.presetValue; - evt.source.container.dispatchEvent(event); - }); - eventBus.on('updateviewarea', evt => { - const event = document.createEvent('UIEvents'); - event.initEvent('updateviewarea', true, true); - event['location'] = evt.location; - evt.source.container.dispatchEvent(event); - }); - eventBus.on('find', evt => { - if (evt.source === window) { - return; // event comes from FirefoxCom, no need to replicate - } - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('find' + evt.type, true, true, { - query: evt.query, - phraseSearch: evt.phraseSearch, - caseSensitive: evt.caseSensitive, - highlightAll: evt.highlightAll, - findPrevious: evt.findPrevious + + fromEvent(eventBus, 'pagechanging') + .pipe(takeUntil(destroy$)) + .subscribe(({ pageNumber, source }) => { + const event = document.createEvent('UIEvents'); + event.initEvent('pagechanging', true, true); + /* tslint:disable:no-string-literal */ + event['pageNumber'] = pageNumber; + source.container.dispatchEvent(event); }); - window.dispatchEvent(event); - }); - eventBus.on('attachmentsloaded', evt => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('attachmentsloaded', true, true, { - attachmentsCount: evt.attachmentsCount + + fromEvent(eventBus, 'pagesinit') + .pipe(takeUntil(destroy$)) + .subscribe(({ source }) => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagesinit', true, true, null); + source.container.dispatchEvent(event); }); - evt.source.container.dispatchEvent(event); - }); - eventBus.on('sidebarviewchanged', evt => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('sidebarviewchanged', true, true, { - view: evt.view + + fromEvent(eventBus, 'pagesloaded') + .pipe(takeUntil(destroy$)) + .subscribe(({ pagesCount, source }) => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagesloaded', true, true, { pagesCount }); + source.container.dispatchEvent(event); }); - evt.source.outerContainer.dispatchEvent(event); - }); - eventBus.on('pagemode', evt => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('pagemode', true, true, { - mode: evt.mode + + fromEvent(eventBus, 'scalechange') + .pipe(takeUntil(destroy$)) + .subscribe(({ scale, presetValue, source }) => { + const event = document.createEvent('UIEvents'); + event.initEvent('scalechange', true, true); + /* tslint:disable:no-string-literal */ + event['scale'] = scale; + /* tslint:disable:no-string-literal */ + event['presetValue'] = presetValue; + source.container.dispatchEvent(event); }); - evt.source.pdfViewer.container.dispatchEvent(event); - }); - eventBus.on('namedaction', evt => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('namedaction', true, true, { - action: evt.action + + fromEvent(eventBus, 'updateviewarea') + .pipe(takeUntil(destroy$)) + .subscribe(({ location, source }) => { + const event = document.createEvent('UIEvents'); + event.initEvent('updateviewarea', true, true); + event['location'] = location; + source.container.dispatchEvent(event); }); - evt.source.pdfViewer.container.dispatchEvent(event); - }); - eventBus.on('presentationmodechanged', evt => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('presentationmodechanged', true, true, { - active: evt.active, - switchInProgress: evt.switchInProgress + + fromEvent(eventBus, 'find') + .pipe(takeUntil(destroy$)) + .subscribe( + ({ + source, + type, + query, + phraseSearch, + caseSensitive, + highlightAll, + findPrevious, + }) => { + if (source === window) { + return; // event comes from FirefoxCom, no need to replicate + } + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('find' + type, true, true, { + query, + phraseSearch, + caseSensitive, + highlightAll, + findPrevious, + }); + window.dispatchEvent(event); + } + ); + + fromEvent(eventBus, 'attachmentsloaded') + .pipe(takeUntil(destroy$)) + .subscribe(({ attachmentsCount, source }) => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('attachmentsloaded', true, true, { + attachmentsCount, + }); + source.container.dispatchEvent(event); }); - window.dispatchEvent(event); - }); - eventBus.on('outlineloaded', evt => { - const event = document.createEvent('CustomEvent'); - event.initCustomEvent('outlineloaded', true, true, { - outlineCount: evt.outlineCount + + fromEvent(eventBus, 'sidebarviewchanged') + .pipe(takeUntil(destroy$)) + .subscribe(({ view, source }) => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('sidebarviewchanged', true, true, { view }); + source.outerContainer.dispatchEvent(event); + }); + + fromEvent(eventBus, 'pagemode') + .pipe(takeUntil(destroy$)) + .subscribe(({ mode, source }) => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagemode', true, true, { mode }); + source.pdfViewer.container.dispatchEvent(event); + }); + + fromEvent(eventBus, 'namedaction') + .pipe(takeUntil(destroy$)) + .subscribe(({ action, source }) => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('namedaction', true, true, { action }); + source.pdfViewer.container.dispatchEvent(event); + }); + + fromEvent(eventBus, 'presentationmodechanged') + .pipe(takeUntil(destroy$)) + .subscribe(({ active, switchInProgress }) => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('presentationmodechanged', true, true, { + active, + switchInProgress, + }); + window.dispatchEvent(event); }); - evt.source.container.dispatchEvent(event); - }); -} -export const createEventBus = _createEventBus; + fromEvent(eventBus, 'outlineloaded') + .pipe(takeUntil(destroy$)) + .subscribe(({ outlineCount, source }) => { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('outlineloaded', true, true, { outlineCount }); + source.container.dispatchEvent(event); + }); +}