mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[MNT-22613] Viewer wildcard extension (#7280)
* support viewer wildcard extensions * update docs * fix lint * fix template
This commit is contained in:
parent
2ff3298a85
commit
2bb7586f93
@ -96,6 +96,29 @@ You also need to provide a [viewer component](../../core/components/viewer.compo
|
||||
}
|
||||
```
|
||||
|
||||
You can also use `*` wildcard to register a single component that opens all files:
|
||||
|
||||
```json
|
||||
{
|
||||
"$version": "1.0.0",
|
||||
"$name": "my viewer extension",
|
||||
"$description": "my viewer plugin",
|
||||
"features": {
|
||||
"viewer": {
|
||||
"content": [
|
||||
{
|
||||
"id": "dev.tools.viewer.viewer",
|
||||
"fileExtension": ["*"],
|
||||
"component": "your-extension.main.component"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> It is recommended to use wildcard replacement only when introducing your own Viewer implementation.
|
||||
|
||||
See the [App extensions](../../user-guide/app-extensions.md) page for
|
||||
further details of how to develop extensions.
|
||||
|
||||
|
@ -199,8 +199,17 @@
|
||||
fxFlexOrder="1"
|
||||
fxFlex="1 1 auto">
|
||||
<div class="adf-viewer-layout-content adf-viewer__fullscreen-container">
|
||||
<div class="adf-viewer-content-container"
|
||||
[ngSwitch]="viewerType">
|
||||
<div class="adf-viewer-content-container" [ngSwitch]="viewerType">
|
||||
<ng-container *ngSwitchCase="'external'">
|
||||
<adf-preview-extension
|
||||
*ngIf="!!externalViewer"
|
||||
[id]="externalViewer.component"
|
||||
[node]="nodeEntry?.entry"
|
||||
[url]="urlFileContent"
|
||||
[extension]="externalViewer.fileExtension"
|
||||
[attr.data-automation-id]="externalViewer.component">
|
||||
</adf-preview-extension>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'pdf'">
|
||||
<adf-pdf-viewer (close)="onBackButtonClick()"
|
||||
|
@ -33,6 +33,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { UploadService } from '../../services/upload.service';
|
||||
import { FileModel } from '../../models';
|
||||
import { AppExtensionService, ViewerExtensionRef } from '@alfresco/adf-extensions';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-viewer-container-toolbar',
|
||||
@ -137,6 +138,7 @@ describe('ViewerComponent', () => {
|
||||
let element: HTMLElement;
|
||||
let dialog: MatDialog;
|
||||
let uploadService: UploadService;
|
||||
let extensionService: AppExtensionService;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
@ -173,14 +175,67 @@ describe('ViewerComponent', () => {
|
||||
uploadService = TestBed.inject(UploadService);
|
||||
alfrescoApiService = TestBed.inject(AlfrescoApiService);
|
||||
dialog = TestBed.inject(MatDialog);
|
||||
extensionService = TestBed.inject(AppExtensionService);
|
||||
});
|
||||
|
||||
describe('Extension Type Test', () => {
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
describe('Extension Type Test', () => {
|
||||
it('should use 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(ViewerComponent);
|
||||
element = fixture.nativeElement;
|
||||
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(element.querySelector('[data-automation-id="custom.component"]')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should use 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(ViewerComponent);
|
||||
element = fixture.nativeElement;
|
||||
component = fixture.componentInstance;
|
||||
|
||||
component.urlFile = 'fake-test-file.pdf';
|
||||
component.ngOnChanges();
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(element.querySelector('[data-automation-id="custom.component.1"]')).not.toBeNull();
|
||||
expect(element.querySelector('[data-automation-id="custom.component.2"]')).toBeNull();
|
||||
});
|
||||
|
||||
it('should extension file pdf be loaded', (done) => {
|
||||
component.urlFile = 'fake-test-file.pdf';
|
||||
component.ngOnChanges();
|
||||
@ -244,11 +299,6 @@ describe('ViewerComponent', () => {
|
||||
});
|
||||
|
||||
describe('MimeType handling', () => {
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
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';
|
||||
|
@ -225,17 +225,39 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
versionEntry: VersionEntry;
|
||||
|
||||
extensionTemplates: { template: TemplateRef<any>, isVisible: boolean }[] = [];
|
||||
externalExtensions: string[] = [];
|
||||
urlFileContent: string;
|
||||
otherMenu: any;
|
||||
extension: string;
|
||||
sidebarRightTemplateContext: { node: Node } = { node: null };
|
||||
sidebarLeftTemplateContext: { node: Node } = { node: null };
|
||||
fileTitle: string;
|
||||
viewerExtensions: Array<ViewerExtensionRef> = [];
|
||||
|
||||
/**
|
||||
* Returns a list of the active Viewer content extensions.
|
||||
*/
|
||||
get viewerExtensions(): ViewerExtensionRef[] {
|
||||
return this.extensionService.getViewerExtensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of file extensions supported by external plugins.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
readOnly = true;
|
||||
|
||||
private cacheBusterNumber;
|
||||
private cacheBusterNumber: number;
|
||||
cacheTypeForContent = '';
|
||||
|
||||
// Extensions that are supported by the Viewer without conversion
|
||||
@ -316,18 +338,9 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
this.closeOverlayManager();
|
||||
this.loadExtensions();
|
||||
this.cacheTypeForContent = '';
|
||||
}
|
||||
|
||||
private loadExtensions() {
|
||||
this.viewerExtensions = this.extensionService.getViewerExtensions();
|
||||
this.viewerExtensions
|
||||
.forEach((extension: ViewerExtensionRef) => {
|
||||
this.externalExtensions.push(extension.fileExtension);
|
||||
});
|
||||
}
|
||||
|
||||
private getNodeVersionProperty(node: Node): string {
|
||||
return node?.properties['cm:versionLabel'] ?? '';
|
||||
}
|
||||
@ -427,13 +440,8 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
this.fileTitle = this.getDisplayName(filenameFromUrl);
|
||||
this.extension = this.getFileExtension(filenameFromUrl);
|
||||
this.urlFileContent = this.urlFile;
|
||||
|
||||
this.fileName = this.displayName;
|
||||
|
||||
this.viewerType = this.urlFileViewer || this.getViewerTypeByExtension(this.extension);
|
||||
if (this.viewerType === 'unknown') {
|
||||
this.viewerType = this.getViewerTypeByMimeType(this.mimeType);
|
||||
}
|
||||
this.viewerType = this.urlFileViewer || this.getViewerType(this.extension, this.mimeType);
|
||||
|
||||
this.extensionChange.emit(this.extension);
|
||||
this.scrollTop();
|
||||
@ -442,8 +450,6 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
private async setUpNodeFile(nodeData: Node, versionData?: Version) {
|
||||
this.readOnly = !this.contentService.hasAllowableOperations(nodeData, 'update');
|
||||
|
||||
let setupNode;
|
||||
|
||||
if (versionData && versionData.content) {
|
||||
this.mimeType = versionData.content.mimeType;
|
||||
} else if (nodeData.content) {
|
||||
@ -461,13 +467,10 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
this.urlFileContent + '&' + currentFileVersion;
|
||||
|
||||
this.extension = this.getFileExtension(versionData ? versionData.name : nodeData.name);
|
||||
|
||||
this.fileName = versionData ? versionData.name : nodeData.name;
|
||||
this.viewerType = this.getViewerType(this.extension, this.mimeType);
|
||||
|
||||
this.viewerType = this.getViewerTypeByExtension(this.extension);
|
||||
if (this.viewerType === 'unknown') {
|
||||
this.viewerType = this.getViewerTypeByMimeType(this.mimeType);
|
||||
}
|
||||
let setupNode: Promise<void>;
|
||||
|
||||
if (this.viewerType === 'unknown') {
|
||||
if (versionData) {
|
||||
@ -485,18 +488,23 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
return setupNode;
|
||||
}
|
||||
|
||||
private getViewerType(extension: string, mimeType: string): string {
|
||||
let viewerType = this.getViewerTypeByExtension(extension);
|
||||
|
||||
if (viewerType === 'unknown') {
|
||||
viewerType = this.getViewerTypeByMimeType(mimeType);
|
||||
}
|
||||
|
||||
return viewerType;
|
||||
}
|
||||
|
||||
private setUpSharedLinkFile(details: any) {
|
||||
this.mimeType = details.entry.content.mimeType;
|
||||
this.fileTitle = this.getDisplayName(details.entry.name);
|
||||
this.extension = this.getFileExtension(details.entry.name);
|
||||
this.fileName = details.entry.name;
|
||||
|
||||
this.urlFileContent = this.contentApi.getSharedLinkContentUrl(this.sharedLinkId, false);
|
||||
|
||||
this.viewerType = this.getViewerTypeByMimeType(this.mimeType);
|
||||
if (this.viewerType === 'unknown') {
|
||||
this.viewerType = this.getViewerTypeByExtension(this.extension);
|
||||
}
|
||||
this.viewerType = this.getViewerType(this.extension, this.mimeType);
|
||||
|
||||
if (this.viewerType === 'unknown') {
|
||||
this.displaySharedLinkRendition(this.sharedLinkId);
|
||||
@ -552,6 +560,10 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
extension = extension.toLowerCase();
|
||||
}
|
||||
|
||||
if (this.isExternalViewer()) {
|
||||
return 'external';
|
||||
}
|
||||
|
||||
if (this.isCustomViewerExtension(extension)) {
|
||||
return 'custom';
|
||||
}
|
||||
@ -628,8 +640,12 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
|
||||
return null;
|
||||
}
|
||||
|
||||
private isExternalViewer(): boolean {
|
||||
return !!this.viewerExtensions.find(ext => ext.fileExtension === '*');
|
||||
}
|
||||
|
||||
isCustomViewerExtension(extension: string): boolean {
|
||||
const extensions: any = this.externalExtensions || [];
|
||||
const extensions = this.externalExtensions || [];
|
||||
|
||||
if (extension && extensions.length > 0) {
|
||||
extension = extension.toLowerCase();
|
||||
|
Loading…
x
Reference in New Issue
Block a user