easy-file-picker
Version:
Easy File Picker is a straightforward library with no dependencies to upload/pick/read files in the browser.
145 lines (144 loc) • 4.78 kB
JavaScript
export async function getFile(options) {
const fileInput = createFileInput(false, options);
const file = new Promise((resolve, reject) => {
fileInput.onchange = (event) => {
const files = convertFileListToFileArray(event.target?.files);
resolve(files[0]);
};
fileInput.oncancel = () => {
resolve(null);
};
fileInput.onerror = (_event, _source, _line, _col, error) => {
reject(error);
};
fileInput.click();
});
return file.finally(() => fileInput.remove());
}
export async function getFiles(options) {
const fileInput = createFileInput(true, options);
const files = new Promise((resolve, reject) => {
fileInput.onchange = (event) => {
const files = convertFileListToFileArray(event.target?.files);
resolve(files);
};
fileInput.oncancel = () => {
resolve([]);
};
fileInput.onerror = (_event, _source, _line, _col, error) => {
reject(error);
};
fileInput.click();
});
return files.finally(() => fileInput.remove());
}
export async function getFileAsString(options) {
const fileInput = createFileInput(false, options);
const file = new Promise((resolve, reject) => {
fileInput.onchange = (event) => {
const files = convertFileListToFileArray(event.target?.files);
convertFileArrayToFileStringArray(files)
.then((str) => resolve(str[0]))
.catch((err) => reject(err));
};
fileInput.oncancel = () => {
resolve(null);
};
fileInput.onerror = (_event, _source, _line, _col, error) => {
reject(error);
};
fileInput.click();
});
return file.finally(() => fileInput.remove());
}
export async function getFilesAsString(options) {
const fileInput = createFileInput(true, options);
const files = new Promise((resolve, reject) => {
fileInput.onchange = (event) => {
const files = convertFileListToFileArray(event.target?.files);
convertFileArrayToFileStringArray(files)
.then((str) => resolve(str))
.catch((err) => reject(err));
};
fileInput.oncancel = () => {
resolve([]);
};
fileInput.onerror = (_event, _source, _line, _col, error) => {
reject(error);
};
fileInput.click();
});
return files.finally(() => fileInput.remove());
}
export async function uploadFilesTo(url, files, methodOrInit = "POST") {
const formData = filesToFormData(files);
const init = typeof methodOrInit === "string"
? {
body: formData,
method: methodOrInit,
}
: {
body: formData,
...methodOrInit,
};
return fetch(url, init);
}
function filesToFormData(files) {
const formData = new FormData();
if (files instanceof File) {
formData.append("file0", files);
}
else if (Array.isArray(files)) {
files.forEach((file, i) => {
formData.append(`file${i}`, file);
});
}
else if (typeof files === "object" && files != null) {
Object.entries(files).forEach(([key, file]) => {
formData.append(key, file);
});
}
return formData;
}
function createFileInput(multipleFiles, options) {
const fileInput = document.createElement("input");
fileInput.hidden = true;
fileInput.type = "file";
fileInput.multiple = multipleFiles;
fileInput.accept = options?.acceptedExtensions?.join(",") ?? "";
return fileInput;
}
function convertFileListToFileArray(files) {
if (files == null) {
return [];
}
const fileArray = [];
for (let i = 0; i < files.length; i++) {
fileArray.push(files[i]);
}
return fileArray;
}
async function convertFileArrayToFileStringArray(files) {
const filePromises = [];
for (const file of files) {
const filePromise = new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => {
resolve({
name: file.name,
size: file.size,
type: file.type,
lastModified: file.lastModified,
webkitRelativePath: file.webkitRelativePath,
content: event.target?.result,
});
};
reader.onerror = () => {
reject(reader.error);
};
reader.readAsText(file, "utf-8");
});
filePromises.push(filePromise);
}
return Promise.all(filePromises);
}