From 4f2e16fdc7515b8a8c7b3e333f9b8c52dcee0626 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 13 Feb 2026 08:38:49 -0800 Subject: [PATCH] Chore: Pngx pdf viewer fixes (#12083) --- .../pdf-viewer/pdf-viewer.component.scss | 4 +++ .../pdf-viewer/pdf-viewer.component.spec.ts | 29 ++++++++++++++++++- .../common/pdf-viewer/pdf-viewer.component.ts | 29 ++++++++++++++++--- .../document-detail.component.html | 2 +- .../document-detail.component.ts | 15 ++++++++++ 5 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.scss b/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.scss index eac316f15..6863f5463 100644 --- a/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.scss +++ b/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.scss @@ -150,4 +150,8 @@ position: absolute; inset: 0; pointer-events: none; + + & .annotationTextContent { + opacity: 0; + } } diff --git a/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.spec.ts b/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.spec.ts index 4703e857d..4e239a2a8 100644 --- a/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.spec.ts +++ b/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.spec.ts @@ -65,6 +65,13 @@ describe('PngxPdfViewerComponent', () => { const pageSpy = jest.fn() component.pageChange.subscribe(pageSpy) + // In real usage the viewer may have multiple pages; our pdfjs mock defaults + // to a single page, so explicitly simulate a multi-page document here. + const pdf = (component as any).pdf as { numPages: number } + pdf.numPages = 3 + const viewer = (component as any).pdfViewer as PDFViewer + viewer.setDocument(pdf) + component.zoomScale = PdfZoomScale.PageFit component.zoom = PdfZoomLevel.Two component.rotation = 90 @@ -81,7 +88,6 @@ describe('PngxPdfViewerComponent', () => { page: new SimpleChange(undefined, 2, false), }) - const viewer = (component as any).pdfViewer as PDFViewer expect(viewer.pagesRotation).toBe(90) expect(viewer.currentPageNumber).toBe(2) expect(pageSpy).toHaveBeenCalledWith(2) @@ -196,6 +202,8 @@ describe('PngxPdfViewerComponent', () => { const scaleSpy = jest.spyOn(component as any, 'applyViewerState') const resizeSpy = jest.spyOn(component as any, 'setupResizeObserver') + // Angular sets the input value before calling ngOnChanges; mirror that here. + component.src = 'test.pdf' component.ngOnChanges({ src: new SimpleChange(undefined, 'test.pdf', true), zoomScale: new SimpleChange( @@ -211,6 +219,25 @@ describe('PngxPdfViewerComponent', () => { expect(scaleSpy).not.toHaveBeenCalled() }) + it('resets viewer state on src change', () => { + const mockViewer = { + setDocument: jest.fn(), + currentPageNumber: 7, + cleanup: jest.fn(), + } + ;(component as any).pdfViewer = mockViewer + ;(component as any).loadingTask = { destroy: jest.fn() } + jest.spyOn(component as any, 'loadDocument').mockImplementation(() => {}) + + component.src = 'test.pdf' + component.ngOnChanges({ + src: new SimpleChange(undefined, 'test.pdf', true), + }) + + expect(mockViewer.setDocument).toHaveBeenCalledWith(null) + expect(mockViewer.currentPageNumber).toBe(1) + }) + it('applies viewer state after view init when already loaded', () => { const applySpy = jest.spyOn(component as any, 'applyViewerState') ;(component as any).hasLoaded = true diff --git a/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.ts b/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.ts index 4a7008b7b..032ccd3e0 100644 --- a/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.ts +++ b/src-ui/src/app/components/common/pdf-viewer/pdf-viewer.component.ts @@ -81,7 +81,7 @@ export class PngxPdfViewerComponent this.dispatchFindIfReady() this.rendered.emit() } - private readonly onPagesInit = () => this.applyScale() + private readonly onPagesInit = () => this.applyViewerState() private readonly onPageChanging = (evt: { pageNumber: number }) => { // Avoid [(page)] two-way binding re-triggers navigation this.lastViewerPage = evt.pageNumber @@ -90,8 +90,10 @@ export class PngxPdfViewerComponent ngOnChanges(changes: SimpleChanges): void { if (changes['src']) { - this.hasLoaded = false - this.loadDocument() + this.resetViewerState() + if (this.src) { + this.loadDocument() + } return } @@ -139,6 +141,21 @@ export class PngxPdfViewerComponent this.pdfViewer = undefined } + private resetViewerState(): void { + this.hasLoaded = false + this.hasRenderedPage = false + this.lastFindQuery = '' + this.lastViewerPage = undefined + this.loadingTask?.destroy() + this.loadingTask = undefined + this.pdf = undefined + this.linkService.setDocument(null) + if (this.pdfViewer) { + this.pdfViewer.setDocument(null) + this.pdfViewer.currentPageNumber = 1 + } + } + private async loadDocument(): Promise { if (this.hasLoaded) { return @@ -222,7 +239,11 @@ export class PngxPdfViewerComponent hasPages && this.page !== this.lastViewerPage ) { - this.pdfViewer.currentPageNumber = this.page + const nextPage = Math.min( + Math.max(Math.trunc(this.page), 1), + this.pdfViewer.pagesCount + ) + this.pdfViewer.currentPageNumber = nextPage } if (this.page === this.lastViewerPage) { this.lastViewerPage = undefined diff --git a/src-ui/src/app/components/document-detail/document-detail.component.html b/src-ui/src/app/components/document-detail/document-detail.component.html index c2b545b09..f17fab55d 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.html +++ b/src-ui/src/app/components/document-detail/document-detail.component.html @@ -457,7 +457,7 @@ @if (!useNativePdfViewer) {
= new Subject() previewUrl: string + pdfSource?: PdfSource thumbUrl: string previewText: string previewLoaded: boolean = false @@ -345,6 +347,17 @@ export class DocumentDetailComponent return ContentRenderType.Other } + private updatePdfSource() { + if (!this.previewUrl) { + this.pdfSource = undefined + return + } + this.pdfSource = { + url: this.previewUrl, + password: this.password || undefined, + } + } + get isRTL() { if (!this.metadata || !this.metadata.lang) return false else { @@ -421,6 +434,7 @@ export class DocumentDetailComponent private loadDocument(documentId: number): void { this.previewUrl = this.documentsService.getPreviewUrl(documentId) + this.updatePdfSource() this.http .get(this.previewUrl, { responseType: 'text' }) .pipe( @@ -1230,6 +1244,7 @@ export class DocumentDetailComponent onPasswordKeyUp(event: KeyboardEvent) { if ('Enter' == event.key) { this.password = (event.target as HTMLInputElement).value + this.updatePdfSource() } }