Implement full CryptDrive export
This commit is contained in:
parent
92ce311694
commit
3e9e92dcac
17
www/code/export.js
Normal file
17
www/code/export.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// This file is used when a user tries to export the entire CryptDrive.
|
||||||
|
// Pads from the code app will be exported using this format instead of plain text.
|
||||||
|
define([
|
||||||
|
'/common/sframe-common-codemirror.js',
|
||||||
|
], function (SFCodeMirror) {
|
||||||
|
var module = {};
|
||||||
|
|
||||||
|
module.main = function (userDoc, cb) {
|
||||||
|
var mode = userDoc.highlightMode || 'gfm';
|
||||||
|
var content = userDoc.content;
|
||||||
|
module.type = SFCodeMirror.getContentExtension(mode);
|
||||||
|
cb(SFCodeMirror.fileExporter(content));
|
||||||
|
};
|
||||||
|
|
||||||
|
return module;
|
||||||
|
});
|
||||||
|
|
||||||
@ -12,11 +12,18 @@ define([
|
|||||||
S.cb(err, doc);
|
S.cb(err, doc);
|
||||||
S.done = true;
|
S.done = true;
|
||||||
|
|
||||||
|
if (!S.hasNetwork) {
|
||||||
var disconnect = Util.find(S, ['network', 'disconnect']);
|
var disconnect = Util.find(S, ['network', 'disconnect']);
|
||||||
if (typeof(disconnect) === 'function') { disconnect(); }
|
if (typeof(disconnect) === 'function') { disconnect(); }
|
||||||
var abort = Util.find(S, ['realtime', 'realtime', 'abort']);
|
}
|
||||||
|
if (S.leave) {
|
||||||
|
try {
|
||||||
|
S.leave();
|
||||||
|
} catch (e) { console.log(e); }
|
||||||
|
}
|
||||||
|
var abort = Util.find(S, ['session', 'realtime', 'abort']);
|
||||||
if (typeof(abort) === 'function') {
|
if (typeof(abort) === 'function') {
|
||||||
S.realtime.realtime.sync();
|
S.session.realtime.sync();
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -51,11 +58,12 @@ define([
|
|||||||
opt = opt || {};
|
opt = opt || {};
|
||||||
|
|
||||||
var config = makeConfig(hash, opt.password);
|
var config = makeConfig(hash, opt.password);
|
||||||
var Session = { cb: cb, };
|
var Session = { cb: cb, hasNetwork: Boolean(opt.network) };
|
||||||
|
|
||||||
config.onReady = function (info) {
|
config.onReady = function (info) {
|
||||||
var rt = Session.session = info.realtime;
|
var rt = Session.session = info.realtime;
|
||||||
Session.network = info.network;
|
Session.network = info.network;
|
||||||
|
Session.leave = info.leave;
|
||||||
finish(Session, void 0, rt.getUserDoc());
|
finish(Session, void 0, rt.getUserDoc());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -59,6 +59,19 @@ define([
|
|||||||
cb();
|
cb();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
common.makeNetwork = function (cb) {
|
||||||
|
require([
|
||||||
|
'/bower_components/netflux-websocket/netflux-client.js',
|
||||||
|
'/common/outer/network-config.js'
|
||||||
|
], function (Netflux, NetConfig) {
|
||||||
|
var wsUrl = NetConfig.getWebsocketURL();
|
||||||
|
Netflux.connect(wsUrl).then(function (network) {
|
||||||
|
cb(null, network);
|
||||||
|
}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// RESTRICTED
|
// RESTRICTED
|
||||||
// Settings only
|
// Settings only
|
||||||
|
|||||||
@ -38,6 +38,12 @@ define([
|
|||||||
return cursor;
|
return cursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.getContentExtension = function (mode) {
|
||||||
|
return (Modes.extensionOf(mode) || '.txt').slice(1);
|
||||||
|
};
|
||||||
|
module.fileExporter = function (content) {
|
||||||
|
return new Blob([ content ], { type: 'text/plain;charset=utf-8' });
|
||||||
|
};
|
||||||
module.setValueAndCursor = function (editor, oldDoc, remoteDoc) {
|
module.setValueAndCursor = function (editor, oldDoc, remoteDoc) {
|
||||||
var scroll = editor.getScrollInfo();
|
var scroll = editor.getScrollInfo();
|
||||||
//get old cursor here
|
//get old cursor here
|
||||||
@ -271,10 +277,10 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
exp.getContentExtension = function () {
|
exp.getContentExtension = function () {
|
||||||
return (Modes.extensionOf(exp.highlightMode) || '.txt').slice(1);
|
return module.getContentExtension(exp.highlightMode);
|
||||||
};
|
};
|
||||||
exp.fileExporter = function () {
|
exp.fileExporter = function () {
|
||||||
return new Blob([ editor.getValue() ], { type: 'text/plain;charset=utf-8' });
|
return module.fileExporter(editor.getValue());
|
||||||
};
|
};
|
||||||
exp.fileImporter = function (content, file) {
|
exp.fileImporter = function (content, file) {
|
||||||
var $toolbarContainer = $('#cme_toolbox');
|
var $toolbarContainer = $('#cme_toolbox');
|
||||||
|
|||||||
@ -21,7 +21,9 @@ define([
|
|||||||
var FilePicker;
|
var FilePicker;
|
||||||
var Messaging;
|
var Messaging;
|
||||||
var Notifier;
|
var Notifier;
|
||||||
var Utils = {};
|
var Utils = {
|
||||||
|
nThen: nThen
|
||||||
|
};
|
||||||
var AppConfig;
|
var AppConfig;
|
||||||
var Test;
|
var Test;
|
||||||
var password;
|
var password;
|
||||||
@ -744,13 +746,46 @@ define([
|
|||||||
Cryptpad.removeLoginBlock(data, cb);
|
Cryptpad.removeLoginBlock(data, cb);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var cgNetwork;
|
||||||
|
var whenCGReady = function (cb) {
|
||||||
|
if (cgNetwork && cgNetwork !== true) { console.log(cgNetwork); return void cb(); }
|
||||||
|
setTimeout(function () {
|
||||||
|
whenCGReady(cb);
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
var i = 0;
|
||||||
sframeChan.on('Q_CRYPTGET', function (data, cb) {
|
sframeChan.on('Q_CRYPTGET', function (data, cb) {
|
||||||
|
var todo = function () {
|
||||||
|
data.opts.network = cgNetwork;
|
||||||
Cryptget.get(data.hash, function (err, val) {
|
Cryptget.get(data.hash, function (err, val) {
|
||||||
cb({
|
cb({
|
||||||
error: err,
|
error: err,
|
||||||
data: val
|
data: val
|
||||||
});
|
});
|
||||||
}, data.opts);
|
}, data.opts);
|
||||||
|
};
|
||||||
|
//return void todo();
|
||||||
|
if (i > 30) {
|
||||||
|
i = 0;
|
||||||
|
cgNetwork = undefined;
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
if (!cgNetwork) {
|
||||||
|
cgNetwork = true;
|
||||||
|
return void Cryptpad.makeNetwork(function (err, nw) {
|
||||||
|
console.log(nw);
|
||||||
|
cgNetwork = nw;
|
||||||
|
todo();
|
||||||
|
});
|
||||||
|
} else if (cgNetwork === true) {
|
||||||
|
return void whenCGReady(todo);
|
||||||
|
}
|
||||||
|
todo();
|
||||||
|
});
|
||||||
|
sframeChan.on('EV_CRYPTGET_DISCONNECT', function () {
|
||||||
|
if (!cgNetwork) { return; }
|
||||||
|
cgNetwork.disconnect();
|
||||||
|
cgNetwork = undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (cfg.addRpc) {
|
if (cfg.addRpc) {
|
||||||
|
|||||||
@ -274,5 +274,6 @@ define({
|
|||||||
|
|
||||||
// Ability to get a pad's content from its hash
|
// Ability to get a pad's content from its hash
|
||||||
'Q_CRYPTGET': true,
|
'Q_CRYPTGET': true,
|
||||||
|
'EV_CRYPTGET_DISCONNECT': true,
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
16
www/kanban/export.js
Normal file
16
www/kanban/export.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// This file is used when a user tries to export the entire CryptDrive.
|
||||||
|
// Pads from the code app will be exported using this format instead of plain text.
|
||||||
|
define([
|
||||||
|
], function () {
|
||||||
|
var module = {};
|
||||||
|
|
||||||
|
module.main = function (userDoc, cb) {
|
||||||
|
var content = userDoc.content;
|
||||||
|
cb(new Blob([JSON.stringify(content, 0, 2)], {
|
||||||
|
type: 'application/json',
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
return module;
|
||||||
|
});
|
||||||
|
|
||||||
@ -368,7 +368,7 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
framework.setFileExporter('json', function () {
|
framework.setFileExporter('json', function () {
|
||||||
return new Blob([JSON.stringify(kanban.getBoardsJSON())], {
|
return new Blob([JSON.stringify(kanban.getBoardsJSON(), 0, 2)], {
|
||||||
type: 'application/json',
|
type: 'application/json',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
64
www/pad/export.js
Normal file
64
www/pad/export.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
define([
|
||||||
|
'jquery',
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/bower_components/hyperjson/hyperjson.js',
|
||||||
|
'/bower_components/nthen/index.js',
|
||||||
|
], function ($, Util, Hyperjson, nThen) {
|
||||||
|
var module = {
|
||||||
|
type: 'html'
|
||||||
|
};
|
||||||
|
|
||||||
|
var exportMediaTags = function (inner, cb) {
|
||||||
|
var $clone = $(inner).clone();
|
||||||
|
nThen(function (waitFor) {
|
||||||
|
$(inner).find('media-tag').each(function (i, el) {
|
||||||
|
if (!$(el).data('blob') || !el.blob) { return; }
|
||||||
|
Util.blobToImage(el.blob || $(el).data('blob'), waitFor(function (imgSrc) {
|
||||||
|
$clone.find('media-tag[src="' + $(el).attr('src') + '"] img')
|
||||||
|
.attr('src', imgSrc);
|
||||||
|
$clone.find('media-tag').parent()
|
||||||
|
.find('.cke_widget_drag_handler_container').remove();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}).nThen(function () {
|
||||||
|
cb($clone[0]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.getHTML = function (inner) {
|
||||||
|
return ('<!DOCTYPE html>\n' + '<html>\n' +
|
||||||
|
' <head><meta charset="utf-8"></head>\n <body>' +
|
||||||
|
inner.innerHTML.replace(/<img[^>]*class="cke_anchor"[^>]*data-cke-realelement="([^"]*)"[^>]*>/g,
|
||||||
|
function(match,realElt){
|
||||||
|
//console.log("returning realElt \"" + unescape(realElt)+ "\".");
|
||||||
|
return decodeURIComponent(realElt); }) +
|
||||||
|
' </body>\n</html>'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.main = function (userDoc, cb) {
|
||||||
|
var inner;
|
||||||
|
if (userDoc instanceof Element || userDoc instanceof HTMLElement) {
|
||||||
|
inner = userDoc;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
if (Array.isArray(userDoc)) {
|
||||||
|
inner = Hyperjson.toDOM(userDoc);
|
||||||
|
} else {
|
||||||
|
console.error('This Pad is not an array!', userDoc);
|
||||||
|
return void cb('');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(JSON.stringify(userDoc));
|
||||||
|
console.error(userDoc);
|
||||||
|
console.error(e);
|
||||||
|
return void cb('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exportMediaTags(inner, function (toExport) {
|
||||||
|
cb(new Blob([ module.getHTML(toExport) ], { type: "text/html;charset=utf-8" }));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return module;
|
||||||
|
});
|
||||||
@ -25,6 +25,7 @@ define([
|
|||||||
'/common/TypingTests.js',
|
'/common/TypingTests.js',
|
||||||
'/customize/messages.js',
|
'/customize/messages.js',
|
||||||
'/pad/links.js',
|
'/pad/links.js',
|
||||||
|
'/pad/export.js',
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/common/media-tag.js',
|
'/common/media-tag.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
@ -49,6 +50,7 @@ define([
|
|||||||
TypingTest,
|
TypingTest,
|
||||||
Messages,
|
Messages,
|
||||||
Links,
|
Links,
|
||||||
|
Exporter,
|
||||||
nThen,
|
nThen,
|
||||||
MediaTag,
|
MediaTag,
|
||||||
ApiConfig,
|
ApiConfig,
|
||||||
@ -166,17 +168,6 @@ define([
|
|||||||
//'AUDIO'
|
//'AUDIO'
|
||||||
];
|
];
|
||||||
|
|
||||||
var getHTML = function (inner) {
|
|
||||||
return ('<!DOCTYPE html>\n' + '<html>\n' +
|
|
||||||
' <head><meta charset="utf-8"></head>\n <body>' +
|
|
||||||
inner.innerHTML.replace(/<img[^>]*class="cke_anchor"[^>]*data-cke-realelement="([^"]*)"[^>]*>/g,
|
|
||||||
function(match,realElt){
|
|
||||||
//console.log("returning realElt \"" + unescape(realElt)+ "\".");
|
|
||||||
return decodeURIComponent(realElt); }) +
|
|
||||||
' </body>\n</html>'
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
var CKEDITOR_CHECK_INTERVAL = 100;
|
var CKEDITOR_CHECK_INTERVAL = 100;
|
||||||
var ckEditorAvailable = function (cb) {
|
var ckEditorAvailable = function (cb) {
|
||||||
var intr;
|
var intr;
|
||||||
@ -647,26 +638,8 @@ define([
|
|||||||
});
|
});
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
var exportMediaTags = function (inner, cb) {
|
framework.setFileExporter(Exporter.type, function (cb) {
|
||||||
var $clone = $(inner).clone();
|
Exporter.main(inner, cb);
|
||||||
nThen(function (waitFor) {
|
|
||||||
$(inner).find('media-tag').each(function (i, el) {
|
|
||||||
if (!$(el).data('blob') || !el.blob) { return; }
|
|
||||||
Util.blobToImage(el.blob || $(el).data('blob'), waitFor(function (imgSrc) {
|
|
||||||
$clone.find('media-tag[src="' + $(el).attr('src') + '"] img')
|
|
||||||
.attr('src', imgSrc);
|
|
||||||
$clone.find('media-tag').parent()
|
|
||||||
.find('.cke_widget_drag_handler_container').remove();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}).nThen(function () {
|
|
||||||
cb($clone[0]);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
framework.setFileExporter('html', function (cb) {
|
|
||||||
exportMediaTags(inner, function (toExport) {
|
|
||||||
cb(new Blob([ getHTML(toExport) ], { type: "text/html;charset=utf-8" }));
|
|
||||||
});
|
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
framework.setNormalizer(function (hjson) {
|
framework.setNormalizer(function (hjson) {
|
||||||
@ -837,7 +810,7 @@ define([
|
|||||||
test.fail("No anchors found. Please adjust document");
|
test.fail("No anchors found. Please adjust document");
|
||||||
} else {
|
} else {
|
||||||
console.log(anchors.length + " anchors found.");
|
console.log(anchors.length + " anchors found.");
|
||||||
var exported = getHTML(window.inner);
|
var exported = Exporter.getHTML(window.inner);
|
||||||
console.log("Obtained exported: " + exported);
|
console.log("Obtained exported: " + exported);
|
||||||
var allFound = true;
|
var allFound = true;
|
||||||
for(var i=0; i<anchors.length; i++) {
|
for(var i=0; i<anchors.length; i++) {
|
||||||
|
|||||||
71
www/poll/export.js
Normal file
71
www/poll/export.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// This file is used when a user tries to export the entire CryptDrive.
|
||||||
|
// Pads from the code app will be exported using this format instead of plain text.
|
||||||
|
define([
|
||||||
|
'/customize/messages.js',
|
||||||
|
], function (Messages) {
|
||||||
|
var module = {};
|
||||||
|
|
||||||
|
var copyObject = function (obj) {
|
||||||
|
return JSON.parse(JSON.stringify(obj));
|
||||||
|
};
|
||||||
|
|
||||||
|
module.getCSV = function (content) {
|
||||||
|
if (!APP.proxy) { return; }
|
||||||
|
var data = copyObject(content);
|
||||||
|
var res = '';
|
||||||
|
|
||||||
|
var escapeStr = function (str) {
|
||||||
|
return '"' + str.replace(/"/g, '""') + '"';
|
||||||
|
};
|
||||||
|
|
||||||
|
[null].concat(data.rowsOrder).forEach(function (rowId, i) {
|
||||||
|
[null].concat(data.colsOrder).forEach(function (colId, j) {
|
||||||
|
// thead
|
||||||
|
if (i === 0) {
|
||||||
|
if (j === 0) { res += ','; return; }
|
||||||
|
if (!colId) { throw new Error("Invalid data"); }
|
||||||
|
res += escapeStr(data.cols[colId] || Messages.anonymous) + ',';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// tbody
|
||||||
|
if (!rowId) { throw new Error("Invalid data"); }
|
||||||
|
if (j === 0) {
|
||||||
|
res += escapeStr(data.rows[rowId] || Messages.poll_optionPlaceholder) + ',';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!colId) { throw new Error("Invalid data"); }
|
||||||
|
res += (data.cells[colId + '_' + rowId] || 3) + ',';
|
||||||
|
});
|
||||||
|
// last column: total
|
||||||
|
// thead
|
||||||
|
if (i === 0) {
|
||||||
|
res += escapeStr(Messages.poll_total) + '\n';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// tbody
|
||||||
|
if (!rowId) { throw new Error("Invalid data"); }
|
||||||
|
res += APP.count[rowId] || '?';
|
||||||
|
res += '\n';
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
module.main = function (userDoc, cb) {
|
||||||
|
var content = userDoc.content;
|
||||||
|
var csv;
|
||||||
|
try {
|
||||||
|
csv = module.getCSV(content);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
var blob2 = new Blob([JSON.stringify(content, 0, 2)], {
|
||||||
|
type: 'application/json',
|
||||||
|
});
|
||||||
|
return void cb(content, true);
|
||||||
|
}
|
||||||
|
var blob = new Blob([csv], {type: "application/csv;charset=utf-8"});
|
||||||
|
cb(blob);
|
||||||
|
};
|
||||||
|
|
||||||
|
return module;
|
||||||
|
});
|
||||||
|
|
||||||
@ -9,6 +9,7 @@ define([
|
|||||||
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
||||||
'/customize/pages.js',
|
'/customize/pages.js',
|
||||||
'/poll/render.js',
|
'/poll/render.js',
|
||||||
|
'/poll/export.js',
|
||||||
'/common/diffMarked.js',
|
'/common/diffMarked.js',
|
||||||
'/common/sframe-common-codemirror.js',
|
'/common/sframe-common-codemirror.js',
|
||||||
'/common/common-thumbnail.js',
|
'/common/common-thumbnail.js',
|
||||||
@ -38,6 +39,7 @@ define([
|
|||||||
Listmap,
|
Listmap,
|
||||||
Pages,
|
Pages,
|
||||||
Renderer,
|
Renderer,
|
||||||
|
Exporter,
|
||||||
DiffMd,
|
DiffMd,
|
||||||
SframeCM,
|
SframeCM,
|
||||||
Thumb,
|
Thumb,
|
||||||
@ -69,56 +71,20 @@ define([
|
|||||||
return JSON.parse(JSON.stringify(obj));
|
return JSON.parse(JSON.stringify(obj));
|
||||||
};
|
};
|
||||||
|
|
||||||
var getCSV = APP.getCSV = function () {
|
APP.getCSV = function () {
|
||||||
if (!APP.proxy) { return; }
|
return Exporter.getCSV(APP.proxy.content);
|
||||||
var data = copyObject(APP.proxy.content);
|
|
||||||
var res = '';
|
|
||||||
|
|
||||||
var escapeStr = function (str) {
|
|
||||||
return '"' + str.replace(/"/g, '""') + '"';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[null].concat(data.rowsOrder).forEach(function (rowId, i) {
|
|
||||||
[null].concat(data.colsOrder).forEach(function (colId, j) {
|
|
||||||
// thead
|
|
||||||
if (i === 0) {
|
|
||||||
if (j === 0) { res += ','; return; }
|
|
||||||
if (!colId) { throw new Error("Invalid data"); }
|
|
||||||
res += escapeStr(data.cols[colId] || Messages.anonymous) + ',';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// tbody
|
|
||||||
if (!rowId) { throw new Error("Invalid data"); }
|
|
||||||
if (j === 0) {
|
|
||||||
res += escapeStr(data.rows[rowId] || Messages.poll_optionPlaceholder) + ',';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!colId) { throw new Error("Invalid data"); }
|
|
||||||
res += (data.cells[colId + '_' + rowId] || 3) + ',';
|
|
||||||
});
|
|
||||||
// last column: total
|
|
||||||
// thead
|
|
||||||
if (i === 0) {
|
|
||||||
res += escapeStr(Messages.poll_total) + '\n';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// tbody
|
|
||||||
if (!rowId) { throw new Error("Invalid data"); }
|
|
||||||
res += APP.count[rowId] || '?';
|
|
||||||
res += '\n';
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
var exportFile = function () {
|
var exportFile = function () {
|
||||||
var csv = getCSV();
|
Exporter.main(APP.proxy, function (blob, isJson) {
|
||||||
var suggestion = Title.suggestTitle(Title.defaultTitle);
|
var suggestion = Title.suggestTitle(Title.defaultTitle);
|
||||||
|
var ext = isJson ? '.json' : '.csv';
|
||||||
UI.prompt(Messages.exportPrompt,
|
UI.prompt(Messages.exportPrompt,
|
||||||
Util.fixFileName(suggestion) + '.csv', function (filename) {
|
Util.fixFileName(suggestion) + ext, function (filename) {
|
||||||
if (!(typeof(filename) === 'string' && filename)) { return; }
|
if (!(typeof(filename) === 'string' && filename)) { return; }
|
||||||
var blob = new Blob([csv], {type: "application/csv;charset=utf-8"});
|
|
||||||
saveAs(blob, filename);
|
saveAs(blob, filename);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -862,13 +862,13 @@ define([
|
|||||||
|
|
||||||
var accountName = privateData.accountName;
|
var accountName = privateData.accountName;
|
||||||
var displayName = metadataMgr.getUserData().name || '';
|
var displayName = metadataMgr.getUserData().name || '';
|
||||||
|
var name = displayName || accountName || Messages.anonymous;
|
||||||
|
var suggestion = name + '-' + new Date().toDateString();
|
||||||
|
|
||||||
var exportFile = function () {
|
var exportFile = function () {
|
||||||
sframeChan.query("Q_SETTINGS_DRIVE_GET", null, function (err, data) {
|
sframeChan.query("Q_SETTINGS_DRIVE_GET", null, function (err, data) {
|
||||||
if (err) { return void console.error(err); }
|
if (err) { return void console.error(err); }
|
||||||
var sjson = JSON.stringify(data);
|
var sjson = JSON.stringify(data);
|
||||||
var name = displayName || accountName || Messages.anonymous;
|
|
||||||
var suggestion = name + '-' + new Date().toDateString();
|
|
||||||
UI.prompt(Messages.exportPrompt,
|
UI.prompt(Messages.exportPrompt,
|
||||||
Util.fixFileName(suggestion) + '.json', function (filename) {
|
Util.fixFileName(suggestion) + '.json', function (filename) {
|
||||||
if (!(typeof(filename) === 'string' && filename)) { return; }
|
if (!(typeof(filename) === 'string' && filename)) { return; }
|
||||||
@ -916,16 +916,14 @@ define([
|
|||||||
|
|
||||||
Backup.create(data, getPad, function (blob) {
|
Backup.create(data, getPad, function (blob) {
|
||||||
saveAs(blob, filename);
|
saveAs(blob, filename);
|
||||||
|
sframeChan.event('EV_CRYPTGET_DISCONNECT');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
sframeChan.query("Q_SETTINGS_DRIVE_GET", null, function (err, data) {
|
sframeChan.query("Q_SETTINGS_DRIVE_GET", "full", function (err, data) {
|
||||||
if (err) { return void console.error(err); }
|
if (err) { return void console.error(err); }
|
||||||
var sjson = JSON.stringify(data);
|
if (data.error) { return void console.error(data.error); }
|
||||||
var name = displayName || accountName || Messages.anonymous;
|
UI.prompt('TODO are you sure? if yes, pick a name...', // XXX
|
||||||
var suggestion = name + '-' + new Date().toDateString();
|
Util.fixFileName(suggestion) + '.zip', function (filename) {
|
||||||
|
|
||||||
UI.prompt('TODO are you sure? if ye,s pick a name...', // XXX
|
|
||||||
Util.fixFileName(suggestion) + '.json', function (filename) {
|
|
||||||
if (!(typeof(filename) === 'string' && filename)) { return; }
|
if (!(typeof(filename) === 'string' && filename)) { return; }
|
||||||
todo(data, filename);
|
todo(data, filename);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -43,7 +43,26 @@ define([
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_SETTINGS_DRIVE_GET', function (d, cb) {
|
sframeChan.on('Q_SETTINGS_DRIVE_GET', function (d, cb) {
|
||||||
Cryptpad.getUserObject(cb);
|
if (d === "full") {
|
||||||
|
// We want shared folders too
|
||||||
|
}
|
||||||
|
Cryptpad.getUserObject(function (obj) {
|
||||||
|
if (obj.error) { return void cb(obj); }
|
||||||
|
var result = {
|
||||||
|
uo: obj,
|
||||||
|
sf: {}
|
||||||
|
};
|
||||||
|
if (!obj.drive || !obj.drive.sharedFolders) { return void cb(result); }
|
||||||
|
Utils.nThen(function (waitFor) {
|
||||||
|
Object.keys(obj.drive.sharedFolders).forEach(function (id) {
|
||||||
|
Cryptpad.getSharedFolder(id, waitFor(function (obj) {
|
||||||
|
result.sf[id] = obj;
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}).nThen(function () {
|
||||||
|
cb(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_SETTINGS_DRIVE_SET', function (data, cb) {
|
sframeChan.on('Q_SETTINGS_DRIVE_SET', function (data, cb) {
|
||||||
var sjson = JSON.stringify(data);
|
var sjson = JSON.stringify(data);
|
||||||
|
|||||||
@ -1,24 +1,51 @@
|
|||||||
define([
|
define([
|
||||||
'/common/cryptget.js',
|
'/common/cryptget.js',
|
||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/file/file-crypto.js',
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/bower_components/saferphore/index.js',
|
'/bower_components/saferphore/index.js',
|
||||||
'/bower_components/jszip/dist/jszip.min.js',
|
'/bower_components/jszip/dist/jszip.min.js',
|
||||||
], function (Crypt, Hash, nThen, Saferphore, JsZip) {
|
], function (Crypt, Hash, Util, FileCrypto, nThen, Saferphore, JsZip) {
|
||||||
|
|
||||||
var sanitize = function (str) {
|
var sanitize = function (str) {
|
||||||
return str.replace(/[^a-z0-9]/gi, '_').toLowerCase();
|
return str.replace(/[\\/?%*:|"<>]/gi, '_')/*.toLowerCase()*/;
|
||||||
};
|
};
|
||||||
|
|
||||||
var getUnique = function (name, ext, existing) {
|
var getUnique = function (name, ext, existing) {
|
||||||
var n = name;
|
var n = name + ext;
|
||||||
var i = 1;
|
var i = 1;
|
||||||
while (existing.indexOf(n) !== -1) {
|
while (existing.indexOf(n.toLowerCase()) !== -1) {
|
||||||
n = name + ' ('+ i++ + ')';
|
n = name + ' ('+ i++ + ')' + ext;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var transform = function (ctx, type, sjson, cb) {
|
||||||
|
var result = {
|
||||||
|
data: sjson,
|
||||||
|
ext: '.json',
|
||||||
|
};
|
||||||
|
var json;
|
||||||
|
try {
|
||||||
|
json = JSON.parse(sjson);
|
||||||
|
} catch (e) {
|
||||||
|
return void cb(result);
|
||||||
|
}
|
||||||
|
var path = '/' + type + '/export.js';
|
||||||
|
require([path], function (Exporter) {
|
||||||
|
Exporter.main(json, function (data) {
|
||||||
|
result.ext = '.' + Exporter.type;
|
||||||
|
result.data = data;
|
||||||
|
cb(result);
|
||||||
|
});
|
||||||
|
}, function () {
|
||||||
|
cb(result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add a file to the zip. We have to cryptget&transform it if it's a pad
|
||||||
|
// or fetch&decrypt it if it's a file.
|
||||||
var addFile = function (ctx, zip, fData, existingNames) {
|
var addFile = function (ctx, zip, fData, existingNames) {
|
||||||
if (!fData.href && !fData.roHref) {
|
if (!fData.href && !fData.roHref) {
|
||||||
return void ctx.errors.push({
|
return void ctx.errors.push({
|
||||||
@ -28,70 +55,121 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
var parsed = Hash.parsePadUrl(fData.href || fData.roHref);
|
var parsed = Hash.parsePadUrl(fData.href || fData.roHref);
|
||||||
// TODO deal with files here
|
if (['pad', 'file'].indexOf(parsed.hashData.type) === -1) { return; }
|
||||||
if (parsed.hashData.type !== 'pad') { return; }
|
|
||||||
|
|
||||||
|
// waitFor is used to make sure all the pads and files are process before downloading the zip.
|
||||||
var w = ctx.waitFor();
|
var w = ctx.waitFor();
|
||||||
|
|
||||||
|
// Work with only 10 pad/files at a time
|
||||||
ctx.sem.take(function (give) {
|
ctx.sem.take(function (give) {
|
||||||
var opts = {
|
var opts = {
|
||||||
password: fData.password
|
password: fData.password
|
||||||
};
|
};
|
||||||
var rawName = fData.fileName || fData.title || 'File';
|
var rawName = fData.filename || fData.title || 'File';
|
||||||
console.log(rawName);
|
console.log(rawName);
|
||||||
ctx.get({
|
var g = give();
|
||||||
hash: parsed.hash,
|
|
||||||
opts: opts
|
var done = function () {
|
||||||
}, give(function (err, val) {
|
//setTimeout(g, 2000);
|
||||||
|
g();
|
||||||
w();
|
w();
|
||||||
if (err) {
|
};
|
||||||
|
var error = function (err) {
|
||||||
|
done();
|
||||||
return void ctx.errors.push({
|
return void ctx.errors.push({
|
||||||
error: err,
|
error: err,
|
||||||
data: fData
|
data: fData
|
||||||
});
|
});
|
||||||
}
|
|
||||||
// TODO transform file here
|
|
||||||
// var blob = transform(val, type);
|
|
||||||
var opts = {};
|
|
||||||
var fileName = getUnique(sanitize(rawName), '.txt', existingNames);
|
|
||||||
existingNames.push(fileName);
|
|
||||||
zip.file(fileName, val, opts);
|
|
||||||
console.log('DONE ---- ' + rawName);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
// cb(err, blob);
|
|
||||||
// wiht blob.name not undefined
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var makeFolder = function (ctx, root, zip) {
|
// 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add folders and their content recursively in the zip
|
||||||
|
var makeFolder = function (ctx, root, zip, fd) {
|
||||||
if (typeof (root) !== "object") { return; }
|
if (typeof (root) !== "object") { return; }
|
||||||
var existingNames = [];
|
var existingNames = [];
|
||||||
Object.keys(root).forEach(function (k) {
|
Object.keys(root).forEach(function (k) {
|
||||||
var el = root[k];
|
var el = root[k];
|
||||||
if (typeof el === "object") {
|
if (typeof el === "object") {
|
||||||
var fName = getUnique(sanitize(k), '', existingNames);
|
var fName = getUnique(sanitize(k), '', existingNames);
|
||||||
existingNames.push(fName);
|
existingNames.push(fName.toLowerCase());
|
||||||
return void makeFolder(ctx, el, zip.folder(fName));
|
return void makeFolder(ctx, el, zip.folder(fName), fd);
|
||||||
}
|
}
|
||||||
if (ctx.data.sharedFolders[el]) {
|
if (ctx.data.sharedFolders[el]) {
|
||||||
// TODO later...
|
var sfData = ctx.sf[el].metadata;
|
||||||
return;
|
var sfName = getUnique(sanitize(sfData.title || 'Folder'), '', existingNames);
|
||||||
|
existingNames.push(sfName.toLowerCase());
|
||||||
|
return void makeFolder(ctx, ctx.sf[el].root, zip.folder(sfName), ctx.sf[el].filesData);
|
||||||
}
|
}
|
||||||
var fData = ctx.data.filesData[el];
|
var fData = fd[el];
|
||||||
if (fData) {
|
if (fData) {
|
||||||
addFile(ctx, zip, fData, existingNames);
|
addFile(ctx, zip, fData, existingNames);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// What is this element?
|
|
||||||
console.error(el);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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) {
|
||||||
if (!data || !data.drive) { return void cb('EEMPTY'); }
|
if (!data || !data.uo || !data.uo.drive) { return void cb('EEMPTY'); }
|
||||||
var sem = Saferphore.create(10);
|
var sem = Saferphore.create(5);
|
||||||
var ctx = {
|
var ctx = {
|
||||||
get: getPad,
|
get: getPad,
|
||||||
data: data.drive,
|
data: data.uo.drive,
|
||||||
|
sf: data.sf,
|
||||||
zip: new JsZip(),
|
zip: new JsZip(),
|
||||||
errors: [],
|
errors: [],
|
||||||
sem: sem,
|
sem: sem,
|
||||||
@ -99,9 +177,8 @@ define([
|
|||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
ctx.waitFor = waitFor;
|
ctx.waitFor = waitFor;
|
||||||
var zipRoot = ctx.zip.folder('Root');
|
var zipRoot = ctx.zip.folder('Root');
|
||||||
makeFolder(ctx, data.drive.root, zipRoot);
|
makeFolder(ctx, ctx.data.root, zipRoot, ctx.data.filesData);
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
// TODO call cb with ctx.zip here
|
|
||||||
console.log(ctx.zip);
|
console.log(ctx.zip);
|
||||||
console.log(ctx.errors);
|
console.log(ctx.errors);
|
||||||
ctx.zip.generateAsync({type: 'blob'}).then(function (content) {
|
ctx.zip.generateAsync({type: 'blob'}).then(function (content) {
|
||||||
|
|||||||
18
www/slide/export.js
Normal file
18
www/slide/export.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// This file is used when a user tries to export the entire CryptDrive.
|
||||||
|
// Pads from the slide app will be exported using this format instead of plain text.
|
||||||
|
define([
|
||||||
|
'/common/sframe-common-codemirror.js',
|
||||||
|
], function (SFCodeMirror) {
|
||||||
|
var module = {
|
||||||
|
type: 'md'
|
||||||
|
};
|
||||||
|
|
||||||
|
module.main = function (userDoc, cb) {
|
||||||
|
var content = userDoc.content;
|
||||||
|
cb(SFCodeMirror.fileExporter(content));
|
||||||
|
};
|
||||||
|
|
||||||
|
return module;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
24
www/whiteboard/export.js
Normal file
24
www/whiteboard/export.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// This file is used when a user tries to export the entire CryptDrive.
|
||||||
|
// Pads from the code app will be exported using this format instead of plain text.
|
||||||
|
define([
|
||||||
|
'/bower_components/secure-fabric.js/dist/fabric.min.js',
|
||||||
|
], function () {
|
||||||
|
var module = {};
|
||||||
|
|
||||||
|
var Fabric = window.fabric;
|
||||||
|
module.main = function (userDoc, cb) {
|
||||||
|
var canvas_node = document.createElement('canvas');
|
||||||
|
canvas_node.setAttribute('style', 'width:600px;height:600px;');
|
||||||
|
canvas_node.setAttribute('width', '600');
|
||||||
|
canvas_node.setAttribute('height', '600');
|
||||||
|
var canvas = new Fabric.Canvas(canvas_node);
|
||||||
|
var content = userDoc.content;
|
||||||
|
canvas.loadFromJSON(content, function () {
|
||||||
|
module.type = 'svg';
|
||||||
|
cb(canvas.toSVG());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return module;
|
||||||
|
});
|
||||||
|
|
||||||
@ -277,6 +277,7 @@ define([
|
|||||||
|
|
||||||
// Start of the main loop
|
// Start of the main loop
|
||||||
var andThen2 = function (framework) {
|
var andThen2 = function (framework) {
|
||||||
|
APP.framework = framework;
|
||||||
var canvas = APP.canvas = new Fabric.Canvas('cp-app-whiteboard-canvas', {
|
var canvas = APP.canvas = new Fabric.Canvas('cp-app-whiteboard-canvas', {
|
||||||
containerClass: 'cp-app-whiteboard-canvas-container'
|
containerClass: 'cp-app-whiteboard-canvas-container'
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user