mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-02-14 00:09:35 -06:00
Chore: Pngx pdf viewer fixes (#12083)
This commit is contained in:
@@ -150,4 +150,8 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
|
& .annotationTextContent {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,13 @@ describe('PngxPdfViewerComponent', () => {
|
|||||||
const pageSpy = jest.fn()
|
const pageSpy = jest.fn()
|
||||||
component.pageChange.subscribe(pageSpy)
|
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.zoomScale = PdfZoomScale.PageFit
|
||||||
component.zoom = PdfZoomLevel.Two
|
component.zoom = PdfZoomLevel.Two
|
||||||
component.rotation = 90
|
component.rotation = 90
|
||||||
@@ -81,7 +88,6 @@ describe('PngxPdfViewerComponent', () => {
|
|||||||
page: new SimpleChange(undefined, 2, false),
|
page: new SimpleChange(undefined, 2, false),
|
||||||
})
|
})
|
||||||
|
|
||||||
const viewer = (component as any).pdfViewer as PDFViewer
|
|
||||||
expect(viewer.pagesRotation).toBe(90)
|
expect(viewer.pagesRotation).toBe(90)
|
||||||
expect(viewer.currentPageNumber).toBe(2)
|
expect(viewer.currentPageNumber).toBe(2)
|
||||||
expect(pageSpy).toHaveBeenCalledWith(2)
|
expect(pageSpy).toHaveBeenCalledWith(2)
|
||||||
@@ -196,6 +202,8 @@ describe('PngxPdfViewerComponent', () => {
|
|||||||
const scaleSpy = jest.spyOn(component as any, 'applyViewerState')
|
const scaleSpy = jest.spyOn(component as any, 'applyViewerState')
|
||||||
const resizeSpy = jest.spyOn(component as any, 'setupResizeObserver')
|
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({
|
component.ngOnChanges({
|
||||||
src: new SimpleChange(undefined, 'test.pdf', true),
|
src: new SimpleChange(undefined, 'test.pdf', true),
|
||||||
zoomScale: new SimpleChange(
|
zoomScale: new SimpleChange(
|
||||||
@@ -211,6 +219,25 @@ describe('PngxPdfViewerComponent', () => {
|
|||||||
expect(scaleSpy).not.toHaveBeenCalled()
|
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', () => {
|
it('applies viewer state after view init when already loaded', () => {
|
||||||
const applySpy = jest.spyOn(component as any, 'applyViewerState')
|
const applySpy = jest.spyOn(component as any, 'applyViewerState')
|
||||||
;(component as any).hasLoaded = true
|
;(component as any).hasLoaded = true
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export class PngxPdfViewerComponent
|
|||||||
this.dispatchFindIfReady()
|
this.dispatchFindIfReady()
|
||||||
this.rendered.emit()
|
this.rendered.emit()
|
||||||
}
|
}
|
||||||
private readonly onPagesInit = () => this.applyScale()
|
private readonly onPagesInit = () => this.applyViewerState()
|
||||||
private readonly onPageChanging = (evt: { pageNumber: number }) => {
|
private readonly onPageChanging = (evt: { pageNumber: number }) => {
|
||||||
// Avoid [(page)] two-way binding re-triggers navigation
|
// Avoid [(page)] two-way binding re-triggers navigation
|
||||||
this.lastViewerPage = evt.pageNumber
|
this.lastViewerPage = evt.pageNumber
|
||||||
@@ -90,8 +90,10 @@ export class PngxPdfViewerComponent
|
|||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
if (changes['src']) {
|
if (changes['src']) {
|
||||||
this.hasLoaded = false
|
this.resetViewerState()
|
||||||
this.loadDocument()
|
if (this.src) {
|
||||||
|
this.loadDocument()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,6 +141,21 @@ export class PngxPdfViewerComponent
|
|||||||
this.pdfViewer = undefined
|
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<void> {
|
private async loadDocument(): Promise<void> {
|
||||||
if (this.hasLoaded) {
|
if (this.hasLoaded) {
|
||||||
return
|
return
|
||||||
@@ -222,7 +239,11 @@ export class PngxPdfViewerComponent
|
|||||||
hasPages &&
|
hasPages &&
|
||||||
this.page !== this.lastViewerPage
|
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) {
|
if (this.page === this.lastViewerPage) {
|
||||||
this.lastViewerPage = undefined
|
this.lastViewerPage = undefined
|
||||||
|
|||||||
@@ -457,7 +457,7 @@
|
|||||||
@if (!useNativePdfViewer) {
|
@if (!useNativePdfViewer) {
|
||||||
<div class="preview-sticky pdf-viewer-container">
|
<div class="preview-sticky pdf-viewer-container">
|
||||||
<pngx-pdf-viewer
|
<pngx-pdf-viewer
|
||||||
[src]="{ url: previewUrl, password: password }"
|
[src]="pdfSource"
|
||||||
[renderMode]="PdfRenderMode.All"
|
[renderMode]="PdfRenderMode.All"
|
||||||
[(page)]="previewCurrentPage"
|
[(page)]="previewCurrentPage"
|
||||||
[zoomScale]="previewZoomScale"
|
[zoomScale]="previewZoomScale"
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ import { PDFEditorComponent } from '../common/pdf-editor/pdf-editor.component'
|
|||||||
import { PngxPdfViewerComponent } from '../common/pdf-viewer/pdf-viewer.component'
|
import { PngxPdfViewerComponent } from '../common/pdf-viewer/pdf-viewer.component'
|
||||||
import {
|
import {
|
||||||
PdfRenderMode,
|
PdfRenderMode,
|
||||||
|
PdfSource,
|
||||||
PdfZoomLevel,
|
PdfZoomLevel,
|
||||||
PdfZoomScale,
|
PdfZoomScale,
|
||||||
PngxPdfDocumentProxy,
|
PngxPdfDocumentProxy,
|
||||||
@@ -227,6 +228,7 @@ export class DocumentDetailComponent
|
|||||||
title: string
|
title: string
|
||||||
titleSubject: Subject<string> = new Subject()
|
titleSubject: Subject<string> = new Subject()
|
||||||
previewUrl: string
|
previewUrl: string
|
||||||
|
pdfSource?: PdfSource
|
||||||
thumbUrl: string
|
thumbUrl: string
|
||||||
previewText: string
|
previewText: string
|
||||||
previewLoaded: boolean = false
|
previewLoaded: boolean = false
|
||||||
@@ -345,6 +347,17 @@ export class DocumentDetailComponent
|
|||||||
return ContentRenderType.Other
|
return ContentRenderType.Other
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updatePdfSource() {
|
||||||
|
if (!this.previewUrl) {
|
||||||
|
this.pdfSource = undefined
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.pdfSource = {
|
||||||
|
url: this.previewUrl,
|
||||||
|
password: this.password || undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get isRTL() {
|
get isRTL() {
|
||||||
if (!this.metadata || !this.metadata.lang) return false
|
if (!this.metadata || !this.metadata.lang) return false
|
||||||
else {
|
else {
|
||||||
@@ -421,6 +434,7 @@ export class DocumentDetailComponent
|
|||||||
|
|
||||||
private loadDocument(documentId: number): void {
|
private loadDocument(documentId: number): void {
|
||||||
this.previewUrl = this.documentsService.getPreviewUrl(documentId)
|
this.previewUrl = this.documentsService.getPreviewUrl(documentId)
|
||||||
|
this.updatePdfSource()
|
||||||
this.http
|
this.http
|
||||||
.get(this.previewUrl, { responseType: 'text' })
|
.get(this.previewUrl, { responseType: 'text' })
|
||||||
.pipe(
|
.pipe(
|
||||||
@@ -1230,6 +1244,7 @@ export class DocumentDetailComponent
|
|||||||
onPasswordKeyUp(event: KeyboardEvent) {
|
onPasswordKeyUp(event: KeyboardEvent) {
|
||||||
if ('Enter' == event.key) {
|
if ('Enter' == event.key) {
|
||||||
this.password = (event.target as HTMLInputElement).value
|
this.password = (event.target as HTMLInputElement).value
|
||||||
|
this.updatePdfSource()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user