import { CancelToken } from "@web-atoms/core/dist/core/types"; import DISingleton from "@web-atoms/core/dist/di/DISingleton"; import { BaseService } from "@web-atoms/core/dist/services/http/RestService"; export interface ISelectFileOption { accept?: string; multiple?: boolean; } @DISingleton({}) export default class FileUploadService extends BaseService { public async selectFile({ accept, multiple }: ISelectFileOption = {}): Promise { const input = document.createElement("input"); input.type = "file"; input.style.position = "absolute"; input.style.left = "-100px"; input.style.top = "-100px"; if (accept) { input.accept = accept; } if (multiple) { input.multiple = multiple; } document.body.appendChild(input); return new Promise((resolve, reject) => { input.onchange = () => { setTimeout(() => { input.onchange = null; input.remove(); }, 100); const files = input.files; if (files && files.length) { const r = []; for (let i = 0; i < files.length; i ++) { r.push(files.item(i)); } resolve(r); } else { reject(); } }; input.click(); }); } public async saveContent(content: string): Promise { const fd = new FormData(); const b = new Blob([content], { type: "text/plain" } ); fd.append("a.txt", b, "a.txt"); const rs = await fetch("/api/tmp", { method: "POST", body: fd }); if (rs.status > 300) { throw new Error(await rs.text()); } const data = await rs.json(); return data[0]; } public async saveTemp(path: string): Promise { if (path.startsWith("https://")) { return path; } const fileName = path.split("/").pop(); let rs = await fetch(path); let data = await rs.blob(); const fd = new FormData(); fd.append(fileName, data, fileName); rs = await fetch("/api/tmp", { method: "POST", body: fd }); if (rs.status > 300) { throw new Error(await rs.text()); } data = await rs.json(); return data[0]; } public uploadAsync( files: File[], progress: ((sent: number, size: number) => void), ct: CancelToken): Promise { return new Promise((resolve, reject) => { const xhr: XMLHttpRequest = new XMLHttpRequest(); const upload: XMLHttpRequestUpload = xhr.upload; try { xhr.timeout = 3600000; } catch (e) { // tslint:disable-next-line:no-console console.error(e); } if (progress) { upload.addEventListener("progress", (evt: ProgressEvent) => { if (evt.lengthComputable) { progress(evt.loaded, evt.total); } }); } upload.addEventListener("timeout", (evt) => { reject("timeout"); }); upload.addEventListener("abort", (evt) => { reject("abort"); }); upload.addEventListener("error", (evt) => { reject(evt); }); xhr.addEventListener("timeout", (evt) => { reject("timeout"); }); xhr.addEventListener("abort", (evt) => { reject("abort"); }); xhr.addEventListener("error", (evt) => { reject(evt); }); xhr.addEventListener("load", (evt) => { if (xhr.status < 300) { resolve(JSON.parse(xhr.responseText)); } else { reject(xhr.responseText || `Upload error ${xhr.status}`); } }); xhr.open("POST", "/api/tmp"); const fd = new FormData(); for (const file of files as any as File[]) { fd.append(file.name, file, file.name); } xhr.send(fd); if (ct) { ct.registerForCancel(() => { xhr.abort(); }); } }); } }