From e5afe96a52e78a139ef48a4ddbf043d594bac1d4 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 1 Feb 2018 17:14:32 +0000 Subject: [PATCH] [ADF-2138] Viewer enhancements (#2897) * greatly improved rendition management * code cleanup * test fixes * better handling of media types * docs update * fix code style * fix tests after rebase --- docs/viewer.component.md | 53 +++++- lib/core/services/renditions.service.ts | 21 ++- lib/core/services/thumbnail.service.ts | 155 +++++++++++------- .../components/viewer.component.spec.ts | 2 +- .../viewer/components/viewer.component.ts | 128 +++++++++------ 5 files changed, 238 insertions(+), 121 deletions(-) diff --git a/docs/viewer.component.md b/docs/viewer.component.md index ec54d7b5ee..5a195c34bd 100644 --- a/docs/viewer.component.md +++ b/docs/viewer.component.md @@ -69,6 +69,7 @@ Using with file url: | canNavigateBefore | boolean | true | Toggle the "before" ("<") button. Requires `allowNavigate` to be enabled. | | canNavigateNext | boolean | true | Toggle the next (">") button. Requires `allowNavigate` to be enabled.| | allowFullScreen | boolean | true | Toggle the 'Full Screen' feature. | +| maxRetries | number | 5 | Number of times the Viewer will retry fetching content Rendition. Retries have at least 1 second delay in between. | ### Events @@ -143,15 +144,53 @@ You can provide custom file parameters, for example a value for the `mimeType` o ### Supported file formats -| Type | Extension | -| ---- | --------- | -| Media | wav, Mp3, Mp4, WebM, Ogv | -| Images | png, jpg, jpeg, gif, bmp | -| Text | pdf, txt | +The Viewer component consists of separate Views that handle particular types of type families based on either a file extension or a mime type: -### PDF Conversion +- PDF View + - application/pdf + - *.pdf +- Image View + - image/png + - image/jpeg + - image/gif + - image/bmp + - image/svg+xml + - *.png + - *.jpg + - *.jpeg + - *.gif + - *.bpm + - *.svg +- Text View + - text/plain + - text/csv + - text/xml + - text/html + - application/x-javascript + - *.txt + - *.xml + - *.js + - *.html + - *.json + - *.ts +- Media View + - video/mp4 + - video/webm + - video/ogg + - audio/mpeg + - audio/ogg + - audio/wav + - *.wav + - *.mp4 + - *.mp3 + - *.webm + - *.ogg -For unsupported extensions or mime types the viewer will try to fetch PDF rendition utilising the [renditions service api](https://community.alfresco.com/docs/DOC-5879-rendition-service) +### Content Renditions + +For those extensions and mime types that cannot be natively displayed in the browser, the Viewer will try to fetch corresponding rendition by utilising the [renditions service api](https://community.alfresco.com/docs/DOC-5879-rendition-service). + +For the full list of supported types please refer to: [File types that support preview and thumbnail generation](http://docs.alfresco.com/5.2/references/valid-transformations-preview.html). ### Configuring PDF.js library diff --git a/lib/core/services/renditions.service.ts b/lib/core/services/renditions.service.ts index 3ccc69af02..97ab434ad3 100644 --- a/lib/core/services/renditions.service.ts +++ b/lib/core/services/renditions.service.ts @@ -26,7 +26,9 @@ import 'rxjs/add/observable/interval'; import 'rxjs/add/operator/takeWhile'; /** + * @deprecated * RenditionsService + * (this service is deprecated in 2.2.0 and will be removed in future revisions) * * @returns {RenditionsService} . */ @@ -36,6 +38,7 @@ export class RenditionsService { constructor(private apiService: AlfrescoApiService) { } + /** @deprecated */ isRenditionAvailable(nodeId: string, encoding: string): Observable { return Observable.create((observer) => { this.getRendition(nodeId, encoding).subscribe( @@ -55,6 +58,7 @@ export class RenditionsService { }); } + /** @deprecated */ isConversionPossible(nodeId: string, encoding: string): Observable { return Observable.create((observer) => { this.getRendition(nodeId, encoding).subscribe( @@ -70,31 +74,42 @@ export class RenditionsService { }); } + /** @deprecated */ getRenditionUrl(nodeId: string, encoding: string): string { return this.apiService.contentApi.getRenditionUrl(nodeId, encoding); } + /** @deprecated */ getRendition(nodeId: string, encoding: string): Observable { return Observable.fromPromise(this.apiService.renditionsApi.getRendition(nodeId, encoding)); } + /** @deprecated */ getRenditionsListByNodeId(nodeId: string): Observable { return Observable.fromPromise(this.apiService.renditionsApi.getRenditions(nodeId)); } + /** @deprecated */ createRendition(nodeId: string, encoding: string): Observable<{}> { return Observable.fromPromise(this.apiService.renditionsApi.createRendition(nodeId, {id: encoding})); } - convert(nodeId: string, encoding: string, pollingInterval: number = 1000) { + /** @deprecated */ + convert(nodeId: string, encoding: string, pollingInterval: number = 1000, retries: number = 5) { return this.createRendition(nodeId, encoding) - .concatMap(() => this.pollRendition(nodeId, encoding, pollingInterval)); + .concatMap(() => this.pollRendition(nodeId, encoding, pollingInterval, retries)); } - private pollRendition(nodeId: string, encoding: string, interval: number = 1000) { + /** @deprecated */ + private pollRendition(nodeId: string, encoding: string, interval: number = 1000, retries: number = 5) { + let attempts = 0; return Observable.interval(interval) .switchMap(() => this.getRendition(nodeId, encoding)) .takeWhile((data) => { + attempts += 1; + if (attempts > retries) { + return false; + } return (data.entry.status.toString() !== 'CREATED'); }); } diff --git a/lib/core/services/thumbnail.service.ts b/lib/core/services/thumbnail.service.ts index 646f2800f5..7c4a2f99c1 100644 --- a/lib/core/services/thumbnail.service.ts +++ b/lib/core/services/thumbnail.service.ts @@ -29,97 +29,130 @@ export class ThumbnailService { 'image/png': './assets/images/ft_ic_raster_image.svg', 'image/jpeg': './assets/images/ft_ic_raster_image.svg', 'image/gif': './assets/images/ft_ic_raster_image.svg', + 'image/bmp': './assets/images/ft_ic_raster_image.svg', + 'image/cgm': './assets/images/ft_ic_raster_image.svg', + 'image/ief': './assets/images/ft_ic_raster_image.svg', + 'image/jp2': './assets/images/ft_ic_raster_image.svg', + 'image/tiff': './assets/images/ft_ic_raster_image.svg', + 'image/vnd.adobe.photoshop': './assets/images/ft_ic_raster_image.svg', + 'image/vnd.adobe.premiere': './assets/images/ft_ic_raster_image.svg', + 'image/x-cmu-raster': './assets/images/ft_ic_raster_image.svg', + 'image/x-dwt': './assets/images/ft_ic_raster_image.svg', + 'image/x-portable-anymap': './assets/images/ft_ic_raster_image.svg', + 'image/x-portable-bitmap': './assets/images/ft_ic_raster_image.svg', + 'image/x-portable-graymap': './assets/images/ft_ic_raster_image.svg', + 'image/x-portable-pixmap': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-adobe': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-canon': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-fuji': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-hasselblad': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-kodak': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-leica': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-minolta': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-nikon': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-olympus': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-panasonic': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-pentax': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-red': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-sigma': './assets/images/ft_ic_raster_image.svg', + 'image/x-raw-sony': './assets/images/ft_ic_raster_image.svg', + 'image/x-xbitmap': './assets/images/ft_ic_raster_image.svg', + 'image/x-xpixmap': './assets/images/ft_ic_raster_image.svg', + 'image/x-xwindowdump': './assets/images/ft_ic_raster_image.svg', + 'image/svg+xml': './assets/images/ft_ic_vector_image.svg', 'application/eps': './assets/images/ft_ic_raster_image.svg', 'application/illustrator': './assets/images/ft_ic_raster_image.svg', 'application/pdf': './assets/images/ft_ic_pdf.svg', 'application/vnd.ms-excel': './assets/images/ft_ic_ms_excel.svg', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': './assets/images/ft_ic_ms_excel.svg', 'application/vnd.openxmlformats-officedocument.spreadsheetml.template': './assets/images/ft_ic_ms_excel.svg', + 'application/vnd.ms-excel.addin.macroenabled.12': './assets/images/ft_ic_ms_excel.svg', + 'application/vnd.ms-excel.sheet.binary.macroenabled.12': './assets/images/ft_ic_ms_excel.svg', + 'application/vnd.ms-excel.sheet.macroenabled.12': './assets/images/ft_ic_ms_excel.svg', + 'application/vnd.ms-excel.template.macroenabled.12': './assets/images/ft_ic_ms_excel.svg', + 'application/vnd.sun.xml.calc': './assets/images/ft_ic_ms_excel.svg', + 'application/vnd.sun.xml.calc.template': './assets/images/ft_ic_ms_excel.svg', + 'application/vnd.ms-outlook': './assets/images/ft_ic_document.svg', 'application/msword': './assets/images/ft_ic_ms_word.svg', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': './assets/images/ft_ic_ms_word.svg', 'application/vnd.openxmlformats-officedocument.wordprocessingml.template': './assets/images/ft_ic_ms_word.svg', + 'application/vnd.ms-word.document.macroenabled.12': './assets/images/ft_ic_ms_word.svg', + 'application/vnd.ms-word.template.macroenabled.12': './assets/images/ft_ic_ms_word.svg', + 'application/vnd.sun.xml.writer': './assets/images/ft_ic_ms_word.svg', + 'application/vnd.sun.xml.writer.template': './assets/images/ft_ic_ms_word.svg', + 'application/rtf': './assets/images/ft_ic_ms_word.svg', 'application/vnd.ms-powerpoint': './assets/images/ft_ic_ms_powerpoint.svg', 'application/vnd.openxmlformats-officedocument.presentationml.presentation': './assets/images/ft_ic_ms_powerpoint.svg', 'application/vnd.openxmlformats-officedocument.presentationml.template': './assets/images/ft_ic_ms_powerpoint.svg', 'application/vnd.openxmlformats-officedocument.presentationml.slideshow': './assets/images/ft_ic_ms_powerpoint.svg', + 'application/vnd.oasis.opendocument.presentation': './assets/images/ft_ic_ms_powerpoint.svg', + 'application/vnd.oasis.opendocument.presentation-template': './assets/images/ft_ic_ms_powerpoint.svg', + 'application/vnd.openxmlformats-officedocument.presentationml.slide': './assets/images/ft_ic_ms_powerpoint.svg', + 'application/vnd.sun.xml.impress': './assets/images/ft_ic_ms_powerpoint.svg', + 'application/vnd.sun.xml.impress.template': './assets/images/ft_ic_ms_powerpoint.svg', + 'application/vnd.oasis.opendocument.spreadsheet': './assets/images/ft_ic_ms_excel.svg', + 'application/vnd.oasis.opendocument.spreadsheet-template': './assets/images/ft_ic_ms_excel.svg', + 'application/vnd.ms-powerpoint.addin.macroenabled.12': './assets/images/ft_ic_ms_powerpoint.svg', + 'application/vnd.ms-powerpoint.presentation.macroenabled.12': './assets/images/ft_ic_ms_powerpoint.svg', + 'application/vnd.ms-powerpoint.slide.macroenabled.12': './assets/images/ft_ic_ms_powerpoint.svg', + 'application/vnd.ms-powerpoint.slideshow.macroenabled.12': './assets/images/ft_ic_ms_powerpoint.svg', + 'application/vnd.ms-powerpoint.template.macroenabled.12': './assets/images/ft_ic_ms_powerpoint.svg', 'video/mp4': './assets/images/ft_ic_video.svg', + 'video/3gpp': './assets/images/ft_ic_video.svg', + 'video/3gpp2': './assets/images/ft_ic_video.svg', + 'video/mp2t': './assets/images/ft_ic_video.svg', + 'video/mpeg': './assets/images/ft_ic_video.svg', + 'video/mpeg2': './assets/images/ft_ic_video.svg', + 'video/ogg': './assets/images/ft_ic_video.svg', + 'video/quicktime': './assets/images/ft_ic_video.svg', + 'video/webm': './assets/images/ft_ic_video.svg', + 'video/x-flv': './assets/images/ft_ic_video.svg', + 'video/x-m4v': './assets/images/ft_ic_video.svg', + 'video/x-ms-asf': './assets/images/ft_ic_video.svg', + 'video/x-ms-wmv': './assets/images/ft_ic_video.svg', + 'video/x-msvideo': './assets/images/ft_ic_video.svg', + 'video/x-rad-screenplay': './assets/images/ft_ic_video.svg', + 'video/x-sgi-movie': './assets/images/ft_ic_video.svg', + 'video/x-matroska': './assets/images/ft_ic_video.svg', + 'audio/mpeg': './assets/images/ft_ic_audio.svg', + 'audio/ogg': './assets/images/ft_ic_audio.svg', + 'audio/wav': './assets/images/ft_ic_audio.svg', + 'audio/basic': './assets/images/ft_ic_audio.svg', + 'audio/mp4': './assets/images/ft_ic_audio.svg', + 'audio/vnd.adobe.soundbooth': './assets/images/ft_ic_audio.svg', + 'audio/vorbis': './assets/images/ft_ic_audio.svg', + 'audio/x-aiff': './assets/images/ft_ic_audio.svg', + 'audio/x-flac': './assets/images/ft_ic_audio.svg', + 'audio/x-ms-wma': './assets/images/ft_ic_audio.svg', + 'audio/x-wav': './assets/images/ft_ic_audio.svg', + 'x-world/x-vrml': './assets/images/ft_ic_video.svg', 'text/plain': './assets/images/ft_ic_document.svg', + 'application/vnd.oasis.opendocument.text': './assets/images/ft_ic_document.svg', + 'application/vnd.oasis.opendocument.text-template': './assets/images/ft_ic_document.svg', 'application/x-javascript': './assets/images/ft_ic_document.svg', 'application/json': './assets/images/ft_ic_document.svg', - 'image/svg+xml': './assets/images/ft_ic_vector_image.svg', + 'text/csv': './assets/images/ft_ic_document.svg', + 'text/xml': './assets/images/ft_ic_document.svg', 'text/html': './assets/images/ft_ic_website.svg', 'application/x-compressed': './assets/images/ft_ic_archive.svg', 'application/x-zip-compressed': './assets/images/ft_ic_archive.svg', 'application/zip': './assets/images/ft_ic_archive.svg', + 'application/x-tar': './assets/images/ft_ic_archive.svg', 'application/vnd.apple.keynote': './assets/images/ft_ic_presentation.svg', 'application/vnd.apple.pages': './assets/images/ft_ic_document.svg', 'application/vnd.apple.numbers': './assets/images/ft_ic_spreadsheet.svg', + 'application/vnd.visio': './assets/images/ft_ic_document.svg', + 'application/wordperfect': './assets/images/ft_ic_document.svg', + 'application/x-cpio': './assets/images/ft_ic_document.svg', 'folder': './assets/images/ft_ic_folder.svg', 'disable/folder': './assets/images/ft_ic_folder_disable.svg', 'selected': './assets/images/ft_ic_selected.svg' }; constructor(public contentService: ContentService, matIconRegistry: MatIconRegistry, sanitizer: DomSanitizer) { - matIconRegistry.addSvgIcon('image/png', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_raster_image.svg')); - matIconRegistry.addSvgIcon('image/jpeg', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_raster_image.svg')); - matIconRegistry.addSvgIcon('image/gif', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_raster_image.svg')); - matIconRegistry.addSvgIcon('application/pdf', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_pdf.svg')); - matIconRegistry.addSvgIcon('application/vnd.ms-excel', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_ms_excel.svg')); - matIconRegistry.addSvgIcon('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_ms_excel.svg')); - matIconRegistry.addSvgIcon('application/vnd.openxmlformats-officedocument.spreadsheetml.template', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_ms_excel.svg')); - matIconRegistry.addSvgIcon('application/msword', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_ms_word.svg')); - matIconRegistry.addSvgIcon('application/vnd.openxmlformats-officedocument.wordprocessingml.document', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_ms_word.svg')); - matIconRegistry.addSvgIcon('application/vnd.openxmlformats-officedocument.wordprocessingml.template', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_ms_word.svg')); - matIconRegistry.addSvgIcon('application/vnd.ms-powerpoint', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_ms_powerpoint.svg')); - matIconRegistry.addSvgIcon('application/vnd.openxmlformats-officedocument.presentationml.presentation', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_ms_powerpoint.svg')); - matIconRegistry.addSvgIcon('application/vnd.openxmlformats-officedocument.presentationml.template', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_ms_powerpoint.svg')); - matIconRegistry.addSvgIcon('application/vnd.openxmlformats-officedocument.presentationml.slideshow', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_ms_powerpoint.svg')); - matIconRegistry.addSvgIcon('video/mp4', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_video.svg')); - matIconRegistry.addSvgIcon('text/plain', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_document.svg')); - matIconRegistry.addSvgIcon('application/x-javascript', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_document.svg')); - matIconRegistry.addSvgIcon('application/json', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_document.svg')); - matIconRegistry.addSvgIcon('image/svg+xml', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_vector_image.svg')); - matIconRegistry.addSvgIcon('text/html', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_website.svg')); - matIconRegistry.addSvgIcon('application/x-compressed', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_archive.svg')); - matIconRegistry.addSvgIcon('application/x-zip-compressed', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_archive.svg')); - matIconRegistry.addSvgIcon('application/zip', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_archive.svg')); - matIconRegistry.addSvgIcon('application/vnd.apple.keynote', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_presentation.svg')); - matIconRegistry.addSvgIcon('application/vnd.apple.pages', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_document.svg')); - matIconRegistry.addSvgIcon('application/vnd.apple.numbers', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_spreadsheet.svg')); - matIconRegistry.addSvgIcon('folder', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_folder.svg')); - matIconRegistry.addSvgIcon('disable/folder', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_folder_disable.svg')); - matIconRegistry.addSvgIcon('selected', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_selected.svg')); - matIconRegistry.addSvgIcon('default', - sanitizer.bypassSecurityTrustResourceUrl('./assets/images/ft_ic_miscellaneous.svg')); + Object.keys(this.mimeTypeIcons).forEach(key => { + matIconRegistry.addSvgIcon(key, sanitizer.bypassSecurityTrustResourceUrl(this.mimeTypeIcons[key])); + }); } /** diff --git a/lib/core/viewer/components/viewer.component.spec.ts b/lib/core/viewer/components/viewer.component.spec.ts index 4dfd5c5428..480dbd5bdc 100644 --- a/lib/core/viewer/components/viewer.component.spec.ts +++ b/lib/core/viewer/components/viewer.component.spec.ts @@ -622,7 +622,7 @@ describe('ViewerComponent', () => { it('should display the txt viewer if the file identified by mimetype is a txt when the filename has wrong extension', async(() => { component.urlFile = 'content.bin'; - component.mimeType = 'text/txt'; + component.mimeType = 'text/plain'; component.urlFile = require('../assets/fake-test-file.txt'); fixture.detectChanges(); component.ngOnChanges(null); diff --git a/lib/core/viewer/components/viewer.component.ts b/lib/core/viewer/components/viewer.component.ts index db4ad2edb8..465b035cc2 100644 --- a/lib/core/viewer/components/viewer.component.ts +++ b/lib/core/viewer/components/viewer.component.ts @@ -20,11 +20,10 @@ import { Component, ContentChild, EventEmitter, HostListener, ElementRef, Input, OnChanges, Output, SimpleChanges, TemplateRef, ViewEncapsulation } from '@angular/core'; -import { MinimalNodeEntryEntity } from 'alfresco-js-api'; +import { MinimalNodeEntryEntity, RenditionEntry } from 'alfresco-js-api'; import { BaseEvent } from '../../events'; import { AlfrescoApiService } from '../../services/alfresco-api.service'; import { LogService } from '../../services/log.service'; -import { RenditionsService } from '../../services/renditions.service'; import { ViewerMoreActionsComponent } from './viewer-more-actions.component'; import { ViewerOpenWithComponent } from './viewer-open-with.component'; import { ViewerSidebarComponent } from './viewer-sidebar.component'; @@ -123,6 +122,9 @@ export class ViewerComponent implements OnChanges { @Input() downloadUrl: string = null; + @Input() + maxRetries = 5; + @Output() goBack = new EventEmitter>(); @@ -158,22 +160,25 @@ export class ViewerComponent implements OnChanges { extension: string; sidebarTemplateContext: { node: MinimalNodeEntryEntity } = { node: null }; + // Extensions that are supported by the Viewer without conversion private extensions = { - image: ['png', 'jpg', 'jpeg', 'gif', 'bpm'], + image: ['png', 'jpg', 'jpeg', 'gif', 'bpm', 'svg'], media: ['wav', 'mp4', 'mp3', 'webm', 'ogg'], text: ['txt', 'xml', 'js', 'html', 'json', 'ts'], pdf: ['pdf'] }; - private mimeTypes = [ - { mimeType: 'application/x-javascript', type: 'text' }, - { mimeType: 'application/pdf', type: 'pdf' } - ]; + // Mime types that are supported by the Viewer without conversion + private mimeTypes = { + text: ['text/plain', 'text/csv', 'text/xml', 'text/html', 'application/x-javascript'], + pdf: ['application/pdf'], + image: ['image/png', 'image/jpeg', 'image/gif', 'image/bmp', 'image/svg+xml'], + media: ['video/mp4', 'video/webm', 'video/ogg', 'audio/mpeg', 'audio/ogg', 'audio/wav'] + }; constructor(private apiService: AlfrescoApiService, private logService: LogService, private location: Location, - private renditionService: RenditionsService, private el: ElementRef) { } @@ -315,25 +320,11 @@ export class ViewerComponent implements OnChanges { if (mimeType) { mimeType = mimeType.toLowerCase(); - if (mimeType.startsWith('image/')) { - return 'image'; - } - - if (mimeType.startsWith('text/')) { - return 'text'; - } - - if (mimeType.startsWith('video/')) { - return 'media'; - } - - if (mimeType.startsWith('audio/')) { - return 'media'; - } - - const registered = this.mimeTypes.find(t => t.mimeType === mimeType); - if (registered) { - return registered.type; + const editorTypes = Object.keys(this.mimeTypes); + for (let type of editorTypes) { + if (this.mimeTypes[type].indexOf(mimeType) >= 0) { + return type; + } } } return 'unknown'; @@ -531,33 +522,20 @@ export class ViewerComponent implements OnChanges { this.isLoading = true; try { - const rendition = await this.apiService.renditionsApi.getRendition(nodeId, 'pdf'); - const status = rendition.entry.status.toString(); + const rendition = await this.resolveRendition(nodeId, 'pdf'); + if (rendition) { + const renditionId = rendition.entry.id; - if (status === 'CREATED') { - this.viewerType = 'pdf'; - this.urlFileContent = this.apiService.contentApi.getRenditionUrl(nodeId, 'pdf'); - } else if (status === 'NOT_CREATED') { - try { - await this.renditionService.convert(nodeId, 'pdf').toPromise(); + if (renditionId === 'pdf') { this.viewerType = 'pdf'; - this.urlFileContent = this.apiService.contentApi.getRenditionUrl(nodeId, 'pdf'); - } catch (error) { - this.logService.error(error); - } - } - } catch (error) { - this.logService.error(error); - - try { - const imagePreview = await this.apiService.renditionsApi.getRendition(nodeId, 'imgpreview'); - if (imagePreview.entry.status.toString() === 'CREATED') { + } else if (renditionId === 'imgpreview') { this.viewerType = 'image'; - this.urlFileContent = this.apiService.contentApi.getRenditionUrl(nodeId, 'imgpreview'); } - } catch (error) { - this.logService.error(error); + + this.urlFileContent = this.apiService.contentApi.getRenditionUrl(nodeId, renditionId); } + } catch (err) { + this.logService.error(err); } this.isLoading = false; @@ -587,4 +565,56 @@ export class ViewerComponent implements OnChanges { this.isLoading = false; } + + private async resolveRendition(nodeId: string, renditionId: string): Promise { + renditionId = renditionId.toLowerCase(); + + const supported = await this.apiService.renditionsApi.getRenditions(nodeId); + + let rendition = supported.list.entries.find(obj => obj.entry.id.toLowerCase() === renditionId); + if (!rendition) { + renditionId = 'imgpreview'; + rendition = supported.list.entries.find(obj => obj.entry.id.toLowerCase() === renditionId); + + if (!rendition) { + return null; + } + } + + const status = rendition.entry.status.toString(); + + if (status === 'CREATED') { + return rendition; + } else if (status === 'NOT_CREATED') { + try { + await this.apiService.renditionsApi.createRendition(nodeId, {id: renditionId}); + return await this.waitRendition(nodeId, renditionId, 0); + } catch (err) { + this.logService.error(err); + return null; + } + } + } + + private async waitRendition(nodeId: string, renditionId: string, retries: number): Promise { + const rendition = await this.apiService.renditionsApi.getRendition(nodeId, renditionId); + + if (retries > this.maxRetries) { + return null; + } + + const status = rendition.entry.status.toString(); + + if (status === 'CREATED') { + return rendition; + } else { + retries += 1; + await this.wait(1000); + return await this.waitRendition(nodeId, renditionId, retries); + } + } + + private wait(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); + } }