2024-09-22 03:35:12 -04:00
|
|
|
import {makeArray} from './array.ts';
|
2024-09-22 02:38:13 -04:00
|
|
|
import {JSONAttemptParse} from './objects.ts';
|
2024-07-19 09:02:42 -04:00
|
|
|
import {PromiseProgress} from './promise-progress';
|
2024-07-19 08:45:33 -04:00
|
|
|
|
2024-09-22 03:35:12 -04:00
|
|
|
/**
|
|
|
|
* Download blob as a file
|
|
|
|
*
|
|
|
|
* @param {Blob} blob File as a blob
|
|
|
|
* @param {string} name Name blob will be downloaded as
|
|
|
|
*/
|
|
|
|
export function downloadFile(blob: Blob | string | string[], name: string) {
|
|
|
|
if(!(blob instanceof Blob)) blob = new Blob(makeArray(blob));
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
downloadUrl(url, name);
|
|
|
|
URL.revokeObjectURL(url);
|
|
|
|
}
|
|
|
|
|
2024-09-22 02:38:13 -04:00
|
|
|
/**
|
|
|
|
* Download a file from a URL
|
|
|
|
*
|
|
|
|
* @param href URL that will be downloaded
|
|
|
|
* @param {string} name Override download name
|
|
|
|
*/
|
2024-09-22 03:35:12 -04:00
|
|
|
export function downloadUrl(href: any, name?: string) {
|
2024-07-19 08:45:33 -04:00
|
|
|
const a = document.createElement('a');
|
|
|
|
a.href = href;
|
2024-09-22 02:38:13 -04:00
|
|
|
a.download = name || href.split('/').pop();
|
2024-07-19 08:45:33 -04:00
|
|
|
document.body.appendChild(a);
|
|
|
|
a.click();
|
|
|
|
document.body.removeChild(a);
|
|
|
|
}
|
|
|
|
|
2024-09-22 02:38:13 -04:00
|
|
|
/**
|
|
|
|
* Open filebrowser & return selected file
|
|
|
|
*
|
|
|
|
* @param {{accept?: string, multiple?: boolean}} options accept - selectable mimetypes, multiple - Allow selecting more than 1 file
|
|
|
|
* @return {Promise<File[]>} Array of selected files
|
|
|
|
*/
|
2024-07-19 08:45:33 -04:00
|
|
|
export function fileBrowser(options: {accept?: string, multiple?: boolean} = {}): Promise<File[]> {
|
|
|
|
return new Promise(res => {
|
|
|
|
const input = document.createElement('input');
|
|
|
|
input.type = 'file';
|
|
|
|
input.accept = options.accept || '*';
|
|
|
|
input.style.display='none';
|
|
|
|
input.multiple = !!options.multiple;
|
|
|
|
input.onblur = input.onchange = async () => {
|
|
|
|
res(Array.from(<any>input.files));
|
|
|
|
input.remove();
|
|
|
|
}
|
|
|
|
document.body.appendChild(input);
|
|
|
|
input.click();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-11-09 15:35:05 -05:00
|
|
|
/**
|
|
|
|
* Extract text from a file
|
|
|
|
*
|
|
|
|
* @param file File to extract text from
|
|
|
|
* @return {Promise<string | null>} File contents
|
|
|
|
*/
|
|
|
|
export function fileText(file: any): Promise<string | null> {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const reader = new FileReader();
|
|
|
|
reader.onload = () => resolve(<string>reader.result);
|
|
|
|
reader.onerror = () => reject(reader.error);
|
|
|
|
reader.readAsText(file);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-09-22 02:38:13 -04:00
|
|
|
/**
|
|
|
|
* Create timestamp intended for filenames from a date
|
|
|
|
*
|
|
|
|
* @param {string} name Name of file, `{{TIMESTAMP}}` will be replaced
|
|
|
|
* @param {Date | number | string} date Date to use for timestamp
|
|
|
|
* @return {string} Interpolated filename, or the raw timestamp if name was omitted
|
|
|
|
*/
|
|
|
|
export function timestampFilename(name?: string, date: Date | number | string = new Date()) {
|
|
|
|
if(typeof date == 'number' || typeof date == 'string') date = new Date(date);
|
|
|
|
const timestamp = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}_${date.getHours().toString().padStart(2, '0')}-${date.getMinutes().toString().padStart(2, '0')}-${date.getSeconds().toString().padStart(2, '0')}`;
|
|
|
|
return name ? name.replace('{{TIMESTAMP}}', timestamp) : timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Upload file to URL with progress callback using PromiseProgress
|
|
|
|
*
|
|
|
|
* @param {{url: string, files: File[], headers?: {[p: string]: string}, withCredentials?: boolean}} options
|
|
|
|
* @return {PromiseProgress<T>} Promise of request with `onProgress` callback
|
|
|
|
*/
|
2024-07-19 08:59:15 -04:00
|
|
|
export function uploadWithProgress<T>(options: {
|
2024-07-19 08:45:33 -04:00
|
|
|
url: string;
|
2024-07-19 08:59:15 -04:00
|
|
|
files: File[];
|
2024-07-19 08:45:33 -04:00
|
|
|
headers?: {[key: string]: string};
|
|
|
|
withCredentials?: boolean;
|
2024-07-19 08:59:15 -04:00
|
|
|
}): PromiseProgress<T> {
|
|
|
|
return new PromiseProgress<T>((res, rej, prog) => {
|
2024-07-19 08:45:33 -04:00
|
|
|
const xhr = new XMLHttpRequest();
|
|
|
|
const formData = new FormData();
|
2024-07-19 08:59:15 -04:00
|
|
|
options.files.forEach(f => formData.append('file', f));
|
2024-07-19 08:45:33 -04:00
|
|
|
|
2024-08-17 14:21:05 -04:00
|
|
|
xhr.withCredentials = !!options.withCredentials;
|
2024-07-19 08:45:33 -04:00
|
|
|
xhr.upload.addEventListener('progress', (event) => event.lengthComputable ? prog(event.loaded / event.total) : null);
|
2024-08-17 14:21:05 -04:00
|
|
|
xhr.addEventListener('loadend', () => res(<T>JSONAttemptParse(xhr.responseText)));
|
|
|
|
xhr.addEventListener('error', () => rej(JSONAttemptParse(xhr.responseText)));
|
|
|
|
xhr.addEventListener('timeout', () => rej({error: 'Request timed out'}));
|
2024-07-19 08:45:33 -04:00
|
|
|
|
|
|
|
xhr.open('POST', options.url);
|
2024-07-19 10:16:31 -04:00
|
|
|
Object.entries(options.headers || {}).forEach(([key, value]) => xhr.setRequestHeader(key, value));
|
2024-07-19 08:45:33 -04:00
|
|
|
xhr.send(formData);
|
|
|
|
});
|
|
|
|
}
|