diff --git a/frontend/src/resources/template/ervu/component/FileUploadV2.html b/frontend/src/resources/template/ervu/component/FileUploadV2.html new file mode 100644 index 00000000..a8a4b0d4 --- /dev/null +++ b/frontend/src/resources/template/ervu/component/FileUploadV2.html @@ -0,0 +1,29 @@ +
+
+ {{selectFileFieldText}} + + +
+
+
+ {{item?.file?.name}} + {{item?.file?.size/1024/1024 | number: '.2'}} MB + +
+
+
+
+
+ +
\ No newline at end of file diff --git a/frontend/src/ts/ervu/component/fileupload/FileUploadV2.ts b/frontend/src/ts/ervu/component/fileupload/FileUploadV2.ts new file mode 100644 index 00000000..1a934dbc --- /dev/null +++ b/frontend/src/ts/ervu/component/fileupload/FileUploadV2.ts @@ -0,0 +1,184 @@ +import { + InputControl, + NotNull, + Visible, + Event, + MessagesService, + UnsupportedOperationError +} from "@webbpm/base-package"; +import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef} from "@angular/core"; +import {FileItem, FileUploader, ParsedResponseHeaders} from "ng2-file-upload"; +import {FileLikeObject} from "ng2-file-upload/file-upload/file-like-object.class"; + +@Component({ + moduleId: module.id, + selector: "file-upload-v2", + templateUrl: "./../../../../../src/resources/template/ervu/component/FileUploadV2.html", + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FileUploadV2 extends InputControl { + @NotNull("true") + public selectFileFieldText: string; + @NotNull("true") + public selectFileButtonName: string; + @NotNull("true") + public removeFileButtonName: string; + public maxFileSizeMb: number; + public extensionFilter: string[] = []; + public maxFilesToUpload: number; + @NotNull("true") + public displayFileSize: boolean = false; + @NotNull("true") + public displayProgressBar: boolean = false; + + @Visible("false") + public uploader: FileUploader; + @Visible("false") + public fileAddedEvent: Event = new Event(); + @Visible("false") + public fileDeletedEvent: Event = new Event(); + @Visible("false") + public fileUploadStartEvent: Event = new Event(); + @Visible("false") + public fileUploadEndEvent: Event = new Event(); + @Visible("false") + public fileUploadFailedEvent: Event = new Event(); + + private fileInputEl: any; + private url: string = '/files/upload'; + private messagesService: MessagesService; + + constructor(el: ElementRef, cd: ChangeDetectorRef) { + super(el, cd); + this.uploader = new FileUploader({url: this.url}); + } + + initialize() { + super.initialize(); + this.messagesService = this.injector.get(MessagesService); + + this.uploader.setOptions({ + url: this.url, + autoUpload: false, + filters: [{ + name: 'extension', + fn: (item: any): boolean => { + if (!this.extensionFilter.length) { + return true; + } + const fileExtension = item.name.substring(item.name.lastIndexOf('.') + 1, item.name.length); + for (let ext of this.extensionFilter) { + if (ext.toUpperCase() === fileExtension.toUpperCase()) { + return true; + } + } + return false; + } + }], + maxFileSize: this.maxFileSizeMb ? this.maxFileSizeMb * 1024 * 1024 : undefined, + queueLimit: this.maxFilesToUpload ? this.maxFilesToUpload : undefined + }); + + this.setUploaderMethods(); + } + + ngAfterViewInit() { + super.ngAfterViewInit(); + this.fileInputEl = $(this.el.nativeElement).find('.file-input'); + } + + openFileChooseDialog() { + this.fileInputEl.click(); + } + + @Visible() + uploadFiles() { + this.uploader.uploadAll(); + } + + removeFile(item: FileItem) { + item.remove(); + this.fileDeletedEvent.trigger(); + } + + private setUploaderMethods() { + this.uploader.onBeforeUploadItem = (fileItem: FileItem) => { + this.fileUploadStartEvent.trigger(); + }; + + this.uploader.onErrorItem = (item: FileItem, + response: string) => { + this.fileUploadFailedEvent.trigger(); + this.messagesService.error(`Не удалось отправить файл ${item.file.name}.`); + throw new Error(`Fail upload file ${item.file.name}: ${response}`); + }; + + this.uploader.onCompleteAll = () => { + this.fileUploadEndEvent.trigger(); + }; + + this.uploader.onAfterAddingFile = (fileItem: FileItem) => { + this.fileAddedEvent.trigger(); + } + + this.uploader.onWhenAddingFileFailed = (item: FileLikeObject, filter: any, options: any) => { + switch (filter.name) { + case "fileSize": + this.messagesService.error(`Размер файла ${item.name} превышает предельно допустимый = ${this.maxFileSizeMb} MB`); + break; + case "queueLimit": + this.messagesService.error(`Не удалось добавить файл ${item.name}. ` + + `Достигнуто максимальное количество файлов для загрузки = ${this.maxFilesToUpload}`); + break; + case "extension": + this.messagesService.error(`Файл ${item.name} имеет недопустимое расширение.`); + break; + default: + this.messagesService.error(`Не удалось добавить файл ${item.name}.`); + } + }; + } + + @Visible() + getExtensions(): string { + if (this.extensionFilter) { + return this.extensionFilter + .map(s => '.' + s) + .join(',') + } + return undefined; + } + + subscribeToModelChange() { + //empty because there is no ngModel here + } + + unsubscribeToModelChange() { + //empty because there is no ngModel here + } + + @Visible() + getPresentationValue(): string | number | boolean { + let fileNames: string = ''; + let fileItems: FileItem[] = this.uploader.queue; + if (fileItems) { + fileItems.forEach((fileItem) => { + fileNames += fileItem.file.name; + }); + } + return fileNames; + } + + @Visible() + getValue(): any { + return this.uploader.queue.map(fileItem => fileItem._file); + } + + getValueAsModel(): any { + throw new UnsupportedOperationError("Unsupported operation"); + } + + setValue(value: any): any { + throw new UnsupportedOperationError("Unsupported operation"); + } +} \ No newline at end of file diff --git a/frontend/src/ts/modules/app/app.module.ts b/frontend/src/ts/modules/app/app.module.ts index ae1e2be4..01ee3f50 100644 --- a/frontend/src/ts/modules/app/app.module.ts +++ b/frontend/src/ts/modules/app/app.module.ts @@ -31,6 +31,7 @@ import {ProcessListComponent} from "./component/process-list.component"; import {TaskComponent} from "./component/task.component"; import {TaskNotFoundComponent} from "./component/task-not-found.component"; import {FileUploadModule} from "ng2-file-upload"; +import {FileUploadV2} from "../../ervu/component/fileupload/FileUploadV2"; registerLocaleData(localeRu); export const DIRECTIVES = [ @@ -49,7 +50,8 @@ export const DIRECTIVES = [ forwardRef(() => TaskListComponent), forwardRef(() => ProcessListComponent), forwardRef(() => TaskComponent), - forwardRef(() => TaskNotFoundComponent) + forwardRef(() => TaskNotFoundComponent), + forwardRef(() => FileUploadV2) ]; @NgModule({