-
![]()
+
+
@@ -201,14 +66,14 @@
-
-
+
+
+
+
+
+
+
+
@@ -217,16 +82,15 @@
[allowThumbnails]="allowThumbnails"
[blobFile]="blobFile"
[urlFile]="urlFileContent"
- [nameFile]="displayName"
+ [fileName]="fileName"
[cacheType]="cacheTypeForContent"
(error)="onUnsupportedFile()">
@@ -235,10 +99,9 @@
@@ -247,25 +110,15 @@
[blobFile]="blobFile">
-
-
-
{{ 'ADF_VIEWER.LOADING' | translate }}
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
") button. Requires `allowNavigate` to be enabled. */
- @Input()
- canNavigateNext = true;
-
- /** Allow the left the sidebar. */
- @Input()
- allowLeftSidebar = false;
-
- /** Allow the right sidebar. */
- @Input()
- allowRightSidebar = false;
-
/** Toggles PDF thumbnails. */
@Input()
allowThumbnails = true;
- /** Toggles right sidebar visibility. Requires `allowRightSidebar` to be set to `true`. */
- @Input()
- showRightSidebar = false;
-
- /** Toggles left sidebar visibility. Requires `allowLeftSidebar` to be set to `true`. */
- @Input()
- showLeftSidebar = false;
-
/** The template for the right sidebar. The template context contains the loaded node data. */
@Input()
sidebarRightTemplate: TemplateRef = null;
@@ -180,15 +114,22 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
@Input()
mimeType: string;
- /** Content filename. */
+ /** Override Content filename. */
@Input()
fileName: string;
- /** Number of times the Viewer will retry fetching content Rendition.
- * There is a delay of at least one second between attempts.
- */
+ /** Override Content view type.
+ Viewer to use with the `urlFile` address (`pdf`, `image`, `media`, `text`).*/
@Input()
- maxRetries = 30;
+ viewerType: string = 'unknown';
+
+ /** Allows `back` navigation */
+ @Input()
+ allowGoBack = true;
+
+ /** Override loading status */
+ @Input()
+ isLoading = false;
/** Emitted when user clicks the 'Back' button. */
@Output()
@@ -206,29 +147,16 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
@Output()
extensionChange = new EventEmitter();
- /** Emitted when user clicks 'Navigate Before' ("<") button. */
+ /** Emitted when the img is submitted in the img viewer. */
@Output()
- navigateBefore = new EventEmitter();
-
- /** Emitted when user clicks 'Navigate Next' (">") button. */
- @Output()
- navigateNext = new EventEmitter();
-
- /** Emitted when the shared link used is not valid. */
- @Output()
- invalidSharedLink = new EventEmitter();
-
- viewerType = 'unknown';
- isLoading = false;
- nodeEntry: NodeEntry;
- versionEntry: VersionEntry;
+ submitFile = new EventEmitter();
extensionTemplates: { template: TemplateRef; isVisible: boolean }[] = [];
urlFileContent: string;
otherMenu: any;
extension: string;
- sidebarRightTemplateContext: { node: Node } = { node: null };
- sidebarLeftTemplateContext: { node: Node } = { node: null };
+ // sidebarRightTemplateContext: { node: Node } = { node: null };
+ // sidebarLeftTemplateContext: { node: Node } = { node: null };
fileTitle: string;
/**
@@ -254,116 +182,32 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
return this._externalViewer;
}
- readOnly = true;
+ // readOnly = true;
- private cacheBusterNumber: number;
cacheTypeForContent = '';
- // Extensions that are supported by the Viewer without conversion
- private extensions = {
- image: ['png', 'jpg', 'jpeg', 'gif', 'bpm', 'svg'],
- media: ['wav', 'mp4', 'mp3', 'webm', 'ogg'],
- text: ['txt', 'xml', 'html', 'json', 'ts', 'css', 'md'],
- pdf: ['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/mp3', 'audio/ogg', 'audio/wav']
- };
-
private onDestroy$ = new Subject();
private shouldCloseViewer = true;
private keyDown$ = fromEvent(document, 'keydown');
- _sharedLinksApi: SharedlinksApi;
- get sharedLinksApi(): SharedlinksApi {
- this._sharedLinksApi = this._sharedLinksApi ?? new SharedlinksApi(this.apiService.getInstance());
- return this._sharedLinksApi;
- }
-
- _versionsApi: VersionsApi;
- get versionsApi(): VersionsApi {
- this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance());
- return this._versionsApi;
- }
-
- _nodesApi: NodesApi;
- get nodesApi(): NodesApi {
- this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance());
- return this._nodesApi;
- }
-
- _contentApi: ContentApi;
- get contentApi(): ContentApi {
- this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance());
- return this._contentApi;
- }
-
- constructor(private apiService: AlfrescoApiService,
- private viewUtilService: ViewUtilService,
- private logService: LogService,
+ constructor(private viewUtilService: ViewUtilService,
private extensionService: AppExtensionService,
- private contentService: ContentService,
- private uploadService: UploadService,
private el: ElementRef,
- public dialog: MatDialog,
- private cdr: ChangeDetectorRef) {
- viewUtilService.maxRetries = this.maxRetries;
- }
-
- isSourceDefined(): boolean {
- return !!(this.urlFile || this.blobFile || this.nodeId || this.sharedLinkId);
+ public dialog: MatDialog) {
}
ngOnInit() {
- this.apiService.nodeUpdated.pipe(
- filter((node) => node && node.id === this.nodeId &&
- (node.name !== this.fileName ||
- this.getNodeVersionProperty(this.nodeEntry.entry) !== this.getNodeVersionProperty(node))),
- takeUntil(this.onDestroy$)
- ).subscribe((node) => this.onNodeUpdated(node));
-
- this.viewUtilService.viewerTypeChange.pipe(takeUntil(this.onDestroy$)).subscribe((type: string) => {
- this.viewerType = type;
- });
-
- this.viewUtilService.urlFileContentChange.pipe(takeUntil(this.onDestroy$)).subscribe((content: string) => {
- this.urlFileContent = content;
- });
-
this.closeOverlayManager();
this.cacheTypeForContent = '';
}
- private getNodeVersionProperty(node: Node): string {
- return node?.properties['cm:versionLabel'] ?? '';
- }
-
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
- private onNodeUpdated(node: Node) {
- if (node && node.id === this.nodeId) {
- this.cacheTypeForContent = 'no-cache';
- this.generateCacheBusterNumber();
- this.isLoading = true;
- this.setUpNodeFile(node).then(() => {
- this.isLoading = false;
- });
- }
- }
-
ngOnChanges() {
if (this.showViewer) {
- if (!this.isSourceDefined()) {
- throw new Error('A content source attribute value is missing.');
- }
this.isLoading = true;
if (this.blobFile) {
@@ -372,60 +216,13 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
} else if (this.urlFile) {
this.setUpUrlFile();
this.isLoading = false;
- } else if (this.nodeId) {
- this.setupNode();
- } else if (this.sharedLinkId) {
- this.setupSharedLink();
}
}
}
- private setupSharedLink() {
- this.allowGoBack = false;
-
- this.sharedLinksApi.getSharedLink(this.sharedLinkId).then(
- (sharedLinkEntry: SharedLinkEntry) => {
- this.setUpSharedLinkFile(sharedLinkEntry);
- this.isLoading = false;
- },
- () => {
- this.isLoading = false;
- this.logService.error('This sharedLink does not exist');
- this.invalidSharedLink.next();
- });
- }
-
- private setupNode() {
- this.nodesApi.getNode(this.nodeId, { include: ['allowableOperations'] }).then(
- (node: NodeEntry) => {
- this.nodeEntry = node;
- if (this.versionId) {
- this.versionsApi.getVersion(this.nodeId, this.versionId).then(
- (version: VersionEntry) => {
- this.versionEntry = version;
- this.setUpNodeFile(node.entry, version.entry).then(() => {
- this.isLoading = false;
- });
- }
- );
- } else {
- this.setUpNodeFile(node.entry).then(() => {
- this.isLoading = false;
- this.cdr.detectChanges();
- });
- }
- },
- () => {
- this.isLoading = false;
- this.logService.error('This node does not exist');
- }
- );
- }
-
private setUpBlobData() {
- this.fileTitle = this.getDisplayName('Unknown');
this.mimeType = this.blobFile.type;
- this.viewerType = this.getViewerTypeByMimeType(this.mimeType);
+ this.viewerType = this.viewUtilService.getViewerTypeByMimeType(this.mimeType);
this.allowDownload = false;
// TODO: wrap blob into the data url and allow downloading
@@ -435,164 +232,24 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
}
private setUpUrlFile() {
- const filenameFromUrl = this.getFilenameFromUrl(this.urlFile);
- this.fileTitle = this.getDisplayName(filenameFromUrl);
- this.extension = this.getFileExtension(filenameFromUrl);
+ this.fileName = this.fileName ? this.fileName : this.viewUtilService.getFilenameFromUrl(this.urlFile);
+ this.extension = this.viewUtilService.getFileExtension(this.fileTitle);
this.urlFileContent = this.urlFile;
- this.fileName = this.displayName;
- this.viewerType = this.urlFileViewer || this.getViewerType(this.extension, this.mimeType);
+ this.viewerType = this.viewerType === 'unknown' ? this.viewUtilService.getViewerType(this.extension, this.mimeType) : this.viewerType;
this.extensionChange.emit(this.extension);
this.scrollTop();
}
- private async setUpNodeFile(nodeData: Node, versionData?: Version): Promise {
- this.readOnly = !this.contentService.hasAllowableOperations(nodeData, 'update');
-
- if (versionData && versionData.content) {
- this.mimeType = versionData.content.mimeType;
- } else if (nodeData.content) {
- this.mimeType = nodeData.content.mimeType;
- }
-
- this.fileTitle = this.getDisplayName(versionData ? versionData.name : nodeData.name);
-
- const currentFileVersion = this.nodeEntry?.entry?.properties && this.nodeEntry.entry.properties['cm:versionLabel'] ?
- encodeURI(this.nodeEntry?.entry?.properties['cm:versionLabel']) : encodeURI('1.0');
-
- this.urlFileContent = versionData ? this.contentApi.getVersionContentUrl(this.nodeId, versionData.id) :
- this.contentApi.getContentUrl(this.nodeId);
- this.urlFileContent = this.cacheBusterNumber ? this.urlFileContent + '&' + currentFileVersion + '&' + this.cacheBusterNumber :
- 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);
-
- if (this.viewerType === 'unknown') {
- if (versionData) {
- await this.viewUtilService.displayNodeRendition(nodeData.id, versionData.id);
- } else {
- await this.viewUtilService.displayNodeRendition(nodeData.id);
- }
- }
-
- this.extensionChange.emit(this.extension);
- this.sidebarRightTemplateContext.node = nodeData;
- this.sidebarLeftTemplateContext.node = nodeData;
- this.scrollTop();
- }
-
- 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.getViewerType(this.extension, this.mimeType);
-
- if (this.viewerType === 'unknown') {
- this.displaySharedLinkRendition(this.sharedLinkId);
- }
-
- this.extensionChange.emit(this.extension);
- }
-
- toggleSidebar() {
- this.showRightSidebar = !this.showRightSidebar;
- if (this.showRightSidebar && this.nodeId) {
- this.nodesApi.getNode(this.nodeId, { include: ['allowableOperations'] })
- .then((nodeEntry: NodeEntry) => {
- this.sidebarRightTemplateContext.node = nodeEntry.entry;
- });
- }
- }
-
- toggleLeftSidebar() {
- this.showLeftSidebar = !this.showLeftSidebar;
- if (this.showRightSidebar && this.nodeId) {
- this.nodesApi.getNode(this.nodeId, { include: ['allowableOperations'] })
- .then((nodeEntry: NodeEntry) => {
- this.sidebarLeftTemplateContext.node = nodeEntry.entry;
- });
- }
- }
-
- private getDisplayName(name) {
- return this.displayName || name;
- }
scrollTop() {
window.scrollTo(0, 1);
}
- getViewerTypeByMimeType(mimeType: string) {
- if (mimeType) {
- mimeType = mimeType.toLowerCase();
-
- const editorTypes = Object.keys(this.mimeTypes);
- for (const type of editorTypes) {
- if (this.mimeTypes[type].indexOf(mimeType) >= 0) {
- return type;
- }
- }
- }
- return 'unknown';
- }
-
- getViewerTypeByExtension(extension: string): string {
- if (extension) {
- extension = extension.toLowerCase();
- }
-
- if (this.isExternalViewer()) {
- return 'external';
- }
-
- if (this.isCustomViewerExtension(extension)) {
- return 'custom';
- }
-
- if (this.extensions.image.indexOf(extension) >= 0) {
- return 'image';
- }
-
- if (this.extensions.media.indexOf(extension) >= 0) {
- return 'media';
- }
-
- if (this.extensions.text.indexOf(extension) >= 0) {
- return 'text';
- }
-
- if (this.extensions.pdf.indexOf(extension) >= 0) {
- return 'pdf';
- }
-
- return 'unknown';
- }
-
onBackButtonClick() {
this.close();
}
- onNavigateBeforeClick(event: MouseEvent | KeyboardEvent) {
- this.navigateBefore.next(event);
- }
-
- onNavigateNextClick(event: MouseEvent | KeyboardEvent) {
- this.navigateNext.next(event);
- }
/**
* close the viewer
@@ -605,50 +262,6 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
this.showViewerChange.emit(this.showViewer);
}
- /**
- * get File name from url
- *
- * @param url - url file
- */
- getFilenameFromUrl(url: string): string {
- const anchor = url.indexOf('#');
- const query = url.indexOf('?');
- const end = Math.min(
- anchor > 0 ? anchor : url.length,
- query > 0 ? query : url.length);
- return url.substring(url.lastIndexOf('/', end) + 1, end);
- }
-
- /**
- * Get file extension from the string.
- * Supports the URL formats like:
- * http://localhost/test.jpg?cache=1000
- * http://localhost/test.jpg#cache=1000
- *
- * @param fileName - file name
- */
- getFileExtension(fileName: string): string {
- if (fileName) {
- const match = fileName.match(/\.([^\./\?\#]+)($|\?|\#)/);
- return match ? match[1] : null;
- }
- return null;
- }
-
- private isExternalViewer(): boolean {
- return !!this.viewerExtensions.find(ext => ext.fileExtension === '*');
- }
-
- isCustomViewerExtension(extension: string): boolean {
- const extensions = this.externalExtensions || [];
-
- if (extension && extensions.length > 0) {
- extension = extension.toLowerCase();
- return extensions.flat().indexOf(extension) >= 0;
- }
-
- return false;
- }
/**
* Keyboard event listener
@@ -663,18 +276,6 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
const key = event.keyCode;
- // Left arrow
- if (key === 37 && this.canNavigateBefore) {
- event.preventDefault();
- this.onNavigateBeforeClick(event);
- }
-
- // Right arrow
- if (key === 39 && this.canNavigateNext) {
- event.preventDefault();
- this.onNavigateNextClick(event);
- }
-
// Ctrl+F
if (key === 70 && event.ctrlKey) {
event.preventDefault();
@@ -684,12 +285,7 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
printContent() {
if (this.allowPrint) {
- const args = new BaseEvent();
- this.print.next(args);
-
- if (!args.defaultPrevented) {
- this.viewUtilService.printFileGeneric(this.nodeId, this.mimeType);
- }
+ this.print.next(new BaseEvent());
}
}
@@ -713,27 +309,6 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
}
}
- private async displaySharedLinkRendition(sharedId: string) {
- try {
- const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'pdf');
- if (rendition.entry.status.toString() === 'CREATED') {
- this.viewerType = 'pdf';
- this.urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'pdf');
- }
- } catch (error) {
- this.logService.error(error);
- try {
- const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'imgpreview');
- if (rendition.entry.status.toString() === 'CREATED') {
- this.viewerType = 'image';
- this.urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'imgpreview');
- }
- } catch (renditionError) {
- this.logService.error(renditionError);
- }
- }
- }
-
checkExtensions(extensionAllowed) {
if (typeof extensionAllowed === 'string') {
return this.extension.toLowerCase() === extensionAllowed.toLowerCase();
@@ -743,21 +318,7 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
}
onSubmitFile(newImageBlob: Blob) {
- if (this?.nodeEntry?.entry?.id && !this.readOnly) {
- const newImageFile: File = new File([newImageBlob], this?.nodeEntry?.entry?.name, { type: this?.nodeEntry?.entry?.content?.mimeType });
- const newFile = new FileModel(
- newImageFile,
- {
- majorVersion: false,
- newVersion: true,
- parentId: this?.nodeEntry?.entry?.parentId,
- nodeType: this?.nodeEntry?.entry?.content?.mimeType
- },
- this?.nodeEntry?.entry?.id
- );
- this.uploadService.addToQueue(...[newFile]);
- this.uploadService.uploadFilesInTheQueue();
- }
+ this.submitFile.next(newImageBlob);
}
onUnsupportedFile() {
@@ -788,7 +349,4 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
});
}
- private generateCacheBusterNumber() {
- this.cacheBusterNumber = Date.now();
- }
}
diff --git a/lib/core/src/lib/viewer/services/rendition-viewer.service.ts b/lib/core/src/lib/viewer/services/rendition-viewer.service.ts
new file mode 100644
index 0000000000..22144afc92
--- /dev/null
+++ b/lib/core/src/lib/viewer/services/rendition-viewer.service.ts
@@ -0,0 +1,288 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * 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 { Injectable } from '@angular/core';
+import { ContentApi, RenditionEntry, RenditionPaging, RenditionsApi, VersionsApi } from '@alfresco/js-api';
+import { AlfrescoApiService } from '../../services/alfresco-api.service';
+import { LogService } from '../../services/log.service';
+import { Track } from '../models/viewer.model';
+import { TranslationService } from '../../services/translation.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class RenditionViewerService {
+
+ /**
+ * Content groups based on categorization of files that can be viewed in the web browser. This
+ * implementation or grouping is tied to the definition the ng component: ViewerComponent
+ */
+ static ContentGroup = {
+ IMAGE: 'image',
+ MEDIA: 'media',
+ PDF: 'pdf',
+ TEXT: 'text'
+ };
+
+ /**
+ * The name of the rendition with the media subtitles in the supported format
+ */
+ static SUBTITLES_RENDITION_NAME = 'webvtt';
+
+ /**
+ * Based on ViewerComponent Implementation, this value is used to determine how many times we try
+ * to get the rendition of a file for preview, or printing.
+ */
+ maxRetries = 5;
+
+ /**
+ * Mime-type grouping based on the ViewerComponent.
+ */
+ 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']
+ };
+
+ /**
+ * Timeout used for setInterval.
+ */
+ private TRY_TIMEOUT: number = 10000;
+
+
+ _renditionsApi: RenditionsApi;
+ get renditionsApi(): RenditionsApi {
+ this._renditionsApi = this._renditionsApi ?? new RenditionsApi(this.apiService.getInstance());
+ return this._renditionsApi;
+ }
+
+ _contentApi: ContentApi;
+ get contentApi(): ContentApi {
+ this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance());
+ return this._contentApi;
+ }
+
+ _versionsApi: VersionsApi;
+ private DEFAULT_RENDITION: string = 'imgpreview';
+
+ get versionsApi(): VersionsApi {
+ this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance());
+ return this._versionsApi;
+ }
+
+ constructor(private apiService: AlfrescoApiService,
+ private logService: LogService,
+ private translateService: TranslationService) {
+ }
+
+
+ getRenditionUrl(nodeId: string, type: string, renditionExists: boolean): string {
+ return (renditionExists && type !== RenditionViewerService.ContentGroup.IMAGE) ?
+ this.contentApi.getRenditionUrl(nodeId, RenditionViewerService.ContentGroup.PDF) :
+ this.contentApi.getContentUrl(nodeId, false);
+ }
+
+ private async waitRendition(nodeId: string, renditionId: string, retries: number): Promise {
+ const rendition = await this.renditionsApi.getRendition(nodeId, renditionId);
+
+ if (this.maxRetries < retries) {
+ const status = rendition.entry.status.toString();
+
+ if (status === 'CREATED') {
+ return rendition;
+ } else {
+ retries += 1;
+ await this.wait(1000);
+ return this.waitRendition(nodeId, renditionId, retries);
+ }
+ }
+
+ return Promise.resolve(null);
+ }
+
+ getViewerTypeByMimeType(mimeType: string): string {
+ if (mimeType) {
+ mimeType = mimeType.toLowerCase();
+
+ const editorTypes = Object.keys(this.mimeTypes);
+ for (const type of editorTypes) {
+ if (this.mimeTypes[type].indexOf(mimeType) >= 0) {
+ return type;
+ }
+ }
+ }
+ return 'unknown';
+ }
+
+ private wait(ms: number): Promise {
+ return new Promise((resolve) => setTimeout(resolve, ms));
+ }
+
+ async getRendition(nodeId: string, renditionId: string): Promise {
+ const renditionPaging: RenditionPaging = await this.renditionsApi.listRenditions(nodeId);
+ let rendition: RenditionEntry = renditionPaging.list.entries.find((renditionEntry: RenditionEntry) => renditionEntry.entry.id.toLowerCase() === renditionId);
+
+ if (rendition) {
+ const status = rendition.entry.status.toString();
+
+ if (status === 'NOT_CREATED') {
+ try {
+ await this.renditionsApi.createRendition(nodeId, {id: renditionId});
+ rendition = await this.waitRendition(nodeId, renditionId, 0);
+ } catch (err) {
+ this.logService.error(err);
+ }
+ }
+ }
+ return new Promise((resolve) => resolve(rendition));
+ }
+
+ async getNodeRendition(nodeId: string, versionId?: string): Promise<{ url: string, viewerType: string }> {
+ try {
+ return versionId ? await this.resolveNodeRendition(nodeId, 'pdf', versionId) :
+ await this.resolveNodeRendition(nodeId, 'pdf');
+ } catch (err) {
+ this.logService.error(err);
+ return null;
+ }
+ }
+
+ private async resolveNodeRendition(nodeId: string, renditionId: string, versionId?: string): Promise<{ url: string, viewerType: string }> {
+ renditionId = renditionId.toLowerCase();
+
+ const supportedRendition: RenditionPaging = versionId ? await this.versionsApi.listVersionRenditions(nodeId, versionId) :
+ await this.renditionsApi.listRenditions(nodeId);
+
+ let rendition = this.findRenditionById(supportedRendition, renditionId);
+ if (!rendition) {
+ renditionId = this.DEFAULT_RENDITION;
+ rendition = this.findRenditionById(supportedRendition, this.DEFAULT_RENDITION);
+ }
+
+ if (rendition) {
+ const status: string = rendition.entry.status.toString();
+
+ if (status === 'NOT_CREATED') {
+ return this.requestCreateRendition(nodeId, renditionId, versionId);
+ } else {
+ return this.handleNodeRendition(nodeId, renditionId, versionId);
+ }
+ }
+
+ return null;
+ }
+
+ private async requestCreateRendition(nodeId: string, renditionId: string, versionId: string) {
+ try {
+ if (versionId) {
+ await this.versionsApi.createVersionRendition(nodeId, versionId, {id: renditionId})
+ } else {
+ await this.renditionsApi.createRendition(nodeId, {id: renditionId});
+ }
+ try {
+ return versionId ? await this.waitNodeRendition(nodeId, renditionId, versionId) : await this.waitNodeRendition(nodeId, renditionId);
+ } catch (e) {
+ return null;
+ }
+
+ } catch (err) {
+ this.logService.error(err);
+ return null;
+ }
+ }
+
+ private findRenditionById(supportedRendition: RenditionPaging, renditionId: string) {
+ let rendition: RenditionEntry = supportedRendition.list.entries.find((renditionEntry: RenditionEntry) => renditionEntry.entry.id.toLowerCase() === renditionId);
+ return rendition;
+ }
+
+ private async waitNodeRendition(nodeId: string, renditionId: string, versionId?: string): Promise<{ url: string, viewerType: string }> {
+ let currentRetry: number = 0;
+ return new Promise<{ url: string, viewerType: string }>((resolve, reject) => {
+ const intervalId = setInterval(() => {
+ currentRetry++;
+ if (this.maxRetries >= currentRetry) {
+ if (versionId) {
+ this.versionsApi.getVersionRendition(nodeId, versionId, renditionId).then((rendition: RenditionEntry) => {
+ const status: string = rendition.entry.status.toString();
+
+ if (status === 'CREATED') {
+ clearInterval(intervalId);
+ return resolve(this.handleNodeRendition(nodeId, renditionId, versionId));
+ }
+ }, () => reject());
+ } else {
+ this.renditionsApi.getRendition(nodeId, renditionId).then((rendition: RenditionEntry) => {
+ const status: string = rendition.entry.status.toString();
+
+ if (status === 'CREATED') {
+ clearInterval(intervalId);
+ return resolve(this.handleNodeRendition(nodeId, renditionId, versionId));
+ }
+ }, () => reject());
+ }
+ } else {
+ clearInterval(intervalId);
+ return reject();
+ }
+ }, this.TRY_TIMEOUT);
+ });
+ }
+
+ private async handleNodeRendition(nodeId: string, renditionId: string, versionId?: string): Promise<{ url: string, viewerType: string }> {
+ let viewerType = '';
+
+ if (renditionId === 'pdf') {
+ viewerType = 'pdf';
+ } else if (renditionId === 'imgpreview') {
+ viewerType = 'image';
+ }
+
+ const url = versionId ? this.contentApi.getVersionRenditionUrl(nodeId, versionId, renditionId) :
+ this.contentApi.getRenditionUrl(nodeId, renditionId);
+
+ return {url, viewerType};
+ }
+
+ async generateMediaTracksRendition(nodeId: string): Promise