@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
177 lines (170 loc) • 13 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, Component, Inject, Input, EventEmitter, NgModule } from '@angular/core';
import * as i3 from '@c8y/ngx-components';
import { gettext, CoreModule, CommonModule } from '@c8y/ngx-components';
import * as i1 from 'ngx-bootstrap/modal';
import * as i2 from '@angular/platform-browser';
import { takeUntil, first } from 'rxjs/operators';
import { Subject } from 'rxjs';
import * as i4 from '@angular/common';
const PRODUCT_EXPERIENCE_FILE_PREVIEW = {
EVENTS: {
FILE_PREVIEW: 'filePreview'
},
COMPONENTS: {
FILE_PREVIEW_COMPONENT: 'file-preview'
},
ACTIONS: {
OPEN_PREVIEW: 'openPreview'
}
};
/**
* Provides InjectionToken used in FilePreviewModule. This token is used to inject EventEmitter instance, that is
* shared among all instances of FilePreviewComponent. These components communicate between each other using this
* emitter, which enables them to clear downloaded files from memory, if other instance of FilePreviewComponent
* started downloading different file. Value emitted by this EventEmitter is ID of downloaded file.
*/
const DOWNLOAD_EMITTER = new InjectionToken('downloadEmitter');
/**
* A component which shows a button that opens a modal with the preview of a binary managed object.
* This component requires CSP 'blob:' rule for img-src and media-src to be set.
*
* ```html
* <c8y-file-preview [mo]="managedObject">
* <button customButton>Preview</button>
* </c8y-file-preview>
* ```
* If no custom button provided, the component will use the default search icon button instead.
*
*/
class FilePreviewComponent {
set _mo(mo) {
this.mo = mo;
this.setContentType();
}
constructor(downloadEmitter, modalRef, modalService, sanitizer, filesService, alertService, gainsightService) {
this.downloadEmitter = downloadEmitter;
this.modalRef = modalRef;
this.modalService = modalService;
this.sanitizer = sanitizer;
this.filesService = filesService;
this.alertService = alertService;
this.gainsightService = gainsightService;
this.contentType = 'unsupported';
this.BUFFERING_STATUS_TEXT = gettext('{{speed}}/s - {{bufferedBytes}} of {{totalBytes}} buffered ({{percentage}}%)');
this.destroy$ = new Subject();
downloadEmitter.pipe(takeUntil(this.destroy$)).subscribe(id => {
if (this.dataUrl && this.mo.id !== id) {
this.removeDownloadedFile();
}
});
}
ngOnDestroy() {
this.removeDownloadedFile();
this.destroy$.next(true);
this.destroy$.complete();
}
async openModal(template) {
this.modalRef = this.modalService.show(template, {
ariaDescribedby: 'modal-body',
ariaLabelledBy: 'modal-title',
ignoreBackdropClick: true
});
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_FILE_PREVIEW.EVENTS.FILE_PREVIEW, {
component: PRODUCT_EXPERIENCE_FILE_PREVIEW.COMPONENTS.FILE_PREVIEW_COMPONENT,
action: PRODUCT_EXPERIENCE_FILE_PREVIEW.ACTIONS.OPEN_PREVIEW
});
if (this.dataUrl) {
return;
}
this.downloadEmitter.emit(this.mo.id);
const subscription = this.filesService
.fetchFileWithProgress$(this.mo)
.pipe(takeUntil(this.destroy$))
.subscribe(progress => {
this.progress = progress;
if (this.progress.blob) {
this.dataUrl = URL.createObjectURL(progress.blob);
this.safeDataUrl = this.sanitizer.bypassSecurityTrustUrl(this.dataUrl);
}
}, e => {
this.modalRef.hide();
this.alertService.addServerFailure(e);
});
this.modalRef.onHide.pipe(first(), takeUntil(this.destroy$)).subscribe(() => {
subscription.unsubscribe();
});
}
removeDownloadedFile() {
URL.revokeObjectURL(this.dataUrl);
delete this.dataUrl;
delete this.safeDataUrl;
}
setContentType() {
if (!this.mo || !this.mo.hasOwnProperty('c8y_IsBinary')) {
// eslint-disable-next-line no-console
console.warn('Provided Managed object is not binary');
this.contentType = 'unsupported';
return;
}
if (this.mo.contentType.startsWith('image/')) {
this.contentType = 'image';
}
else if (this.mo.contentType.startsWith('video/')) {
this.contentType = 'video';
}
else if (this.mo.contentType.startsWith('text/')) {
// @TODO: Implement in future
this.contentType = 'unsupported';
}
else if (this.mo.contentType.startsWith('application/json')) {
// @TODO: Implement in future
this.contentType = 'unsupported';
}
else {
this.contentType = 'unsupported';
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilePreviewComponent, deps: [{ token: DOWNLOAD_EMITTER }, { token: i1.BsModalRef }, { token: i1.BsModalService }, { token: i2.DomSanitizer }, { token: i3.FilesService }, { token: i3.AlertService }, { token: i3.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FilePreviewComponent, selector: "c8y-file-preview", inputs: { _mo: ["mo", "_mo"] }, ngImport: i0, template: "<div\n class=\"d-inline-block\"\n *ngIf=\"contentType !== 'unsupported'\"\n (click)=\"openModal(modalTemplate)\"\n>\n <div #customButtonRef>\n <ng-content select=\"[customButton]\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"!customButtonRef.children.length\">\n <button [title]=\"'Preview file' | translate\" type=\"button\" class=\"btn btn-default btn-icon\">\n <i c8yIcon=\"search\"></i>\n </button>\n </ng-container>\n</div>\n\n<ng-template #modalTemplate>\n <c8y-modal\n [title]=\"mo.name\"\n [customFooter]=\"false\"\n (onClose)=\"modalRef.hide()\"\n (onDismiss)=\"modalRef.hide()\"\n [labels]=\"{ cancel: '', ok: 'Close' | translate }\"\n class=\"text-break-word\"\n >\n <div class=\"text-center d-block\" *ngIf=\"!dataUrl\">\n <c8y-loading layout=\"application\" [progress]=\"progress.percentage\"></c8y-loading>\n {{\n BUFFERING_STATUS_TEXT\n | translate\n : {\n totalBytes: progress.totalBytes | bytes,\n bufferedBytes: progress.bufferedBytes | bytes,\n percentage: progress.percentage,\n speed: progress.bytesPerSecond | bytes\n }\n }}\n </div>\n\n <ng-container *ngIf=\"dataUrl\" [ngSwitch]=\"contentType\" id=\"modal-body\">\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"fit-w\" alt=\"safeDataUrl\" [src]=\"safeDataUrl\" />\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'video'\">\n <video controls autoplay class=\"fit-w\">\n <source [src]=\"safeDataUrl\" />\n {{ 'Your browser does not support the video tag.' | translate }}\n </video>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'text'\">\n <!-- @TODO: Implement text viewer-->\n text\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'json'\">\n <!-- @TODO: Implement json viewer-->\n json\n </ng-container>\n\n <ng-container *ngSwitchDefault></ng-container>\n </ng-container>\n </c8y-modal>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i4.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i4.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "component", type: i3.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i3.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.BytesPipe, name: "bytes" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilePreviewComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-file-preview', template: "<div\n class=\"d-inline-block\"\n *ngIf=\"contentType !== 'unsupported'\"\n (click)=\"openModal(modalTemplate)\"\n>\n <div #customButtonRef>\n <ng-content select=\"[customButton]\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"!customButtonRef.children.length\">\n <button [title]=\"'Preview file' | translate\" type=\"button\" class=\"btn btn-default btn-icon\">\n <i c8yIcon=\"search\"></i>\n </button>\n </ng-container>\n</div>\n\n<ng-template #modalTemplate>\n <c8y-modal\n [title]=\"mo.name\"\n [customFooter]=\"false\"\n (onClose)=\"modalRef.hide()\"\n (onDismiss)=\"modalRef.hide()\"\n [labels]=\"{ cancel: '', ok: 'Close' | translate }\"\n class=\"text-break-word\"\n >\n <div class=\"text-center d-block\" *ngIf=\"!dataUrl\">\n <c8y-loading layout=\"application\" [progress]=\"progress.percentage\"></c8y-loading>\n {{\n BUFFERING_STATUS_TEXT\n | translate\n : {\n totalBytes: progress.totalBytes | bytes,\n bufferedBytes: progress.bufferedBytes | bytes,\n percentage: progress.percentage,\n speed: progress.bytesPerSecond | bytes\n }\n }}\n </div>\n\n <ng-container *ngIf=\"dataUrl\" [ngSwitch]=\"contentType\" id=\"modal-body\">\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"fit-w\" alt=\"safeDataUrl\" [src]=\"safeDataUrl\" />\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'video'\">\n <video controls autoplay class=\"fit-w\">\n <source [src]=\"safeDataUrl\" />\n {{ 'Your browser does not support the video tag.' | translate }}\n </video>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'text'\">\n <!-- @TODO: Implement text viewer-->\n text\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'json'\">\n <!-- @TODO: Implement json viewer-->\n json\n </ng-container>\n\n <ng-container *ngSwitchDefault></ng-container>\n </ng-container>\n </c8y-modal>\n</ng-template>\n" }]
}], ctorParameters: () => [{ type: i0.EventEmitter, decorators: [{
type: Inject,
args: [DOWNLOAD_EMITTER]
}] }, { type: i1.BsModalRef }, { type: i1.BsModalService }, { type: i2.DomSanitizer }, { type: i3.FilesService }, { type: i3.AlertService }, { type: i3.GainsightService }], propDecorators: { _mo: [{
type: Input,
args: ['mo']
}] } });
const downloadEmitter = new EventEmitter();
class FilePreviewModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilePreviewModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: FilePreviewModule, declarations: [FilePreviewComponent], imports: [CoreModule, CommonModule], exports: [FilePreviewComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilePreviewModule, providers: [
{
provide: DOWNLOAD_EMITTER,
useValue: downloadEmitter
}
], imports: [CoreModule, CommonModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilePreviewModule, decorators: [{
type: NgModule,
args: [{
declarations: [FilePreviewComponent],
imports: [CoreModule, CommonModule],
exports: [FilePreviewComponent],
providers: [
{
provide: DOWNLOAD_EMITTER,
useValue: downloadEmitter
}
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { FilePreviewComponent, FilePreviewModule };
//# sourceMappingURL=c8y-ngx-components-file-preview.mjs.map