Feature-parity migration to ngx-extended-pdf-viewer
This commit is contained in:
@@ -51,7 +51,7 @@ import { SavedViewWidgetComponent } from './components/dashboard/widgets/saved-v
|
||||
import { StatisticsWidgetComponent } from './components/dashboard/widgets/statistics-widget/statistics-widget.component'
|
||||
import { UploadFileWidgetComponent } from './components/dashboard/widgets/upload-file-widget/upload-file-widget.component'
|
||||
import { WidgetFrameComponent } from './components/dashboard/widgets/widget-frame/widget-frame.component'
|
||||
import { PdfViewerModule } from 'ng2-pdf-viewer'
|
||||
import { NgxExtendedPdfViewerModule } from 'ngx-extended-pdf-viewer'
|
||||
import { WelcomeWidgetComponent } from './components/dashboard/widgets/welcome-widget/welcome-widget.component'
|
||||
import { YesNoPipe } from './pipes/yes-no.pipe'
|
||||
import { FileSizePipe } from './pipes/file-size.pipe'
|
||||
@@ -265,11 +265,11 @@ function initializeApp(settings: SettingsService) {
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
NgxFileDropModule,
|
||||
PdfViewerModule,
|
||||
NgSelectModule,
|
||||
ColorSliderModule,
|
||||
TourNgBootstrapModule,
|
||||
DragDropModule,
|
||||
NgxExtendedPdfViewerModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<p class="mb-0">{{toast.content}}</p>
|
||||
<details *ngIf="toast.error">
|
||||
<div class="mt-2">
|
||||
<dl class="row mb-0" *ngIf="isDetailedError(toast.error)">
|
||||
<dl class="row mb-0" *ngIf="isDetailedError(toast.error); else simpleError">
|
||||
<dt class="col-sm-3 fw-normal text-end">URL</dt>
|
||||
<dd class="col-sm-9">{{ toast.error.url }}</dd>
|
||||
<dt class="col-sm-3 fw-normal text-end" i18n>Status</dt>
|
||||
@@ -24,6 +24,12 @@
|
||||
<dt class="col-sm-3 fw-normal text-end" i18n>Error</dt>
|
||||
<dd class="col-sm-9">{{ getErrorText(toast.error) }}</dd>
|
||||
</dl>
|
||||
<ng-template #simpleError>
|
||||
<dl class="row mb-0">
|
||||
<dt class="col-sm-3 fw-normal text-end" i18n>Error</dt>
|
||||
<dd class="col-sm-9">{{ getErrorText(toast.error) }}</dd>
|
||||
</dl>
|
||||
</ng-template>
|
||||
<div class="row">
|
||||
<div class="col offset-sm-3">
|
||||
<button class="btn btn-sm btn-outline-dark" (click)="copyError(toast.error)">
|
||||
|
||||
@@ -189,24 +189,7 @@
|
||||
<li [ngbNavItem]="DocumentDetailNavIDs.Preview" class="d-md-none">
|
||||
<a ngbNavLink i18n>Preview</a>
|
||||
<ng-template ngbNavContent *ngIf="!pdfPreview.offsetParent">
|
||||
<div class="position-relative">
|
||||
<ng-container *ngIf="getContentType() === 'application/pdf'">
|
||||
<div class="preview-sticky pdf-viewer-container" *ngIf="!useNativePdfViewer ; else nativePdfViewer">
|
||||
<pdf-viewer [src]="{ url: previewUrl, password: password }" [original-size]="false" [show-borders]="true" [show-all]="true" [(page)]="previewCurrentPage" [render-text-mode]="2" (error)="onError($event)" (after-load-complete)="pdfPreviewLoaded($event)"></pdf-viewer>
|
||||
</div>
|
||||
<ng-template #nativePdfViewer>
|
||||
<object [data]="previewUrl | safeUrl" class="preview-sticky" width="100%"></object>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="getContentType() === 'text/plain'">
|
||||
<object [data]="previewUrl | safeUrl" type="text/plain" class="preview-sticky bg-light overflow-auto" width="100%"></object>
|
||||
</ng-container>
|
||||
<div *ngIf="requiresPassword" class="password-prompt">
|
||||
<form>
|
||||
<input autocomplete="" class="form-control" i18n-placeholder placeholder="Enter Password" type="password" (keyup)="onPasswordKeyUp($event)" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngTemplateOutlet="previewContent"></ng-container>
|
||||
</ng-template>
|
||||
</li>
|
||||
|
||||
@@ -233,22 +216,41 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-xl-8 mb-3 d-none d-md-block position-relative" #pdfPreview>
|
||||
<ng-container *ngIf="getContentType() === 'application/pdf'">
|
||||
<div class="preview-sticky pdf-viewer-container" *ngIf="!useNativePdfViewer ; else nativePdfViewer">
|
||||
<pdf-viewer [src]="{ url: previewUrl, password: password }" [original-size]="false" [show-borders]="true" [show-all]="true" [(page)]="previewCurrentPage" [render-text-mode]="2" (error)="onError($event)" (after-load-complete)="pdfPreviewLoaded($event)"></pdf-viewer>
|
||||
</div>
|
||||
<ng-template #nativePdfViewer>
|
||||
<object [data]="previewUrl | safeUrl" class="preview-sticky" width="100%"></object>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="renderAsPlainText">
|
||||
<div [innerText]="previewText" class="preview-sticky bg-light p-3 overflow-auto" width="100%"></div>
|
||||
</ng-container>
|
||||
<div *ngIf="requiresPassword" class="password-prompt">
|
||||
<form>
|
||||
<input autocomplete="" class="form-control" i18n-placeholder placeholder="Enter Password" type="password" (keyup)="onPasswordKeyUp($event)" />
|
||||
</form>
|
||||
</div>
|
||||
<ng-container *ngTemplateOutlet="previewContent"></ng-container>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<ng-template #previewContent>
|
||||
<ng-container *ngIf="getContentType() === 'application/pdf'">
|
||||
<div class="preview-sticky pdf-viewer-container" *ngIf="!useNativePdfViewer ; else nativePdfViewer">
|
||||
<ngx-extended-pdf-viewer
|
||||
[src]="previewUrl"
|
||||
[useBrowserLocale]="true"
|
||||
[showPagingButtons]="false"
|
||||
[showRotateButton]="false"
|
||||
[showHandToolButton]="false"
|
||||
[showOpenFileButton]="false"
|
||||
[showDownloadButton]="false"
|
||||
[showDrawEditor]="false"
|
||||
[showTextEditor]="false"
|
||||
[showSecondaryToolbarButton]="false"
|
||||
[showStampEditor]="false"
|
||||
(pagesLoaded)="onPagesLoaded($event)"
|
||||
(pdfLoadingFailed)="onPdfLoadingFailed($event)"
|
||||
[(page)]="previewCurrentPage">
|
||||
</ngx-extended-pdf-viewer>
|
||||
</div>
|
||||
<ng-template #nativePdfViewer>
|
||||
<object [data]="previewUrl | safeUrl" class="preview-sticky" width="100%"></object>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="renderAsPlainText">
|
||||
<div [innerText]="previewText" class="preview-sticky bg-light p-3 overflow-auto" width="100%"></div>
|
||||
</ng-container>
|
||||
<div *ngIf="showPasswordField" class="password-prompt">
|
||||
<form>
|
||||
<input autocomplete="" autofocus="true" class="form-control" i18n-placeholder placeholder="Enter Password" type="password" (keyup)="onPasswordKeyUp($event)" />
|
||||
</form>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -653,14 +653,14 @@ describe('DocumentDetailComponent', () => {
|
||||
it('should support password-protected PDFs with a password field', () => {
|
||||
initNormally()
|
||||
component.onError({ name: 'PasswordException' }) // normally dispatched by pdf viewer
|
||||
expect(component.requiresPassword).toBeTruthy()
|
||||
expect(component.showPasswordField).toBeTruthy()
|
||||
fixture.detectChanges()
|
||||
expect(
|
||||
fixture.debugElement.query(By.css('input[type=password]'))
|
||||
).not.toBeUndefined()
|
||||
component.password = 'foo'
|
||||
component.pdfPreviewLoaded({ numPages: 1000 } as any)
|
||||
expect(component.requiresPassword).toBeFalsy()
|
||||
expect(component.showPasswordField).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should support Enter key in password field', () => {
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
ViewChild,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core'
|
||||
import { FormArray, FormControl, FormGroup } from '@angular/forms'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import {
|
||||
@@ -21,7 +27,6 @@ import { DocumentService } from 'src/app/services/rest/document.service'
|
||||
import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component'
|
||||
import { CorrespondentEditDialogComponent } from '../common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component'
|
||||
import { DocumentTypeEditDialogComponent } from '../common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component'
|
||||
import { PDFDocumentProxy } from 'ng2-pdf-viewer'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { TextComponent } from '../common/input/text/text.component'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
@@ -69,6 +74,9 @@ import {
|
||||
} from 'src/app/data/paperless-custom-field'
|
||||
import { PaperlessCustomFieldInstance } from 'src/app/data/paperless-custom-field-instance'
|
||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||
import { InvalidPDFException } from 'ngx-extended-pdf-viewer/lib/events/invalid-pdf-exception'
|
||||
import { PagesLoadedEvent } from 'ngx-extended-pdf-viewer/lib/events/pages-loaded-event'
|
||||
import { pdfDefaultOptions } from 'ngx-extended-pdf-viewer'
|
||||
|
||||
enum DocumentDetailNavIDs {
|
||||
Details = 1,
|
||||
@@ -136,8 +144,7 @@ export class DocumentDetailComponent
|
||||
unsubscribeNotifier: Subject<any> = new Subject()
|
||||
docChangeNotifier: Subject<any> = new Subject()
|
||||
|
||||
requiresPassword: boolean = false
|
||||
password: string
|
||||
showPasswordField: boolean = false
|
||||
|
||||
ogDate: Date
|
||||
|
||||
@@ -160,6 +167,8 @@ export class DocumentDetailComponent
|
||||
DocumentDetailNavIDs = DocumentDetailNavIDs
|
||||
activeNavID: number
|
||||
|
||||
setPasswordCallback: (password: string) => void
|
||||
|
||||
constructor(
|
||||
private documentsService: DocumentService,
|
||||
private route: ActivatedRoute,
|
||||
@@ -176,9 +185,23 @@ export class DocumentDetailComponent
|
||||
private permissionsService: PermissionsService,
|
||||
private userService: UserService,
|
||||
private customFieldsService: CustomFieldsService,
|
||||
private http: HttpClient
|
||||
private http: HttpClient,
|
||||
private ref: ChangeDetectorRef
|
||||
) {
|
||||
super()
|
||||
pdfDefaultOptions.passwordPrompt = {
|
||||
// ngx-extended-pdf-viewer PasswordPrompt
|
||||
open: () => {
|
||||
this.showPasswordField = true
|
||||
ref.detectChanges() // manually trigger change detection
|
||||
},
|
||||
setUpdateCallback: (
|
||||
updateCallback: (password: string) => void,
|
||||
reason: 1 | 2
|
||||
) => {
|
||||
this.setPasswordCallback = updateCallback
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
titleKeyUp(event) {
|
||||
@@ -397,7 +420,6 @@ export class DocumentDetailComponent
|
||||
|
||||
updateComponent(doc: PaperlessDocument) {
|
||||
this.document = doc
|
||||
this.requiresPassword = false
|
||||
// this.customFields = doc.custom_fields.concat([])
|
||||
this.updateFormForCustomFields()
|
||||
this.documentsService
|
||||
@@ -727,20 +749,21 @@ export class DocumentDetailComponent
|
||||
})
|
||||
}
|
||||
|
||||
pdfPreviewLoaded(pdf: PDFDocumentProxy) {
|
||||
this.previewNumPages = pdf.numPages
|
||||
if (this.password) this.requiresPassword = false
|
||||
onPagesLoaded(event: PagesLoadedEvent) {
|
||||
this.previewNumPages = event.pagesCount
|
||||
}
|
||||
|
||||
onError(event) {
|
||||
if (event.name == 'PasswordException') {
|
||||
this.requiresPassword = true
|
||||
}
|
||||
onPdfLoadingFailed(event: InvalidPDFException) {
|
||||
this.toastService.showError($localize`Error loading PDF`, {
|
||||
error: event.message,
|
||||
})
|
||||
this.ref.detectChanges() // manually trigger change detection
|
||||
}
|
||||
|
||||
onPasswordKeyUp(event: KeyboardEvent) {
|
||||
if ('Enter' == event.key) {
|
||||
this.password = (event.target as HTMLInputElement).value
|
||||
this.showPasswordField = false
|
||||
this.setPasswordCallback((event.target as HTMLInputElement).value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user