/* as soon as all the elements of the page has been loaded */
document.addEventListener('DOMContentLoaded', function() {
/* we reference the most used elements into variables, making it easier to use later */
var dropzone = document.getElementById('dropzone'),
dialog = document.getElementById('dropzone-dialog'),
submit = document.getElementById('submit'),
progress = document.querySelector('progress'),
_current = null; // we keep track what file the user is changing its metadata
/* when the user drags something over our div, we must prevent the browser's default
behavior and we change a CSS class only for usability reasons */
dropzone.addEventListener('dragover', function(e) {
e.preventDefault();
dropzone.classList.add('dragging');
});
/* when the user leaves our div, we must remove the CSS class we put before */
dropzone.addEventListener('dragleave', function(e) {
e.preventDefault();
dropzone.classList.remove('dragging');
});
/* that's the heart of our code,
when the user effectively drops one or more files into the div */
dropzone.addEventListener('drop', function(e) {
/* again we must prevent the default browser's behavior,
and we need to remove the CSS clas we put before */
e.preventDefault();
dropzone.classList.remove('dragging');
submit.classList.add('hidden');
/* we change our div's text */
dropzone.textContent = 'File(s) dropped:';
/* we create an UL element, so we can loop through the files make a list */
var ul = document.createElement('ul');
/* since the files property is not an array, but it is Array-like,
we call the Array.prototype.forEach method passing the files to be the context */
[].forEach.call(e.dataTransfer.files, function(file) {
/* for each file the user has dropped, we create a LI and an anchor inside it */
var li = document.createElement('li');
var a = document.createElement('a');
a.href = '#';
a.textContent = file.name;
a.title = 'Enter metadata';
/* we create a property __file into our anchor to reference the dropped file */
a.__file = file;
li.appendChild(a);
ul.appendChild(li);
});
dropzone.appendChild(ul);
});
/* here, we add a 'click' event handler to our div dropzone,
so we can add the file's metadata behavior.
the idea here is to make an event delegation, that is, when the user clicks anywhere
inside the div, we see if the element that was clicked is one of the files */
dropzone.addEventListener('click', function(e) {
var el = e.target;
/* if the element clicked is an anchor, it's because it's one of the files */
if (el.tagName === 'A') {
/* we prevent the browser's default behavior */
e.preventDefault();
/* we keep track that the current clicked file/anchor is the last clicked */
_current = el;
/* and then, we show our dialog, so the user can input the file's metadata */
dialog.classList.remove('hidden');
/* we set focus on the first element of the dialog, only for usability reasons */
dialog.querySelector('#name').focus();
}
});
/* we add an event handler to the dialog's close button,
so it can effectively close the dialog */
dialog.querySelector('.close').addEventListener('click', clearDialog);
/* this is the second heart of our code.
we add an event handler to the dialog's save button,
so it can handle the saving of metadata */
dialog.querySelector('#save').addEventListener('click', function() {
/* here you can add any validation you want, e.g: required fields, etc */
/* if everything was cool, we set a new property __dataFile to our anchor
so, we can save the metadata for future use (the form submission) */
_current.__dataFile = {
name: dialog.querySelector('#name').value,
category: dialog.querySelector('#category').value
/* put here any other metadata property you will save */
};
/* when the user saves the metadata, we add a CSS class only for usability reasons */
_current.classList.add('finished');
/* then, we keep track if there is any file with no metadata saved yet */
var btnsLeft = [].filter.call(dropzone.querySelectorAll('a'), function(el, i) {
return !('__dataFile' in el);
});
/* if all the files' metadatas have been saved, we show the submit button */
if (btnsLeft.length === 0)
submit.classList.remove('hidden');
/* and we clear/close our dialog */
clearDialog();
});
function clearDialog() {
/* when the dialog is closed, we set our current-clicked anchor to null */
_current = null;
/* we clean all the input fields of the dialog */
[].forEach.call(dialog.querySelectorAll('input'), function(el, i) {
el.value = '';
});
/* and we effectively hide/close the dialog */
dialog.classList.add('hidden');
}
/* this is third heart of our code.
we add a click event handler to our submit button,
so we can effectively send our form to the server */
submit.querySelector('button').addEventListener('click', function(e) {
e.preventDefault(); // we must prevent the browser's default behavior
/* we create a XMLHttpRequest to send our AJAX to the server */
var xhr = new XMLHttpRequest();
/* we add a 'load' event handler, so we can keep track when the upload is finished */
xhr.addEventListener('load', finished);
/* we do the same for progress and error, so we can inform our user what's going on */
xhr.upload.addEventListener('progress', progress);
xhr.addEventListener('error', error);
/* now it's time to save all our data, so we create a FormData */
var fd = new FormData();
/* and for each anchor(file) inside our dropzone, we add new data to our FormData */
[].forEach.call(dropzone.querySelectorAll('a'), function(el, i) {
/* here we loop through our __dataFile previously created property,
so we can add the file's metadata parameter */
for (var prop in el.__dataFile) {
/* since we are sending multiple files/metadatas,
it's important to name our field with [] */
fd.append(prop + '[]', el.__dataFile[prop]);
}
/* and then, we append the file itself - again, with the [] at the end */
fd.append('file[]', e.__file);
});
/* now we open the xhr, and we effectively send the request to the server */
xhr.open('POST', '/api/uploadfiles/'); // change for your API URL
xhr.send(fd);
});
/* this is the xhr's progress, so we can update our HTMLProgressElement's percent */
function progress(e) {
progress.value = progress.innerHTML = (e.loaded/e.total * 100 | 0);
}
/* this is the xhr's finished event handler,
we show a friendly message and hide the submit button */
function finished(e) {
progress.value = progress.innerHTML = 100;
dropzone.innerHTML = '<h3>Files successfully uploaded</h3>';
submit.classList.add('hidden');
}
/* this is the xhr's error event handler. If there is any known error, we show it */
function error(e) {
var xhr = e.target;
submit.classList.add('hidden');
dropzone.innerHTML = '<h3>Error while uploading</h3>' +
(xhr.status ? '<span>' + xhr.status + ' - ' + xhr.statusText + '</span>' : '');
}
});
#dropzone {
width: 450px;
height: 165px;
background-color: #CCC;
font: 16px Verdana;
padding: 10px;
box-sizing: border-box;
}
#dropzone.dragging {
background-color: #EEE;
}
#dropzone > h3 {
text-align: center;
}
#dropzone a {
text-decoration: none;
}
#dropzone a:hover {
text-decoration: underline;
}
#dropzone a.finished:after {
content: ' √';
color: green;
font-weight: bold;
text-decoration: none;
}
#dropzone ul {
list-style: none;
margin-left: 15px;
padding: 0;
}
#dropzone li {
margin-top: 8px;
}
#dropzone li:before {
content: '> ';
}
.hidden {
display: none;
}
.dialog {
background-color: #AAAAFF;
font-family: Verdana;
padding: 12px;
border-radius: 10px;
width: 300px;
height: 150px;
position: absolute;
top: 20px;
}
.dialog h3 {
text-align: center;
}
.dialog .close {
text-decoration: none;
float: right;
}
.dialog .close:after {
content: '✖';
cursor: pointer;
}
.dialog > div {
display: table;
}
.dialog > div > div {
display: table-row;
}
.dialog > div > div > div,
.dialog > div > div > label {
display: table-cell;
padding: 2px 0 2px 10px;
}
#submit {
height: 160px;
width: 450px;
text-align: right;
position: fixed;
top: 10px;
}
#submit button {
font-size: 20px;
padding: 10px;
background-color: orange;
}
progress {
width: 450px;
}
<div id="dropzone">
<h3>Drop your files here</h3>
</div>
<div>
<progress min="0" max="100" value="0"></progress>
</div>
<div id="submit" class="hidden">
<button>Submit</button>
</div>
<div id="dropzone-dialog" class="dialog hidden">
<a class="close"></a>
<h3>File Metadata</h3>
<div>
<div>
<label for="name">
Name
</label>
<div>
<input id="name">
</div>
</div>
<div>
<label for="category">
Category
</label>
<div>
<input id="category">
</div>
</div>
<div>
<div></div>
<div style="text-align: right">
<button id="save">Save</button>
</div>
</div>
</div>
</div>
Sì, ho, Ma dobbiamo rispondere in base alla domanda :(questo è molto bello libreria con cui ho lavorato –
@AmirHosseinMehrvarzi Se ho compreso correttamente la tua domanda, sto vedendo che vuoi e rispondi che dice come farlo usando filedrop.js O anche qualsiasi libreria js di terze parti che abbia funzionalità simili? La mia risposta è stata sostanzialmente la seguente: tu usi dropzone.js invece di filedrop.js e sembra che tu abbia già lavorato con esso. Se stai cercando una soluzione "only" usando jquery-filedrop.js, ripeti la domanda a – vvs
@AmirHosseinMehrvarzi Appena realizzato OP, un'altra persona: OP vuole una risposta che dice come farlo utilizzando filedrop.js O anche qualsiasi libreria js di terze parti che ha funzionalità simili? La mia risposta è stata fondamentalmente affermativa che si utilizza dropzone.js anziché filedrop.js in quanto ha la funzionalità di interesse disponibile per impostazione predefinita. Sembra che tu abbia già lavorato con esso, quindi penso che tu possa aggiungere un po 'di colore alla risposta. Nel caso in cui OP stia cercando una soluzione "only" usando jquery-filedrop.js, suggerisco di riformulare la domanda per dirlo. – vvs