Make a copy

pull/1/head
yflory 5 years ago
parent 2cceb54aac
commit 3abe522a9f

@ -2158,6 +2158,17 @@ define([
if (data.accept) { $input.attr('accept', data.accept); } if (data.accept) { $input.attr('accept', data.accept); }
button.click(function () { $input.click(); }); button.click(function () { $input.click(); });
break; break;
case 'copy':
button = $('<button>', {
'class': 'fa fa-clone cp-toolbar-icon-import',
title: Messages.makeACopy,
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.makeACopy));
button
.click(common.prepareFeedback(type))
.click(function () {
sframeChan.query('EV_MAKE_A_COPY');
});
break;
case 'importtemplate': case 'importtemplate':
if (!AppConfig.enableTemplates) { return; } if (!AppConfig.enableTemplates) { return; }
if (!common.isLoggedIn()) { return; } if (!common.isLoggedIn()) { return; }

@ -543,6 +543,25 @@ define([
}); });
}; };
var fixPadMetadata = function (parsed) {
var meta;
if (Array.isArray(parsed) && typeof(parsed[3]) === "object") {
meta = parsed[3].metadata; // pad
} else if (parsed.info) {
meta = parsed.info; // poll
} else {
meta = parsed.metadata;
}
if (typeof(meta) === "object") {
meta.defaultTitle = meta.title || meta.defaultTitle;
meta.title = "";
delete meta.users;
delete meta.chat2;
delete meta.chat;
delete meta.cursor;
}
};
common.useTemplate = function (data, Crypt, cb, optsPut) { common.useTemplate = function (data, Crypt, cb, optsPut) {
// opts is used to overrides options for chainpad-netflux in cryptput // opts is used to overrides options for chainpad-netflux in cryptput
// it allows us to add owners and expiration time if it is a new file // it allows us to add owners and expiration time if it is a new file
@ -576,24 +595,7 @@ define([
try { try {
// Try to fix the title before importing the template // Try to fix the title before importing the template
var parsed = JSON.parse(val); var parsed = JSON.parse(val);
var meta; fixPadMetadata(parsed);
if (Array.isArray(parsed) && typeof(parsed[3]) === "object") {
meta = parsed[3].metadata; // pad
} else if (parsed.info) {
meta = parsed.info; // poll
} else {
meta = parsed.metadata;
}
if (typeof(meta) === "object") {
meta.defaultTitle = meta.title || meta.defaultTitle;
meta.title = "";
delete meta.users;
delete meta.chat2;
delete meta.chat;
delete meta.cursor;
if (data.chat) { meta.chat2 = data.chat; }
if (data.cursor) { meta.cursor = data.cursor; }
}
val = JSON.stringify(parsed); val = JSON.stringify(parsed);
} catch (e) { } catch (e) {
console.log("Can't fix template title", e); console.log("Can't fix template title", e);
@ -608,58 +610,96 @@ define([
var data = common.fromFileData; var data = common.fromFileData;
var parsed = Hash.parsePadUrl(data.href); var parsed = Hash.parsePadUrl(data.href);
var parsed2 = Hash.parsePadUrl(currentPad.href); var parsed2 = Hash.parsePadUrl(currentPad.href);
var hash = parsed.hash;
var name = data.title; if (parsed2.type === 'poll') { optsPut.initialState = '{}'; }
var secret = Hash.getSecrets('file', hash, data.password);
var src = fileHost + Hash.getBlobPathFromHex(secret.channel);
var key = secret.keys && secret.keys.cryptKey;
var u8;
var res;
var mode;
var val; var val;
Nthen(function(waitFor) { Nthen(function(_waitFor) {
Util.fetch(src, waitFor(function (err, _u8) { // If pad, use cryptget
if (err) { return void waitFor.abort(); } if (parsed.hashData && parsed.hashData.type === 'pad') {
u8 = _u8; var optsGet = {
})); password: data.password,
}).nThen(function (waitFor) { initialState: parsed.type === 'poll' ? '{}' : undefined
require(["/file/file-crypto.js"], waitFor(function (FileCrypto) { };
FileCrypto.decrypt(u8, key, waitFor(function (err, _res) { Crypt.get(parsed.hash, _waitFor(function (err, _val) {
if (err || !_res.content) { return void waitFor.abort(); } if (err) {
res = _res; _waitFor.abort();
})); return void cb();
})); }
}).nThen(function (waitFor) { try {
var ext = Util.parseFilename(data.title).ext; val = JSON.parse(_val);
if (!ext) { fixPadMetadata(val);
mode = "text"; } catch (e) {
_waitFor.abort();
return void cb();
}
}), optsGet);
return; return;
} }
require(["/common/modes.js"], waitFor(function (Modes) {
Modes.list.some(function (fType) { var name = data.title;
if (fType.ext === ext) { var secret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
mode = fType.mode; var src = fileHost + Hash.getBlobPathFromHex(secret.channel);
return true; var key = secret.keys && secret.keys.cryptKey;
var u8;
var res;
var mode;
// Otherwise, it's a text blob "open in code": get blob data & convert format
Nthen(function (waitFor) {
Util.fetch(src, waitFor(function (err, _u8) {
if (err) {
_waitFor.abort();
return void waitFor.abort();
} }
}); u8 = _u8;
})); }));
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
var reader = new FileReader(); require(["/file/file-crypto.js"], waitFor(function (FileCrypto) {
reader.addEventListener('loadend', waitFor(function (e) { FileCrypto.decrypt(u8, key, waitFor(function (err, _res) {
val = { if (err || !_res.content) {
content: e.srcElement.result, _waitFor.abort();
highlightMode: mode, return void waitFor.abort();
metadata: { }
defaultTitle: name, res = _res;
title: name, }));
type: "code", }));
}, }).nThen(function (waitFor) {
}; var ext = Util.parseFilename(data.title).ext;
})); if (!ext) {
reader.readAsText(res.content); mode = "text";
return;
}
require(["/common/modes.js"], waitFor(function (Modes) {
Modes.list.some(function (fType) {
if (fType.ext === ext) {
mode = fType.mode;
return true;
}
});
}));
}).nThen(function (waitFor) {
var reader = new FileReader();
reader.addEventListener('loadend', waitFor(function (e) {
val = {
content: e.srcElement.result,
highlightMode: mode,
metadata: {
defaultTitle: name,
title: name,
type: "code",
},
};
}));
reader.readAsText(res.content);
}).nThen(_waitFor());
}).nThen(function () { }).nThen(function () {
Crypt.put(parsed2.hash, JSON.stringify(val), cb, optsPut); Crypt.put(parsed2.hash, JSON.stringify(val), function () {
cb();
Crypt.get(parsed2.hash, function (err, val) {
console.warn(val);
});
}, optsPut);
}); });
}; };
@ -1906,6 +1946,9 @@ define([
// if a pad is created from a file // if a pad is created from a file
if (sessionStorage[Constants.newPadFileData]) { if (sessionStorage[Constants.newPadFileData]) {
common.fromFileData = JSON.parse(sessionStorage[Constants.newPadFileData]); common.fromFileData = JSON.parse(sessionStorage[Constants.newPadFileData]);
var _parsed1 = Hash.parsePadUrl(common.fromFileData.href);
var _parsed2 = Hash.parsePadUrl(window.location.href);
if (_parsed1.type !== _parsed2.type) { delete common.fromFileData; }
delete sessionStorage[Constants.newPadFileData]; delete sessionStorage[Constants.newPadFileData];
} }

@ -78,6 +78,7 @@ define([
var faRename = 'fa-pencil'; var faRename = 'fa-pencil';
var faColor = 'cptools-palette'; var faColor = 'cptools-palette';
var faTrash = 'fa-trash'; var faTrash = 'fa-trash';
var faCopy = 'fa-clone';
var faDelete = 'fa-eraser'; var faDelete = 'fa-eraser';
var faProperties = 'fa-info-circle'; var faProperties = 'fa-info-circle';
var faTags = 'fa-hashtag'; var faTags = 'fa-hashtag';
@ -431,6 +432,10 @@ define([
'data-icon': faTags, 'data-icon': faTags,
}, Messages.fc_hashtag)), }, Messages.fc_hashtag)),
$separator.clone()[0], $separator.clone()[0],
h('li', h('a.cp-app-drive-context-makeacopy.dropdown-item.cp-app-drive-context-editable', {
'tabindex': '-1',
'data-icon': faCopy,
}, Messages.makeACopy)),
h('li', h('a.cp-app-drive-context-delete.dropdown-item.cp-app-drive-context-editable', { h('li', h('a.cp-app-drive-context-delete.dropdown-item.cp-app-drive-context-editable', {
'tabindex': '-1', 'tabindex': '-1',
'data-icon': faTrash, 'data-icon': faTrash,
@ -1179,6 +1184,9 @@ define([
if (!metadata || !Util.isPlainTextFile(metadata.fileType, metadata.title)) { if (!metadata || !Util.isPlainTextFile(metadata.fileType, metadata.title)) {
hide.push('openincode'); hide.push('openincode');
} }
if (!metadata.channel || metadata.channel.length > 32) {
hide.push('makeacopy'); // Not for blobs
}
} else if ($element.is('.cp-app-drive-element-sharedf')) { } else if ($element.is('.cp-app-drive-element-sharedf')) {
if (containsFolder) { if (containsFolder) {
// More than 1 folder selected: cannot create a new subfolder // More than 1 folder selected: cannot create a new subfolder
@ -1191,6 +1199,7 @@ define([
hide.push('openincode'); hide.push('openincode');
hide.push('hashtag'); hide.push('hashtag');
hide.push('delete'); hide.push('delete');
hide.push('makeacopy');
//hide.push('deleteowned'); //hide.push('deleteowned');
} else { // it's a folder } else { // it's a folder
if (containsFolder) { if (containsFolder) {
@ -1205,6 +1214,7 @@ define([
hide.push('openincode'); hide.push('openincode');
hide.push('properties'); hide.push('properties');
hide.push('hashtag'); hide.push('hashtag');
hide.push('makeacopy');
} }
// If we're in the trash, hide restore and properties for non-root elements // If we're in the trash, hide restore and properties for non-root elements
if (type === "trash" && path && path.length > 4) { if (type === "trash" && path && path.length > 4) {
@ -1241,6 +1251,7 @@ define([
hide.push('share'); hide.push('share');
hide.push('savelocal'); hide.push('savelocal');
hide.push('openincode'); // can't because of race condition hide.push('openincode'); // can't because of race condition
hide.push('makeacopy');
} }
if (containsFolder && paths.length > 1) { if (containsFolder && paths.length > 1) {
// Cannot open multiple folders // Cannot open multiple folders
@ -1258,11 +1269,11 @@ define([
break; break;
case 'tree': case 'tree':
show = ['open', 'openro', 'openincode', 'expandall', 'collapseall', show = ['open', 'openro', 'openincode', 'expandall', 'collapseall',
'color', 'download', 'share', 'savelocal', 'rename', 'delete', 'color', 'download', 'share', 'savelocal', 'rename', 'delete', 'makeacopy',
'deleteowned', 'removesf', 'properties', 'hashtag']; 'deleteowned', 'removesf', 'properties', 'hashtag'];
break; break;
case 'default': case 'default':
show = ['open', 'openro', 'share', 'openparent', 'delete', 'deleteowned', 'properties', 'hashtag']; show = ['open', 'openro', 'share', 'openparent', 'delete', 'deleteowned', 'properties', 'hashtag', 'makeacopy'];
break; break;
case 'trashtree': { case 'trashtree': {
show = ['empty']; show = ['empty'];
@ -3977,6 +3988,35 @@ define([
openFile(el, true); openFile(el, true);
}); });
} }
else if ($this.hasClass('cp-app-drive-context-makeacopy')) {
if (paths.length !== 1) { return; }
el = manager.find(paths[0].path);
var _metadata = manager.getFileData(el);
var _simpleData = {
title: _metadata.filename || _metadata.title,
href: _metadata.href || _metadata.roHref,
password: _metadata.password,
channel: _metadata.channel,
};
nThen(function (waitFor) {
var path = currentPath;
if (path[0] !== ROOT) { path = [ROOT]; }
common.sessionStorage.put(Constants.newPadFileData, JSON.stringify(_simpleData), waitFor());
common.sessionStorage.put(Constants.newPadPathKey, path, waitFor());
common.sessionStorage.put(Constants.newPadTeamKey, APP.team, waitFor());
}).nThen(function () {
var parsed = Hash.parsePadUrl(_metadata.href || _metadata.roHref);
common.openURL(Hash.hashToHref('', parsed.type));
// We need to restore sessionStorage for the next time we want to create a pad from this tab
// NOTE: the 100ms timeout is to fix a race condition in firefox where sessionStorage
// would be deleted before the new tab was created
setTimeout(function () {
common.sessionStorage.put(Constants.newPadFileData, '', function () {});
common.sessionStorage.put(Constants.newPadPathKey, '', function () {});
common.sessionStorage.put(Constants.newPadTeamKey, '', function () {});
}, 100);
});
}
else if ($this.hasClass('cp-app-drive-context-openincode')) { else if ($this.hasClass('cp-app-drive-context-openincode')) {
if (paths.length !== 1) { return; } if (paths.length !== 1) { return; }
var p = paths[0]; var p = paths[0];

@ -674,6 +674,9 @@ define([
$hist.addClass('cp-hidden-if-readonly'); $hist.addClass('cp-hidden-if-readonly');
toolbar.$drawer.append($hist); toolbar.$drawer.append($hist);
var $copy = common.createButton('copy', true);
toolbar.$drawer.append($copy);
if (!cpNfInner.metadataMgr.getPrivateData().isTemplate) { if (!cpNfInner.metadataMgr.getPrivateData().isTemplate) {
var templateObj = { var templateObj = {
rt: cpNfInner.chainpad, rt: cpNfInner.chainpad,

@ -801,6 +801,20 @@ define([
Cryptpad.saveAsTemplate(Cryptget.put, data, cb); Cryptpad.saveAsTemplate(Cryptget.put, data, cb);
}); });
sframeChan.on('EV_MAKE_A_COPY', function () {
var data = {
channel: secret.channel,
href: currentPad.href,
password: password,
title: currentTitle
};
sessionStorage[Utils.Constants.newPadFileData] = JSON.stringify(data);
window.open(window.location.pathname);
setTimeout(function () {
delete sessionStorage[Utils.Constants.newPadFileData];
}, 100);
});
// Messaging // Messaging
sframeChan.on('Q_SEND_FRIEND_REQUEST', function (data, cb) { sframeChan.on('Q_SEND_FRIEND_REQUEST', function (data, cb) {
Cryptpad.messaging.sendFriendRequest(data, cb); Cryptpad.messaging.sendFriendRequest(data, cb);

@ -1184,6 +1184,9 @@ define([
$rightside.append($templateButton); $rightside.append($templateButton);
} }
var $copy = common.createButton('copy', true);
$drawer.append($copy);
/* add an export button */ /* add an export button */
var $export = common.createButton('export', true, {}, exportFile); var $export = common.createButton('export', true, {}, exportFile);
$drawer.append($export); $drawer.append($export);

Loading…
Cancel
Save