mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-09-17 14:21:29 +00:00
AAE-34298 Move viewer to separate entry point
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
<div *ngIf="isLoading$ | async" class="adf-viewer-render-main-loader">
|
||||
<div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container">
|
||||
<div class="adf-viewer-render-content-container">
|
||||
<div class="adf-viewer-render__loading-screen">
|
||||
<h2>{{ 'ADF_VIEWER.LOADING' | translate }}</h2>
|
||||
<div>
|
||||
<mat-spinner class="adf-viewer-render__loading-screen__spinner" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="urlFile || blobFile">
|
||||
<div [hidden]="isLoading$ | async" class="adf-viewer-render-main">
|
||||
<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"
|
||||
[nodeId]="nodeId"
|
||||
[attr.data-automation-id]="externalViewer.component"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'pdf'">
|
||||
<adf-pdf-viewer
|
||||
[thumbnailsTemplate]="thumbnailsTemplate"
|
||||
[allowThumbnails]="allowThumbnails"
|
||||
[blobFile]="blobFile"
|
||||
[urlFile]="urlFile"
|
||||
[fileName]="internalFileName"
|
||||
[cacheType]="cacheTypeForContent"
|
||||
(pagesLoaded)="markAsLoaded()"
|
||||
(close)="onClose()"
|
||||
(error)="onUnsupportedFile()"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'image'">
|
||||
<adf-img-viewer
|
||||
[urlFile]="urlFile"
|
||||
[readOnly]="readOnly"
|
||||
[fileName]="internalFileName"
|
||||
[allowedEditActions]="allowedEditActions"
|
||||
[blobFile]="blobFile"
|
||||
(error)="onUnsupportedFile()"
|
||||
(submit)="onSubmitFile($event)"
|
||||
(imageLoaded)="markAsLoaded()"
|
||||
(isSaving)="isSaving.emit($event)"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'media'">
|
||||
<adf-media-player
|
||||
id="adf-mdedia-player"
|
||||
[urlFile]="urlFile"
|
||||
[tracks]="tracks"
|
||||
[mimeType]="mimeType"
|
||||
[blobFile]="blobFile"
|
||||
[fileName]="internalFileName"
|
||||
(error)="onUnsupportedFile()"
|
||||
(canPlay)="markAsLoaded()"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'text'">
|
||||
<adf-txt-viewer [urlFile]="urlFile" [blobFile]="blobFile" />
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'custom'">
|
||||
<ng-container *ngFor="let ext of viewerExtensions">
|
||||
<adf-preview-extension
|
||||
*ngIf="checkExtensions(ext.fileExtension)"
|
||||
[id]="ext.component"
|
||||
[url]="urlFile"
|
||||
[extension]="extension"
|
||||
[nodeId]="nodeId"
|
||||
[attr.data-automation-id]="ext.component"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let extensionTemplate of extensionTemplates">
|
||||
<span *ngIf="extensionTemplate.isVisible" class="adf-viewer-render-custom-content">
|
||||
<ng-template
|
||||
[ngTemplateOutlet]="extensionTemplate.template"
|
||||
[ngTemplateOutletContext]="{ urlFile: urlFile, extension: extension }"
|
||||
/>
|
||||
</span>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchDefault>
|
||||
<adf-viewer-unknown-format [customError]="customError" />
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="viewerTemplateExtensions">
|
||||
<ng-template [ngTemplateOutlet]="viewerTemplateExtensions" [ngTemplateOutletInjector]="injector" />
|
||||
</ng-container>
|
@@ -0,0 +1,88 @@
|
||||
/* stylelint-disable scss/at-extend-no-missing-placeholder */
|
||||
|
||||
.adf-full-screen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--adf-theme-background-card-color);
|
||||
}
|
||||
|
||||
.adf-viewer-render-main-loader {
|
||||
position: fixed;
|
||||
top: 64px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.adf-viewer-render {
|
||||
&-main {
|
||||
width: 0;
|
||||
order: 1;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&-content-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&-layout-content {
|
||||
@extend .adf-full-screen;
|
||||
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
background-color: var(--theme-background-color);
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
flex: 1;
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
margin: 0 auto;
|
||||
align-items: stretch;
|
||||
height: 93vh;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&-overlay-container {
|
||||
.adf-viewer-render-content {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
|
||||
&__loading-screen {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
height: 85vh;
|
||||
|
||||
&__spinner {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&-custom-content {
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
&-unknown-content {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&-pdf {
|
||||
display: contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,540 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AppExtensionService, ViewerExtensionRef } from '@alfresco/adf-extensions';
|
||||
import { Location } from '@angular/common';
|
||||
import { SpyLocation } from '@angular/common/testing';
|
||||
import { Component, DebugElement, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { ComponentFixture, DeferBlockBehavior, TestBed } from '@angular/core/testing';
|
||||
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '../../../testing';
|
||||
import { RenderingQueueServices } from '../../services/rendering-queue.services';
|
||||
import { ViewerRenderComponent } from './viewer-render.component';
|
||||
import { ImgViewerComponent, MediaPlayerComponent, PdfViewerComponent, ViewerExtensionDirective } from '@alfresco/adf-core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-double-viewer',
|
||||
standalone: true,
|
||||
imports: [ViewerExtensionDirective, ViewerRenderComponent],
|
||||
template: `
|
||||
<adf-viewer-render [urlFile]="urlFileViewer1" [viewerTemplateExtensions]="viewerTemplateExtensions" #viewer1 />
|
||||
<adf-viewer-render [urlFile]="urlFileViewer2" #viewer2 />
|
||||
<ng-template #viewerExtension>
|
||||
<adf-viewer-extension [supportedExtensions]="['json']">
|
||||
<ng-template>
|
||||
<h1>JSON Viewer</h1>
|
||||
</ng-template>
|
||||
</adf-viewer-extension>
|
||||
<adf-viewer-extension [supportedExtensions]="['test']">
|
||||
<ng-template>
|
||||
<h1>Test Viewer</h1>
|
||||
</ng-template>
|
||||
</adf-viewer-extension>
|
||||
</ng-template>
|
||||
`
|
||||
})
|
||||
class DoubleViewerComponent {
|
||||
@ViewChild('viewer1')
|
||||
viewer1: ViewerRenderComponent;
|
||||
|
||||
@ViewChild('viewer2')
|
||||
viewer2: ViewerRenderComponent;
|
||||
|
||||
@ViewChild('viewerExtension', { static: true })
|
||||
viewerTemplateExtensions: TemplateRef<any>;
|
||||
|
||||
urlFileViewer1: string;
|
||||
urlFileViewer2: string;
|
||||
}
|
||||
|
||||
describe('ViewerComponent', () => {
|
||||
let component: ViewerRenderComponent;
|
||||
let fixture: ComponentFixture<ViewerRenderComponent>;
|
||||
let extensionService: AppExtensionService;
|
||||
let testingUtils: UnitTestingUtils;
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [NoopTranslateModule, NoopAnimationsModule, MatDialogModule, ViewerRenderComponent, DoubleViewerComponent],
|
||||
providers: [RenderingQueueServices, { provide: Location, useClass: SpyLocation }, MatDialog],
|
||||
deferBlockBehavior: DeferBlockBehavior.Playthrough
|
||||
});
|
||||
fixture = TestBed.createComponent(ViewerRenderComponent);
|
||||
testingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
extensionService = TestBed.inject(AppExtensionService);
|
||||
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
describe('Double viewer Test', () => {
|
||||
it('should not reload the content of all the viewer after type change', async () => {
|
||||
const fixtureDouble = TestBed.createComponent(DoubleViewerComponent);
|
||||
|
||||
fixtureDouble.componentInstance.urlFileViewer1 = 'fake-test-file.pdf';
|
||||
fixtureDouble.componentInstance.urlFileViewer2 = 'fake-test-file-two.xls';
|
||||
|
||||
fixtureDouble.detectChanges();
|
||||
await fixtureDouble.whenStable();
|
||||
|
||||
fixtureDouble.componentInstance.viewer1.ngOnChanges();
|
||||
fixtureDouble.componentInstance.viewer2.ngOnChanges();
|
||||
|
||||
fixtureDouble.detectChanges();
|
||||
await fixtureDouble.whenStable();
|
||||
|
||||
expect(fixtureDouble.componentInstance.viewer1.viewerType).toBe('pdf');
|
||||
expect(fixtureDouble.componentInstance.viewer2.viewerType).toBe('unknown');
|
||||
|
||||
fixtureDouble.componentInstance.urlFileViewer1 = 'fake-test-file.pdf';
|
||||
fixtureDouble.componentInstance.urlFileViewer2 = 'fake-test-file-two.png';
|
||||
|
||||
fixtureDouble.detectChanges();
|
||||
await fixtureDouble.whenStable();
|
||||
|
||||
fixtureDouble.componentInstance.viewer1.ngOnChanges();
|
||||
fixtureDouble.componentInstance.viewer2.ngOnChanges();
|
||||
|
||||
expect(fixtureDouble.componentInstance.viewer1.viewerType).toBe('pdf');
|
||||
expect(fixtureDouble.componentInstance.viewer2.viewerType).toBe('image');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Extension Type Test', () => {
|
||||
it('should display pdf external viewer via wildcard notation', async () => {
|
||||
const extension: ViewerExtensionRef = {
|
||||
component: 'custom.component',
|
||||
id: 'custom.component.id',
|
||||
fileExtension: '*'
|
||||
};
|
||||
spyOn(extensionService, 'getViewerExtensions').and.returnValue([extension]);
|
||||
|
||||
fixture = TestBed.createComponent(ViewerRenderComponent);
|
||||
testingUtils.setDebugElement(fixture.debugElement);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
component.urlFile = 'fake-test-file.pdf';
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(component.externalExtensions.includes('*')).toBe(true);
|
||||
expect(component.externalViewer).toBe(extension);
|
||||
expect(component.viewerType).toBe('external');
|
||||
expect(testingUtils.getByDataAutomationId('custom.component')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should display pdf with the first external viewer provided', async () => {
|
||||
const extensions: ViewerExtensionRef[] = [
|
||||
{
|
||||
component: 'custom.component.1',
|
||||
id: 'custom.component.id',
|
||||
fileExtension: '*'
|
||||
},
|
||||
{
|
||||
component: 'custom.component.2',
|
||||
id: 'custom.component.id',
|
||||
fileExtension: '*'
|
||||
}
|
||||
];
|
||||
spyOn(extensionService, 'getViewerExtensions').and.returnValue(extensions);
|
||||
|
||||
fixture = TestBed.createComponent(ViewerRenderComponent);
|
||||
testingUtils.setDebugElement(fixture.debugElement);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
component.urlFile = 'fake-test-file.pdf';
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(testingUtils.getByDataAutomationId('custom.component.1')).not.toBeNull();
|
||||
expect(testingUtils.getByDataAutomationId('custom.component.2')).toBeNull();
|
||||
});
|
||||
|
||||
it('should display url with the external viewer provided', async () => {
|
||||
const extension: ViewerExtensionRef = {
|
||||
component: 'custom.component',
|
||||
id: 'custom.component.id',
|
||||
fileExtension: '*'
|
||||
};
|
||||
spyOn(extensionService, 'getViewerExtensions').and.returnValue([extension]);
|
||||
|
||||
fixture = TestBed.createComponent(ViewerRenderComponent);
|
||||
testingUtils.setDebugElement(fixture.debugElement);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
component.urlFile = 'http://localhost:4200/alfresco';
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(component.externalExtensions.includes('*')).toBe(true);
|
||||
expect(component.externalViewer).toBe(extension);
|
||||
expect(component.viewerType).toBe('external');
|
||||
expect(testingUtils.getByDataAutomationId('custom.component')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should extension file pdf be loaded', (done) => {
|
||||
component.urlFile = 'fake-test-file.pdf';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('adf-pdf-viewer')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should extension file png be loaded', (done) => {
|
||||
component.urlFile = 'fake-url-file.png';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('#viewer-image')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should extension file mp4 be loaded', (done) => {
|
||||
component.urlFile = 'fake-url-file.mp4';
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('adf-media-player')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should extension file txt be loaded', (done) => {
|
||||
component.urlFile = 'fake-test-file.txt';
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('adf-txt-viewer')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display [unknown format] for unsupported extensions', (done) => {
|
||||
component.urlFile = 'fake-url-file.unsupported';
|
||||
component.mimeType = '';
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('adf-viewer-unknown-format')).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Custom viewer extension template', () => {
|
||||
const getCustomViewerContent = (customFixture: ComponentFixture<DoubleViewerComponent>): HTMLHeadingElement => {
|
||||
testingUtils.setDebugElement(customFixture.debugElement);
|
||||
return testingUtils.getByCSS('.adf-viewer-render-custom-content h1').nativeElement;
|
||||
};
|
||||
|
||||
it('should render provided custom template when file type matches supported extensions', async () => {
|
||||
const fixtureCustom = TestBed.createComponent(DoubleViewerComponent);
|
||||
fixtureCustom.detectChanges();
|
||||
await fixtureCustom.whenStable();
|
||||
|
||||
const customComponent = fixtureCustom.componentInstance.viewer1;
|
||||
fixtureCustom.componentInstance.urlFileViewer1 = 'fake-url-file.json';
|
||||
customComponent.ngOnChanges();
|
||||
|
||||
fixtureCustom.detectChanges();
|
||||
await fixtureCustom.whenStable();
|
||||
|
||||
let customContent = getCustomViewerContent(fixtureCustom);
|
||||
expect(customComponent.extensionsSupportedByTemplates).toEqual(['json', 'test']);
|
||||
expect(customComponent.extensionTemplates.length).toBe(2);
|
||||
expect(customComponent.extensionTemplates[0].isVisible).toBeTrue();
|
||||
expect(customComponent.extensionTemplates[1].isVisible).toBeFalse();
|
||||
expect(customContent.innerText).toBe('JSON Viewer');
|
||||
|
||||
fixtureCustom.componentInstance.urlFileViewer1 = 'fake-url-file.test';
|
||||
customComponent.ngOnChanges();
|
||||
|
||||
fixtureCustom.detectChanges();
|
||||
await fixtureCustom.whenStable();
|
||||
|
||||
customContent = getCustomViewerContent(fixtureCustom);
|
||||
expect(customComponent.extensionTemplates[0].isVisible).toBeFalse();
|
||||
expect(customComponent.extensionTemplates[1].isVisible).toBeTrue();
|
||||
expect(customContent.innerText).toBe('Test Viewer');
|
||||
});
|
||||
});
|
||||
|
||||
describe('MimeType handling', () => {
|
||||
it('should display an image file identified by mimetype when the filename has no extension', (done) => {
|
||||
component.urlFile = 'fake-content-img';
|
||||
component.mimeType = 'image/png';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('#viewer-image')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display a image file identified by mimetype when the file extension is wrong', (done) => {
|
||||
component.urlFile = 'fake-content-img.bin';
|
||||
component.mimeType = 'image/png';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('#viewer-image')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display the txt viewer if the file identified by mimetype is a txt when the filename has wrong extension', (done) => {
|
||||
component.urlFile = 'fake-content-txt.bin';
|
||||
component.mimeType = 'text/plain';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('adf-txt-viewer')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display the media player if the file identified by mimetype is a media when the filename has wrong extension', (done) => {
|
||||
component.urlFile = 'fake-content-video.bin';
|
||||
component.mimeType = 'video/mp4';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('adf-media-player')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
}, 25000);
|
||||
|
||||
it('should display the media player if the file identified by mimetype is a media when the filename has no extension', (done) => {
|
||||
component.urlFile = 'fake-content-video';
|
||||
component.mimeType = 'video/mp4';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('adf-media-player')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
}, 25000);
|
||||
|
||||
it('should display a PDF file identified by mimetype when the filename has no extension', (done) => {
|
||||
component.urlFile = 'fake-content-pdf';
|
||||
component.mimeType = 'application/pdf';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.getDeferBlocks().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('adf-pdf-viewer')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
}, 25000);
|
||||
|
||||
it('should display a PDF file identified by mimetype when the file extension is wrong', (done) => {
|
||||
component.urlFile = 'fake-content-pdf.bin';
|
||||
component.mimeType = 'application/pdf';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('adf-pdf-viewer')).not.toBeNull();
|
||||
done();
|
||||
});
|
||||
}, 25000);
|
||||
});
|
||||
|
||||
describe('Base component', () => {
|
||||
beforeEach(() => {
|
||||
component.urlFile = 'fake-test-file.pdf';
|
||||
component.mimeType = 'application/pdf';
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should emit new value when isSaving emits new event', () => {
|
||||
spyOn(component.isSaving, 'emit');
|
||||
component.urlFile = 'fake-url-file.png';
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
const imgViewer = testingUtils.getByCSS('adf-img-viewer');
|
||||
imgViewer.triggerEventHandler('isSaving', true);
|
||||
|
||||
expect(component.isSaving.emit).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
describe('Attribute', () => {
|
||||
it('should urlFile present not thrown any error ', () => {
|
||||
expect(() => {
|
||||
component.ngOnChanges();
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
it('should switch to the unknown template if the type specific viewers throw an error', (done) => {
|
||||
component.urlFile = 'fake-url-file.icns';
|
||||
component.mimeType = 'image/png';
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
component.onUnsupportedFile();
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(testingUtils.getByCSS('adf-viewer-unknown-format')).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Events', () => {
|
||||
it('should if the extension change extension Change event be fired ', (done) => {
|
||||
component.extensionChange.subscribe((fileExtension) => {
|
||||
expect(fileExtension).toEqual('png');
|
||||
done();
|
||||
});
|
||||
|
||||
component.urlFile = 'fake-url-file.png';
|
||||
|
||||
component.ngOnChanges();
|
||||
});
|
||||
});
|
||||
|
||||
describe('display name property override by urlFile', () => {
|
||||
it('should fileName override the default name if is present and urlFile is set', () => {
|
||||
component.urlFile = 'fake-test-file.pdf';
|
||||
component.fileName = 'test name';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
expect(component.internalFileName).toEqual('test name');
|
||||
});
|
||||
|
||||
it('should use the urlFile name if fileName is NOT set and urlFile is set', () => {
|
||||
component.urlFile = 'fake-test-file.pdf';
|
||||
component.fileName = '';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
expect(component.internalFileName).toEqual('fake-test-file.pdf');
|
||||
});
|
||||
});
|
||||
|
||||
describe('display name property override by blobFile', () => {
|
||||
it('should fileName override the name if is present and blobFile is set', () => {
|
||||
component.fileName = 'blob file display name';
|
||||
component.blobFile = new Blob(['This is my blob content'], { type: 'text/plain' });
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
|
||||
expect(component.internalFileName).toEqual('blob file display name');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Spinner', () => {
|
||||
const getMainLoader = (): DebugElement => testingUtils.getByCSS('.adf-viewer-render-main-loader');
|
||||
|
||||
it('should not show spinner by default', (done) => {
|
||||
component.isLoading$.subscribe((isLoading) => {
|
||||
fixture.detectChanges();
|
||||
expect(isLoading).toBeFalse();
|
||||
expect(getMainLoader()).toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display spinner when viewerType is media', () => {
|
||||
component.urlFile = 'some-file.mp4';
|
||||
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getMainLoader()).not.toBeNull();
|
||||
|
||||
const mediaViewer = testingUtils.getByDirective(MediaPlayerComponent);
|
||||
mediaViewer.triggerEventHandler('canPlay', null);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getMainLoader()).toBeNull();
|
||||
expect(component.viewerType).toBe('media');
|
||||
});
|
||||
|
||||
it('should display spinner when viewerType is pdf', () => {
|
||||
component.urlFile = 'some-url.pdf';
|
||||
expect(getMainLoader()).toBeNull();
|
||||
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
const imgViewer = testingUtils.getByDirective(PdfViewerComponent);
|
||||
imgViewer.triggerEventHandler('pagesLoaded', null);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.viewerType).toBe('pdf');
|
||||
});
|
||||
|
||||
it('should display spinner when viewerType is image', () => {
|
||||
component.urlFile = 'some-url.png';
|
||||
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
expect(getMainLoader()).not.toBeNull();
|
||||
|
||||
const imgViewer = testingUtils.getByDirective(ImgViewerComponent);
|
||||
imgViewer.triggerEventHandler('imageLoaded', null);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getMainLoader()).toBeNull();
|
||||
expect(component.viewerType).toBe('image');
|
||||
});
|
||||
});
|
||||
});
|
@@ -0,0 +1,250 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AppExtensionService, ExtensionsModule, ViewerExtensionRef } from '@alfresco/adf-extensions';
|
||||
import { AsyncPipe, NgForOf, NgIf, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet } from '@angular/common';
|
||||
import { Component, EventEmitter, Injector, Input, OnChanges, OnInit, Output, TemplateRef, ViewEncapsulation } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
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';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
type ViewerType = 'media' | 'image' | 'pdf' | 'external' | 'text' | 'custom' | 'unknown';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-viewer-render',
|
||||
standalone: true,
|
||||
templateUrl: './viewer-render.component.html',
|
||||
styleUrls: ['./viewer-render.component.scss'],
|
||||
host: { class: 'adf-viewer-render' },
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
imports: [
|
||||
TranslateModule,
|
||||
MatProgressSpinnerModule,
|
||||
NgSwitch,
|
||||
NgSwitchCase,
|
||||
NgIf,
|
||||
PdfViewerComponent,
|
||||
ImgViewerComponent,
|
||||
MediaPlayerComponent,
|
||||
TxtViewerComponent,
|
||||
NgTemplateOutlet,
|
||||
UnknownFormatComponent,
|
||||
ExtensionsModule,
|
||||
NgForOf,
|
||||
NgSwitchDefault,
|
||||
AsyncPipe
|
||||
],
|
||||
providers: [ViewUtilService]
|
||||
})
|
||||
export class ViewerRenderComponent implements OnChanges, OnInit {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Input()
|
||||
urlFile = '';
|
||||
|
||||
/** Loads a Blob File */
|
||||
@Input()
|
||||
blobFile: Blob;
|
||||
|
||||
/** Toggles the 'Full Screen' feature. */
|
||||
@Input()
|
||||
allowFullScreen = true;
|
||||
|
||||
/** Toggles PDF thumbnails. */
|
||||
@Input()
|
||||
allowThumbnails = true;
|
||||
|
||||
/** The template for the pdf thumbnails. */
|
||||
@Input()
|
||||
thumbnailsTemplate: TemplateRef<any> = null;
|
||||
|
||||
/** MIME type of the file content (when not determined by the filename extension). */
|
||||
@Input()
|
||||
mimeType: string;
|
||||
|
||||
/** Override Content filename. */
|
||||
@Input()
|
||||
fileName: string;
|
||||
|
||||
/** Enable when where is possible the editing functionalities */
|
||||
@Input()
|
||||
readOnly = true;
|
||||
|
||||
/**
|
||||
* Controls which actions are enabled in the viewer.
|
||||
* Example:
|
||||
* { rotate: true, crop: false } will enable rotation but disable cropping.
|
||||
*/
|
||||
@Input()
|
||||
allowedEditActions: { [key: string]: boolean } = {
|
||||
rotate: true,
|
||||
crop: true
|
||||
};
|
||||
|
||||
/** media subtitles for the media player*/
|
||||
@Input()
|
||||
tracks: Track[] = [];
|
||||
|
||||
/** Identifier of a node that is opened by the viewer. */
|
||||
@Input()
|
||||
nodeId: string = null;
|
||||
|
||||
/** Template containing ViewerExtensionDirective instances providing different viewer extensions based on supported file extension. */
|
||||
@Input()
|
||||
viewerTemplateExtensions: TemplateRef<any>;
|
||||
|
||||
/** Custom error message to be displayed in the viewer. */
|
||||
@Input()
|
||||
customError: string = undefined;
|
||||
|
||||
/** Emitted when the filename extension changes. */
|
||||
@Output()
|
||||
extensionChange = new EventEmitter<string>();
|
||||
|
||||
/** Emitted when the img is submitted in the img viewer. */
|
||||
@Output()
|
||||
submitFile = new EventEmitter<Blob>();
|
||||
|
||||
/** Emitted when the img is submitted in the img viewer. */
|
||||
@Output()
|
||||
close = new EventEmitter<boolean>();
|
||||
|
||||
/** Emitted when the img is saving. */
|
||||
@Output()
|
||||
isSaving = new EventEmitter<boolean>();
|
||||
|
||||
extensionTemplates: { template: TemplateRef<any>; isVisible: boolean }[] = [];
|
||||
extensionsSupportedByTemplates: string[] = [];
|
||||
extension: string;
|
||||
internalFileName: string;
|
||||
viewerType: ViewerType = 'unknown';
|
||||
readonly isLoading$ = new BehaviorSubject(false);
|
||||
|
||||
/**
|
||||
* Returns a list of the active Viewer content extensions.
|
||||
*
|
||||
* @returns list of extension references
|
||||
*/
|
||||
get viewerExtensions(): ViewerExtensionRef[] {
|
||||
return this.extensionService.getViewerExtensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of file extensions supported by external plugins.
|
||||
*
|
||||
* @returns list of extensions
|
||||
*/
|
||||
get externalExtensions(): string[] {
|
||||
return this.viewerExtensions.map((ext) => ext.fileExtension);
|
||||
}
|
||||
|
||||
private _externalViewer: ViewerExtensionRef;
|
||||
get externalViewer(): ViewerExtensionRef {
|
||||
if (!this._externalViewer) {
|
||||
this._externalViewer = this.viewerExtensions.find((ext) => ext.fileExtension === '*');
|
||||
}
|
||||
|
||||
return this._externalViewer;
|
||||
}
|
||||
|
||||
cacheTypeForContent = 'no-cache';
|
||||
|
||||
constructor(
|
||||
private viewUtilService: ViewUtilService,
|
||||
private extensionService: AppExtensionService,
|
||||
public dialog: MatDialog,
|
||||
public readonly injector: Injector
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.cacheTypeForContent = 'no-cache';
|
||||
this.setDefaultLoadingState();
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
if (this.blobFile) {
|
||||
this.setUpBlobData();
|
||||
} else if (this.urlFile) {
|
||||
this.setUpUrlFile();
|
||||
}
|
||||
}
|
||||
|
||||
markAsLoaded() {
|
||||
this.isLoading$.next(false);
|
||||
}
|
||||
|
||||
private setUpBlobData() {
|
||||
this.internalFileName = this.fileName;
|
||||
this.viewerType = this.viewUtilService.getViewerTypeByMimeType(this.blobFile.type) as ViewerType;
|
||||
|
||||
this.extensionChange.emit(this.blobFile.type);
|
||||
this.scrollTop();
|
||||
}
|
||||
|
||||
private setUpUrlFile() {
|
||||
this.internalFileName = this.fileName ? this.fileName : this.viewUtilService.getFilenameFromUrl(this.urlFile);
|
||||
this.extension = this.viewUtilService.getFileExtension(this.internalFileName);
|
||||
this.viewerType = this.viewUtilService.getViewerType(this.extension, this.mimeType, this.extensionsSupportedByTemplates) as ViewerType;
|
||||
|
||||
this.extensionChange.emit(this.extension);
|
||||
this.scrollTop();
|
||||
}
|
||||
|
||||
scrollTop() {
|
||||
window.scrollTo(0, 1);
|
||||
}
|
||||
|
||||
checkExtensions(extensionAllowed) {
|
||||
if (typeof extensionAllowed === 'string') {
|
||||
return this.extension.toLowerCase() === extensionAllowed.toLowerCase();
|
||||
} else if (extensionAllowed.length > 0) {
|
||||
return extensionAllowed.find((currentExtension) => this.extension.toLowerCase() === currentExtension.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
onSubmitFile(newImageBlob: Blob) {
|
||||
this.submitFile.next(newImageBlob);
|
||||
}
|
||||
|
||||
onUnsupportedFile() {
|
||||
this.viewerType = 'unknown';
|
||||
}
|
||||
|
||||
onClose() {
|
||||
this.close.next(true);
|
||||
}
|
||||
|
||||
private canBePreviewed(): boolean {
|
||||
return this.viewerType === 'media' || this.viewerType === 'pdf' || this.viewerType === 'image';
|
||||
}
|
||||
|
||||
private setDefaultLoadingState() {
|
||||
if (this.canBePreviewed()) {
|
||||
this.isLoading$.next(true);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user