@rdkmaster/jigsaw-labs
Version:
Jigsaw, the next generation component set for RDK
198 lines (162 loc) • 6.13 kB
text/typescript
import {AbstractJigsawComponent} from "../common";
import {ElementRef, EventEmitter, Input, OnDestroy, Optional, Output, Renderer2} from "@angular/core";
import {HttpClient} from "@angular/common/http";
import {TranslateService} from "@ngx-translate/core";
export type UploadFileInfo = {
name: string, url: string, file: File, reason: string,
state: 'pause' | 'loading' | 'success' | 'error'
};
export class JigsawUploadBase extends AbstractJigsawComponent implements OnDestroy {
constructor( protected _http: HttpClient,
protected _renderer: Renderer2,
protected _elementRef: ElementRef,
protected _translateService: TranslateService) {
super();
}
public targetUrl: string = '/rdk/service/common/upload';
public fileType: string;
public multiple: boolean = true;
/**
* @internal
*
* 保持向下兼容,v1.2里删除这个事件
*/
public process: EventEmitter<UploadFileInfo>;
public progress = new EventEmitter<UploadFileInfo>();
public remove = new EventEmitter<UploadFileInfo>();
public complete = new EventEmitter<UploadFileInfo[]>();
public start = new EventEmitter<void>();
public update = new EventEmitter<UploadFileInfo[]>();
public _$uploadMode: 'select' | 'selectAndList' = 'select';
public _$fileInfoList: UploadFileInfo[] = [];
protected _fileInputEl: Element;
private _removeFileChangeEvent: Function;
/**
* @internal
*/
public _$selectFile($event) {
$event.preventDefault();
$event.stopPropagation();
let e = document.createEvent("MouseEvent");
e.initEvent("click", true, true);
if (!this._fileInputEl) {
this._fileInputEl = document.createElement('input');
this._fileInputEl.setAttribute('type', 'file');
}
if (this.multiple) {
this._fileInputEl.setAttribute('multiple', 'true');
} else {
this._fileInputEl.removeAttribute('multiple');
}
this._fileInputEl.setAttribute('accept', this.fileType);
this._removeFileChangeEvent = this._removeFileChangeEvent ? this._removeFileChangeEvent :
this._renderer.listen(this._fileInputEl, 'change', () => {
this._upload();
});
this._fileInputEl.dispatchEvent(e);
}
protected _upload(files?: FileList) {
if (!files) {
const fileInput = this._fileInputEl;
files = fileInput['files'];
}
if (!files || !files.length) {
console.warn('there are no upload files');
return;
}
let validFiles = this._filterValidFiles(Array.from(files));
this._$fileInfoList = this._filterValidFiles(this._$fileInfoList);
validFiles.forEach((file: File, index) => {
const fileInfo: UploadFileInfo = {
name: file.name, state: 'pause', url: '', file: file, reason: ''
};
if (this.multiple) {
this._$fileInfoList.push(fileInfo);
} else {
this._$fileInfoList = [fileInfo];
}
if (index < 5) {
this._sequenceUpload(fileInfo);
}
});
this._$uploadMode = 'selectAndList';
this.start.emit();
if (this._fileInputEl) {
this._fileInputEl['value'] = null;
}
}
private _filterValidFiles(files) {
if (!this.fileType) return files;
const fileTypes = this.fileType.split(',');
return files.filter(f =>
!!fileTypes.find(ft => new RegExp(`${ft.trim()}$`,'i').test(f.name)));
}
private _isAllFilesUploaded(): boolean {
return !this._$fileInfoList.find(f => f.state == 'loading' || f.state == 'pause');
}
private _sequenceUpload(fileInfo: UploadFileInfo) {
fileInfo.state = 'loading';
const formData = new FormData();
formData.append('file', fileInfo.file);
formData.append("filename", encodeURI(fileInfo.file.name));
if (!this._http) {
console.error('Jigsaw upload component must inject HttpClientModule, please import it to the module!');
return;
}
this._http.post(this.targetUrl, formData, {responseType: 'text'}).subscribe(res => {
fileInfo.state = 'success';
fileInfo.url = res;
fileInfo.reason = '';
this._afterCurFileUploaded(fileInfo);
}, (e) => {
fileInfo.state = 'error';
fileInfo.reason = this._translateService.instant(`upload.${e.statusText}`);
this._afterCurFileUploaded(fileInfo);
});
}
private _afterCurFileUploaded(fileInfo: UploadFileInfo) {
this.progress.emit(fileInfo);
if (this.process) {
this.process.emit(fileInfo);
}
const waitingFile = this._$fileInfoList.find(f => f.state == 'pause');
if (waitingFile) {
this._sequenceUpload(waitingFile)
} else if (this._isAllFilesUploaded()) {
this.complete.emit(this._$fileInfoList);
this.update.emit(this._$fileInfoList)
}
}
public _$removeFile(file) {
this.remove.emit(file);
const fileIndex = this._$fileInfoList.findIndex(f => f == file);
if (fileIndex == -1) return;
this._$fileInfoList.splice(fileIndex, 1);
if (this._isAllFilesUploaded()) {
this.update.emit(this._$fileInfoList);
}
if (this._fileInputEl) {
this._fileInputEl['value'] = null;
}
}
public clearFileList() {
this._$fileInfoList = [];
}
ngOnDestroy() {
super.ngOnDestroy();
if (this._removeFileChangeEvent) {
this._removeFileChangeEvent();
this._removeFileChangeEvent = null;
}
this._fileInputEl = null;
}
}