diff --git a/customize.dist/src/less2/include/fileupload.less b/customize.dist/src/less2/include/fileupload.less index c10abeec4..e993d3030 100644 --- a/customize.dist/src/less2/include/fileupload.less +++ b/customize.dist/src/less2/include/fileupload.less @@ -21,9 +21,11 @@ tr:nth-child(1) { background-color: darken(@colortheme_modal-bg, 20%); td { - text-align: center; font-weight: bold; padding: 0.25em; + &:nth-child(4), &:nth-child(5) { + text-align: center; + } } } @upload_pad_h: 0.25em; @@ -38,7 +40,7 @@ } } .cp-fileupload-table-progress { - width: 200px; + width: 25%; position: relative; text-align: center; box-sizing: border-box; diff --git a/www/common/common-util.js b/www/common/common-util.js index 825c31f48..edc7e7074 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -138,11 +138,19 @@ define([], function () { }; // given a path, asynchronously return an arraybuffer - Util.fetch = function (src, cb) { + Util.fetch = function (src, cb, progress) { var CB = Util.once(cb); var xhr = new XMLHttpRequest(); xhr.open("GET", src, true); + if (progress) { + xhr.addEventListener("progress", function (evt) { + if (evt.lengthComputable) { + var percentComplete = evt.loaded / evt.total; + progress(percentComplete); + } + }, false); + } xhr.responseType = "arraybuffer"; xhr.onerror = function (err) { CB(err); }; xhr.onload = function () { diff --git a/www/common/sframe-common-file.js b/www/common/sframe-common-file.js index 5ad74d512..81aa61663 100644 --- a/www/common/sframe-common-file.js +++ b/www/common/sframe-common-file.js @@ -5,12 +5,15 @@ define([ '/common/common-interface.js', '/common/common-ui-elements.js', '/common/common-util.js', + '/common/common-hash.js', '/common/hyperscript.js', '/customize/messages.js', + '/bower_components/file-saver/FileSaver.min.js', '/bower_components/tweetnacl/nacl-fast.min.js', -], function ($, FileCrypto, Thumb, UI, UIElements, Util, h, Messages) { +], function ($, FileCrypto, Thumb, UI, UIElements, Util, Hash, h, Messages) { var Nacl = window.nacl; + var saveAs = window.saveAs; var module = {}; var blobToArrayBuffer = function (blob, cb) { @@ -41,6 +44,7 @@ define([ var $table = File.$table = $('
').text(Messages.upload_type).appendTo($thead); $(' | ').text(Messages.upload_name).appendTo($thead); $(' | ').text(Messages.upload_size).appendTo($thead); $(' | ').text(Messages.upload_progress).appendTo($thead);
@@ -180,6 +184,7 @@ define([
// setTimeout to fix a firefox error 'NS_ERROR_NOT_AVAILABLE'
window.setTimeout(function () { File.$container.show(); });
var file = queue.queue.shift();
+ if (file.dl) { return void file.dl(file); }
upload(file);
};
queue.push = function (obj) {
@@ -189,7 +194,7 @@ define([
// setTimeout to fix a firefox error 'NS_ERROR_NOT_AVAILABLE'
window.setTimeout(function () { $table.show(); });
- var estimate = FileCrypto.computeEncryptedSize(obj.blob.byteLength, obj.metadata);
+ var estimate = obj.dl ? obj.size : FileCrypto.computeEncryptedSize(obj.blob.byteLength, obj.metadata);
var $progressBar = $(' ', {'class':'cp-fileupload-table-progress-container'});
var $progressValue = $('', {'class':'cp-fileupload-table-progress-value'}).text(Messages.upload_pending);
@@ -206,8 +211,9 @@ define([
var $link = $('', {
'class': 'cp-fileupload-table-link',
'rel': 'noopener noreferrer'
- }).text(obj.metadata.name);
+ }).text(obj.dl ? obj.name : obj.metadata.name);
+ $(' ').text(obj.dl ? Messages.download_dl : Messages.upload_up).appendTo($tr);
$(' | ').append($link).appendTo($tr);
$(' | ').text(prettySize(estimate)).appendTo($tr);
$(' | ', {'class': 'cp-fileupload-table-progress'}).append($progressBar).append($progressValue).appendTo($tr);
@@ -433,8 +439,124 @@ define([
createUploader(config.dropArea, config.hoverArea, config.body);
+ File.downloadFile = function (fData, cb) {
+ var parsed = Hash.parsePadUrl(fData.href || fData.roHref);
+ var hash = parsed.hash;
+ var name = fData.filename || fData.title;
+ var secret = Hash.getSecrets('file', hash, fData.password);
+ var src = Hash.getBlobPathFromHex(secret.channel);
+ var key = secret.keys && secret.keys.cryptKey;
+ common.getFileSize(secret.channel, function (e, data) {
+ var todo = function (file) {
+ if (queue.inProgress) { return; }
+ queue.inProgress = true;
+ var id = file.id;
+
+ var $row = $table.find('tr[id="'+id+'"]');
+ var $pv = $row.find('.cp-fileupload-table-progress-value');
+ var $pb = $row.find('.cp-fileupload-table-progress-container');
+ var $pc = $row.find('.cp-fileupload-table-progress');
+ var $link = $row.find('.cp-fileupload-table-link');
+
+ var done = function () {
+ $row.find('.cp-fileupload-table-cancel').text('-');
+ queue.inProgress = false;
+ queue.next();
+ };
+
+ var updateDLProgress = function (progressValue) {
+ var text = Math.round(progressValue*100) + '%';
+ text += ' ('+ Messages.download_step1 +'...)';
+ $pv.text(text);
+ $pb.css({
+ width: progressValue * $pc.width()+'px'
+ });
+ };
+ var updateProgress = function (progressValue) {
+ var text = Math.round(progressValue*100) + '%';
+ text += progressValue === 1 ? '' : ' ('+ Messages.download_step2 +'...)';
+ $pv.text(text);
+ $pb.css({
+ width: progressValue * $pc.width()+'px'
+ });
+ };
+
+ var dl = module.downloadFile(fData, function (err, obj) {
+ $link.prepend($('', {'class': 'fa fa-external-link'}))
+ .attr('href', '#')
+ .click(function (e) {
+ e.preventDefault();
+ obj.download();
+ });
+ done();
+ if (obj) { obj.download(); }
+ cb(err, obj);
+ }, {
+ src: src,
+ key: key,
+ name: name,
+ progress: updateDLProgress,
+ progress2: updateProgress,
+ });
+
+ var $cancel = $('', {'class': 'cp-fileupload-table-cancel-button fa fa-times'}).click(function () {
+ dl.cancel();
+ $cancel.remove();
+ $row.find('.cp-fileupload-table-progress-value').text(Messages.upload_cancelled);
+ done();
+ });
+ $row.find('.cp-fileupload-table-cancel').html('').append($cancel);
+ };
+ queue.push({
+ dl: todo,
+ size: data,
+ name: name
+ });
+ });
+ };
+
return File;
};
+ module.downloadFile = function (fData, cb, obj) {
+ var cancelled = false;
+ var cancel = function () {
+ cancelled = true;
+ };
+ var src, key, name;
+ if (obj && obj.src && obj.key && obj.name) {
+ src = obj.src;
+ key = obj.key;
+ name = obj.name;
+ } else {
+ var parsed = Hash.parsePadUrl(fData.href || fData.roHref);
+ var hash = parsed.hash;
+ name = fData.filename || fData.title;
+ var secret = Hash.getSecrets('file', hash, fData.password);
+ src = Hash.getBlobPathFromHex(secret.channel);
+ key = secret.keys && secret.keys.cryptKey;
+ }
+ Util.fetch(src, function (err, u8) {
+ if (cancelled) { return; }
+ if (err) { return void cb('E404'); }
+ FileCrypto.decrypt(u8, key, function (err, res) {
+ if (cancelled) { return; }
+ if (err) { return void cb(err); }
+ if (!res.content) { return void cb('EEMPTY'); }
+ var dl = function () {
+ saveAs(res.content, name || res.metadata.name);
+ };
+ cb(null, {
+ metadata: res.metadata,
+ content: res.content,
+ download: dl
+ });
+ }, obj && obj.progress2);
+ }, obj && obj.progress);
+ return {
+ cancel: cancel
+ };
+ };
+
return module;
});
diff --git a/www/common/translations/messages.fr.js b/www/common/translations/messages.fr.js
index 93273c2f3..b1f96afe9 100644
--- a/www/common/translations/messages.fr.js
+++ b/www/common/translations/messages.fr.js
@@ -666,6 +666,7 @@ define(function () {
out.settings_changePasswordNewPasswordSameAsOld = "Votre nouveau mot de passe doit être différent de votre mot de passe actuel.";
out.upload_title = "Hébergement de fichiers";
+ out.upload_type = "Type";
out.upload_modal_title = "Options d'importation du fichier";
out.upload_modal_filename = "Nom (extension {0} ajoutée automatiquement)";
out.upload_modal_owner = "Être propriétaire du fichier";
@@ -683,9 +684,13 @@ define(function () {
out.upload_size = "Taille";
out.upload_progress = "État";
out.upload_mustLogin = "Vous devez vous connecter pour importer un fichier";
+ out.upload_up = "Envoyer";
out.download_button = "Déchiffrer et télécharger";
out.download_mt_button = "Télécharger";
out.download_resourceNotAvailable = "Le fichier demandé n'est pas disponible... Appuyez sur Échap pour continuer.";
+ out.download_dl = "Télécharger";
+ out.download_step1 = "Téléchargement";
+ out.download_step2 = "Déchiffrement";
out.todo_title = "CryptTodo";
out.todo_newTodoNamePlaceholder = "Décrivez votre tâche...";
diff --git a/www/common/translations/messages.js b/www/common/translations/messages.js
index e1f11b0fb..b1fd0965f 100644
--- a/www/common/translations/messages.js
+++ b/www/common/translations/messages.js
@@ -676,6 +676,7 @@ define(function () {
out.settings_changePasswordNewPasswordSameAsOld = "Your new password must be different than your current password.";
out.upload_title = "File upload";
+ out.upload_type = "Type";
out.upload_modal_title = "File upload options";
out.upload_modal_filename = "File name (extension {0} added automatically)";
out.upload_modal_owner = "Owned file";
@@ -693,9 +694,13 @@ define(function () {
out.upload_size = "Size";
out.upload_progress = "Progress";
out.upload_mustLogin = "You must be logged in to upload files";
+ out.upload_up = "Upload";
out.download_button = "Decrypt & Download";
out.download_mt_button = "Download";
out.download_resourceNotAvailable = "The requested resource was not available... Press Esc to continue.";
+ out.download_dl = "Download";
+ out.download_step1 = "Downloading";
+ out.download_step2 = "Decrypting";
out.todo_title = "CryptTodo";
out.todo_newTodoNamePlaceholder = "Describe your task...";
diff --git a/www/drive/inner.js b/www/drive/inner.js
index bc29394a3..b64c0283b 100644
--- a/www/drive/inner.js
+++ b/www/drive/inner.js
@@ -85,6 +85,7 @@ define([
var faEmpty = 'fa-trash-o';
var faRestore = 'fa-repeat';
var faShowParent = 'fa-location-arrow';
+ var faDownload = 'cptools-file';
var $folderIcon = $('', {
"class": faFolder + " cptools cp-app-drive-icon-folder cp-app-drive-content-icon"
});
@@ -265,6 +266,10 @@ define([
'tabindex': '-1',
'data-icon': faReadOnly,
}, Messages.fc_open_ro)),
+ h('li', h('a.cp-app-drive-context-download.dropdown-item', {
+ 'tabindex': '-1',
+ 'data-icon': faDownload,
+ }, Messages.download_mt_button)),
h('li', h('a.cp-app-drive-context-share.dropdown-item', {
'tabindex': '-1',
'data-icon': 'fa-shhare-alt',
@@ -846,6 +851,9 @@ define([
// We can only open parent in virtual categories
hide.push('openparent');
}
+ if (!$element.is('.cp-border-color-file')) {
+ hide.push('download');
+ }
if ($element.is('.cp-app-drive-element-file')) {
// No folder in files
hide.push('newfolder');
@@ -903,6 +911,7 @@ define([
hide.push('rename');
hide.push('openparent');
hide.push('hashtag');
+ hide.push('download');
}
if (containsFolder && paths.length > 1) {
// Cannot open multiple folders
@@ -919,7 +928,7 @@ define([
show = ['newfolder', 'newsharedfolder', 'newdoc'];
break;
case 'tree':
- show = ['open', 'openro', 'share', 'rename', 'delete', 'deleteowned', 'removesf',
+ show = ['open', 'openro', 'download', 'share', 'rename', 'delete', 'deleteowned', 'removesf',
'newfolder', 'properties', 'hashtag'];
break;
case 'default':
@@ -1018,7 +1027,8 @@ define([
$actions.each(function (i, el) {
var $a = $(' | |