UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

177 lines (170 loc) 13 kB
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