', { 'class': 'cp-settings-delete cp-sidebarlayout-element'});
@@ -857,6 +818,143 @@ define([
return $div;
};
+
+ var createExportUI = function () {
+ var progress = h('div.cp-export-progress');
+ var actions = h('div.cp-export-actions');
+ var errors = h('div.cp-export-errors', [
+ h('p', Messages.settings_exportErrorDescription)
+ ]);
+ var exportUI = h('div#cp-export-container', [
+ h('div.cp-export-block', [
+ h('h3', Messages.settings_exportTitle),
+ h('p', [
+ Messages.settings_exportDescription,
+ h('br'),
+ Messages.settings_exportWarning
+ ]),
+ progress,
+ actions,
+ errors
+ ])
+ ]);
+ $('body').append(exportUI);
+ $('#cp-sidebarlayout-container').hide();
+
+ var close = function () {
+ $(exportUI).remove();
+ $('#cp-sidebarlayout-container').show();
+ };
+
+ var _onCancel = [];
+ var onCancel = function (h) {
+ if (typeof (h) !== "function") { return; }
+ _onCancel.push(h);
+ };
+ var cancel = h('button.btn.btn-default', Messages.cancel);
+ $(cancel).click(function () {
+ UI.confirm(Messages.settings_exportCancel, function (yes) {
+ if (!yes) { return; }
+ _onCancel.forEach(function (h) { h(); });
+ });
+ }).appendTo(actions);
+
+ var error = h('button.btn.btn-danger', Messages.settings_exportError);
+ var translateErrors = function (err) {
+ if (err === 'EEMPTY') {
+ return Messages.settings_exportErrorEmpty;
+ }
+ if (['E404', 'EEXPIRED', 'EDELETED'].indexOf(err) !== -1) {
+ return Messages.settings_exportErrorMissing;
+ }
+ return Messages._getKey('settings_exportErrorOther', [err]);
+ };
+ var addErrors = function (errs) {
+ if (!errs.length) { return; }
+ var onClick = function () {
+ console.error('clicked?');
+ $(errors).toggle();
+ };
+ $(error).click(onClick).appendTo(actions);
+ var list = h('div.cp-export-errors-list');
+ $(list).appendTo(errors);
+ errs.forEach(function (err) {
+ if (!err.data) { return; }
+ var href = err.data.href || err.data.roHref;
+ $(h('div', [
+ h('div.title', err.data.filename || err.data.title),
+ h('div.link', [
+ h('a', {
+ href: err.data.href || err.data.roHref,
+ target: '_blank'
+ }, privateData.origin + href)
+ ]),
+ h('div.reason', translateErrors(err.error))
+ ])).appendTo(list);
+ });
+ };
+
+ var download = h('button.btn.btn-primary', Messages.download_mt_button);
+ var completed = false;
+ var complete = function (h, err) {
+ if (completed) { return; }
+ completed = true;
+ $(progress).find('.fa-square-o').removeClass('fa-square-o')
+ .addClass('fa-check-square-o');
+ $(cancel).text(Messages.filePicker_close).off('click').click(function () {
+ _onCancel.forEach(function (h) { h(); });
+ });
+ $(download).click(h).appendTo(actions);
+ addErrors(err);
+ };
+
+ var done = {};
+ var update = function (step, state) {
+ console.log(step, state);
+ console.log(done[step]);
+ if (done[step] && done[step] === -1) { return; }
+
+
+ // New step
+ if (!done[step]) {
+ $(progress).find('.fa-square-o').removeClass('fa-square-o')
+ .addClass('fa-check-square-o');
+ $(progress).append(h('p', [
+ h('span.fa.fa-square-o'),
+ h('span.text', Messages['settings_export_'+step] || step)
+ ]));
+ done[step] = state; // -1 if no bar, object otherwise
+ if (state !== -1) {
+ var bar = h('div.cp-export-progress-bar');
+ $(progress).append(h('div.cp-export-progress-bar-container', [
+ bar
+ ]));
+ done[step] = { bar: bar };
+ }
+ return;
+ }
+
+ // Updating existing step
+ if (typeof state !== "object") { return; }
+ var b = done[step].bar;
+ var w = (state.current/state.max) * 100;
+ $(b).css('width', w + '%');
+ if (!done[step].text) {
+ done[step].text = h('div.cp-export-progress-text');
+ $(done[step].text).appendTo(b);
+ }
+ $(done[step].text).text(state.current + ' / ' + state.max);
+ if (state.current === state.max) { done[step] = -1; }
+ };
+
+ return {
+ close: close,
+ update: update,
+ complete: complete,
+ onCancel: onCancel
+ };
+ };
+
create['drive-backup'] = function () {
var $div = $('
', {'class': 'cp-settings-drive-backup cp-sidebarlayout-element'});
@@ -911,18 +1009,28 @@ define([
if (err) { return void cb(err); }
if (obj.error) { return void cb(obj.error); }
cb(null, obj.data);
- });
+ }, { timeout: 5 * 60 * 1000 });
};
- Backup.create(data, getPad, function (blob) {
+ var ui = createExportUI();
+
+ var bu = Backup.create(data, getPad, function (blob, errors) {
+ console.log(blob);
saveAs(blob, filename);
sframeChan.event('EV_CRYPTGET_DISCONNECT');
+ ui.complete(function () {
+ saveAs(blob, filename);
+ }, errors);
+ }, ui.update);
+ ui.onCancel(function () {
+ ui.close();
+ bu.stop();
});
};
sframeChan.query("Q_SETTINGS_DRIVE_GET", "full", function (err, data) {
if (err) { return void console.error(err); }
if (data.error) { return void console.error(data.error); }
- UI.prompt('TODO are you sure? if yes, pick a name...', // XXX
+ UI.prompt(Messages.settings_backup2Confirm,
Util.fixFileName(suggestion) + '.zip', function (filename) {
if (!(typeof(filename) === 'string' && filename)) { return; }
todo(data, filename);
@@ -931,9 +1039,9 @@ define([
};
$('', {'class': 'cp-sidebarlayout-description'})
.text(Messages.settings_backupHint2).appendTo($div);
- var $export = common.createButton('export', true, {}, exportDrive);
- $export.attr('class', 'btn btn-success').text(Messages.settings_backup2);
- $div.append($export);
+ var $export2 = common.createButton('export', true, {}, exportDrive);
+ $export2.attr('class', 'btn btn-success').text(Messages.settings_backup2);
+ $div.append($export2);
return $div;
};
diff --git a/www/settings/make-backup.js b/www/settings/make-backup.js
index 9238df59a..c49e8b986 100644
--- a/www/settings/make-backup.js
+++ b/www/settings/make-backup.js
@@ -60,79 +60,92 @@ define([
// waitFor is used to make sure all the pads and files are process before downloading the zip.
var w = ctx.waitFor();
+ ctx.max++;
// Work with only 10 pad/files at a time
ctx.sem.take(function (give) {
- var opts = {
- password: fData.password
- };
- var rawName = fData.filename || fData.title || 'File';
- console.log(rawName);
var g = give();
+ if (ctx.stop) { return; }
+ setTimeout(function () {
+ if (ctx.stop) { return; }
+ var opts = {
+ password: fData.password
+ };
+ var rawName = fData.filename || fData.title || 'File';
+ console.log(rawName);
- var done = function () {
- //setTimeout(g, 2000);
- g();
- w();
- };
- var error = function (err) {
- done();
- return void ctx.errors.push({
- error: err,
- data: fData
- });
- };
-
- // Pads (pad,code,slide,kanban,poll,...)
- var todoPad = function () {
- ctx.get({
- hash: parsed.hash,
- opts: opts
- }, function (err, val) {
- if (err) { return void error(err); }
- if (!val) { return void error('EEMPTY'); }
-
- var opts = {
- binary: true,
- };
- transform(ctx, parsed.type, val, function (res) {
- if (!res.data) { return void error('EEMPTY'); }
- var fileName = getUnique(sanitize(rawName), res.ext, existingNames);
- existingNames.push(fileName.toLowerCase());
- zip.file(fileName, res.data, opts);
- console.log('DONE ---- ' + fileName);
- setTimeout(done, 1000);
+ var done = function () {
+ if (ctx.stop) { return; }
+ //setTimeout(g, 2000);
+ g();
+ w();
+ ctx.done++;
+ ctx.updateProgress('download', {max: ctx.max, current: ctx.done});
+ };
+ var error = function (err) {
+ if (ctx.stop) { return; }
+ done();
+ return void ctx.errors.push({
+ error: err,
+ data: fData
});
- });
- };
+ };
- // Files (mediatags...)
- var todoFile = function () {
- var secret = Hash.getSecrets('file', parsed.hash, fData.password);
- var hexFileName = secret.channel;
- var src = Hash.getBlobPathFromHex(hexFileName);
- var key = secret.keys && secret.keys.cryptKey;
- Util.fetch(src, function (err, u8) {
- if (err) { return void error('E404'); }
- FileCrypto.decrypt(u8, key, function (err, res) {
+ // Pads (pad,code,slide,kanban,poll,...)
+ var todoPad = function () {
+ ctx.get({
+ hash: parsed.hash,
+ opts: opts
+ }, function (err, val) {
+ if (ctx.stop) { return; }
if (err) { return void error(err); }
+ if (!val) { return void error('EEMPTY'); }
+
var opts = {
binary: true,
};
- var extIdx = rawName.lastIndexOf('.');
- var name = extIdx !== -1 ? rawName.slice(0,extIdx) : rawName;
- var ext = extIdx !== -1 ? rawName.slice(extIdx) : "";
- var fileName = getUnique(sanitize(name), ext, existingNames);
- existingNames.push(fileName.toLowerCase());
- zip.file(fileName, res.content, opts);
- console.log('DONE ---- ' + fileName);
- setTimeout(done, 1000);
+ transform(ctx, parsed.type, val, function (res) {
+ if (ctx.stop) { return; }
+ if (!res.data) { return void error('EEMPTY'); }
+ var fileName = getUnique(sanitize(rawName), res.ext, existingNames);
+ existingNames.push(fileName.toLowerCase());
+ zip.file(fileName, res.data, opts);
+ console.log('DONE ---- ' + fileName);
+ setTimeout(done, 500);
+ });
});
- });
- };
- if (parsed.hashData.type === 'file') {
- return void todoFile();
- }
- todoPad();
+ };
+
+ // Files (mediatags...)
+ var todoFile = function () {
+ var secret = Hash.getSecrets('file', parsed.hash, fData.password);
+ var hexFileName = secret.channel;
+ var src = Hash.getBlobPathFromHex(hexFileName);
+ var key = secret.keys && secret.keys.cryptKey;
+ Util.fetch(src, function (err, u8) {
+ if (ctx.stop) { return; }
+ if (err) { return void error('E404'); }
+ FileCrypto.decrypt(u8, key, function (err, res) {
+ if (ctx.stop) { return; }
+ if (err) { return void error(err); }
+ var opts = {
+ binary: true,
+ };
+ var extIdx = rawName.lastIndexOf('.');
+ var name = extIdx !== -1 ? rawName.slice(0,extIdx) : rawName;
+ var ext = extIdx !== -1 ? rawName.slice(extIdx) : "";
+ var fileName = getUnique(sanitize(name), ext, existingNames);
+ existingNames.push(fileName.toLowerCase());
+ zip.file(fileName, res.content, opts);
+ console.log('DONE ---- ' + fileName);
+ setTimeout(done, 1000);
+ });
+ });
+ };
+ if (parsed.hashData.type === 'file') {
+ return void todoFile();
+ }
+ todoPad();
+ });
});
// cb(err, blob);
};
@@ -163,7 +176,7 @@ define([
};
// Main function. Create the empty zip and fill it starting from drive.root
- var create = function (data, getPad, cb) {
+ var create = function (data, getPad, cb, progress) {
if (!data || !data.uo || !data.uo.drive) { return void cb('EEMPTY'); }
var sem = Saferphore.create(5);
var ctx = {
@@ -173,18 +186,33 @@ define([
zip: new JsZip(),
errors: [],
sem: sem,
+ updateProgress: progress,
+ max: 0,
+ done: 0
};
+ progress('reading', -1);
nThen(function (waitFor) {
ctx.waitFor = waitFor;
var zipRoot = ctx.zip.folder('Root');
makeFolder(ctx, ctx.data.root, zipRoot, ctx.data.filesData);
+ progress('download', {});
}).nThen(function () {
console.log(ctx.zip);
console.log(ctx.errors);
+ progress('compressing', -1);
ctx.zip.generateAsync({type: 'blob'}).then(function (content) {
- cb(content);
+ progress('done', -1);
+ cb(content, ctx.errors);
});
});
+
+ var stop = function () {
+ ctx.stop = true;
+ delete ctx.zip;
+ };
+ return {
+ stop: stop
+ };
};
return {