Merge branch 'staging' of github.com:xwiki-labs/cryptpad into staging
This commit is contained in:
@@ -156,12 +156,14 @@ define([
|
||||
]);
|
||||
};
|
||||
|
||||
dialog.frame = function (content) {
|
||||
dialog.frame = function (content, opt) {
|
||||
opt = opt || {};
|
||||
var cls = opt.wide ? '.wide' : '';
|
||||
return $(h('div.alertify', {
|
||||
tabindex: 1,
|
||||
}, [
|
||||
h('div.dialog', [
|
||||
h('div', content),
|
||||
h('div'+cls, content),
|
||||
])
|
||||
])).click(function (e) {
|
||||
e.stopPropagation();
|
||||
@@ -351,6 +353,9 @@ define([
|
||||
var close = function (el) {
|
||||
var $el = $(el).fadeOut(150, function () {
|
||||
$el.detach();
|
||||
if (opt.onClose) {
|
||||
opt.onClose();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -373,10 +378,10 @@ define([
|
||||
if (opt.forefront) { $(frame).addClass('forefront'); }
|
||||
return frame;
|
||||
};
|
||||
UI.openCustomModal = function (content) {
|
||||
UI.openCustomModal = function (content, opt) {
|
||||
var frame = dialog.frame([
|
||||
content
|
||||
]);
|
||||
], opt);
|
||||
$(frame).find('button[data-keys]').each(function (i, el) {
|
||||
var keys = JSON.parse($(el).attr('data-keys'));
|
||||
customListenForKeys(keys, function () {
|
||||
|
||||
@@ -78,5 +78,27 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
Msg.updateMyData = function (store, curve) {
|
||||
if (store.messenger) {
|
||||
store.messenger.updateMyData();
|
||||
}
|
||||
var myData = createData(store.proxy);
|
||||
var todo = function (friend) {
|
||||
if (!friend || !friend.notifications) { return; }
|
||||
myData.channel = friend.channel;
|
||||
store.mailbox.sendTo('UPDATE_DATA', myData, {
|
||||
channel: friend.notifications,
|
||||
curvePublic: friend.curvePublic
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { console.error(obj); }
|
||||
});
|
||||
};
|
||||
if (curve) {
|
||||
var friend = getFriend(store.proxy, curve);
|
||||
return void todo(friend);
|
||||
}
|
||||
eachFriend(store.proxy.friends || {}, todo);
|
||||
};
|
||||
|
||||
return Msg;
|
||||
});
|
||||
|
||||
@@ -44,6 +44,7 @@ define([
|
||||
profile: proxy.profile && proxy.profile.view,
|
||||
edPublic: proxy.edPublic,
|
||||
curvePublic: proxy.curvePublic,
|
||||
notifications: Util.find(proxy, ['mailboxes', 'notifications', 'channel']),
|
||||
avatar: proxy.profile && proxy.profile.avatar
|
||||
};
|
||||
};
|
||||
@@ -611,6 +612,15 @@ define([
|
||||
cb();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
removeFromFriendList(curvePublic, function () {
|
||||
delete channels[channel.id];
|
||||
emit('UNFRIEND', {
|
||||
curvePublic: curvePublic,
|
||||
fromMe: true
|
||||
});
|
||||
cb();
|
||||
});
|
||||
}
|
||||
channel.wc.bcast(cryptMsg).then(function () {}, function (err) {
|
||||
console.error(err);
|
||||
|
||||
@@ -205,7 +205,7 @@ define([
|
||||
if (content === oldThumbnailState) { return; }
|
||||
oldThumbnailState = content;
|
||||
Thumb.fromDOM(opts, function (err, b64) {
|
||||
Thumb.setPadThumbnail(common, opts.href, null, b64);
|
||||
Thumb.setPadThumbnail(common, opts.type, null, b64);
|
||||
});
|
||||
};
|
||||
var nafa = Util.notAgainForAnother(mkThumbnail, Thumb.UPDATE_INTERVAL);
|
||||
@@ -243,11 +243,10 @@ define([
|
||||
var getKey = function (type, channel) {
|
||||
return 'thumbnail-' + type + '-' + channel;
|
||||
};
|
||||
Thumb.setPadThumbnail = function (common, href, channel, b64, cb) {
|
||||
Thumb.setPadThumbnail = function (common, type, channel, b64, cb) {
|
||||
cb = cb || function () {};
|
||||
var parsed = Hash.parsePadUrl(href);
|
||||
channel = channel || common.getMetadataMgr().getPrivateData().channel;
|
||||
var k = getKey(parsed.type, channel);
|
||||
var k = getKey(type, channel);
|
||||
common.setThumbnail(k, b64, cb);
|
||||
};
|
||||
Thumb.displayThumbnail = function (common, href, channel, password, $container, cb) {
|
||||
@@ -270,7 +269,7 @@ define([
|
||||
if (!v) {
|
||||
v = 'EMPTY';
|
||||
}
|
||||
Thumb.setPadThumbnail(common, href, hexFileName, v, function (err) {
|
||||
Thumb.setPadThumbnail(common, parsed.type, hexFileName, v, function (err) {
|
||||
if (!metadata.thumbnail) { return; }
|
||||
addThumbnail(err, metadata.thumbnail, $container, cb);
|
||||
});
|
||||
|
||||
@@ -316,39 +316,209 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
var getFriendsList = function (config) {
|
||||
var common = config.common;
|
||||
var title = config.title;
|
||||
var friends = config.friends;
|
||||
var myName = common.getMetadataMgr().getUserData().name;
|
||||
var order = [];
|
||||
if (!friends) { return; }
|
||||
|
||||
var others = Object.keys(friends).map(function (curve, i) {
|
||||
if (curve.length <= 40) { return; }
|
||||
var data = friends[curve];
|
||||
if (!data.notifications) { return; }
|
||||
var avatar = h('span.cp-share-friend-avatar.cp-avatar');
|
||||
UIElements.displayAvatar(common, $(avatar), data.avatar, data.displayName);
|
||||
return h('div.cp-share-friend', {
|
||||
'data-curve': data.curvePublic,
|
||||
'data-name': data.displayName,
|
||||
'data-order': i,
|
||||
style: 'order:'+i+';'
|
||||
},[
|
||||
avatar,
|
||||
h('span.cp-share-friend-name', data.displayName)
|
||||
]);
|
||||
}).filter(function (x) { return x; });
|
||||
var smallCurves = Object.keys(friends).map(function (c) {
|
||||
return friends[c].curvePublic.slice(0,8);
|
||||
});
|
||||
|
||||
var noOthers = others.length === 0 ? '.cp-recent-only' : '';
|
||||
|
||||
var buttonSelect = h('button.cp-share-with-friends', Messages.share_selectAll);
|
||||
var buttonDeselect = h('button.cp-share-with-friends', Messages.share_deselectAll);
|
||||
var inputFilter = h('input', {
|
||||
placeholder: Messages.share_filterFriend
|
||||
});
|
||||
|
||||
var div = h('div.cp-share-friends.cp-share-column' + noOthers, [
|
||||
h('label', Messages.share_linkFriends),
|
||||
h('div.cp-share-grid-filter', [
|
||||
inputFilter,
|
||||
buttonSelect,
|
||||
buttonDeselect
|
||||
]),
|
||||
]);
|
||||
var $div = $(div);
|
||||
|
||||
// Fill with fake friends to have a uniform spacing (from the flexbox)
|
||||
var addFake = function (els) {
|
||||
$div.find('.cp-fake-friend').remove();
|
||||
var n = (6 - els.length%6)%6;
|
||||
for (var j = 0; j < n; j++) {
|
||||
els.push(h('div.cp-share-friend.cp-fake-friend', {
|
||||
style: 'order:9999999;'
|
||||
}));
|
||||
}
|
||||
};
|
||||
addFake(others);
|
||||
|
||||
// Hide friends when they are filtered using the text input
|
||||
var redraw = function () {
|
||||
var name = $(inputFilter).val().trim().replace(/"/g, '');
|
||||
$div.find('.cp-share-friend').show();
|
||||
if (!name) { return; }
|
||||
$div.find('.cp-share-friend:not(.cp-selected):not([data-name*="'+name+'"])').hide();
|
||||
};
|
||||
|
||||
$(inputFilter).on('keydown keyup change', redraw);
|
||||
$(buttonSelect).click(function () {
|
||||
$div.find('.cp-share-friend:not(.cp-selected):visible').addClass('cp-selected');
|
||||
});
|
||||
$(buttonDeselect).click(function () {
|
||||
$div.find('.cp-share-friend.cp-selected').removeClass('cp-selected').each(function (i, el) {
|
||||
var order = $(el).attr('data-order');
|
||||
if (!order) { return; }
|
||||
$(el).attr('style', 'order:'+order);
|
||||
});
|
||||
redraw();
|
||||
});
|
||||
|
||||
// Replace "copy link" by "share with friends" if at least one friedn is selected
|
||||
// Also create the "share with friends" button if it doesn't exist
|
||||
var refreshButtons = function () {
|
||||
var $nav = $div.parents('.alertify').find('nav');
|
||||
if (!$nav.find('.cp-share-with-friends').length) {
|
||||
var button = h('button.primary.cp-share-with-friends', {
|
||||
'data-keys': '[13]'
|
||||
}, Messages.share_withFriends);
|
||||
$(button).click(function () {
|
||||
var href = Hash.getRelativeHref($('#cp-share-link-preview').val());
|
||||
var $friends = $div.find('.cp-share-friend.cp-selected');
|
||||
$friends.each(function (i, el) {
|
||||
var curve = $(el).attr('data-curve');
|
||||
if (!curve || !friends[curve]) { return; }
|
||||
var friend = friends[curve];
|
||||
if (!friend.notifications || !friend.curvePublic) { return; }
|
||||
common.mailbox.sendTo("SHARE_PAD", {
|
||||
href: href,
|
||||
name: myName,
|
||||
title: title
|
||||
}, {
|
||||
channel: friend.notifications,
|
||||
curvePublic: friend.curvePublic
|
||||
});
|
||||
});
|
||||
|
||||
UI.findCancelButton().click();
|
||||
|
||||
// Update the "recently shared with" array:
|
||||
// Get the selected curves
|
||||
var curves = $friends.toArray().map(function (el) {
|
||||
return ($(el).attr('data-curve') || '').slice(0,8);
|
||||
}).filter(function (x) { return x; });
|
||||
// Prepend them to the "order" array
|
||||
Array.prototype.unshift.apply(order, curves);
|
||||
order = Util.deduplicateString(order);
|
||||
// Make sure we don't have "old" friends and save
|
||||
order = order.filter(function (curve) {
|
||||
return smallCurves.indexOf(curve) !== -1;
|
||||
});
|
||||
common.setAttribute(['general', 'share-friends'], order);
|
||||
});
|
||||
$nav.append(button);
|
||||
}
|
||||
|
||||
var friendMode = $div.find('.cp-share-friend.cp-selected').length;
|
||||
if (friendMode) {
|
||||
$nav.find('button.primary[data-keys]').hide();
|
||||
$nav.find('button.cp-share-with-friends').show();
|
||||
} else {
|
||||
$nav.find('button.primary[data-keys]').show();
|
||||
$nav.find('button.cp-share-with-friends').hide();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
common.getAttribute(['general', 'share-friends'], function (err, val) {
|
||||
order = val || [];
|
||||
// Sort friends by "recently shared with"
|
||||
others.sort(function (a, b) {
|
||||
var ca = ($(a).attr('data-curve') || '').slice(0,8);
|
||||
var cb = ($(b).attr('data-curve') || '').slice(0,8);
|
||||
if (!ca && !cb) { return 0; }
|
||||
if (!ca) { return 1; }
|
||||
if (!cb) { return -1; }
|
||||
var ia = order.indexOf(ca);
|
||||
var ib = order.indexOf(cb);
|
||||
if (ia === -1 && ib === -1) { return 0; }
|
||||
if (ia === -1) { return 1; }
|
||||
if (ib === -1) { return -1; }
|
||||
return ia - ib;
|
||||
});
|
||||
// Reorder the friend icons
|
||||
others.forEach(function (el, i) {
|
||||
if ($(el).is('.cp-fake-friend')) { return; }
|
||||
$(el).attr('data-order', i).css('order', i);
|
||||
});
|
||||
// Display them
|
||||
$div.append(h('div.cp-share-grid', others));
|
||||
$div.find('.cp-share-friend').click(function () {
|
||||
var sel = $(this).hasClass('cp-selected');
|
||||
if (!sel) {
|
||||
$(this).addClass('cp-selected');
|
||||
} else {
|
||||
var order = $(this).attr('data-order');
|
||||
order = order ? 'order:'+order : '';
|
||||
$(this).removeClass('cp-selected').attr('style', order);
|
||||
}
|
||||
refreshButtons();
|
||||
});
|
||||
});
|
||||
return div;
|
||||
};
|
||||
|
||||
UIElements.createShareModal = function (config) {
|
||||
var origin = config.origin;
|
||||
var pathname = config.pathname;
|
||||
var hashes = config.hashes;
|
||||
var common = config.common;
|
||||
|
||||
if (!hashes) { return; }
|
||||
|
||||
// Share link tab
|
||||
var link = h('div.cp-share-modal', [
|
||||
h('label', Messages.share_linkAccess),
|
||||
h('br'),
|
||||
UI.createRadio('cp-share-editable', 'cp-share-editable-true',
|
||||
Messages.share_linkEdit, true, { mark: {tabindex:1} }),
|
||||
UI.createRadio('cp-share-editable', 'cp-share-editable-false',
|
||||
Messages.share_linkView, false, { mark: {tabindex:1} }),
|
||||
/*h('input#cp-share-editable-true.cp-share-editable-value', {
|
||||
type: 'radio',
|
||||
name: 'cp-share-editable',
|
||||
value: 1,
|
||||
}),
|
||||
h('label', { 'for': 'cp-share-editable-true' }, Messages.share_linkEdit),
|
||||
h('input#cp-share-editable-false.cp-share-editable-value', {
|
||||
type: 'radio',
|
||||
name: 'cp-share-editable',
|
||||
value: 0
|
||||
}),
|
||||
h('label', { 'for': 'cp-share-editable-false' }, Messages.share_linkView),*/
|
||||
h('br'),
|
||||
h('label', Messages.share_linkOptions),
|
||||
h('br'),
|
||||
UI.createCheckbox('cp-share-embed', Messages.share_linkEmbed, false, { mark: {tabindex:1} }),
|
||||
UI.createCheckbox('cp-share-present', Messages.share_linkPresent, false, { mark: {tabindex:1} }),
|
||||
h('br'),
|
||||
UI.dialog.selectable('', { id: 'cp-share-link-preview', tabindex: 1 })
|
||||
var hasFriends = Object.keys(config.friends || {}).length !== 0;
|
||||
var friendsList = hasFriends ? getFriendsList(config) : undefined;
|
||||
var friendsUIClass = hasFriends ? '.cp-share-columns' : '';
|
||||
var link = h('div.cp-share-modal' + friendsUIClass, [
|
||||
h('div.cp-share-column', [
|
||||
hasFriends ? h('p', Messages.share_description) : undefined,
|
||||
h('label', Messages.share_linkAccess),
|
||||
h('br'),
|
||||
UI.createRadio('cp-share-editable', 'cp-share-editable-true',
|
||||
Messages.share_linkEdit, true, { mark: {tabindex:1} }),
|
||||
UI.createRadio('cp-share-editable', 'cp-share-editable-false',
|
||||
Messages.share_linkView, false, { mark: {tabindex:1} }),
|
||||
h('br'),
|
||||
h('label', Messages.share_linkOptions),
|
||||
h('br'),
|
||||
UI.createCheckbox('cp-share-embed', Messages.share_linkEmbed, false, { mark: {tabindex:1} }),
|
||||
UI.createCheckbox('cp-share-present', Messages.share_linkPresent, false, { mark: {tabindex:1} }),
|
||||
h('br'),
|
||||
UI.dialog.selectable('', { id: 'cp-share-link-preview', tabindex: 1 }),
|
||||
]),
|
||||
friendsList
|
||||
]);
|
||||
if (!hashes.editHash) {
|
||||
$(link).find('#cp-share-editable-false').attr('checked', true);
|
||||
@@ -380,6 +550,7 @@ define([
|
||||
$(link).find('#cp-share-link-preview').val(getLinkValue());
|
||||
});
|
||||
var linkButtons = [{
|
||||
className: 'cancel',
|
||||
name: Messages.cancel,
|
||||
onClick: function () {},
|
||||
keys: [27]
|
||||
@@ -403,7 +574,10 @@ define([
|
||||
},
|
||||
keys: [[13, 'ctrl']]
|
||||
}];
|
||||
var frameLink = UI.dialog.customModal(link, {buttons: linkButtons});
|
||||
var frameLink = UI.dialog.customModal(link, {
|
||||
buttons: linkButtons,
|
||||
onClose: config.onClose,
|
||||
});
|
||||
|
||||
// Embed tab
|
||||
var getEmbedValue = function () {
|
||||
@@ -420,6 +594,7 @@ define([
|
||||
UI.dialog.selectable(getEmbedValue())
|
||||
]);
|
||||
var embedButtons = [{
|
||||
className: 'cancel',
|
||||
name: Messages.cancel,
|
||||
onClick: function () {},
|
||||
keys: [27]
|
||||
@@ -433,7 +608,10 @@ define([
|
||||
},
|
||||
keys: [13]
|
||||
}];
|
||||
var frameEmbed = UI.dialog.customModal(embed, { buttons: embedButtons});
|
||||
var frameEmbed = UI.dialog.customModal(embed, {
|
||||
buttons: embedButtons,
|
||||
onClose: config.onClose,
|
||||
});
|
||||
|
||||
// Create modal
|
||||
var tabs = [{
|
||||
@@ -464,7 +642,9 @@ define([
|
||||
$(link).find('#cp-share-link-preview').val(getLinkValue(val));
|
||||
});
|
||||
common.getMetadataMgr().onChange(function () {
|
||||
hashes = common.getMetadataMgr().getPrivateData().availableHashes;
|
||||
// "hashes" is only available is the secure "share" app
|
||||
hashes = common.getMetadataMgr().getPrivateData().hashes;
|
||||
if (!hashes) { return; }
|
||||
$(link).find('#cp-share-link-preview').val(getLinkValue());
|
||||
});
|
||||
return tabs;
|
||||
@@ -481,12 +661,20 @@ define([
|
||||
|
||||
|
||||
// Share link tab
|
||||
var link = h('div.cp-share-modal', [
|
||||
UI.dialog.selectable('', { id: 'cp-share-link-preview' })
|
||||
var hasFriends = Object.keys(config.friends || {}).length !== 0;
|
||||
var friendsList = hasFriends ? getFriendsList(config) : undefined;
|
||||
var friendsUIClass = hasFriends ? '.cp-share-columns' : '';
|
||||
var link = h('div.cp-share-modal' + friendsUIClass, [
|
||||
h('div.cp-share-column', [
|
||||
hasFriends ? h('p', Messages.share_description) : undefined,
|
||||
UI.dialog.selectable('', { id: 'cp-share-link-preview' }),
|
||||
]),
|
||||
friendsList
|
||||
]);
|
||||
var getLinkValue = function () { return url; };
|
||||
$(link).find('#cp-share-link-preview').val(getLinkValue());
|
||||
var linkButtons = [{
|
||||
className: 'cancel',
|
||||
name: Messages.cancel,
|
||||
onClick: function () {},
|
||||
keys: [27]
|
||||
@@ -513,6 +701,7 @@ define([
|
||||
UI.dialog.selectable(common.getMediatagFromHref(fileData)),
|
||||
]);
|
||||
var embedButtons = [{
|
||||
className: 'cancel',
|
||||
name: Messages.cancel,
|
||||
onClick: function () {},
|
||||
keys: [27]
|
||||
@@ -554,12 +743,20 @@ define([
|
||||
var url = origin + pathname + '#' + hashes.editHash;
|
||||
|
||||
// Share link tab
|
||||
var link = h('div.cp-share-modal', [
|
||||
h('label', Messages.sharedFolders_share),
|
||||
h('br'),
|
||||
UI.dialog.selectable(url, { id: 'cp-share-link-preview', tabindex: 1 })
|
||||
var hasFriends = Object.keys(config.friends || {}).length !== 0;
|
||||
var friendsList = hasFriends ? getFriendsList(config) : undefined;
|
||||
var friendsUIClass = hasFriends ? '.cp-share-columns' : '';
|
||||
var link = h('div.cp-share-modal' + friendsUIClass, [
|
||||
h('div.cp-share-column', [
|
||||
h('label', Messages.sharedFolders_share),
|
||||
h('br'),
|
||||
hasFriends ? h('p', Messages.share_description) : undefined,
|
||||
UI.dialog.selectable(url, { id: 'cp-share-link-preview', tabindex: 1 })
|
||||
]),
|
||||
friendsList
|
||||
]);
|
||||
var linkButtons = [{
|
||||
className: 'cancel',
|
||||
name: Messages.cancel,
|
||||
onClick: function () {},
|
||||
keys: [27]
|
||||
@@ -791,16 +988,23 @@ define([
|
||||
button = $('<span>');
|
||||
break;
|
||||
}
|
||||
var active = $(".cp-toolbar-history:visible").length !== 0;
|
||||
button = $('<button>', {
|
||||
title: Messages.historyButton,
|
||||
title: active ? Messages.history_closeTitle : Messages.historyButton,
|
||||
'class': "fa fa-history cp-toolbar-icon-history",
|
||||
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.historyText));
|
||||
button.toggleClass("active", active);
|
||||
if (data.histConfig) {
|
||||
button
|
||||
.click(common.prepareFeedback(type))
|
||||
.on('click', function () {
|
||||
common.getHistory(data.histConfig);
|
||||
});
|
||||
if (active) {
|
||||
button.click(function () { $(".cp-toolbar-history-close").trigger("click"); });
|
||||
}
|
||||
else {
|
||||
button
|
||||
.click(common.prepareFeedback(type))
|
||||
.on('click', function () {
|
||||
common.getHistory(data.histConfig);
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'more':
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
define([
|
||||
'/customize/application_config.js',
|
||||
'/common/common-feedback.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-util.js',
|
||||
'/common/common-messenger.js',
|
||||
'/common/outer/mailbox.js',
|
||||
'/bower_components/nthen/index.js',
|
||||
], function (Feedback, Hash, Util, nThen) {
|
||||
'/bower_components/chainpad-crypto/crypto.js',
|
||||
], function (AppConfig, Feedback, Hash, Util, Messenger, Mailbox, nThen, Crypto) {
|
||||
// Start migration check
|
||||
// Versions:
|
||||
// 1: migrate pad attributes
|
||||
// 2: migrate indent settings (codemirror)
|
||||
|
||||
return function (userObject, cb, progress) {
|
||||
return function (userObject, cb, progress, store) {
|
||||
var version = userObject.version || 0;
|
||||
|
||||
nThen(function () {
|
||||
@@ -186,6 +190,135 @@ define([
|
||||
Feedback.send('Migrate-8', true);
|
||||
userObject.version = version = 8;
|
||||
}
|
||||
}).nThen(function () {
|
||||
if (!AppConfig.migrateFriends) { return; } // XXX
|
||||
|
||||
|
||||
// Migration 9: send our mailbox channel to existing friends
|
||||
var migrateFriends = function () {
|
||||
var network = store.network;
|
||||
var channels = {};
|
||||
var ctx = {
|
||||
store: store
|
||||
};
|
||||
var myData = Messenger.createData(userObject);
|
||||
|
||||
var close = function (chan) {
|
||||
var channel = channels[chan];
|
||||
if (!channel) { return; }
|
||||
try {
|
||||
channel.wc.leave();
|
||||
} catch (e) {}
|
||||
delete channels[chan];
|
||||
};
|
||||
|
||||
var onDirectMessage = function (msg, sender) {
|
||||
if (sender !== network.historyKeeper) { return; }
|
||||
var parsed = JSON.parse(msg);
|
||||
|
||||
// Metadata msg? we don't care
|
||||
if ((parsed.validateKey || parsed.owners) && parsed.channel) { return; }
|
||||
|
||||
// End of history message, "onReady"
|
||||
if (parsed.channel && channels[parsed.channel]) {
|
||||
// History cleared while we were offline
|
||||
// ==> we asked for an invalid last known hash
|
||||
if (parsed.error && parsed.error === "EINVAL") {
|
||||
var histMsg = ['GET_HISTORY', parsed.channel, {}];
|
||||
network.sendto(network.historyKeeper, JSON.stringify(histMsg))
|
||||
.then(function () {}, function () {});
|
||||
return;
|
||||
}
|
||||
// End of history
|
||||
if (parsed.state && parsed.state === 1) {
|
||||
// Channel is ready and we didn't receive their mailbox channel: send our channel
|
||||
myData.channel = parsed.channel;
|
||||
var updateMsg = ['UPDATE', myData.curvePublic, +new Date(), myData];
|
||||
var cryptMsg = channels[parsed.channel].encrypt(JSON.stringify(updateMsg));
|
||||
channels[parsed.channel].wc.bcast(cryptMsg).then(function () {}, function (err) {
|
||||
console.error("Can't migrate this friend", channels[parsed.channel].friend, err);
|
||||
});
|
||||
close(parsed.channel);
|
||||
return;
|
||||
}
|
||||
} else if (parsed.channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
// History message: we only care about "UPDATE" messages
|
||||
var chan = parsed[3];
|
||||
if (!chan || !channels[chan]) { return; }
|
||||
var channel = channels[chan];
|
||||
var msgIn = channel.decrypt(parsed[4]);
|
||||
var parsedMsg = JSON.parse(msgIn);
|
||||
if (parsedMsg[0] === 'UPDATE') {
|
||||
if (parsedMsg[1] === myData.curvePublic) { return; }
|
||||
var data = parsedMsg[3];
|
||||
// If it doesn't contain the mailbox channel, ignore the message
|
||||
if (!data.notifications) { return; }
|
||||
// Otherwise we know their channel, we can send them our own
|
||||
channel.friend.notifications = data.notifications;
|
||||
myData.channel = chan;
|
||||
Mailbox.sendTo(ctx, 'UPDATE_DATA', myData, {
|
||||
channel: data.notifications,
|
||||
curvePublic: data.curvePublic
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { return void console.error(obj); }
|
||||
console.log('friend migrated', channel.friend);
|
||||
});
|
||||
close(chan);
|
||||
}
|
||||
};
|
||||
|
||||
network.on('message', function(msg, sender) {
|
||||
try {
|
||||
onDirectMessage(msg, sender);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
var friends = userObject.friends || {};
|
||||
Object.keys(friends).forEach(function (curve) {
|
||||
if (curve.length !== 44) { return; }
|
||||
var friend = friends[curve];
|
||||
|
||||
// Check if it is already a "new" friend
|
||||
if (friend.notifications) { return; }
|
||||
|
||||
/** Old friend:
|
||||
* 1. Open the messenger channel
|
||||
* 2. Check if they sent us their mailbox channel
|
||||
* 3.a. Yes ==> sent them a mail containing our mailbox channel
|
||||
* 3.b. No ==> post our mailbox data to the messenger channel
|
||||
*/
|
||||
network.join(friend.channel).then(function (wc) {
|
||||
var keys = Crypto.Curve.deriveKeys(friend.curvePublic, userObject.curvePrivate);
|
||||
var encryptor = Crypto.Curve.createEncryptor(keys);
|
||||
channels[friend.channel] = {
|
||||
wc: wc,
|
||||
friend: friend,
|
||||
decrypt: encryptor.decrypt,
|
||||
encrypt: encryptor.encrypt
|
||||
};
|
||||
var cfg = {
|
||||
lastKnownHash: friend.lastKnownHash
|
||||
};
|
||||
var msg = ['GET_HISTORY', friend.channel, cfg];
|
||||
network.sendto(network.historyKeeper, JSON.stringify(msg))
|
||||
.then(function () {}, function (err) {
|
||||
console.error("Can't migrate this friend", friend, err);
|
||||
});
|
||||
}, function (err) {
|
||||
console.error("Can't migrate this friend", friend, err);
|
||||
});
|
||||
});
|
||||
};
|
||||
if (version < 9) {
|
||||
migrateFriends();
|
||||
Feedback.send('Migrate-9', true);
|
||||
userObject.version = version = 9;
|
||||
}
|
||||
/*}).nThen(function (waitFor) {
|
||||
// Test progress bar in the loading screen
|
||||
var i = 0;
|
||||
@@ -197,7 +330,7 @@ define([
|
||||
}, 500);
|
||||
progress(0, 0);*/
|
||||
}).nThen(function () {
|
||||
cb();
|
||||
setTimeout(cb);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/common/hyperscript.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-ui-elements.js',
|
||||
'/customize/messages.js',
|
||||
], function ($, h, UIElements, Messages) {
|
||||
], function ($, h, Hash, UIElements, Messages) {
|
||||
|
||||
var handlers = {};
|
||||
|
||||
// Friend request
|
||||
|
||||
handlers['FRIEND_REQUEST'] = function (common, data, el) {
|
||||
var content = data.content;
|
||||
var msg = content.msg;
|
||||
@@ -17,9 +20,9 @@ define([
|
||||
common.addFriendRequest(data);
|
||||
|
||||
// Display the notification
|
||||
$(el).find('.cp-notification-content').addClass("cp-clickable");
|
||||
$(el).find('.cp-notification-content p')
|
||||
.html(Messages._getKey('friendRequest_notification', [msg.content.displayName || Messages.anonymous]))
|
||||
.html(Messages._getKey('friendRequest_notification', [msg.content.displayName || Messages.anonymous]));
|
||||
$(el).find('.cp-notification-content').addClass("cp-clickable")
|
||||
.click(function () {
|
||||
UIElements.displayFriendRequestModal(common, data);
|
||||
});
|
||||
@@ -41,6 +44,24 @@ define([
|
||||
$(el).find('.cp-notification-dismiss').css('display', 'flex');
|
||||
};
|
||||
|
||||
// Share pad
|
||||
|
||||
handlers['SHARE_PAD'] = function (common, data, el) {
|
||||
var content = data.content;
|
||||
var msg = content.msg;
|
||||
var type = Hash.parsePadUrl(msg.content.href).type;
|
||||
var key = type === 'drive' ? 'notification_folderShared' :
|
||||
(type === 'file' ? 'notification_fileShared' :
|
||||
'notification_padShared');
|
||||
$(el).find('.cp-notification-content p')
|
||||
.html(Messages._getKey(key, [msg.content.name || Messages.anonymous, msg.content.title]));
|
||||
$(el).find('.cp-notification-content').addClass("cp-clickable")
|
||||
.click(function () {
|
||||
common.openURL(msg.content.href);
|
||||
});
|
||||
$(el).find('.cp-notification-dismiss').css('display', 'flex');
|
||||
};
|
||||
|
||||
return {
|
||||
add: function (common, data, el) {
|
||||
var type = data.content.msg.type;
|
||||
|
||||
@@ -66,7 +66,7 @@ define([
|
||||
}
|
||||
broadcast([clientId], "UPDATE_METADATA");
|
||||
if (Array.isArray(path) && path[0] === 'profile' && store.messenger) {
|
||||
store.messenger.updateMyData();
|
||||
Messaging.updateMyData(store);
|
||||
}
|
||||
onSync(cb);
|
||||
};
|
||||
@@ -644,7 +644,7 @@ define([
|
||||
}
|
||||
store.proxy[Constants.displayNameKey] = value;
|
||||
broadcast([clientId], "UPDATE_METADATA");
|
||||
if (store.messenger) { store.messenger.updateMyData(); }
|
||||
Messaging.updateMyData(store);
|
||||
onSync(cb);
|
||||
};
|
||||
|
||||
@@ -1644,14 +1644,16 @@ define([
|
||||
});
|
||||
userObject.migrate(waitFor());
|
||||
}).nThen(function (waitFor) {
|
||||
Store.initAnonRpc(null, null, waitFor());
|
||||
Store.initRpc(null, null, waitFor());
|
||||
}).nThen(function (waitFor) {
|
||||
loadMailbox(waitFor);
|
||||
Migrate(proxy, waitFor(), function (version, progress) {
|
||||
postMessage(clientId, 'LOADING_DRIVE', {
|
||||
state: (2 + (version / 10)),
|
||||
progress: progress
|
||||
});
|
||||
});
|
||||
Store.initAnonRpc(null, null, waitFor());
|
||||
Store.initRpc(null, null, waitFor());
|
||||
}).nThen(function (waitFor) {
|
||||
postMessage(clientId, 'LOADING_DRIVE', {
|
||||
state: 3
|
||||
@@ -1661,7 +1663,6 @@ define([
|
||||
loadMessenger();
|
||||
loadCursor();
|
||||
loadOnlyOffice();
|
||||
loadMailbox(waitFor);
|
||||
loadUniversal(Profile, 'profile', waitFor);
|
||||
cleanFriendRequests();
|
||||
}).nThen(function () {
|
||||
@@ -1816,8 +1817,8 @@ define([
|
||||
|
||||
// Ping clients regularly to make sure one tab was not closed without sending a removeClient()
|
||||
// command. This allow us to avoid phantom viewers in pads.
|
||||
var PING_INTERVAL = 30000;
|
||||
var MAX_PING = 5000;
|
||||
var PING_INTERVAL = 120000;
|
||||
var MAX_PING = 30000;
|
||||
var MAX_FAILED_PING = 2;
|
||||
|
||||
setInterval(function () {
|
||||
|
||||
@@ -144,8 +144,30 @@ define([
|
||||
cb(true);
|
||||
};
|
||||
|
||||
handlers['UPDATE_DATA'] = function (ctx, box, data, cb) {
|
||||
var msg = data.msg;
|
||||
var curve = msg.author;
|
||||
var friend = ctx.store.proxy.friends && ctx.store.proxy.friends[curve];
|
||||
if (!friend || typeof msg.content !== "object") { return void cb(true); }
|
||||
Object.keys(msg.content).forEach(function (key) {
|
||||
friend[key] = msg.content[key];
|
||||
});
|
||||
ctx.updateMetadata();
|
||||
cb(true);
|
||||
};
|
||||
|
||||
return {
|
||||
add: function (ctx, box, data, cb) {
|
||||
/**
|
||||
* data = {
|
||||
msg: {
|
||||
type: 'STRING',
|
||||
author: 'curvePublicString',
|
||||
content: {} (depend on the "type")
|
||||
},
|
||||
hash: 'string'
|
||||
}
|
||||
*/
|
||||
if (!data.msg) { return void cb(true); }
|
||||
var type = data.msg.type;
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ proxy.mailboxes = {
|
||||
};
|
||||
|
||||
// Send a message to someone else
|
||||
var sendTo = function (ctx, type, msg, user, cb) {
|
||||
var sendTo = Mailbox.sendTo = function (ctx, type, msg, user, cb) {
|
||||
if (!Crypto.Mailbox) {
|
||||
return void cb({error: "chainpad-crypto is outdated and doesn't support mailboxes."});
|
||||
}
|
||||
|
||||
@@ -357,16 +357,14 @@ define([
|
||||
UI.removeLoadingScreen(emitResize);
|
||||
|
||||
var privateDat = cpNfInner.metadataMgr.getPrivateData();
|
||||
var hash = privateDat.availableHashes.editHash ||
|
||||
privateDat.availableHashes.viewHash;
|
||||
var href = privateDat.pathname + '#' + hash;
|
||||
var type = privateDat.app;
|
||||
if (AppConfig.textAnalyzer && textContentGetter) {
|
||||
AppConfig.textAnalyzer(textContentGetter, privateDat.channel);
|
||||
}
|
||||
|
||||
if (options.thumbnail && privateDat.thumbnails) {
|
||||
if (hash) {
|
||||
options.thumbnail.href = href;
|
||||
if (type) {
|
||||
options.thumbnail.type = type;
|
||||
options.thumbnail.getContent = function () {
|
||||
if (!cpNfInner.chainpad) { return; }
|
||||
return cpNfInner.chainpad.getUserDoc();
|
||||
|
||||
@@ -231,7 +231,20 @@ define([
|
||||
};
|
||||
var $block = exp.$language = UIElements.createDropdown(dropdownConfig);
|
||||
$block.find('button').attr('title', Messages.languageButtonTitle);
|
||||
$block.find('a').click(function () {
|
||||
|
||||
var isHovering = false;
|
||||
var $aLanguages = $block.find('a');
|
||||
$aLanguages.mouseenter(function () {
|
||||
isHovering = true;
|
||||
setMode($(this).attr('data-value'));
|
||||
});
|
||||
$aLanguages.mouseleave(function () {
|
||||
if (isHovering) {
|
||||
setMode($block.find(".cp-dropdown-element-active").attr('data-value'));
|
||||
}
|
||||
});
|
||||
$aLanguages.click(function () {
|
||||
isHovering = false;
|
||||
setMode($(this).attr('data-value'), onModeChanged);
|
||||
onLocal();
|
||||
});
|
||||
@@ -272,12 +285,26 @@ define([
|
||||
|
||||
setTheme(lastTheme, $block);
|
||||
|
||||
$block.find('a').click(function () {
|
||||
var isHovering = false;
|
||||
var $aThemes = $block.find('a');
|
||||
$aThemes.mouseenter(function () {
|
||||
isHovering = true;
|
||||
var theme = $(this).attr('data-value');
|
||||
setTheme(theme, $block);
|
||||
});
|
||||
$aThemes.mouseleave(function () {
|
||||
if (isHovering) {
|
||||
setTheme(lastTheme, $block);
|
||||
Common.setAttribute(themeKey, lastTheme);
|
||||
}
|
||||
});
|
||||
$aThemes.click(function () {
|
||||
isHovering = false;
|
||||
var theme = $(this).attr('data-value');
|
||||
setTheme(theme, $block);
|
||||
Common.setAttribute(themeKey, theme);
|
||||
});
|
||||
|
||||
|
||||
if ($drawer) { $drawer.append($block); }
|
||||
if (cb) { cb(); }
|
||||
};
|
||||
|
||||
@@ -5,7 +5,8 @@ define([
|
||||
'/common/common-ui-elements.js',
|
||||
'/common/notifications.js',
|
||||
'/common/hyperscript.js',
|
||||
], function ($, Util, UI, UIElements, Notifications, h) {
|
||||
'/customize/messages.js',
|
||||
], function ($, Util, UI, UIElements, Notifications, h, Messages) {
|
||||
var Mailbox = {};
|
||||
|
||||
Mailbox.create = function (Common) {
|
||||
@@ -48,7 +49,10 @@ define([
|
||||
};
|
||||
var createElement = function (data) {
|
||||
var notif;
|
||||
var dismiss = h('span.fa.fa-times');
|
||||
var dismissIcon = h('span.fa.fa-times');
|
||||
var dismiss = h('div.cp-notification-dismiss', {
|
||||
title: Messages.notifications_dismiss
|
||||
}, dismissIcon)
|
||||
dismiss.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -65,7 +69,7 @@ define([
|
||||
'data-hash': data.content.hash
|
||||
}, [
|
||||
h('div.cp-notification-content', h('p', formatData(data))),
|
||||
h('div.cp-notification-dismiss', dismiss)
|
||||
dismiss
|
||||
]);
|
||||
return notif;
|
||||
};
|
||||
@@ -132,9 +136,14 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
var subscribed = false;
|
||||
|
||||
// Get all existing notifications + the new ones when they come
|
||||
mailbox.subscribe = function (cfg) {
|
||||
if (!subscribed) {
|
||||
execCommand('SUBSCRIBE', null, function () {});
|
||||
subscribed = true;
|
||||
}
|
||||
if (typeof(cfg.onViewed) === "function") {
|
||||
onViewedHandlers.push(cfg.onViewed);
|
||||
}
|
||||
@@ -166,10 +175,6 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
execCommand('SUBSCRIBE', null, function () {
|
||||
//console.log('subscribed');
|
||||
});
|
||||
|
||||
return mailbox;
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ define([
|
||||
var SFrameChannel;
|
||||
var sframeChan;
|
||||
var FilePicker;
|
||||
var Share;
|
||||
var Messaging;
|
||||
var Notifier;
|
||||
var Utils = {
|
||||
@@ -38,6 +39,7 @@ define([
|
||||
'/common/cryptget.js',
|
||||
'/common/outer/worker-channel.js',
|
||||
'/filepicker/main.js',
|
||||
'/share/main.js',
|
||||
'/common/common-messaging.js',
|
||||
'/common/common-notifier.js',
|
||||
'/common/common-hash.js',
|
||||
@@ -49,7 +51,7 @@ define([
|
||||
'/customize/application_config.js',
|
||||
'/common/test.js',
|
||||
], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, _SFrameChannel,
|
||||
_FilePicker, _Messaging, _Notifier, _Hash, _Util, _Realtime,
|
||||
_FilePicker, _Share, _Messaging, _Notifier, _Hash, _Util, _Realtime,
|
||||
_Constants, _Feedback, _LocalStore, _AppConfig, _Test) {
|
||||
CpNfOuter = _CpNfOuter;
|
||||
Cryptpad = _Cryptpad;
|
||||
@@ -57,6 +59,7 @@ define([
|
||||
Cryptget = _Cryptget;
|
||||
SFrameChannel = _SFrameChannel;
|
||||
FilePicker = _FilePicker;
|
||||
Share = _Share;
|
||||
Messaging = _Messaging;
|
||||
Notifier = _Notifier;
|
||||
Utils.Hash = _Hash;
|
||||
@@ -269,9 +272,6 @@ define([
|
||||
sessionStorage[Utils.Constants.displayPadCreationScreen];
|
||||
delete sessionStorage[Utils.Constants.displayPadCreationScreen];
|
||||
var updateMeta = function () {
|
||||
// TODO availableHashes in privateData may need updates once we have
|
||||
// a better privileges workflow
|
||||
|
||||
//console.log('EV_METADATA_UPDATE');
|
||||
var metaObj, isTemplate;
|
||||
nThen(function (waitFor) {
|
||||
@@ -290,12 +290,12 @@ define([
|
||||
type: cfg.type || parsed.type
|
||||
};
|
||||
var additionalPriv = {
|
||||
app: parsed.type,
|
||||
accountName: Utils.LocalStore.getAccountName(),
|
||||
origin: window.location.origin,
|
||||
pathname: window.location.pathname,
|
||||
fileHost: ApiConfig.fileHost,
|
||||
readOnly: readOnly,
|
||||
availableHashes: hashes,
|
||||
isTemplate: isTemplate,
|
||||
feedbackAllowed: Utils.Feedback.state,
|
||||
isPresent: parsed.hashData && parsed.hashData.present,
|
||||
@@ -326,6 +326,10 @@ define([
|
||||
additionalPriv.registeredOnly = true;
|
||||
}
|
||||
|
||||
if (['debug', 'profile'].indexOf(parsed.type) !== -1) {
|
||||
additionalPriv.hashes = hashes;
|
||||
}
|
||||
|
||||
for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; }
|
||||
|
||||
if (cfg.addData) {
|
||||
@@ -380,6 +384,27 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
sframeChan.on('Q_GET_ATTRIBUTE', function (data, cb) {
|
||||
Cryptpad.getAttribute(data.key, function (e, data) {
|
||||
cb({
|
||||
error: e,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
});
|
||||
sframeChan.on('Q_SET_ATTRIBUTE', function (data, cb) {
|
||||
Cryptpad.setAttribute(data.key, data.value, function (e) {
|
||||
cb({error:e});
|
||||
});
|
||||
});
|
||||
|
||||
Cryptpad.mailbox.onEvent.reg(function (data) {
|
||||
sframeChan.event('EV_MAILBOX_EVENT', data);
|
||||
});
|
||||
sframeChan.on('Q_MAILBOX_COMMAND', function (data, cb) {
|
||||
Cryptpad.mailbox.execCommand(data, cb);
|
||||
});
|
||||
|
||||
};
|
||||
addCommonRpc(sframeChan);
|
||||
|
||||
@@ -589,20 +614,6 @@ define([
|
||||
}, href);
|
||||
});
|
||||
|
||||
sframeChan.on('Q_GET_ATTRIBUTE', function (data, cb) {
|
||||
Cryptpad.getAttribute(data.key, function (e, data) {
|
||||
cb({
|
||||
error: e,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
});
|
||||
sframeChan.on('Q_SET_ATTRIBUTE', function (data, cb) {
|
||||
Cryptpad.setAttribute(data.key, data.value, function (e) {
|
||||
cb({error:e});
|
||||
});
|
||||
});
|
||||
|
||||
sframeChan.on('Q_DRIVE_GETDELETED', function (data, cb) {
|
||||
Cryptpad.getDeletedPads(data, function (err, obj) {
|
||||
if (err) { return void console.error(err); }
|
||||
@@ -711,6 +722,45 @@ define([
|
||||
initFilePicker(data);
|
||||
});
|
||||
|
||||
// Share modal
|
||||
var ShareModal = {};
|
||||
var initShareModal = function (cfg) {
|
||||
cfg.hashes = hashes;
|
||||
cfg.password = password;
|
||||
// cfg.hidden means pre-loading the filepicker while keeping it hidden.
|
||||
// if cfg.hidden is true and the iframe already exists, do nothing
|
||||
if (!ShareModal.$iframe) {
|
||||
var config = {};
|
||||
config.onShareAction = function (data) {
|
||||
sframeChan.event('EV_SHARE_ACTION', data);
|
||||
};
|
||||
config.onClose = function () {
|
||||
ShareModal.$iframe.hide();
|
||||
};
|
||||
config.data = cfg;
|
||||
config.addCommonRpc = addCommonRpc;
|
||||
config.modules = {
|
||||
Cryptpad: Cryptpad,
|
||||
SFrameChannel: SFrameChannel,
|
||||
Utils: Utils
|
||||
};
|
||||
ShareModal.$iframe = $('<iframe>', {id: 'sbox-share-iframe'}).appendTo($('body'));
|
||||
ShareModal.modal = Share.create(config);
|
||||
} else if (!cfg.hidden) {
|
||||
ShareModal.modal.refresh(cfg, function () {
|
||||
ShareModal.$iframe.show();
|
||||
});
|
||||
}
|
||||
if (cfg.hidden) {
|
||||
ShareModal.$iframe.hide();
|
||||
return;
|
||||
}
|
||||
ShareModal.$iframe.focus();
|
||||
};
|
||||
sframeChan.on('EV_SHARE_OPEN', function (data) {
|
||||
initShareModal(data || {});
|
||||
});
|
||||
|
||||
sframeChan.on('Q_TEMPLATE_USE', function (data, cb) {
|
||||
Cryptpad.useTemplate(data, Cryptget, cb);
|
||||
});
|
||||
@@ -879,13 +929,6 @@ define([
|
||||
Cryptpad.universal.execCommand(data, cb);
|
||||
});
|
||||
|
||||
Cryptpad.mailbox.onEvent.reg(function (data) {
|
||||
sframeChan.event('EV_MAILBOX_EVENT', data);
|
||||
});
|
||||
sframeChan.on('Q_MAILBOX_COMMAND', function (data, cb) {
|
||||
Cryptpad.mailbox.execCommand(data, cb);
|
||||
});
|
||||
|
||||
Cryptpad.onTimeoutEvent.reg(function () {
|
||||
sframeChan.event('EV_WORKER_TIMEOUT');
|
||||
});
|
||||
|
||||
@@ -121,13 +121,9 @@ define([
|
||||
return '<script src="' + origin + '/common/media-tag-nacl.min.js"></script>';
|
||||
};
|
||||
funcs.getMediatagFromHref = function (obj) {
|
||||
if (!obj || !obj.hash) { return; }
|
||||
var data = ctx.metadataMgr.getPrivateData();
|
||||
var secret;
|
||||
if (obj) {
|
||||
secret = Hash.getSecrets('file', obj.hash, obj.password);
|
||||
} else {
|
||||
secret = Hash.getSecrets('file', data.availableHashes.fileHash, data.password);
|
||||
}
|
||||
var secret = Hash.getSecrets('file', obj.hash, obj.password);
|
||||
if (secret.keys && secret.channel) {
|
||||
var key = Hash.encodeBase64(secret.keys && secret.keys.cryptKey);
|
||||
var hexFileName = secret.channel;
|
||||
@@ -391,12 +387,6 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
funcs.isStrongestStored = function () {
|
||||
var data = ctx.metadataMgr.getPrivateData();
|
||||
if (data.availableHashes.fileHash) { return true; }
|
||||
return !data.readOnly || !data.availableHashes.editHash;
|
||||
};
|
||||
|
||||
funcs.setDisplayName = function (name, cb) {
|
||||
cb = cb || $.noop;
|
||||
ctx.sframeChan.query('Q_SETTINGS_SET_DISPLAY_NAME', name, cb);
|
||||
@@ -432,6 +422,19 @@ define([
|
||||
return JSON.parse(JSON.stringify(friendRequests));
|
||||
};
|
||||
|
||||
funcs.getFriends = function () {
|
||||
var priv = ctx.metadataMgr.getPrivateData();
|
||||
var friends = priv.friends;
|
||||
var goodFriends = {};
|
||||
Object.keys(friends).forEach(function (curve) {
|
||||
if (curve.length !== 44) { return; }
|
||||
var data = friends[curve];
|
||||
if (!data.notifications) { return; }
|
||||
goodFriends[curve] = friends[curve];
|
||||
});
|
||||
return goodFriends;
|
||||
};
|
||||
|
||||
// Feedback
|
||||
funcs.prepareFeedback = function (key) {
|
||||
if (typeof(key) !== 'string') { return $.noop; }
|
||||
|
||||
@@ -304,8 +304,10 @@ MessengerUI, Messages) {
|
||||
} else if (Common.isLoggedIn() && data.curvePublic && !friends[data.curvePublic]
|
||||
&& !priv.readOnly) {
|
||||
if (pendingFriends[data.curvePublic] && pendingFriends[data.curvePublic] > friendTo) {
|
||||
$('<span>', {'class': 'cp-toolbar-userlist-friend'}).text(Messages.userlist_pending)
|
||||
.appendTo($rightCol);
|
||||
$('<button>', {
|
||||
'class': 'fa fa-hourglass-half cp-toolbar-userlist-button',
|
||||
'title': Messages.profile_friendRequestSent
|
||||
}).appendTo($nameSpan);
|
||||
} else if (friendRequests[data.curvePublic]) {
|
||||
$('<button>', {
|
||||
'class': 'fa fa-bell cp-toolbar-userlist-button',
|
||||
@@ -491,7 +493,7 @@ MessengerUI, Messages) {
|
||||
if ($messagebox.length) {
|
||||
$messagebox.scrollTop($messagebox[0].scrollHeight);
|
||||
}
|
||||
|
||||
|
||||
$button.addClass('cp-toolbar-button-active');
|
||||
config.$contentContainer.addClass('cp-chat-visible');
|
||||
$button.removeClass('cp-toolbar-notification');
|
||||
@@ -523,23 +525,18 @@ MessengerUI, Messages) {
|
||||
if (!config.metadataMgr) {
|
||||
throw new Error("You must provide a `metadataMgr` to display the userlist");
|
||||
}
|
||||
var metadataMgr = config.metadataMgr;
|
||||
var origin = config.metadataMgr.getPrivateData().origin;
|
||||
var pathname = config.metadataMgr.getPrivateData().pathname;
|
||||
var hashes = metadataMgr.getPrivateData().availableHashes;
|
||||
|
||||
var $shareBlock = $('<button>', {
|
||||
'class': 'fa fa-shhare-alt cp-toolbar-share-button',
|
||||
title: Messages.shareButton
|
||||
});
|
||||
var modal = UIElements.createShareModal({
|
||||
origin: origin,
|
||||
pathname: pathname,
|
||||
hashes: hashes,
|
||||
common: Common
|
||||
Common.getSframeChannel().event('EV_SHARE_OPEN', {
|
||||
hidden: true
|
||||
});
|
||||
$shareBlock.click(function () {
|
||||
UI.openCustomModal(UI.dialog.tabs(modal));
|
||||
Common.getSframeChannel().event('EV_SHARE_OPEN', {
|
||||
title: Common.getMetadataMgr().getMetadata().title
|
||||
});
|
||||
});
|
||||
|
||||
toolbar.$leftside.append($shareBlock);
|
||||
@@ -552,23 +549,19 @@ MessengerUI, Messages) {
|
||||
if (!config.metadataMgr) {
|
||||
throw new Error("You must provide a `metadataMgr` to display the userlist");
|
||||
}
|
||||
var metadataMgr = config.metadataMgr;
|
||||
var origin = config.metadataMgr.getPrivateData().origin;
|
||||
var pathname = config.metadataMgr.getPrivateData().pathname;
|
||||
var hashes = metadataMgr.getPrivateData().availableHashes;
|
||||
|
||||
var $shareBlock = $('<button>', {
|
||||
'class': 'fa fa-shhare-alt cp-toolbar-share-button',
|
||||
title: Messages.shareButton
|
||||
});
|
||||
var modal = UIElements.createFileShareModal({
|
||||
origin: origin,
|
||||
pathname: pathname,
|
||||
hashes: hashes,
|
||||
common: Common
|
||||
Common.getSframeChannel().event('EV_SHARE_OPEN', {
|
||||
hidden: true,
|
||||
file: true
|
||||
});
|
||||
$shareBlock.click(function () {
|
||||
UI.openCustomModal(UI.dialog.tabs(modal));
|
||||
Common.getSframeChannel().event('EV_SHARE_OPEN', {
|
||||
file: true
|
||||
});
|
||||
});
|
||||
|
||||
toolbar.$leftside.append($shareBlock);
|
||||
|
||||
2
www/common/translations/messages.ca.json
Normal file
2
www/common/translations/messages.ca.json
Normal file
@@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
||||
@@ -389,7 +389,7 @@
|
||||
"profile_inviteButtonTitle": "Crear un enlace de invitación para este usuario.",
|
||||
"profile_inviteExplanation": "Hacer clic en <strong>OK</strong> creará un enlace de mensaje seguro que <em>sólo {0} podrá ver.</em><br><br>El enlace será copiado a tu portapapeles y puede ser compartido públicamente.",
|
||||
"profile_viewMyProfile": "Ver mi perfil",
|
||||
"userlist_addAsFriendTitle": "Agregar \"{0}\" como contacto",
|
||||
"userlist_addAsFriendTitle": "Enviar \"{0}\" una solicitud de amistad",
|
||||
"userlist_thisIsYou": "Tú mismo (\"{0}\")",
|
||||
"contacts_title": "Contactos",
|
||||
"contacts_addError": "Error al agregar este contacto a la lista",
|
||||
@@ -561,5 +561,34 @@
|
||||
"fc_remove_sharedfolder": "Eliminar",
|
||||
"fc_hashtag": "Etiquetas",
|
||||
"register_passwordTooShort": "La contraseña debe tener por los menos {0} caracteres de largo.",
|
||||
"useTemplateCancel": "Recomenzar (Esc)"
|
||||
"useTemplateCancel": "Recomenzar (Esc)",
|
||||
"register_whyRegister": "Por qué conectarse?",
|
||||
"settings_cat_cursor": "Cursor",
|
||||
"settings_cat_pad": "Texto enriquecido",
|
||||
"settings_cat_creation": "Nueva hoja",
|
||||
"settings_cat_subscription": "Suscripción",
|
||||
"settings_backupHint": "Respalde o recupere todo sus contenido ne CryptDrive. No tendrán el contenido de sus archivos, solo las llaves para acceder a ellos.",
|
||||
"settings_backupHint2": "Descargue el contenido actual de sus notas. Las notas serán descargadas en un formato de leíble si el formato esta disponible.",
|
||||
"settings_backup2": "Descargar mi CryptDrive",
|
||||
"settings_backup2Confirm": "Esto descargara todas las notas y archivos desde su CryptDrive. Si desea continuar, elija un nombre y presione OK",
|
||||
"settings_exportTitle": "Exportar su CryptDrive",
|
||||
"settings_exportDescription": "Por favor espere mientras descargamos y desencriptamos sus documentos. Esto podría tomar unos minutos. Al cerrar la etiqueta interrumpirá el proceso.",
|
||||
"settings_exportFailed": "Si la nota requiere más de un minuto en ser descargada no será incluida en el archivo exportado. Un link para cada nota que no haya exportada será mostrada.",
|
||||
"settings_exportWarning": "Nota: esta herramienta aún está en versión beta y podría tener problema al ser escalada. Para una mejor performance se recomiendo dejar esta etiqueta con foco.",
|
||||
"settings_exportCancel": "Está seguro que quiera cancelar la exportación? Tendrá que comenzar desde el comienzo la próxima vez.",
|
||||
"settings_export_reading": "Leyendo su CryptDrive...",
|
||||
"settings_export_download": "Descargando y desencriptando sus documentos...",
|
||||
"settings_export_compressing": "Comprimiendo...",
|
||||
"settings_export_done": "Sus descarga está lista!",
|
||||
"settings_exportError": "Ver errores",
|
||||
"settings_exportErrorDescription": "No logramos agregar los siguientes documentos en lo exportado:",
|
||||
"settings_exportErrorEmpty": "Este documento no puede ser exportado (contenido vacío o invalido).",
|
||||
"settings_exportErrorMissing": "Este documento no puede ser encontrado en nuestros servidores (expirado o borrado por su dueño)",
|
||||
"settings_exportErrorOther": "Ha ocurrido un error al tratar de exportar este documento: {0}",
|
||||
"settings_thumbnails": "Imágenes en miniatura",
|
||||
"settings_disableThumbnailsAction": "Deshabilitar la creación de imágenes pequeñas en su CryptDrive",
|
||||
"settings_disableThumbnailsDescription": "Las imágenes en miniatura serán guardadas en su navegador de manera automática cuando visite una nueva hoja. Puede deshabilitar esta función acá.",
|
||||
"settings_resetThumbnailsAction": "Limpiar",
|
||||
"settings_resetThumbnailsDescription": "Limpiar todas las imágenes en miniatura de sus notas guardadas en su navegador.",
|
||||
"settings_resetThumbnailsDone": "Todas las imágenes en miniatura han sido borradas."
|
||||
}
|
||||
|
||||
@@ -278,13 +278,8 @@
|
||||
"profile_create": "Create a profile",
|
||||
"profile_description": "Description",
|
||||
"profile_fieldSaved": "New value saved: {0}",
|
||||
"profile_inviteButton": "Connect",
|
||||
"profile_inviteButtonTitle": "Create a link that will invite this user to connect with you.",
|
||||
"profile_inviteExplanation": "Clicking <strong>OK</strong> will create a link to a secure messaging session that <em>only {0} will be able to redeem.</em><br><br>The link will be copied to your clipboard and can be shared publicly.",
|
||||
"profile_viewMyProfile": "View my profile",
|
||||
"userlist_addAsFriendTitle": "Send \"{0}\" a friend request",
|
||||
"userlist_thisIsYou": "This is you (\"{0}\")",
|
||||
"userlist_pending": "Pending...",
|
||||
"contacts_title": "Contacts",
|
||||
"contacts_addError": "Error while adding that contact to the list",
|
||||
"contacts_added": "Contact invite accepted.",
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
"forgetPrompt": "Нажав ОК, вы удалите документ в корзину. Уверены?",
|
||||
"movedToTrash": "Документ был удалён в корзину.<br><a href=\"/drive/\">Доступ к диску</a>",
|
||||
"shareButton": "Поделиться",
|
||||
"shareSuccess": "Ссылка скопирована в буфер обмена",
|
||||
"shareSuccess": "Ссылка скопирована в буфер обмена.",
|
||||
"userListButton": "Список пользователей",
|
||||
"chatButton": "Чат",
|
||||
"userAccountButton": "Ваш профиль",
|
||||
@@ -370,5 +370,28 @@
|
||||
"fm_padIsOwned": "Вы владелец этого пэда",
|
||||
"fm_padIsOwnedOther": "Этот пэд принадлежит другому пользователю",
|
||||
"fm_deletedPads": "Эти пэды больше не существуют на сервере, они были удалены с вашего CryptDrive: {0}",
|
||||
"fm_tags_name": "Имя тэга"
|
||||
"fm_tags_name": "Имя тэга",
|
||||
"printCSS": "Пользовательские настройки вида (CSS)",
|
||||
"viewEmbedTag": "Чтобы встроить данный документ вставьте iframe в нужную страницу. Вы можете настроить внешний вид используя CSS и HTML атрибуты. ",
|
||||
"debug_getGraphText": "Это код DOT для генерации графика истории этого документа:",
|
||||
"fm_ownedPadsName": "Собственный",
|
||||
"fm_info_anonymous": "Вы не вошли в учетную запись, поэтому срок действия ваших пэдов истечет через 3 месяца (<a href=\"https://blog.cryptpad.fr/2017/05/17/You-gotta-log-in/\" target=\"_blank\">find out more</a>). Они хранятся в вашем браузере, поэтому очистка истории может привести к их исчезновению..<br><a href=\"/register/\">Sign up</a> or <a href=\"/login/\">Log in</a> to keep them alive.<br>",
|
||||
"fm_backup_title": "Резервная ссылка",
|
||||
"fm_burnThisDriveButton": "Удалить всю информацию, хранящуюся на CryptPad в браузере.",
|
||||
"fm_tags_used": "Количество использований",
|
||||
"fm_restoreDrive": "Восстановление прежнего состояния диска. Для достижения наилучших результатов не вносите изменения в диск, пока этот процесс не будет завершен.",
|
||||
"fm_passwordProtected": "Этот документ защищен паролем",
|
||||
"fc_newfolder": "Новая папка",
|
||||
"fc_newsharedfolder": "Новая общая папка",
|
||||
"fc_rename": "Переименовать",
|
||||
"fc_open": "Открыть",
|
||||
"fc_open_ro": "Отркыть (режим чтения)",
|
||||
"fc_delete": "Переместить в корзину",
|
||||
"fc_delete_owned": "Удалить с сервера",
|
||||
"fc_restore": "Восстановить",
|
||||
"fc_remove_sharedfolder": "Удалить",
|
||||
"fc_empty": "Удалить корзину",
|
||||
"fc_prop": "Свойства",
|
||||
"fc_hashtag": "Теги",
|
||||
"fc_sizeInKilobytes": "Размер в килобайтах"
|
||||
}
|
||||
|
||||
3
www/common/translations/messages.te.json
Normal file
3
www/common/translations/messages.te.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user