AAE-34298 Move viewer to separate entry point

This commit is contained in:
Wojciech Duda
2025-05-28 15:19:19 +02:00
parent 5bbb5c5716
commit 4bcfc32d16
79 changed files with 36 additions and 33 deletions

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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');
});
});
});

View File

@@ -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);
}
}
}