Move the file upload code in a separate file
parent
a58162a617
commit
803bad1421
|
@ -0,0 +1,260 @@
|
|||
define([
|
||||
'jquery',
|
||||
'/file/file-crypto.js',
|
||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||
], function ($, FileCrypto) {
|
||||
var Nacl = window.nacl;
|
||||
var module = {};
|
||||
|
||||
module.create = function (common) {
|
||||
var File = {};
|
||||
|
||||
var Messages = common.Messages;
|
||||
|
||||
var queue = File.queue = {
|
||||
queue: [],
|
||||
inProgress: false
|
||||
};
|
||||
|
||||
var uid = function () {
|
||||
return 'file-' + String(Math.random()).substring(2);
|
||||
};
|
||||
|
||||
var $table = File.$table = $('<table>', { id: 'uploadStatus' });
|
||||
var $thead = $('<tr>').appendTo($table);
|
||||
$('<td>').text(Messages.upload_name).appendTo($thead);
|
||||
$('<td>').text(Messages.upload_size).appendTo($thead);
|
||||
$('<td>').text(Messages.upload_progress).appendTo($thead);
|
||||
$('<td>').text(Messages.cancel).appendTo($thead);
|
||||
|
||||
var createTableContainer = function ($body) {
|
||||
File.$container = $('<div>', { id: 'uploadStatusContainer' }).append($table).appendTo($body);
|
||||
return File.$container;
|
||||
};
|
||||
|
||||
var upload = function (blob, metadata, id) {
|
||||
if (queue.inProgress) { return; }
|
||||
queue.inProgress = true;
|
||||
|
||||
var $row = $table.find('tr[id="'+id+'"]');
|
||||
|
||||
$row.find('.upCancel').html('-');
|
||||
var $pv = $row.find('.progressValue');
|
||||
var $pb = $row.find('.progressContainer');
|
||||
var $link = $row.find('.upLink');
|
||||
|
||||
var updateProgress = function (progressValue) {
|
||||
$pv.text(Math.round(progressValue*100)/100 + '%');
|
||||
$pb.css({
|
||||
width: (progressValue/100)*188+'px'
|
||||
});
|
||||
};
|
||||
|
||||
var u8 = new Uint8Array(blob);
|
||||
|
||||
var key = Nacl.randomBytes(32);
|
||||
var next = FileCrypto.encrypt(u8, metadata, key);
|
||||
|
||||
var estimate = FileCrypto.computeEncryptedSize(blob.byteLength, metadata);
|
||||
|
||||
var sendChunk = function (box, cb) {
|
||||
var enc = Nacl.util.encodeBase64(box);
|
||||
Cryptpad.rpc.send.unauthenticated('UPLOAD', enc, function (e, msg) {
|
||||
console.log(box);
|
||||
cb(e, msg);
|
||||
});
|
||||
};
|
||||
|
||||
var actual = 0;
|
||||
var again = function (err, box) {
|
||||
if (err) { throw new Error(err); }
|
||||
if (box) {
|
||||
actual += box.length;
|
||||
var progressValue = (actual / estimate * 100);
|
||||
updateProgress(progressValue);
|
||||
|
||||
return void sendChunk(box, function (e) {
|
||||
if (e) { return console.error(e); }
|
||||
next(again);
|
||||
});
|
||||
}
|
||||
|
||||
if (actual !== estimate) {
|
||||
console.error('Estimated size does not match actual size');
|
||||
}
|
||||
|
||||
// if not box then done
|
||||
Cryptpad.uploadComplete(function (e, id) {
|
||||
if (e) { return void console.error(e); }
|
||||
var uri = ['', 'blob', id.slice(0,2), id].join('/');
|
||||
console.log("encrypted blob is now available as %s", uri);
|
||||
|
||||
var b64Key = Nacl.util.encodeBase64(key);
|
||||
|
||||
var hash = Cryptpad.getFileHashFromKeys(id, b64Key);
|
||||
var href = '/file/#' + hash;
|
||||
$link.attr('href', href)
|
||||
.click(function (e) {
|
||||
e.preventDefault();
|
||||
window.open($link.attr('href'), '_blank');
|
||||
});
|
||||
|
||||
// TODO add button to table which copies link to clipboard?
|
||||
//APP.toolbar.addElement(['fileshare'], {});
|
||||
|
||||
var title = document.title = metadata.name;
|
||||
myFile = blob;
|
||||
myDataType = metadata.type;
|
||||
|
||||
Cryptpad.renamePad(title || "", href, function (err) {
|
||||
if (err) { console.error(err); } // TODO
|
||||
console.log(title);
|
||||
Cryptpad.log(Messages._getKey('upload_success', [title]));
|
||||
queue.inProgress = false;
|
||||
queue.next();
|
||||
})
|
||||
//Title.updateTitle(title || "", href);
|
||||
//APP.toolbar.title.show();
|
||||
});
|
||||
};
|
||||
|
||||
Cryptpad.uploadStatus(estimate, function (e, pending) {
|
||||
if (e) {
|
||||
queue.inProgress = false;
|
||||
queue.next();
|
||||
if (e === 'TOO_LARGE') {
|
||||
// TODO update table to say too big?
|
||||
return void Cryptpad.alert(Messages.upload_tooLarge);
|
||||
}
|
||||
if (e === 'NOT_ENOUGH_SPACE') {
|
||||
// TODO update table to say not enough space?
|
||||
return void Cryptpad.alert(Messages.upload_notEnoughSpace);
|
||||
}
|
||||
console.error(e);
|
||||
return void Cryptpad.alert(Messages.upload_serverError);
|
||||
}
|
||||
|
||||
if (pending) {
|
||||
// TODO keep this message in case of pending files in another window?
|
||||
return void Cryptpad.confirm(Messages.upload_uploadPending, function (yes) {
|
||||
if (!yes) { return; }
|
||||
Cryptpad.uploadCancel(function (e, res) {
|
||||
if (e) {
|
||||
return void console.error(e);
|
||||
}
|
||||
console.log(res);
|
||||
next(again);
|
||||
});
|
||||
});
|
||||
}
|
||||
next(again);
|
||||
});
|
||||
};
|
||||
|
||||
var prettySize = function (bytes) {
|
||||
var kB = Cryptpad.bytesToKilobytes(bytes);
|
||||
if (kB < 1024) { return kB + Messages.KB; }
|
||||
var mB = Cryptpad.bytesToMegabytes(bytes);
|
||||
return mB + Messages.MB;
|
||||
};
|
||||
|
||||
queue.next = function () {
|
||||
if (queue.queue.length === 0) { return; }
|
||||
if (queue.inProgress) { return; }
|
||||
var file = queue.queue.shift();
|
||||
upload(file.blob, file.metadata, file.id);
|
||||
};
|
||||
queue.push = function (obj) {
|
||||
var id = uid();
|
||||
obj.id = id;
|
||||
queue.queue.push(obj);
|
||||
|
||||
$table.show();
|
||||
var estimate = FileCrypto.computeEncryptedSize(obj.blob.byteLength, obj.metadata);
|
||||
|
||||
var $progressBar = $('<div>', {'class':'progressContainer'});
|
||||
var $progressValue = $('<span>', {'class':'progressValue'}).text(Messages.upload_pending);
|
||||
|
||||
var $tr = $('<tr>', {id: id}).appendTo($table);
|
||||
|
||||
var $cancel = $('<span>', {'class': 'cancel fa fa-times'}).click(function () {
|
||||
queue.queue = queue.queue.filter(function (el) { return el.id !== id; });
|
||||
$cancel.remove();
|
||||
$tr.find('.upCancel').text('-');
|
||||
$tr.find('.progressValue').text(Messages.upload_cancelled);
|
||||
});
|
||||
|
||||
var $link = $('<a>', {
|
||||
'class': 'upLink',
|
||||
'rel': 'noopener noreferrer'
|
||||
}).text(obj.metadata.name);
|
||||
|
||||
$('<td>').append($link).appendTo($tr);
|
||||
$('<td>').text(prettySize(estimate)).appendTo($tr);
|
||||
$('<td>', {'class': 'upProgress'}).append($progressBar).append($progressValue).appendTo($tr);
|
||||
$('<td>', {'class': 'upCancel'}).append($cancel).appendTo($tr);
|
||||
|
||||
queue.next();
|
||||
};
|
||||
|
||||
var handleFile = File.handleFile = function (file) {
|
||||
console.log(file);
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
queue.push({
|
||||
blob: this.result,
|
||||
metadata: {
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
}
|
||||
});
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
};
|
||||
|
||||
var createAreaHandlers = File.createDropArea = function ($area, $hoverArea, todo) {
|
||||
var counter = 0;
|
||||
if (!$hoverArea) { $hoverArea = $area; }
|
||||
$hoverArea
|
||||
.on('dragenter', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
counter++;
|
||||
$label.addClass('hovering');
|
||||
})
|
||||
.on('dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
counter--;
|
||||
if (counter <= 0) {
|
||||
$label.removeClass('hovering');
|
||||
}
|
||||
});
|
||||
|
||||
$area
|
||||
.on('drag dragstart dragend dragover drop dragenter dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
})
|
||||
.on('drop', function (e) {
|
||||
e.stopPropagation();
|
||||
var dropped = e.originalEvent.dataTransfer.files;
|
||||
counter = 0;
|
||||
$label.removeClass('hovering');
|
||||
|
||||
Array.prototype.slice.call(dropped).forEach(function (d) {
|
||||
todo(d);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
File.createUploader = function ($area, $hover, $body) {
|
||||
createAreaHandlers($area, null, handleFile);
|
||||
var $c = createTableContainer($body);
|
||||
};
|
||||
|
||||
return File;
|
||||
};
|
||||
|
||||
return module;
|
||||
});
|
|
@ -43,11 +43,12 @@ define(function () {
|
|||
onLocal();
|
||||
};
|
||||
|
||||
exp.updateTitle = function (newTitle) {
|
||||
// update title: href is optional; if not specified, we use window.location.href
|
||||
exp.updateTitle = function (newTitle, href) {
|
||||
if (newTitle === exp.title) { return; }
|
||||
// Change the title now, and set it back to the old value if there is an error
|
||||
var oldTitle = exp.title;
|
||||
Cryptpad.renamePad(newTitle, function (err, data) {
|
||||
Cryptpad.renamePad(newTitle, href, function (err, data) {
|
||||
if (err) {
|
||||
console.log("Couldn't set pad title");
|
||||
console.error(err);
|
||||
|
|
|
@ -11,11 +11,13 @@ define([
|
|||
'/common/common-title.js',
|
||||
'/common/common-metadata.js',
|
||||
'/common/common-codemirror.js',
|
||||
'/common/common-file.js',
|
||||
|
||||
'/common/clipboard.js',
|
||||
'/common/pinpad.js',
|
||||
'/customize/application_config.js'
|
||||
], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata, CodeMirror, Clipboard, Pinpad, AppConfig) {
|
||||
], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata,
|
||||
CodeMirror, Files, Clipboard, Pinpad, AppConfig) {
|
||||
|
||||
/* This file exposes functionality which is specific to Cryptpad, but not to
|
||||
any particular pad type. This includes functions for committing metadata
|
||||
|
@ -114,6 +116,9 @@ define([
|
|||
// CodeMirror
|
||||
common.createCodemirror = CodeMirror.create;
|
||||
|
||||
// Files
|
||||
common.createFileManager = function () { return Files.create(common); };
|
||||
|
||||
// History
|
||||
common.getHistory = function (config) { return History.create(common, config); };
|
||||
|
||||
|
@ -520,8 +525,8 @@ define([
|
|||
cb ("store.forgetPad is not a function");
|
||||
};
|
||||
|
||||
common.setPadTitle = function (name, cb) {
|
||||
var href = window.location.href;
|
||||
common.setPadTitle = function (name, padHref, cb) {
|
||||
var href = padHref || window.location.href;
|
||||
var parsed = parsePadUrl(href);
|
||||
if (!parsed.hash) { return; }
|
||||
href = getRelativeHref(href);
|
||||
|
@ -621,15 +626,15 @@ define([
|
|||
/*
|
||||
* Buttons
|
||||
*/
|
||||
common.renamePad = function (title, callback) {
|
||||
common.renamePad = function (title, href, callback) {
|
||||
if (title === null) { return; }
|
||||
|
||||
if (title.trim() === "") {
|
||||
var parsed = parsePadUrl(window.location.href);
|
||||
var parsed = parsePadUrl(href || window.location.href);
|
||||
title = getDefaultName(parsed);
|
||||
}
|
||||
|
||||
common.setPadTitle(title, function (err) {
|
||||
common.setPadTitle(title, href, function (err) {
|
||||
if (err) {
|
||||
console.log("unable to set pad title");
|
||||
console.log(err);
|
||||
|
|
|
@ -438,7 +438,7 @@ define([
|
|||
if (name === "") {
|
||||
name = $input.attr('placeholder');
|
||||
}
|
||||
Cryptpad.renamePad(name, function (err, newtitle) {
|
||||
Cryptpad.renamePad(name, null, function (err, newtitle) {
|
||||
if (err) { return; }
|
||||
$text.text(newtitle);
|
||||
callback(null, newtitle);
|
||||
|
|
|
@ -77,7 +77,7 @@ body {
|
|||
z-index: 10000;
|
||||
display: block;
|
||||
}
|
||||
#status {
|
||||
#uploadStatus {
|
||||
display: none;
|
||||
width: 80vw;
|
||||
margin-top: 50px;
|
||||
|
@ -85,24 +85,24 @@ body {
|
|||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
#status tr:nth-child(1) {
|
||||
#uploadStatus tr:nth-child(1) {
|
||||
background-color: #ccc;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
#status tr:nth-child(1) td {
|
||||
#uploadStatus tr:nth-child(1) td {
|
||||
text-align: center;
|
||||
}
|
||||
#status td {
|
||||
#uploadStatus td {
|
||||
border-left: 1px solid #BBB;
|
||||
border-right: 1px solid #BBB;
|
||||
padding: 0 10px;
|
||||
}
|
||||
#status .upProgress {
|
||||
#uploadStatus .upProgress {
|
||||
width: 200px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
#status .progressContainer {
|
||||
#uploadStatus .progressContainer {
|
||||
position: absolute;
|
||||
width: 0px;
|
||||
left: 5px;
|
||||
|
@ -110,9 +110,9 @@ body {
|
|||
bottom: 1px;
|
||||
background-color: rgba(0, 0, 255, 0.3);
|
||||
}
|
||||
#status .upCancel {
|
||||
#uploadStatus .upCancel {
|
||||
text-align: center;
|
||||
}
|
||||
#status .fa.cancel {
|
||||
#uploadStatus .fa.cancel {
|
||||
color: #ff0073;
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ html, body {
|
|||
display: block;
|
||||
}
|
||||
|
||||
#status {
|
||||
#uploadStatus {
|
||||
display: none;
|
||||
width: 80vw;
|
||||
margin-top: 50px;
|
||||
|
|
|
@ -21,14 +21,14 @@
|
|||
data-localization="download_button"></label>
|
||||
<span class="block" id="progress"></span>
|
||||
</div>
|
||||
<table id="status" style="display: none;">
|
||||
<!--<table id="status" style="display: none;">
|
||||
<tr>
|
||||
<td data-localization="upload_name">File name</td>
|
||||
<td data-localization="upload_size">Size</td>
|
||||
<td data-localization="upload_progress">Progress</td>
|
||||
<td data-localization="cancel">Cancel</td>
|
||||
</tr>
|
||||
</table>
|
||||
</table>-->
|
||||
<div id="feedback" class="block hidden">
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -17,7 +17,7 @@ define([
|
|||
var APP = {};
|
||||
|
||||
$(function () {
|
||||
|
||||
// TODO race condition with contents() here
|
||||
var ifrw = $('#pad-iframe')[0].contentWindow;
|
||||
var $iframe = $('#pad-iframe').contents();
|
||||
var $form = $iframe.find('#upload-form');
|
||||
|
@ -25,9 +25,10 @@ define([
|
|||
var $label = $form.find('label');
|
||||
var $table = $iframe.find('#status');
|
||||
var $progress = $iframe.find('#progress');
|
||||
var $body = $iframe.find('body');
|
||||
|
||||
$iframe.find('body').on('dragover', function (e) { e.preventDefault(); });
|
||||
$iframe.find('body').on('drop', function (e) { e.preventDefault(); });
|
||||
$body.on('dragover', function (e) { e.preventDefault(); });
|
||||
$body.on('drop', function (e) { e.preventDefault(); });
|
||||
|
||||
Cryptpad.addLoadingScreen();
|
||||
|
||||
|
@ -35,7 +36,7 @@ define([
|
|||
|
||||
var myFile;
|
||||
var myDataType;
|
||||
|
||||
/*
|
||||
var queue = {
|
||||
queue: [],
|
||||
inProgress: false
|
||||
|
@ -206,7 +207,7 @@ define([
|
|||
|
||||
queue.next();
|
||||
};
|
||||
|
||||
*/
|
||||
var uploadMode = false;
|
||||
|
||||
var andThen = function () {
|
||||
|
@ -329,7 +330,7 @@ define([
|
|||
display: 'block',
|
||||
});
|
||||
|
||||
var handleFile = function (file) {
|
||||
/*var handleFile = function (file) {
|
||||
console.log(file);
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
|
@ -342,45 +343,17 @@ define([
|
|||
});
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
};
|
||||
};*/
|
||||
|
||||
var FM = Cryptpad.createFileManager();
|
||||
|
||||
$form.find("#file").on('change', function (e) {
|
||||
var file = e.target.files[0];
|
||||
handleFile(file);
|
||||
FM.handleFile(file);
|
||||
});
|
||||
|
||||
var counter = 0;
|
||||
$label
|
||||
.on('dragenter', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
counter++;
|
||||
$label.addClass('hovering');
|
||||
})
|
||||
.on('dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
counter--;
|
||||
if (counter <= 0) {
|
||||
$label.removeClass('hovering');
|
||||
}
|
||||
});
|
||||
|
||||
$form
|
||||
.on('drag dragstart dragend dragover drop dragenter dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
})
|
||||
.on('drop', function (e) {
|
||||
e.stopPropagation();
|
||||
var dropped = e.originalEvent.dataTransfer.files;
|
||||
counter = 0;
|
||||
$label.removeClass('hovering');
|
||||
|
||||
Array.prototype.slice.call(dropped).forEach(function (d) {
|
||||
handleFile(d);
|
||||
});
|
||||
});
|
||||
//FM.createDropArea($form, $label, handleFile);
|
||||
FM.createUploader($form, $label, $body);
|
||||
|
||||
// we're in upload mode
|
||||
Cryptpad.removeLoadingScreen();
|
||||
|
|
Loading…
Reference in New Issue