mirror of
https://github.com/onionshare/onionshare.git
synced 2025-05-04 07:25:10 -04:00
Refactor file upload interface to use jQuery, and to have separate upload progress bars. The progess bars make clear when the data has been sent to the first Tor node, and when its waiting on the rest of the Tor network. It also allows the sender to cancel uploads
This commit is contained in:
parent
7e709bb234
commit
2d78b545a5
5 changed files with 222 additions and 131 deletions
|
@ -1,94 +1,140 @@
|
|||
// Hide the noscript div, because our javascript is executing
|
||||
document.getElementById('noscript').style.display = 'none';
|
||||
$(function(){
|
||||
// Add a flash message
|
||||
var flash = function(category, message) {
|
||||
$('#flashes').append($('<li>').addClass(category).text(message));
|
||||
};
|
||||
|
||||
var form = document.getElementById('send');
|
||||
var fileSelect = document.getElementById('file-select');
|
||||
var uploadButton = document.getElementById('send-button');
|
||||
var flashes = document.getElementById('flashes');
|
||||
// Add an upload
|
||||
var new_upload_div = function(xhr, filenames) {
|
||||
/*
|
||||
The DOM for an upload looks something like this:
|
||||
|
||||
// Add a flash message
|
||||
function flash(category, message) {
|
||||
var el = document.createElement('li');
|
||||
el.innerText = message;
|
||||
el.className = category;
|
||||
flashes.appendChild(el);
|
||||
}
|
||||
<div class="upload">
|
||||
<div class="upload-meta">
|
||||
<input class="cancel" type="button" value="Cancel" />
|
||||
<div class="upload-filename">educational-video.mp4, secret-plans.pdf</div>
|
||||
<div class="upload-status">Sending to first Tor node ...</div>
|
||||
</div>
|
||||
<progress value="25" max="100"></progress>
|
||||
</div>
|
||||
*/
|
||||
var $progress = $('<progress>').attr({ value: '0', max: 100 });
|
||||
var $cancel_button = $('<input>').addClass('cancel').attr({ type: 'button', value: 'Cancel' });
|
||||
var $upload_filename = $('<div>').addClass('upload-filename').text(filenames.join(', '));
|
||||
var $upload_status = $('<div>').addClass('upload-status').text('Sending data to initial Tor node ...');
|
||||
|
||||
form.onsubmit = function(event) {
|
||||
event.preventDefault();
|
||||
var $upload_div = $('<div>').addClass('upload')
|
||||
.append(
|
||||
$('<div>').addClass('upload-meta')
|
||||
.append($cancel_button)
|
||||
.append($upload_filename)
|
||||
.append($upload_status)
|
||||
)
|
||||
.append($progress);
|
||||
|
||||
// Disable button, and update text
|
||||
uploadButton.innerHTML = 'Uploading ...';
|
||||
uploadButton.disabled = true;
|
||||
fileSelect.disabled = true;
|
||||
$cancel_button.click(function(){
|
||||
// Abort the upload, and remove the upload div
|
||||
xhr.abort();
|
||||
$upload_div.remove()
|
||||
});
|
||||
|
||||
// Create form data
|
||||
var files = fileSelect.files;
|
||||
var formData = new FormData();
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var file = files[i];
|
||||
formData.append('file[]', file, file.name);
|
||||
}
|
||||
return $upload_div;
|
||||
};
|
||||
|
||||
// Set up the request
|
||||
var ajax = new XMLHttpRequest();
|
||||
// Intercept submitting the form
|
||||
$('#send').submit(function(event){
|
||||
event.preventDefault();
|
||||
|
||||
ajax.upload.addEventListener('progress', function(event){
|
||||
console.log('upload progress', 'uploaded '+event.loaded+' bytes / '+event.total+' bytes');
|
||||
var percent = parseInt((event.loaded / event.total) * 100, 10);
|
||||
uploadButton.innerHTML = 'Uploading '+percent+'%';
|
||||
}, false);
|
||||
|
||||
ajax.addEventListener('load', function(event){
|
||||
console.log('upload finished', ajax.response);
|
||||
if(ajax.status == 200) {
|
||||
// Parse response
|
||||
try {
|
||||
var response = JSON.parse(ajax.response);
|
||||
|
||||
// The 'new_body' response replaces the whole HTML document and ends
|
||||
if('new_body' in response) {
|
||||
document.body.innerHTML = response['new_body'];
|
||||
return;
|
||||
}
|
||||
|
||||
// Show error flashes
|
||||
if('error_flashes' in response) {
|
||||
for(var i=0; i<response['error_flashes'].length; i++) {
|
||||
flash('error', response['error_flashes'][i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Show info flashes
|
||||
if('info_flashes' in response) {
|
||||
for(var i=0; i<response['info_flashes'].length; i++) {
|
||||
flash('info', response['info_flashes'][i]);
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
console.log('invalid response', ajax.response);
|
||||
flash('error', 'Invalid response from server: '+ajax.response);
|
||||
}
|
||||
|
||||
// Re-enable button, and update text
|
||||
uploadButton.innerHTML = 'Send Files';
|
||||
uploadButton.disabled = false;
|
||||
fileSelect.disabled = false;
|
||||
// Create form data, and list of filenames
|
||||
var files = $('#file-select').get(0).files;
|
||||
var filenames = [];
|
||||
var formData = new FormData();
|
||||
for(var i = 0; i < files.length; i++) {
|
||||
var file = files[i];
|
||||
filenames.push(file.name);
|
||||
formData.append('file[]', file, file.name);
|
||||
}
|
||||
}, false);
|
||||
|
||||
ajax.addEventListener('error', function(event){
|
||||
console.log('error', event);
|
||||
flash('error', 'Error uploading');
|
||||
}, false);
|
||||
// Reset the upload form
|
||||
$('#send').get(0).reset();
|
||||
|
||||
ajax.addEventListener('abort', function(event){
|
||||
console.log('abort', event);
|
||||
flash('error', 'Upload aborted');
|
||||
}, false);
|
||||
// Start upload
|
||||
xhr = $.ajax({
|
||||
method: 'POST',
|
||||
url: window.location.pathname + '/upload-ajax',
|
||||
data: formData,
|
||||
// Tell jQuery not to process data or worry about content-type
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
// Custom XMLHttpRequest
|
||||
xhr: function() {
|
||||
var xhr = $.ajaxSettings.xhr();
|
||||
if(xhr.upload) {
|
||||
xhr.upload.addEventListener('progress', function(event) {
|
||||
// Update progress bar for this specific upload
|
||||
if(event.lengthComputable) {
|
||||
console.log('upload progress', ''+event.loaded+' bytes / '+event.total+' bytes');
|
||||
$('progress', this.$upload_div).attr({
|
||||
value: event.loaded,
|
||||
max: event.total,
|
||||
});
|
||||
}
|
||||
|
||||
// Send the request
|
||||
ajax.open('POST', window.location.pathname + '/upload-ajax', true);
|
||||
ajax.send(formData);
|
||||
console.log('upload started');
|
||||
}
|
||||
// If it's finished sending all data to the first Tor node, remove cancel button
|
||||
// and update the status
|
||||
if(event.loaded == event.total) {
|
||||
console.log('upload progress', 'complete');
|
||||
$('.cancel', this.$upload_div).remove();
|
||||
$('.upload-status', this.$upload_div).html('<img src="/static/img/ajax.gif" alt="" /> Waiting for data to finish traversing Tor network ...');
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
return xhr;
|
||||
},
|
||||
success: function(data, textStatus, xhr){
|
||||
console.log('upload finished', data);
|
||||
|
||||
// Remove the upload div
|
||||
xhr.$upload_div.remove();
|
||||
|
||||
// Parse response
|
||||
try {
|
||||
var response = JSON.parse(data);
|
||||
|
||||
// The 'new_body' response replaces the whole HTML document and ends
|
||||
if('new_body' in response) {
|
||||
$('body').html(response['new_body']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show error flashes
|
||||
if('error_flashes' in response) {
|
||||
for(var i=0; i<response['error_flashes'].length; i++) {
|
||||
flash('error', response['error_flashes'][i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Show info flashes
|
||||
if('info_flashes' in response) {
|
||||
for(var i=0; i<response['info_flashes'].length; i++) {
|
||||
flash('info', response['info_flashes'][i]);
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
console.log('invalid response');
|
||||
flash('error', 'Invalid response from server: '+data);
|
||||
}
|
||||
},
|
||||
error: function(xhr, textStatus, errorThrown){
|
||||
console.log('error', errorThrown);
|
||||
flash('error', 'Error uploading: ' + errorThrown);
|
||||
}
|
||||
});
|
||||
console.log('upload started', filenames);
|
||||
|
||||
// Make the upload div
|
||||
xhr.$upload_div = new_upload_div(xhr, filenames);
|
||||
$('#uploads').append(xhr.$upload_div);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue