lufi/themes/default/public/js/lufi-up.js

711 lines
26 KiB
JavaScript

// vim:set sw=4 ts=4 sts=4 ft=javascript expandtab:
// total file counter
window.fc = 0;
// Cancelled files indexes
window.cancelled = [];
// Set websocket
window.ws = spawnWebsocket(0, function() {return null;});
// Use slice of 0.75MB
window.sliceLength = 750000;
// Global zip objects for currently created zip file
window.zip = null;
window.zipSize = 0;
// Init the list of files (used by LDAP invitation feature)
window.filesURLs = [];
// Copy a link to clipboard
function copyToClipboard(txt) {
var textArea = $('<textarea>');
textArea.addClass('textarea-hidden');
textArea.val(txt);
$('body').append(textArea);
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? i18n.copySuccess : i18n.copyFail;
Materialize.toast(msg, 4000);
} catch (err) {
el.focus();
var len = el.value.length * 2;
el.setSelectionRange(0, len);
alert(i18n.hit);
}
textArea.remove();
}
// Copy all links to clipboard
function copyAllToClipboard(event) {
event.preventDefault();
var text = new Array();
var a = $('.link-input');
var i;
for (i = 0; i < a.length; i++) {
text.push(a[i].value);
}
var textArea = $('<textarea>');
textArea.addClass('textarea-hidden');
textArea.val(text.join("\n"));
$('body').append(textArea);
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? i18n.copySuccess : i18n.copyFail;
Materialize.toast(msg, 4000);
} catch (err) {
textArea.removeClass('textarea-hidden');
textArea.addClass('white-background');
alert(i18n.hits);
}
textArea.remove();
}
// Add item to localStorage
function addItem(name, url, size, del_at_first_view, created_at, delay, short, token) {
var files = localStorage.getItem(window.prefix + 'files');
if (files === null) {
files = new Array();
} else {
files = JSON.parse(files);
}
files.push({ name: name, short: short, url: url, size: size, del_at_first_view: del_at_first_view, created_at: created_at, delay: delay, token: token });
localStorage.setItem(window.prefix + 'files', JSON.stringify(files));
}
// Remove a file block
function destroyBlock(el) {
$(el).parents('li').remove();
if ($('.link-input').length === 0) {
$('#misc').empty();
if ($('#results li').length === 0 && window.fileList === null) {
$('#results').hide();
}
} else {
updateMailLink();
}
}
// When clicking on del at first view checkbox
function firstViewClicking() {
if ($('#first-view').attr('data-checked') && $('#first-view').attr('data-checked') === 'data-checked') {
$('#first-view').attr('data-checked', null);
} else {
$('#first-view').attr('data-checked', 'data-checked');
}
}
// When clicking on zip checkbox
function zipClicking() {
if ($('#zip-files').attr('data-checked') && $('#zip-files').attr('data-checked') === 'data-checked') {
window.zipSize = 0;
window.zip = null;
$('#zip-files').attr('data-checked', null);
$('#zipname').val('documents.zip');
$('#zipname-input').addClass('hide');
$('#zipping').addClass('hide');
$('#files').removeClass('m6').addClass('m12');
$('#zip-parts').html('');
$('#delete-day').attr('disabled', null);
$('#first-view').attr('disabled', null);
} else {
$('#zip-files').attr('data-checked', 'data-checked');
$('#zipname-input').removeClass('hide');
$('#zip-size').text(filesize(window.zipSize));
}
}
// Get the zip file name
function getZipname() {
var zipname = $('#zipname').val();
if (zipname === '') {
zipname = 'documents.zip';
}
if (!zipname.endsWith('.zip')) {
if (zipname.endsWith('.')) {
zipname += 'zip';
} else {
zipname += '.zip';
}
}
return escapeHtml(zipname);
}
// Update the zip name
function updateZipname() {
$('#zip-name').text(getZipname());
}
// Create blob from zip
function uploadZip(e) {
e.preventDefault();
var delay = $('#delete-day');
var del_at_first_view = $('#first-view');
$('#zip-files').attr('disabled', 'disabled');
$('#file-browser-button').attr('disabled', 'disabled');
$('#file-browser-span').addClass('disabled');
$('#uploadZip').addClass('hide');
$('#zip-parts').text('');
$('#zip-compressing').removeClass('hide');
window.zip.generateAsync({type:"blob"})
.then(function(zipFile) {
// if $('#zipping') is hidden, the zipping has been aborted
if (!$('#zipping').hasClass('hide')) {
window.zip = null;
$('#zipping').addClass('hide');
$('#files').removeClass('m6').addClass('m12');
$('#zipname-input').addClass('hide');
$('#zip-compressing').addClass('hide');
$('#uploadZip').removeClass('hide');
$('#results').show();
$('#zip-files').attr('disabled', null);
var zipname = getZipname();
var file = new File([zipFile], zipname, {type: 'application/zip'});
Materialize.toast(i18n.enqueued.replace('XXX', zipname), 3000, 'teal accent-3');
if (window.fileList === undefined || window.fileList === null) {
window.fileList = [file];
uploadFile(0, delay.val(), del_at_first_view.is(':checked'));
} else {
window.fileList.push(file);
}
}
$('#file-browser-button').attr('disabled', null);
$('#file-browser-span').removeClass('disabled');
});
}
// Update the mail link
function updateMailLink() {
var a = $('.link-input');
var l = new Array();
var i;
for (i = 0; i < a.length; i++) {
l.push(a[i].id);
}
var u = actionURL+'m?links='+JSON.stringify(l);
$('#mailto').attr('href', u);
}
// [Invitation feature] Send URLs of files to server
function sendFilesURLs() {
if (window.filesURLs.length > 0) {
$.ajax({
url: sendFilesURLsURL,
method: 'POST',
dataType: 'json',
data: {
urls: window.filesURLs
},
success: function(data, textStatus, jqXHR) {
if (data.success) {
Materialize.toast(data.msg, 6000, 'teal accent-3');
} else {
Materialize.toast(data.msg, 10000, 'red accent-2');
}
}
});
}
}
// Start uploading the files (called from <input> and from drop zone)
function handleFiles(f) {
var delay = $('#delete-day');
var zip_files = $('#zip-files');
var del_at_first_view = $('#first-view');
delay.attr('disabled', 'disabled');
del_at_first_view.attr('disabled', 'disabled');
if (zip_files.is(':checked')) {
if (window.zip === null) {
window.zip = new JSZip();
}
$('#zipping').removeClass('hide');
$('#files').removeClass('m12').addClass('m6');
for (var i = 0; i < f.length; i++) {
var element = f.item(i);
var filename = element.name;
var origname = filename;
var counter = 0;
while (typeof(window.zip.files[filename]) !== 'undefined') {
counter += 1;
filename = origname.substring(0, origname.lastIndexOf('.')) + '_(' + counter + ')' + origname.substring(origname.lastIndexOf('.'));
}
window.zip.file(filename, element);
window.zipSize += element.size;
$('#zip-size').text(filesize(window.zipSize));
$('#zip-parts').append([
'<li>',
'— ', escapeHtml(filename), ' (', filesize(element.size), ')',
'</li>'
].join(''));
}
} else {
if (window.fileList === undefined || window.fileList === null) {
window.fileList = Array.prototype.slice.call(f);
for (var i = 0; i < window.fileList.length; i++) {
var file = window.fileList[i];
Materialize.toast(i18n.enqueued.replace('XXX', escapeHtml(file.name)), 3000, 'teal accent-3');
}
window.nbFiles = window.fileList.length;
$('#results').show();
uploadFile(0, delay.val(), del_at_first_view.is(':checked'));
} else {
window.fileList = window.fileList.concat(Array.prototype.slice.call(f));
}
}
}
// Create random key
function genRandomKey() {
return sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 10), 0);
}
// Create progress bar and call slicing and uploading function
function uploadFile(i, delay, del_at_first_view) {
// Prevent exiting page before full upload
window.onbeforeunload = confirmExit;
// Create a random key, different for all files
var randomkey = genRandomKey();
// Get the file and properties
var file = window.fileList[i];
var name = escapeHtml(file.name);
var size = filesize(file.size);
var parts = Math.ceil(file.size/window.sliceLength);
if (parts === 0) {
parts = 1;
}
// Create a progress bar for the file
var r = $('#ul-results');
var w = $('<li>');
w.addClass('list-group-item');
w.html(['<div class="card">',
'<div>',
'<a href="#" id="destroy-', window.fc, '">',
'<i class="right mdi-navigation-close small"></i>',
'</a>',
'<div class="card-content">',
'<span class="card-title" id="name-', window.fc, '">', name, '</span> <span id="size-', window.fc ,'">(', size,')</span>',
'<p id="parts-', window.fc, '"></p>',
'</div>',
'<div class="progress">',
'<div id="progress-', window.fc, '" data-key="', randomkey, '" data-name="', name, '" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" role="progressbar" class="determinate width-0">',
'<span class="sr-only">', name, '0%</span>',
'</div>',
'</div>',
'<div>'].join(''));
r.prepend(w);
$('#destroy-'+window.fc).on('click', function(event) {
event.preventDefault();
window.cancelled.push(i);
destroyBlock(this);
});
sliceAndUpload(randomkey, i, parts, 0, delay, del_at_first_view, null, null);
}
// Get a slice of file and send it
function sliceAndUpload(randomkey, i, parts, j, delay, del_at_first_view, short, mod_token) {
if (mod_token !== null && window.cancelled.includes(i)) {
var data = JSON.stringify({
id: short,
mod_token: mod_token,
cancel: true,
i: i
})+'XXMOJOXXuseless';
// Verify that we have a websocket and send json
if (window.ws.readyState === 3) {
window.ws = spawnWebsocket(0, function() {
window.ws.send(data);
});
} else {
window.ws.onclose = function() {
console.log('Websocket closed, waiting 10sec.');
window.ws = spawnWebsocket(0, function() {return null;});
};
window.ws.onerror = function() {
console.log('Error on Websocket, waiting 10sec.');
window.ws = spawnWebsocket(0, function() {return null;});
};
window.ws.send(data);
}
} else {
var file = window.fileList[i];
var slice = file.slice(j * window.sliceLength, (j + 1) * window.sliceLength, file.type);
var fr = new FileReader();
fr.onloadend = function() {
var sl = $('#parts-'+window.fc);
// Get the binary result, different result in IE browsers (see default.html.ep line 27:48)
if (isIE == true){
var bin = fr.content;
} else {
var bin = fr.result;
}
// Transform it in base64
var b = window.btoa(bin);
// Encrypt it
var encrypted = sjcl.encrypt(randomkey, b);
// Prepare json
var data = {
// number of parts
total: parts,
// part X of total
part: j,
size: file.size,
name: file.name,
type: file.type,
delay: delay,
del_at_first_view: del_at_first_view,
zipped: $('#zip-files').is(':checked'),
id: short,
// number of the sent file in the queue
i: i
};
if ($('#file_pwd').length === 1) {
var pwd = $('#file_pwd').val();
if (pwd !== undefined && pwd !== null && pwd !== '') {
data['file_pwd'] = $('#file_pwd').val();
}
}
data = JSON.stringify(data)+'XXMOJOXX'+JSON.stringify(encrypted);;
var percent = Math.round(1000 * j/parts)/10;
console.log('sending slice '+(j + 1)+'/'+parts+' of file '+file.name+' ('+percent+'%)');
sl.html(percent.toFixed(1)+'%');
// Verify that we have a websocket and send json
if (window.ws.readyState === 3) {
window.ws = spawnWebsocket(0, function() {
window.ws.send(data);
});
} else {
window.ws.onclose = function() {
console.log('Websocket closed, waiting 10sec.');
window.ws = spawnWebsocket(0, function() {
console.log('sending again slice '+(j + 1)+'/'+parts+' of file '+file.name);
window.ws.send(data);
});
};
window.ws.onerror = function() {
console.log('Error on Websocket, waiting 10sec.');
window.ws = spawnWebsocket(0, function() {
console.log('sending again slice '+(j + 1)+'/'+parts+' of file '+file.name);
window.ws.send(data);
});
};
window.ws.send(data);
}
}
fr.readAsBinaryString(slice);
}
}
// Update the progress bar
function updateProgressBar(data) {
if (typeof(data.action) !== 'undefined' && data.action === 'cancel') {
if (data.success) {
console.log('Upload successfully cancelled');
} else {
console.log('Upload cancellation failed: ' + data.msg);
}
// Remove the cancelled index
window.cancelled.splice(window.cancelled.indexOf(window.fc), 1);
// Upload next file
window.fc++;
data.i++;
if (data.i < window.fileList.length) {
uploadFile(data.i, $('#delete-day').val(), $('#first-view').is(':checked'));
} else {
// We have finished
window.cancelled = [];
window.fileList = null;
window.onbeforeunload = null;
$('#delete-day').attr('disabled', null);
$('#first-view').attr('disabled', null);
if ($('#zip-files').is(':checked') && window.zip === null) {
$('label[for="zip-files"]').click();
}
}
if ($('#results li').length === 0 && window.fileList === null) {
$('#results').hide();
}
} else {
var i = data.i;
var sent_delay = data.sent_delay;
var del_at_first_view = data.del_at_first_view;
if (data.success) {
var j = data.j;
var delay = data.delay;
var parts = data.parts;
var short = data.short;
var created_at = data.created_at;
console.log('getting response for slice '+(j + 1)+'/'+parts+' of file '+data.name+' ('+data.duration+' sec)');
var dp = $('#progress-'+window.fc);
var key = dp.attr('data-key');
if (j + 1 === parts) {
//
window.ws.onclose = function() {
console.log('Connection is closed.');
};
window.ws.onerror = function() {
console.log('Error on WebSocket connection but file has been fully send, so we don\'t care.');
}
notify(i18n.fileUploaded, data.name);
$('#parts-'+window.fc).remove();
var n = $('#name-'+window.fc);
var s = $('#size-'+window.fc);
var d = $('<div>');
var url = baseURL+'r/'+short+'#'+key;
var del_url = actionURL+'d/'+short+'/'+data.token;
var links = encodeURIComponent('["'+short+'"]');
var limit = (delay === 0) ? i18n.noLimit : i18n.expiration+' '+moment.unix(delay * 86400 + created_at).locale(window.navigator.language).format('LLLL');
if (!isGuest) {
n.html(n.html()+' '+s.html()+' <a href="'+actionURL+'m?links='+links+'"><i class="mdi-communication-email"></i></a><br>'+limit);
d.html(['<div class="card-action">',
'<div class="input-field">',
'<span class="prefix big-prefix">',
'<a href="', url, '" target="_blank">',
'<i class="mdi-file-file-download small" title="', i18n.dlText, '"></i>',
'</a>',
'<a href="#" id="copyurl-', window.fc, '" title="', i18n.cpText, '">',
'<i class="mdi-content-content-copy small"></i>',
'</a>',
'</span>',
'<input id="', short, '" class="form-control link-input white-background" value="', url, '" readonly="" type="text">',
'<label class="active" for="', short, '">', i18n.dlText, '</label>',
'</div>',
'<div class="input-field">',
'<a href="', del_url, '" target="_blank" class="prefix big-prefix">',
'<i class="mdi-action-delete small" title="', i18n.delText, '"></i>',
'</a>',
'<input id="delete-', short, '" class="form-control white-background" value="', del_url, '" readonly="" type="text">',
'<label class="active" for="delete-', short, '">', i18n.delText, '</label>',
'</div>',
'</div>'].join(''));
} else {
n.html(n.html()+' '+s.html());
}
s.remove();
var p2 = dp.parent();
var p1 = p2.parent();
p2.remove();
p1.append(d);
$('#copyurl-'+window.fc).on('click', function(e) {
e.preventDefault();
copyToClipboard(url);
});
$("input[type='text']").on("click", function () {
$(this).select();
});
// Add copy all and mailto buttons
var misc = $('#misc');
if (misc.html() === '' && !isGuest) {
misc.html('<a href="#" id="copyall" class="btn btn-info">'+i18n.copyAll+'</a> <a id="mailto" href="'+actionURL+'m?links='+links+'" class="btn btn-info">'+i18n.mailTo+'</a>');
$('#copyall').on('click', copyAllToClipboard);
} else {
updateMailLink();
}
// Add the file to localStorage
if (!isGuest) {
addItem(data.name, url, data.size, del_at_first_view, created_at, delay, data.short, data.token);
}
if (isGuest && short !== null) {
window.filesURLs.push(JSON.stringify({ name: data.name, short: data.short, url: url, size: data.size, created_at: created_at, delay: delay, token: data.token }));
}
// Upload next file
window.fc++;
i++;
if (i < window.fileList.length) {
uploadFile(i, sent_delay, del_at_first_view);
} else {
// We have finished
window.fileList = null;
window.onbeforeunload = null;
$('#delete-day').attr('disabled', null);
$('#first-view').attr('disabled', null);
if ($('#zip-files').is(':checked') && window.zip === null) {
$('label[for="zip-files"]').click();
}
if (isGuest) {
sendFilesURLs();
}
}
if ($('#results li').length === 0 && window.fileList === null) {
$('#results').hide();
}
} else {
j++;
// Update progress bar
var percent = Math.round(1000 * j/parts)/10;
var wClass = percent.toString().replace('.', '-');
dp.removeClass();
dp.addClass('determinate');
dp.addClass('width-'+wClass);
dp.attr('aria-valuenow', percent);
// Encrypt and upload next slice
sliceAndUpload(key, i, parts, j, delay, del_at_first_view, short, data.token);
}
} else {
addAlertOnFile(data.msg, i, delay, del_at_first_view);
if (isGuest) {
sendFilesURLs();
}
}
}
}
// Write message instead in a file block
function addAlertOnFile(msg, i, sent_delay, del_at_first_view) {
var n = $('#name-'+window.fc);
var p = $('#progress-'+window.fc);
var d = $('<div>');
p.parent().remove();
d.addClass('card pink');
d.html(['<div class="card-content white-text">',
'<strong>', msg, '</strong>',
'</div>'].join(''));
n.parent().append(d);
// Upload next file
window.fc++;
i++;
if (i < window.fileList.length) {
uploadFile(i, sent_delay, del_at_first_view);
} else {
// We have finished
window.onbeforeunload = null;
$('#zip-files').attr('disabled', null);
$('#delete-day').attr('disabled', null);
$('#first-view').attr('disabled', null);
}
}
// Dropzone events functions
function handleDrop(evt) {
evt.stopPropagation();
evt.preventDefault();
var f = evt.dataTransfer.files; // FileList object
handleFiles(f);
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}
// Spawn websocket
function spawnWebsocket(i, callback) {
if (i === undefined || i === null) {
i = 0;
}
var ws = new WebSocket(ws_url);
ws.onopen = function() {
console.log('Connection is established!');
if (callback !== undefined) {
callback();
}
};
ws.onclose = function() {
console.log('Connection is closed.');
}
ws.onmessage = function(e) {
updateProgressBar(JSON.parse(e.data));
}
ws.onerror = function() {
console.log('error');
if (i < 5 && callback !== undefined) {
console.log('Retrying to send file (try '+i+' of 5)');
window.ws = spawnWebsocket(i + 1, callback);
}
}
return ws;
}
// Dropzone events binding
function bindDropZone() {
var dropZone = document.getElementById('files');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleDrop, false);
$('#file-browser-span').removeClass('disabled');
$('#file-browser-span').addClass('cyan');
$('#file-browser-button').attr('disabled', null);
$('#file-browser-button').on('change', function(e) {
handleFiles(this.files);
});
}
// When it's ready
$(document).ready(function() {
$('#zip-files').prop('checked', false);
$('#first-view').prop('checked', false);
$('#zipname').val('documents.zip');
if (!sjcl.random.isReady(10)) {
var loop = setInterval(function() {
if (!sjcl.random.isReady(10)) {
$('#not-enough-entropy').removeClass('hiddendiv');
} else {
$('#not-enough-entropy').addClass('hiddendiv');
bindDropZone();
clearInterval(loop);
}
}, 1000);
} else {
bindDropZone();
}
if (maxSize > 0) {
$('#max-file-size').text(i18n.maxSize.replace('XXX', filesize(maxSize)));
}
$('label[for="first-view"]').on('click', firstViewClicking);
$('label[for="zip-files"]').on('click', zipClicking);
$('#zipname').on('input', updateZipname);
$('#uploadZip').on('click', uploadZip);
$('#reset-zipping').on('click', function() {
window.zip = null;
$('label[for="zip-files"]').click();
$('#zip-files').attr('disabled', null);
$('#zip-compressing').addClass('hide');
$('#file-browser-button').attr('disabled', null);
$('#file-browser-span').removeClass('disabled');
$('#files').removeClass('m6').addClass('m12');
});
});