Skip to content

Instantly share code, notes, and snippets.

@JAndritsch
Created October 16, 2012 16:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JAndritsch/3900258 to your computer and use it in GitHub Desktop.
Save JAndritsch/3900258 to your computer and use it in GitHub Desktop.
jQuery File Uploader with nginx setup - Custom Example
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>jQuery File Upload Example</title>
<style>
table {
width: 90%;
border: 1px solid #ccc;
color: #888;
margin-top: 20px;
padding: 10px 0px 10px 0px;
}
tr {
height: 30px;
border-bottom: 1px solid #ccc;
}
td.filename {
width: 25%;
}
.bar {
background-color: green;
display: block;
text-align: center;
}
td.progress {
width: 20%;
border: 1px solid #ccc;
padding: 0px;
color: #fff;
font-weight: bold;
}
td.start {
width: 10%;
}
td.cancel {
width: 30%;
}
th {
text-align: left;
}
</style>
</head>
<body>
<input id="fileupload" type="file" name="files[]" data-url="http://localhost:8080/upload" multiple>
<button id="start_upload" type="button">Start uploads</button> &nbsp;
<button id="stop_uploads" type="button">Cancel all uploads</button>
&nbsp;&nbsp;&nbsp;&nbsp;<span>Total progress: <span id="total_progress">0%</span></span>
<table id="files">
</table>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="/blueimp/js/vendor/jquery.ui.widget.js"></script>
<script src="/blueimp/js/jquery.iframe-transport.js"></script>
<script src="/blueimp/js/jquery.fileupload.js"></script>
<script src="https://raw.github.com/carlo/jquery-base64/master/jquery.base64.min.js" type="text/javascript"></script>
<script>
$(function () {
// holds the files and their current state. storing the objects here allows me to easily set up start/stop controls rather
// than have the calls fire automatically when a file is added
var files = [];
var calculateProgress = function(data) {
var value = parseInt(data.loaded / data.total * 100, 10) || 0;
return value + "%";
};
var fileName = function(data) {
return data.files[0].name;
};
var uploadedFilePath = function(data) {
return JSON.parse(data.result)[".path"];
};
var cancelUpload = function(index) {
if (files[index]) {
files[index].jqXHR.abort();
}
};
var startUpload = function(index) {
// starts the upload for file at "index". If the context for this object has "uploadedBytes",
// the upload will continue from the previous range rather than start over completely
var data = files[index];
var context = data.context;
data.uploadedBytes = parseInt($(context).attr("uploadedBytes"), 10);
data.data = null;
$(data).submit();
};
var cancelAllUploads = function() {
$(files).each(function(index, file) {
cancelUpload(index);
});
};
var startAllUploads = function() {
$(files).each(function(index, data) {
startUpload(index);
});
};
var createProgressBar = function(progress) {
return '<span class="bar" style="width: ' + progress + '">' + progress + '</span>';
};
var maxChunkSize = 500000;
$('#fileupload').fileupload({
maxChunkSize: maxChunkSize,
multipart: false,
add: function (e, data) {
var progress = calculateProgress(data);
var filename = fileName(data);
var index = $("#files tr").length;
var cancelButton = $('<button type="button" data-file="' + index + '">Cancel upload</button>');
var startButton = $('<button type="button" data-file="' + index + '">Start upload</button>');
cancelButton.click(function() {
cancelUpload($(this).attr("data-file"));
});
startButton.click(function() {
startUpload($(this).attr("data-file"));
});
var row = $('<tr><td class="filename"></td><td class="progress"></td><td class="start"></td><td class="cancel"></td>');
var sessionID = new Date().getTime() + '_' + $.base64.encode(filename).replace(/\+|=|\//g, '');
$(row).find(".filename").text(filename);
$(row).find(".progress").html(createProgressBar(progress));
$(row).find(".start").append(startButton);
$(row).find(".cancel").append(cancelButton);
$(row).attr("sessionID", sessionID);
$(row).appendTo("#files");
data.context = row; // assign the row to the context
files.push(data); // add the object to our files container
},
done: function(e, data) {
// Just a simple method for displaying the path to the uploaded file
var pattern = new RegExp(/[a-zA-Z0-9]\/\w*$/);
var file = uploadedFilePath(data).match(pattern);
var filepath = '<a href="/images/' + file + '">' + file + '</a>';
data.context.find(".cancel").html(filepath);
},
progress: function(e, data) {
var progress = calculateProgress(data);
data.context.find(".progress").html(createProgressBar(progress));
},
progressall: function (e, data) {
var progress = calculateProgress(data);
$("#total_progress").text(progress);
},
beforeSend: function(e, files, index, xhr, handler, callback) {
var file = files.files[0];
var filename = file.name;
var filesize = file.size;
var context = files.context[0];
var sessionID = $(context).attr("sessionID");
var loaded = files.uploadedBytes;
var end;
// because chunks that are larger than the filesize don't automatically resize
if (filesize < maxChunkSize) {
end = filesize - 1;
} else {
end = (loaded + files.chunkSize - 1);
}
// nginx requires the Content-Range header, as well as a few others.
var contentRange = "bytes " + loaded + "-" + end + "/" + filesize;
// store the last range uploaded on the context for resuming the upload later
$(context).attr("uploadedBytes", files.uploadedBytes);
e.setRequestHeader('Content-Disposition', 'attachment; filename="' + sessionID + '.' + filename.split('.').pop() + '"');
e.setRequestHeader('Session-ID', sessionID);
e.setRequestHeader('Content-Range', contentRange);
e.setRequestHeader('X-Chunk-Index', files.chunkIndex);
e.setRequestHeader('X-Chunks-Number', files.chunksNumber);
}
});
$("#start_upload").click(function() {
startAllUploads();
});
$("#stop_uploads").click(function() {
cancelAllUploads();
});
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment