This is a variation of some code I stumbled upon some time ago, as an experiment to use the DND api and a progress bar. Hope it helps. The core functions for what you are looking for are ajaxSingleFileUpload
and handleFileSelect
.
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
.dropZone {
position: relative;
width: 200px;
height: 200px;
border-radius: 10px;
line-height: 200px;
text-align: center;
border: dotted 1px gray;
}
.dropZoneHover {
background: gray;
box-shadow: inset 1px 1px 5px gray;
}
.jsProgressBar{
border:solid 1px rgba(0,0,0,0.3);
height: 1em;
border-radius: 1em;
}
.jsProgress{
background-image: linear-gradient(90deg, rgba(255,0,0,0.5), rgba(0,255,0,0.5));
border-radius: 1em;
}
</style>
</head>
<body>
<div id="drop_zone" class="dropZone">Drop files here</div>
<output id="list"></output>
<script>
var $id = function (id) {return document.getElementById(id)};
Element.prototype.on = Element.prototype.addEventListener;
CSSStyleDeclaration.prototype.add=function(css){
var tmpCSS = this.cssText;
if(typeof css == 'object'){
for(var o in css){
if(Object.prototype.hasOwnProperty.call(css,o)){
tmpCSS+=';'+o+':'+css[o]+';';
}
}
}
else if(typeof css=='string'){
tmpCSS+=';'+css+';';
}
tmpCSS.replace(/;;;/gi,';').replace(/;;/gi,';');
this.cssText=tmpCSS;
};
Event.prototype.stop = function () {
this.stopPropagation();
this.preventDefault();
};
function changePercent(progressBar,val){ $id(progressBar).value(val); }
function ProgressBar(el,width){
el=$id(el);
el.classList.add("jsProgressBar");
var p=document.createElement('div');
var t=document.createElement('div');
var fh= Math.round(el.clientHeight*0.9)+'px';
el.style.add({
display: 'inline-block',
'box-shadow': 'inset 0 0 5px rgba(0,0,0,0.2)',
position: 'relative',
padding:0,
margin: '0 auto'
});
p.classList.add("jsProgress");
p.style.add({width:'0',height:'100%'});
t.style.add({width:'100%','text-align':'center',position:'absolute',top:0,bottom:0,left:0,'font-size':fh,'line-height':(el.clientHeight+'px'),'font-weight':'bold'});
el.appendChild(p);
el.appendChild(t);
el.value=function(val){
if(typeof val != 'undefined'){
val=(val>100)?100:(val<0)?0:val;
p.style.width=val+'%';
t.innerHTML=(val==0)?'':val+'%';
return el;
}
return t.innerHTML.replace(/%/g,'');
};
return el;
}
function _progressCallback(progressBar){
return function(evt){
var percent=(evt.loaded/evt.total *100);
changePercent(progressBar, Math.round(percent));
//$id('status').innerHTML = Math.round(percent)+'% uploaded... pleas wait';
}
}
function ajaxSingleFileUpload(url, fileData, successCallback, failCallback, progressCallback, abortCallback) {
var ajax = new XMLHttpRequest(), boundary = "FileUpload" + btoa("" + (Math.random()));
ajax.open('POST', url);
ajax.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
var blob = fileData.blob;//atob(fileData.blob.split(',')[1]);
var multipartHeader = ['--' ,
boundary ,
'
Content-Disposition: form-data; name="file"; filename="' ,
fileData.name ,
'"
Content-Type: ',
fileData.fileType,
'
'].join('');
var multipartTrailer = ['
--', boundary , '--
'].join('');
var iaHeader = new Uint8Array(multipartHeader.length);
for (var c = 0, l = multipartHeader.length; c < l; c++) {
iaHeader[c] = multipartHeader.charCodeAt(c);
}
multipartHeader=iaHeader;
if(!!progressCallback){ajax.upload.addEventListener('progress',progressCallback,false);}
if(!!successCallback){ajax.addEventListener('load',successCallback,false);}
if(!!failCallback){ajax.addEventListener('error',failCallback,false);}
if(!!abortCallback){ajax.addEventListener('abort',abortCallback,false);}
ajax.send(new Blob([multipartHeader,blob,multipartTrailer]));
}
function handleFileSelect(evt) {
evt.stop();
var files = evt.dataTransfer.files; // FileList object.
// files is a FileList of File objects. List some properties.
var output=[];
for (var i = 0, f; f = files[i]; i++) {
var fileReader = new FileReader();
fileReader.onload = (function (theFile, id) {
return function (e) {
var fileData = e.target.result,
xFile = {
name: theFile.name,
fileType: theFile.type,
blob: fileData
};
ajaxSingleFileUpload('fileUpload.php', xFile,undefined,undefined,_progressCallback('progress'+id));
var img = document.createElement('img');
img.title = theFile.name;
img.id = 'thumb' + id;
img.src = fileData;
if (img.width > img.height) {
img.style.width = (img.width > 60 ? '60' : img.width) + 'px';
}
else {
img.style.height = (img.height > 60 ? '60' : img.height) + 'px';
}
$id('list').insertBefore(img, null);
}
})(f, i);
fileReader.readAsArrayBuffer(f);
output.push('<div><strong>', f.name, '</strong> (', f.type || 'n/a', ') - ',
f.size, ' bytes, last modified: ',
f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
'</div><div id="progress'+i+'" style="width:200px;height:15px;"></div>');
}
document.getElementById('list').innerHTML = output.join('');
for(i=0;i<files.length;i++){
ProgressBar('progress'+i);
}
}
function handleDragOver(evt) {
evt.stop();
evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}
var dropZone = $id('drop_zone');
function handleDragOver2(evt) {
dropZone.classList.add('dropZoneHover');
}
function handleDragLeave2(evt) {
dropZone.classList.remove('dropZoneHover');
}
// Setup the dnd listeners.
dropZone.on('dragover', handleDragOver, false);
dropZone.on('dragover', handleDragOver2, false);
dropZone.on('dragleave', handleDragLeave2, false);
dropZone.on('drop', handleFileSelect, false);
dropZone.on('drop', handleDragLeave2, false);
</script>
</body>
</html>
And for the PHP side (you will have to modify the testUploads with the path you want):
<?php
$fileName=$_FILES['file']['name'];
$fileTmpLoc=$_FILES['file']['tmp_name'];
$fileType=$_FILES['file']['type'];
$fileSize=$_FILES['file']['error'];
if(!$fileTmpLoc){
//file not chosen
echo 'Error: Please browse for a file before clicking the upload button.';
exit();
}
if(move_uploaded_file($fileTmpLoc,"testUploads/$fileName")){
echo "$fileName upload is complete.";
}
else{
echo "Unable to save the file on the server.";
}