[ACS-7389][ADF] Break Viewer dependency on Material Module (#9631)

This commit is contained in:
tamaragruszka
2024-05-09 19:07:34 +02:00
committed by GitHub
parent d0209d466e
commit 0414fa77e0
58 changed files with 627 additions and 601 deletions

View File

@@ -16,12 +16,11 @@
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MatDialogRef } from '@angular/material/dialog';
import { DownloadPromptDialogComponent } from './download-prompt-dialog.component';
import { CoreTestingModule } from '../../../testing/core.testing.module';
import { By } from '@angular/platform-browser';
import { CoreTestingModule } from '../../../testing';
import { DownloadPromptActions } from '../../models/download-prompt.actions';
import { DownloadPromptDialogComponent } from './download-prompt-dialog.component';
const mockDialog = {
close: jasmine.createSpy('close')
@@ -35,8 +34,7 @@ describe('DownloadPromptDialogComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [DownloadPromptDialogComponent],
imports: [CoreTestingModule],
imports: [CoreTestingModule, DownloadPromptDialogComponent],
providers: [{ provide: MatDialogRef, useValue: mockDialog }]
});
matDialogRef = TestBed.inject(MatDialogRef);

View File

@@ -16,10 +16,15 @@
*/
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { TranslateModule } from '@ngx-translate/core';
import { DownloadPromptActions } from '../../models/download-prompt.actions';
@Component({
selector: 'adf-download-prompt-dialog',
standalone: true,
imports: [MatDialogModule, TranslateModule, MatButtonModule],
templateUrl: './download-prompt-dialog.component.html'
})
export class DownloadPromptDialogComponent {

View File

@@ -1,86 +0,0 @@
<div id="adf-image-container"
(keydown)="onKeyDown($event)"
class="adf-image-container"
tabindex="0"
role="button"
[attr.aria-label]="fileName"
data-automation-id="adf-image-container">
<img #image id="viewer-image"
[src]="urlFile"
[alt]="fileName"
(error)="onImageError()" />
</div>
<div class="adf-image-viewer__toolbar" *ngIf="showToolbar">
<adf-toolbar class="adf-main-toolbar">
<button
id="viewer-zoom-out-button"
title="{{ 'ADF_VIEWER.ARIA.ZOOM_OUT' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ZOOM_OUT' | translate }}"
mat-icon-button
(click)="zoomOut()">
<mat-icon>zoom_out</mat-icon>
</button>
<div class="adf-image-viewer__toolbar-page-scale" data-automation-id="adf-page-scale">
{{ currentScaleText }}
</div>
<button
id="viewer-zoom-in-button"
mat-icon-button
title="{{ 'ADF_VIEWER.ARIA.ZOOM_IN' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ZOOM_IN' | translate }}"
(click)="zoomIn()">
<mat-icon>zoom_in</mat-icon>
</button>
<button
*ngIf="!readOnly" id="viewer-rotate-button"
title="{{ 'ADF_VIEWER.ARIA.ROTATE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ROTATE' | translate }}"
mat-icon-button
(click)="rotateImage()">
<mat-icon>rotate_left</mat-icon>
</button>
<button
*ngIf="!readOnly" id="viewer-crop-button"
title="{{ 'ADF_VIEWER.ARIA.CROP' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.CROP' | translate }}"
mat-icon-button
(click)="cropImage()">
<mat-icon>crop</mat-icon>
</button>
<button
id="viewer-reset-button"
title="{{ 'ADF_VIEWER.ARIA.RESET' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.RESET' | translate }}"
mat-icon-button
(click)="reset()">
<mat-icon>zoom_out_map</mat-icon>
</button>
</adf-toolbar>
<adf-toolbar class="adf-secondary-toolbar" *ngIf="!readOnly && isEditing">
<button
id="viewer-cancel-button"
title="{{ 'ADF_VIEWER.ARIA.CANCEL' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.CANCEL' | translate }}"
mat-icon-button
(click)="reset()">
<mat-icon>close</mat-icon>
</button>
<button
id="viewer-save-button"
title="{{ 'ADF_VIEWER.ARIA.SAVE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.SAVE' | translate }}"
mat-icon-button
(click)="save()">
<mat-icon>check</mat-icon>
</button>
</adf-toolbar>
</div>

View File

@@ -0,0 +1,79 @@
<div id="adf-image-container"
(keydown)="onKeyDown($event)"
class="adf-image-container"
tabindex="0"
role="img"
[attr.aria-label]="fileName"
data-automation-id="adf-image-container">
<img #image id="viewer-image"
[src]="urlFile"
[alt]="fileName"
(error)="onImageError()" />
</div>
<div class="adf-image-viewer__toolbar" *ngIf="showToolbar">
<adf-toolbar class="adf-main-toolbar">
<button id="viewer-zoom-out-button"
title="{{ 'ADF_VIEWER.ARIA.ZOOM_OUT' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ZOOM_OUT' | translate }}"
mat-icon-button
(click)="zoomOut()">
<mat-icon>zoom_out</mat-icon>
</button>
<div class="adf-image-viewer__toolbar-page-scale" data-automation-id="adf-page-scale">
{{ currentScaleText }}
</div>
<button id="viewer-zoom-in-button"
mat-icon-button
title="{{ 'ADF_VIEWER.ARIA.ZOOM_IN' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ZOOM_IN' | translate }}"
(click)="zoomIn()">
<mat-icon>zoom_in</mat-icon>
</button>
<button *ngIf="!readOnly" id="viewer-rotate-button"
title="{{ 'ADF_VIEWER.ARIA.ROTATE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ROTATE' | translate }}"
mat-icon-button
(click)="rotateImage()">
<mat-icon>rotate_left</mat-icon>
</button>
<button *ngIf="!readOnly" id="viewer-crop-button"
title="{{ 'ADF_VIEWER.ARIA.CROP' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.CROP' | translate }}"
mat-icon-button
(click)="cropImage()">
<mat-icon>crop</mat-icon>
</button>
<button id="viewer-reset-button"
title="{{ 'ADF_VIEWER.ARIA.RESET' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.RESET' | translate }}"
mat-icon-button
(click)="reset()">
<mat-icon>zoom_out_map</mat-icon>
</button>
</adf-toolbar>
<adf-toolbar class="adf-secondary-toolbar" *ngIf="!readOnly && isEditing">
<button id="viewer-cancel-button"
title="{{ 'ADF_VIEWER.ARIA.CANCEL' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.CANCEL' | translate }}"
mat-icon-button
(click)="reset()">
<mat-icon>close</mat-icon>
</button>
<button id="viewer-save-button"
title="{{ 'ADF_VIEWER.ARIA.SAVE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.SAVE' | translate }}"
mat-icon-button
(click)="save()">
<mat-icon>check</mat-icon>
</button>
</adf-toolbar>
</div>

View File

@@ -31,7 +31,7 @@
left: 50%;
transform: translateX(-50%);
.adf-toolbar .mat-toolbar {
.adf-toolbar .adf-toolbar-container {
max-height: 48px;
background-color: var(--adf-theme-background-card-color);
border-width: 0;

View File

@@ -17,11 +17,11 @@
import { SimpleChange } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { UrlService } from '../../common/services/url.service';
import { ImgViewerComponent } from './img-viewer.component';
import { CoreTestingModule } from '../../testing';
import { AppConfigService } from '../../app-config/app-config.service';
import { By } from '@angular/platform-browser';
import { AppConfigService } from '../../../app-config';
import { UrlService } from '../../../common';
import { CoreTestingModule } from '../../../testing';
import { ImgViewerComponent } from './img-viewer.component';
describe('Test Img viewer component ', () => {
let component: ImgViewerComponent;

View File

@@ -15,29 +15,36 @@
* limitations under the License.
*/
import { NgIf } from '@angular/common';
import {
AfterViewInit,
Component,
ElementRef,
EventEmitter,
HostListener,
Input,
OnChanges,
SimpleChanges,
ViewEncapsulation,
ElementRef,
OnDestroy,
Output,
EventEmitter,
AfterViewInit,
SimpleChanges,
ViewChild,
HostListener,
OnDestroy
ViewEncapsulation
} from '@angular/core';
import { AppConfigService } from '../../app-config/app-config.service';
import { UrlService } from '../../common/services/url.service';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core';
import Cropper from 'cropperjs';
import { AppConfigService } from '../../../app-config';
import { UrlService } from '../../../common';
import { ToolbarComponent } from '../../../toolbar';
@Component({
selector: 'adf-img-viewer',
standalone: true,
templateUrl: './img-viewer.component.html',
styleUrls: ['./img-viewer.component.scss'],
host: { class: 'adf-image-viewer' },
imports: [ToolbarComponent, TranslateModule, MatIconModule, MatButtonModule, NgIf],
encapsulation: ViewEncapsulation.None
})
export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
@@ -78,10 +85,7 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
return Math.round(this.scale * 100) + '%';
}
constructor(
private appConfigService: AppConfigService,
private urlService: UrlService
) {
constructor(private appConfigService: AppConfigService, private urlService: UrlService) {
this.initializeScaling();
}

View File

@@ -1,4 +0,0 @@
<video controls class="adf-video-player" [ngClass]="{'adf-audio-file': mimeType && mimeType.startsWith('audio')}">
<source [src]="urlFile" [type]="mimeType" (error)="onMediaPlayerError($event)"/>
<track *ngFor="let track of tracks" [kind]="track.kind" [label]="track.label" [srclang]="track.srclang" [src]="track.src"/>
</video>

View File

@@ -0,0 +1,11 @@
<video controls class="adf-video-player"
[ngClass]="{ 'adf-audio-file': mimeType && mimeType.startsWith('audio') }">
<source [src]="urlFile"
[type]="mimeType"
(error)="onMediaPlayerError($event)" />
<track *ngFor="let track of tracks"
[kind]="track.kind"
[label]="track.label"
[srclang]="track.srclang"
[src]="track.src" />
</video>

View File

@@ -15,15 +15,18 @@
* limitations under the License.
*/
import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation, Output, EventEmitter } from '@angular/core';
import { Track } from '../models/viewer.model';
import { UrlService } from '../../common/services/url.service';
import { NgClass, NgForOf } from '@angular/common';
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { UrlService } from '../../../common';
import { Track } from '../../models/viewer.model';
@Component({
selector: 'adf-media-player',
standalone: true,
templateUrl: './media-player.component.html',
styleUrls: ['./media-player.component.scss'],
host: { class: 'adf-media-player' },
imports: [NgClass, NgForOf],
encapsulation: ViewEncapsulation.None
})
export class MediaPlayerComponent implements OnChanges {

View File

@@ -16,9 +16,14 @@
*/
import { Component } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { ViewerComponent } from '../viewer.component';
@Component({
selector: 'adf-viewer-container-more-actions',
standalone: true,
imports: [ViewerComponent, MatIconModule, MatMenuModule],
template: `
<adf-viewer>
<adf-viewer-more-actions>
@@ -38,5 +43,4 @@ import { Component } from '@angular/core';
</adf-viewer>
`
})
export class ViewerWithCustomMoreActionsComponent {
}
export class ViewerWithCustomMoreActionsComponent {}

View File

@@ -16,9 +16,14 @@
*/
import { Component } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { ViewerComponent } from '../viewer.component';
@Component({
selector: 'adf-viewer-container-open-with',
standalone: true,
imports: [ViewerComponent, MatIconModule, MatMenuModule],
template: `
<adf-viewer>
<adf-viewer-open-with>
@@ -38,5 +43,4 @@ import { Component } from '@angular/core';
</adf-viewer>
`
})
export class ViewerWithCustomOpenWithComponent {
}
export class ViewerWithCustomOpenWithComponent {}

View File

@@ -16,9 +16,12 @@
*/
import { Component } from '@angular/core';
import { ViewerComponent } from '../viewer.component';
@Component({
selector: 'adf-viewer-container-sidebar',
standalone: true,
imports: [ViewerComponent],
template: `
<adf-viewer>
<adf-viewer-sidebar>
@@ -27,5 +30,4 @@ import { Component } from '@angular/core';
</adf-viewer>
`
})
export class ViewerWithCustomSidebarComponent {
}
export class ViewerWithCustomSidebarComponent {}

View File

@@ -16,9 +16,14 @@
*/
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { ViewerComponent } from '../viewer.component';
@Component({
selector: 'adf-viewer-container-toolbar-actions',
standalone: true,
imports: [ViewerComponent, MatIconModule, MatButtonModule],
template: `
<adf-viewer>
<adf-viewer-toolbar-actions>
@@ -29,5 +34,4 @@ import { Component } from '@angular/core';
</adf-viewer>
`
})
export class ViewerWithCustomToolbarActionsComponent {
}
export class ViewerWithCustomToolbarActionsComponent {}

View File

@@ -16,9 +16,12 @@
*/
import { Component } from '@angular/core';
import { ViewerComponent } from '../viewer.component';
@Component({
selector: 'adf-viewer-container-toolbar',
standalone: true,
imports: [ViewerComponent],
template: `
<adf-viewer>
<adf-viewer-toolbar>
@@ -27,5 +30,4 @@ import { Component } from '@angular/core';
</adf-viewer>
`
})
export class ViewerWithCustomToolbarComponent {
}
export class ViewerWithCustomToolbarComponent {}

View File

@@ -16,9 +16,9 @@
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { CoreTestingModule } from '../../../testing';
import { PdfPasswordDialogComponent } from './pdf-viewer-password-dialog';
import { CoreTestingModule } from '../../testing/core.testing.module';
declare const pdfjsLib: any;

View File

@@ -15,25 +15,30 @@
* limitations under the License.
*/
import { NgIf } from '@angular/common';
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { UntypedFormControl, Validators } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { ReactiveFormsModule, UntypedFormControl, Validators } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { TranslateModule } from '@ngx-translate/core';
declare const pdfjsLib: any;
@Component({
selector: 'adf-pdf-viewer-password-dialog',
standalone: true,
templateUrl: './pdf-viewer-password-dialog.html',
styleUrls: ['./pdf-viewer-password-dialog.scss'],
imports: [MatDialogModule, MatIconModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule, TranslateModule, NgIf, MatButtonModule],
encapsulation: ViewEncapsulation.None
})
export class PdfPasswordDialogComponent implements OnInit {
passwordFormControl: UntypedFormControl;
constructor(
private dialogRef: MatDialogRef<PdfPasswordDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any
) {}
constructor(private dialogRef: MatDialogRef<PdfPasswordDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: any) {}
ngOnInit() {
this.passwordFormControl = new UntypedFormControl('', [Validators.required]);

View File

@@ -1,6 +0,0 @@
<ng-container *ngIf="image$ | async as image">
<img [src]="image" role="button"
[alt]="'ADF_VIEWER.SIDEBAR.THUMBNAILS.PAGE' | translate: { pageNum: page.id }"
title="{{ 'ADF_VIEWER.SIDEBAR.THUMBNAILS.PAGE' | translate: { pageNum: page.id } }}"
[attr.aria-label]="'ADF_VIEWER.SIDEBAR.THUMBNAILS.PAGE' | translate: { pageNum: page.id }">
</ng-container>

View File

@@ -0,0 +1,6 @@
<ng-container *ngIf="image$ | async as image">
<img [src]="image" role="button"
[alt]="'ADF_VIEWER.SIDEBAR.THUMBNAILS.PAGE' | translate: { pageNum: page.id }"
title="{{ 'ADF_VIEWER.SIDEBAR.THUMBNAILS.PAGE' | translate: { pageNum: page.id } }}"
[attr.aria-label]="'ADF_VIEWER.SIDEBAR.THUMBNAILS.PAGE' | translate: { pageNum: page.id }">
</ng-container>

View File

@@ -18,7 +18,7 @@
import { DomSanitizer } from '@angular/platform-browser';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PdfThumbComponent } from './pdf-viewer-thumb.component';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { CoreTestingModule } from '../../../testing';
describe('PdfThumbComponent', () => {
let fixture: ComponentFixture<PdfThumbComponent>;
@@ -32,11 +32,10 @@ describe('PdfThumbComponent', () => {
id: 'pageId',
getPage: jasmine.createSpy('getPage').and.returnValue(
Promise.resolve({
getViewport: () => ({ height: width, width: height }),
getViewport: () => ({ width, height }),
render: jasmine.createSpy('render').and.returnValue({ promise: Promise.resolve() })
})
),
getWidth: jasmine.createSpy('getWidth').and.returnValue(width),
getHeight: jasmine.createSpy('getHeight').and.returnValue(height)
};
@@ -44,7 +43,12 @@ describe('PdfThumbComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CoreTestingModule],
providers: [{ provide: DomSanitizer, useValue: domSanitizer }]
providers: [
{
provide: DomSanitizer,
useValue: domSanitizer
}
]
});
fixture = TestBed.createComponent(PdfThumbComponent);
component = fixture.componentInstance;

View File

@@ -15,25 +15,27 @@
* limitations under the License.
*/
import { FocusableOption } from '@angular/cdk/a11y';
import { AsyncPipe, NgIf } from '@angular/common';
import { Component, ElementRef, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { FocusableOption } from '@angular/cdk/a11y';
import { TranslateModule } from '@ngx-translate/core';
@Component({
selector: 'adf-pdf-thumb',
standalone: true,
templateUrl: './pdf-viewer-thumb.component.html',
encapsulation: ViewEncapsulation.None,
host: { tabindex: '0'}
imports: [AsyncPipe, TranslateModule, NgIf],
host: { tabindex: '0' }
})
export class PdfThumbComponent implements OnInit, FocusableOption {
@Input()
page: any = null;
image$: Promise<string>;
constructor(private sanitizer: DomSanitizer, private element: ElementRef) {
}
constructor(private sanitizer: DomSanitizer, private element: ElementRef) {}
ngOnInit() {
this.image$ = this.page.getPage().then((page) => this.getThumb(page));
@@ -47,15 +49,17 @@ export class PdfThumbComponent implements OnInit, FocusableOption {
const viewport = page.getViewport({ scale: 1 });
const canvas = this.getCanvas();
const scale = Math.min((canvas.height / viewport.height), (canvas.width / viewport.width));
const scale = Math.min(canvas.height / viewport.height, canvas.width / viewport.width);
return page.render({
canvasContext: canvas.getContext('2d'),
viewport: page.getViewport({ scale })
}).promise.then(() => {
const imageSource = canvas.toDataURL();
return this.sanitizer.bypassSecurityTrustUrl(imageSource);
});
return page
.render({
canvasContext: canvas.getContext('2d'),
viewport: page.getViewport({ scale })
})
.promise.then(() => {
const imageSource = canvas.toDataURL();
return this.sanitizer.bypassSecurityTrustUrl(imageSource);
});
}
private getCanvas(): HTMLCanvasElement {
@@ -64,5 +68,4 @@ export class PdfThumbComponent implements OnInit, FocusableOption {
canvas.height = this.page.getHeight();
return canvas;
}
}

View File

@@ -1,12 +0,0 @@
<div class="adf-pdf-thumbnails__content"
data-automation-id='adf-thumbnails-content'
[style.height.px]="virtualHeight"
[style.transform]="'translate(-50%, ' + translateY + 'px)'">
<adf-pdf-thumb *ngFor="let page of renderItems; trackBy: trackByFn"
class="adf-pdf-thumbnails__thumb"
[id]="page.id"
[ngClass]="{'adf-pdf-thumbnails__thumb--selected' : isSelected(page.id)}"
[page]="page"
(click)="goTo(page.id)">
</adf-pdf-thumb>
</div>

View File

@@ -0,0 +1,12 @@
<div class="adf-pdf-thumbnails__content"
data-automation-id='adf-thumbnails-content'
[style.height.px]="virtualHeight"
[style.transform]="'translate(-50%, ' + translateY + 'px)'">
<adf-pdf-thumb *ngFor="let page of renderItems; trackBy: trackByFn"
class="adf-pdf-thumbnails__thumb"
[id]="page.id"
[ngClass]="{'adf-pdf-thumbnails__thumb--selected' : isSelected(page.id)}"
[page]="page"
(click)="goTo(page.id)">
</adf-pdf-thumb>
</div>

View File

@@ -18,8 +18,8 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { PdfThumbListComponent } from './pdf-viewer-thumbnails.component';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { DOWN_ARROW, UP_ARROW, ESCAPE } from '@angular/cdk/keycodes';
import { CoreTestingModule } from '../../../testing';
import { DOWN_ARROW, ESCAPE, UP_ARROW } from '@angular/cdk/keycodes';
declare const pdfjsViewer: any;

View File

@@ -15,21 +15,36 @@
* limitations under the License.
*/
import {
Component, Input, ContentChild, TemplateRef, HostListener, OnInit,
AfterViewInit, ElementRef, OnDestroy, ViewEncapsulation, EventEmitter, Output, Inject, ViewChildren, QueryList
} from '@angular/core';
import { ESCAPE, UP_ARROW, DOWN_ARROW, TAB } from '@angular/cdk/keycodes';
import { DOCUMENT } from '@angular/common';
import { FocusKeyManager } from '@angular/cdk/a11y';
import { PdfThumbComponent } from './pdf-viewer-thumb.component';
import { DOWN_ARROW, ESCAPE, TAB, UP_ARROW } from '@angular/cdk/keycodes';
import { DOCUMENT, NgClass, NgForOf } from '@angular/common';
import {
AfterViewInit,
Component,
ContentChild,
ElementRef,
EventEmitter,
HostListener,
Inject,
Input,
OnDestroy,
OnInit,
Output,
QueryList,
TemplateRef,
ViewChildren,
ViewEncapsulation
} from '@angular/core';
import { delay } from 'rxjs/operators';
import { PdfThumbComponent } from '../pdf-viewer-thumb/pdf-viewer-thumb.component';
@Component({
selector: 'adf-pdf-thumbnails',
standalone: true,
templateUrl: './pdf-viewer-thumbnails.component.html',
styleUrls: ['./pdf-viewer-thumbnails.component.scss'],
host: { class: 'adf-pdf-thumbnails' },
imports: [PdfThumbComponent, NgClass, NgForOf],
encapsulation: ViewEncapsulation.None
})
export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
@@ -68,7 +83,7 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
this.pdfViewer.currentPageNumber += 1;
}
if (keyCode === TAB) {
if (keyCode === TAB) {
if (this.canSelectNextItem()) {
this.pdfViewer.currentPageNumber += 1;
} else {
@@ -109,9 +124,7 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
ngAfterViewInit() {
this.keyManager = new FocusKeyManager(this.thumbsList);
this.thumbsList.changes
.pipe(delay(0))
.subscribe(() => this.keyManager.setActiveItem(this.getPageIndex(this.pdfViewer.currentPageNumber)));
this.thumbsList.changes.pipe(delay(0)).subscribe(() => this.keyManager.setActiveItem(this.getPageIndex(this.pdfViewer.currentPageNumber)));
setTimeout(() => {
this.scrollInto(this.pdfViewer.currentPageNumber);
@@ -183,11 +196,11 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
private calculateItems() {
const { element, viewPort, itemsInView } = this.getContainerSetup();
const indexByScrollTop = element.scrollTop / viewPort * this.items.length / itemsInView;
const indexByScrollTop = ((element.scrollTop / viewPort) * this.items.length) / itemsInView;
const start = Math.floor(indexByScrollTop);
const end = Math.ceil(indexByScrollTop) + (itemsInView);
const end = Math.ceil(indexByScrollTop) + itemsInView;
this.translateY = this.itemHeight * Math.ceil(start);
this.virtualHeight = this.itemHeight * this.items.length - this.translateY;
@@ -223,7 +236,7 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
private getPageIndex(pageNumber: number): number {
const thumbsListArray = this.thumbsList.toArray();
return thumbsListArray.findIndex(el => el.page.id === pageNumber);
return thumbsListArray.findIndex((el) => el.page.id === pageNumber);
}
private canSelectNextItem(): boolean {

View File

@@ -1,10 +1,7 @@
.adf-pdf-viewer {
.textLayer {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
inset: 0;
overflow: hidden;
opacity: 0.2;
line-height: 1;
@@ -15,17 +12,12 @@
position: absolute;
white-space: pre;
cursor: text;
-webkit-transform-origin: 0 0;
-moz-transform-origin: 0 0;
-o-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
}
.adf-highlight {
margin: -1px;
padding: 1px;
background-color: rgb(180, 0, 170);
border-radius: 4px;
@@ -46,22 +38,18 @@
}
}
&::selection { background: rgb(0, 0, 255); }
&::-moz-selection { background: rgb(0, 0, 255); }
&::selection {
background: rgb(0, 0, 255);
}
.adf-endOfContent {
display: block;
position: absolute;
left: 0;
inset: 0;
top: 100%;
right: 0;
bottom: 0;
z-index: -1;
cursor: default;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-moz-user-select: none;
&.adf-active {
top: 0;
@@ -110,7 +98,7 @@
position: absolute;
z-index: 200;
max-width: 20em;
background-color: #ffff99;
background-color: #ff9;
box-shadow: 0 2px 5px #333;
border-radius: 2px;
padding: 0.6em;
@@ -120,7 +108,7 @@
h1 {
font-size: 1em;
border-bottom: 1px solid #000000;
border-bottom: 1px solid #000;
padding-bottom: 0.2em;
}
@@ -162,10 +150,25 @@
.adf-loadingIcon {
position: absolute;
display: block;
left: 0;
top: 0;
right: 0;
bottom: 0;
inset: 0;
width: 100px;
height: 100px;
left: 50%;
top: 50%;
margin-top: -50px;
margin-left: -50px;
font-size: 5px;
text-indent: -9999em;
border-top: 1.1em solid rgba(3, 0, 2, 0.2);
border-right: 1.1em solid rgba(3, 0, 2, 0.2);
border-bottom: 1.1em solid rgba(3, 0, 2, 0.2);
border-left: 1.1em solid #030002;
animation: load8 1.1s infinite linear;
border-radius: 50%;
&::after {
border-radius: 50%;
}
}
* {
@@ -180,74 +183,26 @@
border: none;
}
}
.adf-loadingIcon {
width: 100px;
height: 100px;
left: 50%;
top: 50%;
margin-top: -50px;
margin-left: -50px;
font-size: 5px;
text-indent: -9999em;
border-top: 1.1em solid rgba(3, 0, 2, 0.2);
border-right: 1.1em solid rgba(3, 0, 2, 0.2);
border-bottom: 1.1em solid rgba(3, 0, 2, 0.2);
border-left: 1.1em solid #030002;
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
-webkit-animation: load8 1.1s infinite linear;
animation: load8 1.1s infinite linear;
border-radius: 50%;
&::after {
border-radius: 50%;
}
}
}
.adf-hidden, [hidden] {
.adf-hidden,
[hidden] {
display: none;
}
}
@-webkit-keyframes load8 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes load8 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.adf-viewer-pdf-viewer {
overflow: auto;
-webkit-overflow-scrolling: touch;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
inset: 0;
outline: none;
}
html[dir='ltr'] .adf-viewer-pdf-viewer {
box-shadow: inset 1px 0 0 hsla(0, 0%, 100%, 0.05);
box-shadow: inset 1px 0 0 hsla(0deg, 0%, 100%, 0.05);
}
html[dir='rtl'] .adf-viewer-pdf-viewer {
box-shadow: inset -1px 0 0 hsla(0, 0%, 100%, 0.05);
box-shadow: inset -1px 0 0 hsla(0deg, 0%, 100%, 0.05);
}

View File

@@ -3,12 +3,11 @@
<div class="adf-pdf-viewer__thumbnails">
<div class="adf-thumbnails-template__container">
<div class="adf-thumbnails-template__buttons">
<button
mat-icon-button
data-automation-id='adf-thumbnails-close'
(click)="toggleThumbnails()"
[attr.aria-label]="'ADF_VIEWER.ARIA.THUMBNAILS_PANLEL_CLOSE' | translate"
title="{{ 'ADF_VIEWER.ACTIONS.CLOSE' | translate }}">
<button mat-icon-button
data-automation-id='adf-thumbnails-close'
(click)="toggleThumbnails()"
[attr.aria-label]="'ADF_VIEWER.ARIA.THUMBNAILS_PANLEL_CLOSE' | translate"
title="{{ 'ADF_VIEWER.ACTIONS.CLOSE' | translate }}">
<mat-icon>close</mat-icon>
</button>
</div>
@@ -16,18 +15,26 @@
<ng-container *ngIf="thumbnailsTemplate">
<ng-container *ngTemplateOutlet="thumbnailsTemplate;context:pdfThumbnailsContext"></ng-container>
</ng-container>
<adf-pdf-thumbnails *ngIf="!thumbnailsTemplate && !isPanelDisabled" (close)="toggleThumbnails()" [pdfViewer]="pdfViewer">
<adf-pdf-thumbnails *ngIf="!thumbnailsTemplate && !isPanelDisabled"
(close)="toggleThumbnails()"
[pdfViewer]="pdfViewer">
</adf-pdf-thumbnails>
</div>
</div>
</ng-container>
<div class="adf-pdf-viewer__content">
<div [id]="randomPdfId+'-viewer-pdf-viewer'" class="adf-viewer-pdf-viewer" (window:resize)="onResize()">
<div [id]="randomPdfId+'-viewer-viewerPdf'" class="adf-pdfViewer" role="document" tabindex="0" aria-expanded="true">
<div [id]="randomPdfId + '-viewer-pdf-viewer'"
class="adf-viewer-pdf-viewer"
(window:resize)="onResize()">
<div [id]="randomPdfId + '-viewer-viewerPdf'"
class="adf-pdfViewer"
role="document"
tabindex="0"
aria-expanded="true">
<div id="loader-container" class="adf-loader-container">
<div class="adf-loader-item">
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
<mat-progress-bar class="adf-loader-item-progress-bar" mode="indeterminate"></mat-progress-bar>
</div>
</div>
</div>
@@ -50,21 +57,19 @@
<adf-toolbar-divider></adf-toolbar-divider>
</ng-container>
<button
id="viewer-previous-page-button"
title="{{ 'ADF_VIEWER.ARIA.PREVIOUS_PAGE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.PREVIOUS_PAGE' | translate }}"
mat-icon-button
(click)="previousPage()">
<button id="viewer-previous-page-button"
title="{{ 'ADF_VIEWER.ARIA.PREVIOUS_PAGE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.PREVIOUS_PAGE' | translate }}"
mat-icon-button
(click)="previousPage()">
<mat-icon>keyboard_arrow_up</mat-icon>
</button>
<button
id="viewer-next-page-button"
title="{{ 'ADF_VIEWER.ARIA.NEXT_PAGE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.NEXT_PAGE' | translate }}"
mat-icon-button
(click)="nextPage()">
<button id="viewer-next-page-button"
title="{{ 'ADF_VIEWER.ARIA.NEXT_PAGE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.NEXT_PAGE' | translate }}"
mat-icon-button
(click)="nextPage()">
<mat-icon>keyboard_arrow_down</mat-icon>
</button>
@@ -85,31 +90,28 @@
{{ currentScaleText }}
</div>
<button
id="viewer-zoom-in-button"
title="{{ 'ADF_VIEWER.ARIA.ZOOM_IN' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ZOOM_IN' | translate }}"
mat-icon-button
(click)="zoomIn()">
<button id="viewer-zoom-in-button"
title="{{ 'ADF_VIEWER.ARIA.ZOOM_IN' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ZOOM_IN' | translate }}"
mat-icon-button
(click)="zoomIn()">
<mat-icon>zoom_in</mat-icon>
</button>
<button
id="viewer-zoom-out-button"
title="{{ 'ADF_VIEWER.ARIA.ZOOM_OUT' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ZOOM_OUT' | translate }}"
mat-icon-button
(click)="zoomOut()">
<button id="viewer-zoom-out-button"
title="{{ 'ADF_VIEWER.ARIA.ZOOM_OUT' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ZOOM_OUT' | translate }}"
mat-icon-button
(click)="zoomOut()">
<mat-icon>zoom_out</mat-icon>
</button>
<button
id="viewer-scale-page-button"
role="button" aria-pressed="true"
title="{{ 'ADF_VIEWER.ARIA.FIT_PAGE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.FIT_PAGE' | translate }}"
mat-icon-button
(click)="pageFit()">
<button id="viewer-scale-page-button"
role="button" aria-pressed="true"
title="{{ 'ADF_VIEWER.ARIA.FIT_PAGE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.FIT_PAGE' | translate }}"
mat-icon-button
(click)="pageFit()">
<mat-icon>zoom_out_map</mat-icon>
</button>

View File

@@ -77,7 +77,7 @@
max-height: 100px;
max-width: 300px;
.mat-progress-bar {
&-progress-bar {
max-width: 300px;
margin: 0;
position: absolute;
@@ -96,7 +96,7 @@
left: 50%;
transform: translateX(-50%);
.adf-toolbar .mat-toolbar {
.adf-toolbar .adf-toolbar-container {
max-height: 48px;
background-color: var(--adf-theme-background-card-color);
border-width: 0;

View File

@@ -15,19 +15,19 @@
* limitations under the License.
*/
import { LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';
import { Component, SimpleChange, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
import { EventMock } from '../../mock/event.mock';
import { RenderingQueueServices } from '../services/rendering-queue.services';
import { PdfViewerComponent } from './pdf-viewer.component';
import { RIGHT_ARROW, LEFT_ARROW } from '@angular/cdk/keycodes';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { MatDialog } from '@angular/material/dialog';
import { By } from '@angular/platform-browser';
import { of } from 'rxjs';
import { take } from 'rxjs/operators';
import { AppConfigService } from '../../app-config/app-config.service';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { PdfThumbListComponent } from '@alfresco/adf-core';
import { By } from '@angular/platform-browser';
import { AppConfigService } from '../../../app-config';
import { EventMock } from '../../../mock';
import { CoreTestingModule } from '../../../testing';
import { RenderingQueueServices } from '../../services/rendering-queue.services';
import { PdfThumbListComponent } from '../pdf-viewer-thumbnails/pdf-viewer-thumbnails.component';
import { PdfViewerComponent } from './pdf-viewer.component';
declare const pdfjsLib: any;
@@ -38,7 +38,7 @@ declare const pdfjsLib: any;
class TestDialogComponent {}
@Component({
template: ` <adf-pdf-viewer [allowThumbnails]="true" [showToolbar]="true" [urlFile]="urlFile"> </adf-pdf-viewer> `
template: ` <adf-pdf-viewer [allowThumbnails]="true" [showToolbar]="true" [urlFile]="urlFile"></adf-pdf-viewer> `
})
class UrlTestComponent {
@ViewChild(PdfViewerComponent, { static: true })
@@ -52,7 +52,7 @@ class UrlTestComponent {
}
@Component({
template: ` <adf-pdf-viewer [allowThumbnails]="true" [showToolbar]="true" [urlFile]="urlFile"> </adf-pdf-viewer> `
template: ` <adf-pdf-viewer [allowThumbnails]="true" [showToolbar]="true" [urlFile]="urlFile"></adf-pdf-viewer> `
})
class UrlTestPasswordComponent {
@ViewChild(PdfViewerComponent, { static: true })
@@ -66,7 +66,7 @@ class UrlTestPasswordComponent {
}
@Component({
template: ` <adf-pdf-viewer [allowThumbnails]="true" [showToolbar]="true" [blobFile]="blobFile"> </adf-pdf-viewer> `
template: ` <adf-pdf-viewer [allowThumbnails]="true" [showToolbar]="true" [blobFile]="blobFile"></adf-pdf-viewer> `
})
class BlobTestComponent {
@ViewChild(PdfViewerComponent, { static: true })

View File

@@ -19,25 +19,32 @@
/* eslint-disable no-underscore-dangle */
/* eslint-disable @angular-eslint/no-output-native */
import { NgIf, NgStyle, NgTemplateOutlet } from '@angular/common';
import {
Component,
TemplateRef,
EventEmitter,
HostListener,
Output,
Input,
OnChanges,
OnDestroy,
ViewEncapsulation,
EventEmitter,
SimpleChanges
Output,
SimpleChanges,
TemplateRef,
ViewEncapsulation
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { RenderingQueueServices } from '../services/rendering-queue.services';
import { PdfPasswordDialogComponent } from './pdf-viewer-password-dialog';
import { AppConfigService } from '../../app-config/app-config.service';
import { PDFDocumentProxy, OnProgressParameters, PDFDocumentLoadingTask } from 'pdfjs-dist';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { TranslateModule } from '@ngx-translate/core';
import { OnProgressParameters, PDFDocumentLoadingTask, PDFDocumentProxy } from 'pdfjs-dist';
import { Subject } from 'rxjs';
import { catchError, delay } from 'rxjs/operators';
import { AppConfigService } from '../../../app-config';
import { ToolbarComponent, ToolbarDividerComponent } from '../../../toolbar';
import { RenderingQueueServices } from '../../services/rendering-queue.services';
import { PdfPasswordDialogComponent } from '../pdf-viewer-password-dialog/pdf-viewer-password-dialog';
import { PdfThumbListComponent } from '../pdf-viewer-thumbnails/pdf-viewer-thumbnails.component';
declare const pdfjsLib: any;
declare const pdfjsViewer: any;
@@ -46,10 +53,23 @@ export type PdfScaleMode = 'init' | 'page-actual' | 'page-width' | 'page-height'
@Component({
selector: 'adf-pdf-viewer',
standalone: true,
templateUrl: './pdf-viewer.component.html',
styleUrls: ['./pdf-viewer-host.component.scss', './pdf-viewer.component.scss'],
providers: [RenderingQueueServices],
host: { class: 'adf-pdf-viewer' },
imports: [
MatButtonModule,
MatIconModule,
TranslateModule,
PdfThumbListComponent,
NgIf,
NgTemplateOutlet,
MatProgressBarModule,
NgStyle,
ToolbarComponent,
ToolbarDividerComponent
],
encapsulation: ViewEncapsulation.None
})
export class PdfViewerComponent implements OnChanges, OnDestroy {
@@ -116,11 +136,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
private pdfjsWorkerDestroy$ = new Subject<boolean>();
private onDestroy$ = new Subject<boolean>();
constructor(
private dialog: MatDialog,
private renderingQueueServices: RenderingQueueServices,
private appConfigService: AppConfigService
) {
constructor(private dialog: MatDialog, private renderingQueueServices: RenderingQueueServices, private appConfigService: AppConfigService) {
// needed to preserve "this" context
this.onPageChange = this.onPageChange.bind(this);
this.onPagesLoaded = this.onPagesLoaded.bind(this);

View File

@@ -18,7 +18,7 @@
import { SimpleChange } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TxtViewerComponent } from './txt-viewer.component';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { CoreTestingModule } from '../../../testing';
describe('Text View component', () => {
let component: TxtViewerComponent;

View File

@@ -16,11 +16,12 @@
*/
import { HttpClient } from '@angular/common/http';
import { Component, Input, OnChanges, ViewEncapsulation, SimpleChanges } from '@angular/core';
import { AppConfigService } from '../../app-config/app-config.service';
import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { AppConfigService } from '../../../app-config';
@Component({
selector: 'adf-txt-viewer',
standalone: true,
templateUrl: './txt-viewer.component.html',
styleUrls: ['./txt-viewer.component.scss'],
host: { class: 'adf-txt-viewer' },

View File

@@ -16,12 +16,15 @@
*/
import { Component, ViewEncapsulation } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core';
@Component({
selector: 'adf-viewer-unknown-format',
standalone: true,
templateUrl: './unknown-format.component.html',
styleUrls: ['./unknown-format.component.scss'],
imports: [MatIconModule, TranslateModule],
encapsulation: ViewEncapsulation.None
})
export class UnknownFormatComponent {
}
export class UnknownFormatComponent {}

View File

@@ -19,10 +19,10 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/
@Component({
selector: 'adf-viewer-more-actions',
standalone: true,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'adf-viewer-more-actions' },
template: `<ng-content></ng-content>`
})
export class ViewerMoreActionsComponent {
}
export class ViewerMoreActionsComponent {}

View File

@@ -19,10 +19,10 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/
@Component({
selector: 'adf-viewer-open-with',
standalone: true,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'adf-viewer-open-with' },
template: `<ng-content></ng-content>`
})
export class ViewerOpenWithComponent {
}
export class ViewerOpenWithComponent {}

View File

@@ -6,7 +6,7 @@
<div class="adf-viewer-render__loading-screen">
<h2>{{ 'ADF_VIEWER.LOADING' | translate }}</h2>
<div>
<mat-spinner></mat-spinner>
<mat-spinner class="adf-viewer-render__loading-screen__spinner"></mat-spinner>
</div>
</div>
</ng-container>
@@ -20,12 +20,11 @@
<div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container">
<div class="adf-viewer-render-content-container" [ngSwitch]="viewerType">
<ng-container *ngSwitchCase="'external'">
<adf-preview-extension
*ngIf="!!externalViewer"
[id]="externalViewer.component"
[url]="urlFile"
[extension]="externalViewer.fileExtension"
[attr.data-automation-id]="externalViewer.component">
<adf-preview-extension *ngIf="!!externalViewer"
[id]="externalViewer.component"
[url]="urlFile"
[extension]="externalViewer.fileExtension"
[attr.data-automation-id]="externalViewer.component">
</adf-preview-extension>
</ng-container>

View File

@@ -21,8 +21,7 @@
@extend .adf-full-screen;
position: relative;
overflow-y: hidden;
overflow-x: hidden;
overflow: hidden;
z-index: 1;
background-color: var(--theme-background-color);
display: flex;
@@ -56,7 +55,7 @@
flex-direction: column;
height: 85vh;
.mat-spinner {
&__spinner {
margin: 0 auto;
}
}

View File

@@ -15,18 +15,18 @@
* limitations under the License.
*/
import { AppExtensionService, ViewerExtensionRef } from '@alfresco/adf-extensions';
import { Location } from '@angular/common';
import { SpyLocation } from '@angular/common/testing';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RenderingQueueServices } from '../services/rendering-queue.services';
import { ViewerRenderComponent } from './viewer-render.component';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { MatDialog } from '@angular/material/dialog';
import { AppExtensionService, ViewerExtensionRef } from '@alfresco/adf-extensions';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { By } from '@angular/platform-browser';
import { CoreTestingModule } from '../../../testing';
import { RenderingQueueServices } from '../../services/rendering-queue.services';
import { ViewerRenderComponent } from './viewer-render.component';
@Component({
selector: 'adf-double-viewer',

View File

@@ -15,27 +15,47 @@
* limitations under the License.
*/
import {
Component, EventEmitter,
Input, OnChanges, Output, TemplateRef,
ViewEncapsulation, OnInit, OnDestroy, Injector
} from '@angular/core';
import { Subject } from 'rxjs';
import { ViewUtilService } from '../services/view-util.service';
import { AppExtensionService, ViewerExtensionRef } from '@alfresco/adf-extensions';
import { AppExtensionService, ViewerExtensionRef, ExtensionsModule } from '@alfresco/adf-extensions';
import { NgForOf, NgIf, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet } from '@angular/common';
import { Component, EventEmitter, Injector, Input, OnChanges, OnDestroy, OnInit, Output, TemplateRef, ViewEncapsulation } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Track } from '../models/viewer.model';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { TranslateModule } from '@ngx-translate/core';
import { Subject } from 'rxjs';
import { Track } from '../../models/viewer.model';
import { ViewUtilService } from '../../services/view-util.service';
import { ImgViewerComponent } from '../img-viewer/img-viewer.component';
import { MediaPlayerComponent } from '../media-player/media-player.component';
import { PdfViewerComponent } from '../pdf-viewer/pdf-viewer.component';
import { TxtViewerComponent } from '../txt-viewer/txt-viewer.component';
import { UnknownFormatComponent } from '../unknown-format/unknown-format.component';
@Component({
selector: 'adf-viewer-render',
standalone: true,
templateUrl: './viewer-render.component.html',
styleUrls: ['./viewer-render.component.scss'],
host: {class: 'adf-viewer-render'},
host: { class: 'adf-viewer-render' },
encapsulation: ViewEncapsulation.None,
imports: [
TranslateModule,
MatProgressSpinnerModule,
NgSwitch,
NgSwitchCase,
NgIf,
PdfViewerComponent,
ImgViewerComponent,
MediaPlayerComponent,
TxtViewerComponent,
NgTemplateOutlet,
UnknownFormatComponent,
ExtensionsModule,
NgForOf,
NgSwitchDefault
],
providers: [ViewUtilService]
})
export class ViewerRenderComponent implements OnChanges, OnInit, OnDestroy {
/**
* If you want to load an external file that does not come from ACS you
* can use this URL to specify where to load the file from.
@@ -120,13 +140,13 @@ export class ViewerRenderComponent implements OnChanges, OnInit, OnDestroy {
* @returns list of extensions
*/
get externalExtensions(): string[] {
return this.viewerExtensions.map(ext => ext.fileExtension);
return this.viewerExtensions.map((ext) => ext.fileExtension);
}
private _externalViewer: ViewerExtensionRef;
get externalViewer(): ViewerExtensionRef {
if (!this._externalViewer) {
this._externalViewer = this.viewerExtensions.find(ext => ext.fileExtension === '*');
this._externalViewer = this.viewerExtensions.find((ext) => ext.fileExtension === '*');
}
return this._externalViewer;
@@ -136,11 +156,12 @@ export class ViewerRenderComponent implements OnChanges, OnInit, OnDestroy {
private onDestroy$ = new Subject<boolean>();
constructor(private viewUtilService: ViewUtilService,
private extensionService: AppExtensionService,
public dialog: MatDialog,
public readonly injector: Injector) {
}
constructor(
private viewUtilService: ViewUtilService,
private extensionService: AppExtensionService,
public dialog: MatDialog,
public readonly injector: Injector
) {}
ngOnInit() {
this.cacheTypeForContent = 'no-cache';
@@ -201,5 +222,4 @@ export class ViewerRenderComponent implements OnChanges, OnInit, OnDestroy {
onClose() {
this.close.next(true);
}
}

View File

@@ -19,6 +19,7 @@ import { ChangeDetectionStrategy, Component, HostListener, ViewEncapsulation } f
@Component({
selector: 'adf-viewer-sidebar',
standalone: true,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'adf-viewer-sidebar' },

View File

@@ -19,10 +19,10 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/
@Component({
selector: 'adf-viewer-toolbar-actions',
standalone: true,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'adf-viewer-toolbar-actions' },
template: `<ng-content></ng-content>`
})
export class ViewerToolbarActionsComponent {
}
export class ViewerToolbarActionsComponent {}

View File

@@ -15,18 +15,14 @@
* limitations under the License.
*/
import {
ChangeDetectionStrategy,
Component,
ViewEncapsulation
} from '@angular/core';
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'adf-viewer-toolbar-custom-actions',
standalone: true,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'adf-viewer-toolbar-custom-actions' },
template: `<ng-content></ng-content>`
})
export class ViewerToolbarCustomActionsComponent{
}
export class ViewerToolbarCustomActionsComponent {}

View File

@@ -19,10 +19,10 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/
@Component({
selector: 'adf-viewer-toolbar',
standalone: true,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'adf-viewer-toolbar' },
template: `<ng-content></ng-content>`
})
export class ViewerToolbarComponent {
}
export class ViewerToolbarComponent {}

View File

@@ -10,7 +10,6 @@
<ng-container *ngIf="showToolbar && !toolbar">
<adf-toolbar id="adf-viewer-toolbar" class="adf-viewer-toolbar">
<adf-toolbar-title>
<ng-container *ngIf="allowLeftSidebar">
<button mat-icon-button
[attr.aria-expanded]="showLeftSidebar"
@@ -162,17 +161,16 @@
</div>
</ng-container>
<adf-viewer-render
(close)="onClose()"
[mimeType]="mimeType"
[fileName]="fileName"
[blobFile]="blobFile"
[readOnly]="readOnly"
(submitFile)="onSubmitFile($event)"
[urlFile]="urlFile"
(isSaving)="allowNavigate = !$event"
[tracks]="tracks"
[viewerTemplateExtensions]="viewerExtensions ?? viewerTemplateExtensions">
<adf-viewer-render (close)="onClose()"
[mimeType]="mimeType"
[fileName]="fileName"
[blobFile]="blobFile"
[readOnly]="readOnly"
(submitFile)="onSubmitFile($event)"
[urlFile]="urlFile"
(isSaving)="allowNavigate = !$event"
[tracks]="tracks"
[viewerTemplateExtensions]="viewerExtensions ?? viewerTemplateExtensions">
</adf-viewer-render>
</div>

View File

@@ -15,28 +15,26 @@
* limitations under the License.
*/
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { MatDialog } from '@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import {
CoreTestingModule,
EventMock,
ViewerComponent,
ViewUtilService,
AppConfigService,
DownloadPromptDialogComponent,
DownloadPromptActions,
CloseButtonPosition
} from '@alfresco/adf-core';
import { of } from 'rxjs';
import { ViewerWithCustomMoreActionsComponent } from './mock/adf-viewer-container-more-actions.component.mock';
import { ViewerWithCustomToolbarComponent } from './mock/adf-viewer-container-toolbar.component.mock';
import { ViewerWithCustomSidebarComponent } from './mock/adf-viewer-container-sidebar.component.mock';
import { ViewerWithCustomOpenWithComponent } from './mock/adf-viewer-container-open-with.component.mock';
import { ViewerWithCustomToolbarActionsComponent } from './mock/adf-viewer-container-toolbar-actions.component.mock';
import { Component } from '@angular/core';
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { By } from '@angular/platform-browser';
import { of } from 'rxjs';
import { AppConfigService } from '../../app-config';
import { EventMock } from '../../mock';
import { CoreTestingModule } from '../../testing';
import { DownloadPromptActions } from '../models/download-prompt.actions';
import { CloseButtonPosition } from '../models/viewer.model';
import { ViewUtilService } from '../services/view-util.service';
import { DownloadPromptDialogComponent } from './download-prompt-dialog/download-prompt-dialog.component';
import { ViewerWithCustomMoreActionsComponent } from './mock/adf-viewer-container-more-actions.component.mock';
import { ViewerWithCustomOpenWithComponent } from './mock/adf-viewer-container-open-with.component.mock';
import { ViewerWithCustomSidebarComponent } from './mock/adf-viewer-container-sidebar.component.mock';
import { ViewerWithCustomToolbarActionsComponent } from './mock/adf-viewer-container-toolbar-actions.component.mock';
import { ViewerWithCustomToolbarComponent } from './mock/adf-viewer-container-toolbar.component.mock';
import { ViewerComponent } from './viewer.component';
@Component({
selector: 'adf-dialog-dummy',
@@ -54,8 +52,10 @@ describe('ViewerComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CoreTestingModule, MatButtonModule, MatIconModule],
declarations: [
imports: [
CoreTestingModule,
MatButtonModule,
MatIconModule,
ViewerWithCustomToolbarComponent,
ViewerWithCustomSidebarComponent,
ViewerWithCustomOpenWithComponent,

View File

@@ -15,6 +15,9 @@
* limitations under the License.
*/
import { ExtensionsModule } from '@alfresco/adf-extensions';
import { A11yModule } from '@angular/cdk/a11y';
import { NgIf, NgTemplateOutlet } from '@angular/common';
import {
Component,
ContentChild,
@@ -30,34 +33,55 @@ import {
TemplateRef,
ViewEncapsulation
} from '@angular/core';
import { fromEvent, Subject } from 'rxjs';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { ViewerToolbarComponent } from './viewer-toolbar.component';
import { ViewerOpenWithComponent } from './viewer-open-with.component';
import { ViewerMoreActionsComponent } from './viewer-more-actions.component';
import { ViewerSidebarComponent } from './viewer-sidebar.component';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { TranslateModule } from '@ngx-translate/core';
import { fromEvent, Subject } from 'rxjs';
import { filter, first, skipWhile, takeUntil } from 'rxjs/operators';
import { AppConfigService } from '../../app-config';
import { PipeModule } from '../../pipes';
import { ToolbarComponent, ToolbarDividerComponent, ToolbarTitleComponent } from '../../toolbar';
import { DownloadPromptActions } from '../models/download-prompt.actions';
import { CloseButtonPosition, Track } from '../models/viewer.model';
import { ViewUtilService } from '../services/view-util.service';
import { DownloadPromptDialogComponent } from './download-prompt-dialog/download-prompt-dialog.component';
import { AppConfigService } from '../../app-config';
import { DownloadPromptActions } from '../models/download-prompt.actions';
import { ViewerMoreActionsComponent } from './viewer-more-actions.component';
import { ViewerOpenWithComponent } from './viewer-open-with.component';
import { ViewerRenderComponent } from './viewer-render/viewer-render.component';
import { ViewerSidebarComponent } from './viewer-sidebar.component';
import { ViewerToolbarComponent } from './viewer-toolbar.component';
export interface ViewerComponentConfig {
enableDownloadPrompt?: boolean;
enableDownloadPromptReminder?: boolean;
downloadPromptDelay?: number;
downloadPromptReminderDelay?: number;
enableFileAutoDownload?: boolean;
fileAutoDownloadSizeThresholdInMB?: number;
}
const DEFAULT_NON_PREVIEW_CONFIG = {
enableDownloadPrompt: false,
enableDownloadPromptReminder: false,
downloadPromptDelay: 50,
downloadPromptReminderDelay: 30
};
@Component({
selector: 'adf-viewer',
standalone: true,
templateUrl: './viewer.component.html',
styleUrls: ['./viewer.component.scss'],
host: { class: 'adf-viewer' },
encapsulation: ViewEncapsulation.None,
imports: [
NgIf,
A11yModule,
ToolbarComponent,
ToolbarTitleComponent,
MatButtonModule,
TranslateModule,
MatIconModule,
PipeModule,
MatMenuModule,
ToolbarDividerComponent,
ViewerRenderComponent,
NgTemplateOutlet,
ExtensionsModule
],
providers: [ViewUtilService]
})
export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
@@ -202,26 +226,22 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
/**
* Enable dialog box to allow user to download the previewed file, in case the preview is not responding for a set period of time.
*/
@Input()
enableDownloadPrompt = false;
enableDownloadPrompt: boolean = false;
/**
* Enable reminder dialogs to prompt user to download the file, in case the preview is not responding for a set period of time.
*/
@Input()
enableDownloadPromptReminder = false;
enableDownloadPromptReminder: boolean = false;
/**
* Initial time in seconds to wait before giving the first prompt to user to download the file
*/
@Input()
downloadPromptDelay = 50;
downloadPromptDelay: number = 50;
/**
* Time in seconds to wait before giving the second and consequent reminders to the user to download the file.
*/
@Input()
downloadPromptReminderDelay = 15;
downloadPromptReminderDelay: number = 15;
/**
* Emitted when user clicks on download button on download prompt dialog.
@@ -396,20 +416,12 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
}
private configureDownloadPromptProperties() {
const config = this.appConfigService.get<ViewerComponentConfig>('viewer');
const nonResponsivePreviewConfig = this.appConfigService.get('viewer', DEFAULT_NON_PREVIEW_CONFIG);
if (config) {
this.enableDownloadPrompt = config.enableDownloadPrompt === true;
this.enableDownloadPromptReminder = config.enableDownloadPromptReminder === true;
if (config.downloadPromptDelay !== undefined) {
this.downloadPromptDelay = config.downloadPromptDelay;
}
if (config.downloadPromptReminderDelay !== undefined) {
this.downloadPromptReminderDelay = config.downloadPromptReminderDelay;
}
}
this.enableDownloadPrompt = nonResponsivePreviewConfig.enableDownloadPrompt;
this.enableDownloadPromptReminder = nonResponsivePreviewConfig.enableDownloadPromptReminder;
this.downloadPromptDelay = nonResponsivePreviewConfig.downloadPromptDelay;
this.downloadPromptReminderDelay = nonResponsivePreviewConfig.downloadPromptReminderDelay;
}
private initDownloadPrompt() {

View File

@@ -19,9 +19,9 @@ import { Location } from '@angular/common';
import { SpyLocation } from '@angular/common/testing';
import { ChangeDetectorRef, ElementRef } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { ViewerRenderComponent } from '../components/viewer-render.component';
import { ViewerRenderComponent } from '../components/viewer-render/viewer-render.component';
import { ViewerExtensionDirective } from './viewer-extension.directive';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { CoreTestingModule } from '../../testing';
describe('ExtensionViewerDirective', () => {
let extensionViewerDirective: ViewerExtensionDirective;
@@ -41,7 +41,12 @@ describe('ExtensionViewerDirective', () => {
ViewerExtensionDirective,
{ provide: ElementRef, useClass: MockElementRef },
ViewerRenderComponent,
{ provide: ChangeDetectorRef, useValue: { detectChanges: () => {} } }
{
provide: ChangeDetectorRef,
useValue: {
detectChanges: () => {}
}
}
]
});
extensionViewerDirective = TestBed.inject(ViewerExtensionDirective);

View File

@@ -16,15 +16,15 @@
*/
import { AfterContentInit, ContentChild, Directive, Input, TemplateRef, OnDestroy } from '@angular/core';
import { ViewerRenderComponent } from '../components/viewer-render.component';
import { ViewerRenderComponent } from '../components/viewer-render/viewer-render.component';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Directive({
selector: 'adf-viewer-extension'
selector: 'adf-viewer-extension',
standalone: true
})
export class ViewerExtensionDirective implements AfterContentInit, OnDestroy {
@ContentChild(TemplateRef)
template: any;
@@ -41,19 +41,16 @@ export class ViewerExtensionDirective implements AfterContentInit, OnDestroy {
private onDestroy$ = new Subject<boolean>();
constructor(private viewerComponent: ViewerRenderComponent) {
}
constructor(private viewerComponent: ViewerRenderComponent) {}
ngAfterContentInit() {
this.templateModel = { template: this.template, isVisible: false };
this.viewerComponent.extensionsSupportedByTemplates.push(...this.supportedExtensions);
this.viewerComponent.extensionTemplates.push(this.templateModel);
this.viewerComponent.extensionChange
.pipe(takeUntil(this.onDestroy$))
.subscribe(fileExtension => {
this.templateModel.isVisible = this.isVisible(fileExtension);
});
this.viewerComponent.extensionChange.pipe(takeUntil(this.onDestroy$)).subscribe((fileExtension) => {
this.templateModel.isVisible = this.isVisible(fileExtension);
});
}
ngOnDestroy() {
@@ -70,11 +67,10 @@ export class ViewerExtensionDirective implements AfterContentInit, OnDestroy {
isVisible(fileExtension: string): boolean {
let supportedExtension: string;
if (this.supportedExtensions && (this.supportedExtensions instanceof Array)) {
if (this.supportedExtensions && this.supportedExtensions instanceof Array) {
supportedExtension = this.supportedExtensions.find((extension) => extension.toLowerCase() === fileExtension);
}
return !!supportedExtension;
}
}

View File

@@ -16,14 +16,14 @@
*/
export * from './services/view-util.service';
export * from './components/img-viewer.component';
export * from './components/media-player.component';
export * from './components/pdf-viewer-password-dialog';
export * from './components/pdf-viewer.component';
export * from './components/pdf-viewer-thumbnails.component';
export * from './components/pdf-viewer-thumb.component';
export * from './components/pdf-viewer-thumbnails.component';
export * from './components/txt-viewer.component';
export * from './components/img-viewer/img-viewer.component';
export * from './components/media-player/media-player.component';
export * from './components/pdf-viewer-password-dialog/pdf-viewer-password-dialog';
export * from './components/pdf-viewer/pdf-viewer.component';
export * from './components/pdf-viewer-thumbnails/pdf-viewer-thumbnails.component';
export * from './components/pdf-viewer-thumb/pdf-viewer-thumb.component';
export * from './components/pdf-viewer-thumbnails/pdf-viewer-thumbnails.component';
export * from './components/txt-viewer/txt-viewer.component';
export * from './components/unknown-format/unknown-format.component';
export * from './components/viewer-more-actions.component';
export * from './components/viewer-open-with.component';
@@ -31,7 +31,7 @@ export * from './components/viewer-sidebar.component';
export * from './components/viewer-toolbar.component';
export * from './components/viewer-toolbar-actions.component';
export * from './components/viewer-toolbar-custom-actions.component';
export * from './components/viewer-render.component';
export * from './components/viewer-render/viewer-render.component';
export * from './components/viewer.component';
export * from './components/download-prompt-dialog/download-prompt-dialog.component';

View File

@@ -15,51 +15,28 @@
* limitations under the License.
*/
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ExtensionsModule } from '@alfresco/adf-extensions';
import { MaterialModule } from '../material.module';
import { ToolbarModule } from '../toolbar/toolbar.module';
import { PipeModule } from '../pipes/pipe.module';
import { ImgViewerComponent } from './components/img-viewer.component';
import { MediaPlayerComponent } from './components/media-player.component';
import { PdfViewerComponent } from './components/pdf-viewer.component';
import { PdfPasswordDialogComponent } from './components/pdf-viewer-password-dialog';
import { PdfThumbComponent } from './components/pdf-viewer-thumb.component';
import { PdfThumbListComponent } from './components/pdf-viewer-thumbnails.component';
import { TxtViewerComponent } from './components/txt-viewer.component';
import { DownloadPromptDialogComponent } from './components/download-prompt-dialog/download-prompt-dialog.component';
import { ImgViewerComponent } from './components/img-viewer/img-viewer.component';
import { MediaPlayerComponent } from './components/media-player/media-player.component';
import { PdfPasswordDialogComponent } from './components/pdf-viewer-password-dialog/pdf-viewer-password-dialog';
import { PdfThumbComponent } from './components/pdf-viewer-thumb/pdf-viewer-thumb.component';
import { PdfThumbListComponent } from './components/pdf-viewer-thumbnails/pdf-viewer-thumbnails.component';
import { PdfViewerComponent } from './components/pdf-viewer/pdf-viewer.component';
import { TxtViewerComponent } from './components/txt-viewer/txt-viewer.component';
import { UnknownFormatComponent } from './components/unknown-format/unknown-format.component';
import { ViewerMoreActionsComponent } from './components/viewer-more-actions.component';
import { ViewerOpenWithComponent } from './components/viewer-open-with.component';
import { ViewerRenderComponent } from './components/viewer-render/viewer-render.component';
import { ViewerSidebarComponent } from './components/viewer-sidebar.component';
import { ViewerToolbarComponent } from './components/viewer-toolbar.component';
import { ViewerRenderComponent } from './components/viewer-render.component';
import { ViewerExtensionDirective } from './directives/viewer-extension.directive';
import { ViewerToolbarActionsComponent } from './components/viewer-toolbar-actions.component';
import { DirectiveModule } from '../directives/directive.module';
import { A11yModule } from '@angular/cdk/a11y';
import { ViewerComponent } from './components/viewer.component';
import { ViewerToolbarCustomActionsComponent } from './components/viewer-toolbar-custom-actions.component';
import { DownloadPromptDialogComponent } from './components/download-prompt-dialog/download-prompt-dialog.component';
import { ViewerToolbarComponent } from './components/viewer-toolbar.component';
import { ViewerComponent } from './components/viewer.component';
import { ViewerExtensionDirective } from './directives/viewer-extension.directive';
@NgModule({
imports: [
CommonModule,
MaterialModule,
TranslateModule,
FormsModule,
ReactiveFormsModule,
ToolbarModule,
PipeModule,
DirectiveModule,
A11yModule,
ExtensionsModule
],
declarations: [
PdfPasswordDialogComponent,
ViewerRenderComponent,
ImgViewerComponent,
@@ -99,5 +76,4 @@ import { DownloadPromptDialogComponent } from './components/download-prompt-dial
ViewerToolbarCustomActionsComponent
]
})
export class ViewerModule {
}
export class ViewerModule {}