Skip to content

Instantly share code, notes, and snippets.

@meziantou
Created February 26, 2017 22:03
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save meziantou/935050b4fd415a9e45add91c68ca0c95 to your computer and use it in GitHub Desktop.
Save meziantou/935050b4fd415a9e45add91c68ca0c95 to your computer and use it in GitHub Desktop.
FileUpload (drag and drop files and directories, paste)
improveFileUpload();
function improveFileUpload() {
const input = document.getElementById("FileUpload");
if (!input) {
console.warn("input not found.");
return;
}
if (!(input instanceof HTMLInputElement)) {
console.warn("element is not an input element.");
return;
}
const dropZone = input;
if (dropZone) {
const hoverClassName = "hover";
// TODO replace with addEventListener
dropZone.addEventListener("dragenter", function (e) {
e.preventDefault();
dropZone.classList.add(hoverClassName);
});
dropZone.addEventListener("dragover", function (e) {
e.preventDefault();
dropZone.classList.add(hoverClassName);
});
dropZone.addEventListener("dragleave", function (e) {
e.preventDefault();
dropZone.classList.remove(hoverClassName);
});
dropZone.addEventListener("drop", async function (e) {
e.preventDefault();
dropZone.classList.remove(hoverClassName);
const files = await getFilesAsync(e.dataTransfer);
console.log(files);
});
}
dropZone.addEventListener("paste", async function (e) {
e.preventDefault();
const files = await getFilesAsync(e.clipboardData);
console.log(files);
});
}
async function getFilesAsync(dataTransfer: DataTransfer) {
const files: File[] = [];
for (let i = 0; i < dataTransfer.items.length; i++) {
const item = dataTransfer.items[i];
if (item.kind === "file") {
if (typeof item.webkitGetAsEntry === "function") {
const entry = item.webkitGetAsEntry();
const entryContent = await readEntryContentAsync(entry);
files.push(...entryContent);
continue;
}
const file = item.getAsFile();
if (file) {
files.push(file);
}
}
}
return files;
}
function readEntryContentAsync(entry: FileSystemEntry) {
return new Promise<File[]>((resolve, reject) => {
let reading = 0;
const contents: File[] = [];
readEntry(entry);
function readEntry(entry: FileSystemEntry) {
if (isFile(entry)) {
reading++;
entry.file(file => {
reading--;
contents.push(file);
if (reading === 0) {
resolve(contents);
}
});
} else if (isDirectory(entry)) {
readReaderContent(entry.createReader());
}
}
function readReaderContent(reader: FileSystemDirectoryReader) {
reading++;
reader.readEntries(function (entries) {
reading--;
for (const entry of entries) {
readEntry(entry);
}
if (reading === 0) {
resolve(contents);
}
});
}
});
}
function isDirectory(entry: FileSystemEntry): entry is FileSystemDirectoryEntry {
return entry.isDirectory;
}
function isFile(entry: FileSystemEntry): entry is FileSystemFileEntry {
return entry.isFile;
}
interface FileSystemEntry {
fullPath: string;
isFile: boolean;
isDirectory: boolean;
name: string;
getMetadata(successCallback: (metadata: Metadata) => void, errorCallback?: (error: FileError) => void): void;
}
interface FileSystemFileEntry extends FileSystemEntry {
file(successCallback: (file: File) => void, errorCallback?: (error: FileError) => void): void;
}
interface FileSystemDirectoryEntry extends FileSystemEntry {
createReader(): FileSystemDirectoryReader;
getDirectory(): FileSystemDirectoryEntry;
getFile(): FileSystemFileEntry;
}
interface DataTransferItem {
webkitGetAsEntry?(): FileSystemEntry;
}
interface FileSystemDirectoryReader {
readEntries(successCallback: (entries: FileSystemEntry[]) => void, errorCallback?: (error: FileError) => void): void;
}
interface Metadata {
modificationTime: Date;
size: number;
}
interface FileError extends Error {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment