JSFiddle - React, Tailwind, and code Playground
by Joe
HTML
<main>
<section>
<div id="drop-area">
<form class="my-form" enctype="multipart/form-data">
<p>
You can drag an drop multiple files onto this area to upload them.
</p>
<input type="file" id="fileElem" multiple accept="image/*" onchange="handleFiles(this.files)">
<label for="fileElem" class="button">
Select some files
</label>
<progress id="progress-bar" max=100 value=0></progress>
<div id="gallery"></div>
</form>
</div>
<p id="formError"></p>
</section>
</main>
CSS
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
font-size: 18px;
height: 100%;
overflow: hidden;
}
body {
background-color: #d9d9d9;
font-family: Helvetica;
}
header,
footer {
background-color: #000000;
height: 20vh;
padding: 7vh 10vw;
box-shadow: 0 0 5px 5px;
}
header h1 {
color: #ffffff;
margin: 0;
padding: 0;
}
footer {
height: 10vh;
padding: 1vh 3vw;
}
footer small {
color: #ffffff;
font-size: 12px;
}
footer a {
color: #dfdfdf;
}
main {
height: 70vh;
padding-top: 10vh;
}
#drop-area {
border: 2px dashed #ccc;
border-radius: 10px;
width: 80vw;
max-width: 480px;
font-family: sans-serif;
margin: auto;
padding: 20px;
}
#drop-area.highlight {
border-color: purple;
}
p {
margin: 0;
}
p#formError {
visibility: hidden;
background-color: #cc0000;
border-radius: 6px;
color: #ffffff;
text-align: center;
padding: 8px 0;
width: 80vw;
max-width: 480px;
margin: 1rem auto 0;
}
.my-form {
margin-bottom: 10px;
}
#progress-bar {
display: block;
margin: 1rem auto 0;
width: 90%;
}
#gallery {
margin-top: 10px;
}
#gallery img {
width: 150px;
margin-bottom: 10px;
margin-right: 10px;
vertical-align: middle;
}
.button {
display: inline-block;
padding: 10px;
background: #ccc;
cursor: pointer;
border-radius: 5px;
border: 1px solid #ccc;
}
.button:hover {
background: #ddd;
}
#fileElem {
display: none;
}
JavaScript
let filesDone = 0;
let filesToDo = 0;
let uploadProgress = [];
let progressBar = document.getElementById("progress-bar");
const dropArea = document.getElementById("drop-area");
const preventDefaults = e => {
e.preventDefault();
e.stopPropagation();
};
const highlight = e => {
dropArea.classList.add("highlight");
};
const unhighlight = e => {
dropArea.classList.remove("highlight");
};
const handleDrop = e => {
// shorthand version
// ([...e.dataTransfer.files]).forEach((file)=>{console.log("file...",file)});
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
};
const handleFiles = files => {
const filesArray = [...files];
initializeProgress(filesArray.length);
filesArray.forEach(uploadFile);
filesArray.forEach(previewFile);
};
const uploadFile = (file, i) => {
const url = "http://uploader.localhost/uploadMe.php";
let xhr = new XMLHttpRequest();
let formData = new FormData();
xhr.open("POST", url, true);
xhr.upload.addEventListener("progress", e => {
updateProgress(i, (e.loaded * 100.0 / e.total) || 100);
});
xhr.addEventListener(
"readystatechange",
function(resp) {
if (xhr.readyState == 4 && xhr.status == 200) {
// Upload correct
} else if (xhr.readyState == 4 && xhr.status != 200) {
let formError = document.getElementById("formError");
formError.innerHTML = "Sorry, but there was an error with the upload";
formError.style.visibility = "visible";
}
},
false
);
formData.append("file", file);
xhr.send(formData);
};
["dragenter", "dragover", "dragleave", "drop"].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false);
});
["dragenter", "dragover"].forEach(eventName => {
dropArea.addEventListener(eventName, highlight, false);
});
["dragleave", "drop"].forEach(eventName => {
dropArea.addEventListener(eventName, unhighlight, false);
});
dropArea.addEventListener("drop", handleDrop,...