From cb36a499080d998148e9b5fab52932bc0f235a2e Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 4 Jun 2020 16:54:56 +0200 Subject: [PATCH 01/49] Add team mailbox with the SHARE_PAD example --- www/common/common-ui-elements.js | 46 ++++++++++++++++------------- www/common/notifications.js | 21 ++++++++++++- www/common/outer/mailbox.js | 13 ++++++-- www/common/outer/team.js | 36 ++++++++++++++++++++++ www/common/sframe-common-mailbox.js | 16 ++++++---- www/common/toolbar.js | 2 +- 6 files changed, 105 insertions(+), 29 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 278e8dda8..a7c5d3994 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -272,25 +272,30 @@ define([ var $friends = $div.find('.cp-usergrid-user.cp-selected'); $friends.each(function (i, el) { var curve = $(el).attr('data-curve'); - // Check if the selected element is a friend or a team - if (curve) { // Friend - if (!curve || !friends[curve]) { return; } - var friend = friends[curve]; - if (!friend.notifications || !friend.curvePublic) { return; } - common.mailbox.sendTo("SHARE_PAD", { - href: href, - password: config.password, - isTemplate: config.isTemplate, - name: myName, - title: title - }, { - channel: friend.notifications, - curvePublic: friend.curvePublic - }); - return; - } - // Team var ed = $(el).attr('data-ed'); + var friend = curve && friends[curve]; + var team = teams[ed]; + // If the selected element is a friend or a team without edit right, + // send a notification + var mailbox = friend || ((team && team.viewer) ? team : undefined); + if (mailbox) { // Friend + if (friends[curve] && !mailbox.notifications) { return; } + if (mailbox.notifications && mailbox.curvePublic) { + // XXX we should mark this notification as "viewed" in our own proxy + common.mailbox.sendTo("SHARE_PAD", { + href: href, + password: config.password, + isTemplate: config.isTemplate, + name: myName, + title: title + }, { + channel: mailbox.notifications, + curvePublic: mailbox.curvePublic + }); + return; + } + } + // If it's a team with edit right, add the pad directly var team = teams[ed]; if (!team) { return; } sframeChan.query('Q_STORE_IN_TEAM', { @@ -409,10 +414,11 @@ define([ // config.teamId only exists when we're trying to share a pad from a team drive // In this case, we don't want to share the pad with the current team if (config.teamId && config.teamId === id) { return; } - if (!teamsData[id].hasSecondaryKey) { return; } var t = teamsData[id]; teams[t.edPublic] = { - notifications: true, + viewer: !teamsData[id].hasSecondaryKey, + notifications: t.notifications, + curvePublic: t.curvePublic, displayName: t.name, edPublic: t.edPublic, avatar: t.avatar, diff --git a/www/common/notifications.js b/www/common/notifications.js index 3abc40ca8..348b0cc44 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -84,6 +84,10 @@ define([ // Share pad + Messages.notification_padSharedTeam = "{0} has shared a pad with the team {2}: {1}"; // XXX + Messages.notification_fileSharedTeam = "{0} has shared a file with the team {2}: {1}"; // XXX + Messages.notification_folderSharedTeam = "{0} has shared a pad with the team {2}: {1}"; // XXX + handlers['SHARE_PAD'] = function(common, data) { var content = data.content; var msg = content.msg; @@ -91,10 +95,22 @@ define([ var key = type === 'drive' ? 'notification_folderShared' : (type === 'file' ? 'notification_fileShared' : 'notification_padShared'); + + var teamNotification = /^team-/.test(data.type) && Number(data.type.slice(5)); + var teamName = ''; + if (teamNotification) { + var privateData = common.getMetadataMgr().getPrivateData(); + var teamsData = Util.tryParse(JSON.stringify(privateData.teams)) || {}; + var team = teamsData[teamNotification]; + if (!team || !team.name) { return; } + key += "Team"; + teamName = Util.fixHTML(team.name); + } + var name = Util.fixHTML(msg.content.name) || Messages.anonymous; var title = Util.fixHTML(msg.content.title); content.getFormatText = function() { - return Messages._getKey(key, [name, title]); + return Messages._getKey(key, [name, title, teamName]); }; content.handler = function() { var todo = function() { @@ -105,6 +121,9 @@ define([ if (msg.content.isTemplate) { common.sessionStorage.put(Constants.newPadPathKey, ['template'], waitFor()); } + if (teamNotification) { + common.sessionStorage.put(Constants.newPadTeamKey, teamNotification, waitFor()); + } common.sessionStorage.put('newPadPassword', msg.content.password || '', waitFor()); }).nThen(function() { todo(); diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index 706f1c8c2..ccae95a7e 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -467,6 +467,15 @@ proxy.mailboxes = { } }); + Object.keys(store.proxy.teams || {}).forEach(function (teamId) { + var team = store.proxy.teams[teamId]; + var teamMailbox = team.keys.mailbox || {}; + if (!teamMailbox.channel) { return; } + openChannel(ctx, 'team-'+teamId, teamMailbox, function () { + //console.log('Mailbox team', teamId); + }); + }); + mailbox.post = function (box, type, content) { var b = ctx.boxes[box]; if (!b) { return; } @@ -477,8 +486,8 @@ proxy.mailboxes = { }); }; - mailbox.open = function (key, m, cb) { - if (TYPES.indexOf(key) === -1) { return; } + mailbox.open = function (key, m, cb, team) { + if (TYPES.indexOf(key) === -1 && !team) { return; } openChannel(ctx, key, m, cb); }; diff --git a/www/common/outer/team.js b/www/common/outer/team.js index c151de004..92dc1deda 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -494,6 +494,9 @@ define([ var roHash = Hash.getViewHashFromKeys(secret); var keyPair = Nacl.sign.keyPair(); // keyPair.secretKey , keyPair.publicKey + var curveSeed = Nacl.randomBytes(32); + var curvePair = Nacl.box.keyPair.fromSecretKey(curveSeed); + var rosterSeed = Crypto.Team.createSeed(); var rosterKeys = Crypto.Team.deriveMemberKeys(rosterSeed, { curvePublic: ctx.store.proxy.curvePublic, @@ -585,6 +588,14 @@ define([ proxy.on('ready', function () { // Store keys in our drive var keys = { + mailbox: { + channel: Hash.createChannelId(), + viewed: [], + keys: { + curvePrivate: Nacl.util.encodeBase64(curvePair.secretKey), + curvePublic: Nacl.util.encodeBase64(curvePair.publicKey) + } + }, drive: { edPrivate: Nacl.util.encodeBase64(keyPair.secretKey), edPublic: Nacl.util.encodeBase64(keyPair.publicKey) @@ -1566,6 +1577,26 @@ define([ }); }; + var deriveMailbox = function (team) { + if (!team) { return; } + if (team.keys && team.keys.mailbox) { return team.keys.mailbox; } + var channel = team.channel; + if (!channel) { return; } + // XXX maybe use something else than channel? + var hash = Nacl.hash(Nacl.util.decodeUTF8(channel)); + var seed = hash.slice(0,32); + var channel = Util.uint8ArrayToHex(hash.slice(32,48)); + var curvePair = Nacl.box.keyPair.fromSecretKey(seed); + return { + channel: channel, + viewed: [], + keys: { + curvePrivate: Nacl.util.encodeBase64(curvePair.secretKey), + curvePublic: Nacl.util.encodeBase64(curvePair.publicKey) + } + }; + }; + Team.init = function (cfg, waitFor, emit) { var team = {}; var store = cfg.store; @@ -1595,6 +1626,9 @@ define([ Object.keys(teams).forEach(function (id) { ctx.onReadyHandlers[id] = []; + if (!Util.find(teams, id, 'keys', 'mailbox')) { + teams[id].keys.mailbox = deriveMailbox(teams[id]); + } openChannel(ctx, teams[id], id, waitFor(function (err) { if (err) { return void console.error(err); } console.debug('Team '+id+' ready'); @@ -1615,6 +1649,8 @@ define([ edPublic: Util.find(teams[id], ['keys', 'drive', 'edPublic']), avatar: Util.find(teams[id], ['metadata', 'avatar']), viewer: !Util.find(teams[id], ['keys', 'drive', 'edPrivate']), + notifications: Util.find(teams[id], ['keys', 'mailbox', 'channel']), + curvePublic: Util.find(teams[id], ['keys', 'mailbox', 'keys', 'curvePublic']), }; if (safe && ctx.teams[id]) { diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js index a5602fc3f..eac59462e 100644 --- a/www/common/sframe-common-mailbox.js +++ b/www/common/sframe-common-mailbox.js @@ -105,11 +105,14 @@ define([ }); // Call the onMessage handlers + var isNotification = function (type) { + return type === "notificatons" || /^team-/.test(type); + }; var pushMessage = function (data, handler) { var todo = function (f) { try { var el; - if (data.type === 'notifications') { + if (isNotification(data.type)) { Notifications.add(Common, data); el = createElement(data); } @@ -129,7 +132,7 @@ define([ onViewedHandlers.forEach(function (f) { try { f(data); - if (data.type === 'notifications') { + if (isNotification(data.type)) { Notifications.remove(Common, data); } } catch (e) { @@ -173,20 +176,23 @@ define([ execCommand('SUBSCRIBE', null, function () {}); subscribed = true; } + var teams = types.indexOf('team') !== -1; if (typeof(cfg.onViewed) === "function") { onViewedHandlers.push(function (data) { - if (types.indexOf(data.type) === -1) { return; } + var type = data.type; + if (types.indexOf(type) === -1 && !(teams && /^team-/.test(type))) { return; } cfg.onViewed(data); }); } if (typeof(cfg.onMessage) === "function") { onMessageHandlers.push(function (data, el) { - if (types.indexOf(data.type) === -1) { return; } + var type = data.type; + if (types.indexOf(type) === -1 && !(teams && /^team-/.test(type))) { return; } cfg.onMessage(data, el); }); } Object.keys(history).forEach(function (type) { - if (types.indexOf(type) === -1) { return; } + if (types.indexOf(type) === -1 && !(teams && /^team-/.test(type))) { return; } history[type].forEach(function (data) { pushMessage({ type: type, diff --git a/www/common/toolbar.js b/www/common/toolbar.js index a4683a884..e55cdcf82 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -1025,7 +1025,7 @@ MessengerUI, Messages) { $button.addClass('fa-bell'); }; - Common.mailbox.subscribe(['notifications'], { + Common.mailbox.subscribe(['notifications', 'team'], { onMessage: function (data, el) { if (el) { $(div).prepend(el); From 0390d3df7528ee24ab4f500afaf1f5e512e0b28b Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 5 Jun 2020 12:04:28 +0200 Subject: [PATCH 02/49] Don't show your own team notifications --- www/common/common-ui-elements.js | 2 +- www/common/outer/mailbox.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index a7c5d3994..37a5172db 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -281,7 +281,6 @@ define([ if (mailbox) { // Friend if (friends[curve] && !mailbox.notifications) { return; } if (mailbox.notifications && mailbox.curvePublic) { - // XXX we should mark this notification as "viewed" in our own proxy common.mailbox.sendTo("SHARE_PAD", { href: href, password: config.password, @@ -289,6 +288,7 @@ define([ name: myName, title: title }, { + viewed: team && team.id, channel: mailbox.notifications, curvePublic: mailbox.curvePublic }); diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index ccae95a7e..2250257aa 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -109,6 +109,17 @@ proxy.mailboxes = { }); var ciphertext = crypto.encrypt(text, user.curvePublic); + // If we've sent this message to one of our teams' mailbox, we may want to "dismiss" it + // automatically + if (user.viewed) { + var team = Util.find(ctx, ['store', 'proxy', 'teams', user.viewed]); + if (team) { + var hash = ciphertext.slice(0,64); + var viewed = Util.find(team, ['keys', 'mailbox', 'viewed']); + if (Array.isArray(viewed)) { viewed.push(hash); } + } + } + anonRpc.send("WRITE_PRIVATE_MESSAGE", [ user.channel, ciphertext From f7b61daff325eb9641ad977b6b1aaaf1bea76218 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 5 Jun 2020 12:08:43 +0200 Subject: [PATCH 03/49] lint compliance --- www/common/common-ui-elements.js | 1 - www/common/outer/team.js | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 37a5172db..acab5085b 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -296,7 +296,6 @@ define([ } } // If it's a team with edit right, add the pad directly - var team = teams[ed]; if (!team) { return; } sframeChan.query('Q_STORE_IN_TEAM', { href: href, diff --git a/www/common/outer/team.js b/www/common/outer/team.js index 92dc1deda..4b5c159ea 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -1585,10 +1585,10 @@ define([ // XXX maybe use something else than channel? var hash = Nacl.hash(Nacl.util.decodeUTF8(channel)); var seed = hash.slice(0,32); - var channel = Util.uint8ArrayToHex(hash.slice(32,48)); + var mailboxChannel = Util.uint8ArrayToHex(hash.slice(32,48)); var curvePair = Nacl.box.keyPair.fromSecretKey(seed); return { - channel: channel, + channel: mailboxChannel, viewed: [], keys: { curvePrivate: Nacl.util.encodeBase64(curvePair.secretKey), From bcfa09f7bce625663d574dfcf0cb18b9124f92f4 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 9 Jun 2020 17:40:52 +0200 Subject: [PATCH 04/49] Fix mailbox issue and add XXX --- www/common/outer/team.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/common/outer/team.js b/www/common/outer/team.js index 4b5c159ea..a0c785200 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -1577,6 +1577,8 @@ define([ }); }; + // XXX call mailbox.open when you create or join a team + // XXX close the mailbox hwne you leave the team var deriveMailbox = function (team) { if (!team) { return; } if (team.keys && team.keys.mailbox) { return team.keys.mailbox; } @@ -1626,7 +1628,7 @@ define([ Object.keys(teams).forEach(function (id) { ctx.onReadyHandlers[id] = []; - if (!Util.find(teams, id, 'keys', 'mailbox')) { + if (!Util.find(teams, [id, 'keys', 'mailbox'])) { teams[id].keys.mailbox = deriveMailbox(teams[id]); } openChannel(ctx, teams[id], id, waitFor(function (err) { From 24c7ea985dd385deb9ec6c7f14967d80b3501646 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 10 Jun 2020 12:14:12 +0200 Subject: [PATCH 05/49] Fix issues with the team mailbox --- www/common/outer/mailbox.js | 34 +++++++++++++++++++++-------- www/common/outer/team.js | 27 +++++++++++++++-------- www/common/sframe-common-mailbox.js | 3 ++- www/common/toolbar.js | 1 + 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index 2250257aa..e5b6179c7 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -137,10 +137,9 @@ proxy.mailboxes = { var dismiss = function (ctx, data, cId, cb) { var type = data.type; var hash = data.hash; - var m = Util.find(ctx, ['store', 'proxy', 'mailboxes', type]); - if (!m) { return void cb({error: 'NOT_FOUND'}); } var box = ctx.boxes[type]; if (!box) { return void cb({error: 'NOT_LOADED'}); } + var m = box.data || {}; // If the hash in in our history, get the index from the history: // - if the index is 0, we can change our lastKnownHash @@ -202,7 +201,16 @@ proxy.mailboxes = { }; - var openChannel = function (ctx, type, m, onReady) { + var leaveChannel = function (ctx, type, cb) { + var box = ctx.boxes[type]; + if (!box) { return void cb(); } + if (!box.cpNf || typeof(box.cpNf.stop) !== "function") { return void cb('EINVAL'); } + box.cpNf.stop(); + delete ctx.boxes[type]; + }; + var openChannel = function (ctx, type, m, onReady, opts) { + console.error(type, m, opts); + opts = opts || {}; var box = ctx.boxes[type] = { channel: m.channel, type: type, @@ -221,7 +229,8 @@ proxy.mailboxes = { console.error(e); } box.queue.push(msg); - } + }, + data: m }; if (!Crypto.Mailbox) { return void console.error("chainpad-crypto is outdated and doesn't support mailboxes."); @@ -235,7 +244,7 @@ proxy.mailboxes = { channel: m.channel, noChainPad: true, crypto: crypto, - owners: [ctx.store.proxy.edPublic], + owners: opts.owners || [ctx.store.proxy.edPublic], lastKnownHash: m.lastKnownHash }; cfg.onConnectionChange = function () {}; // Allow reconnections in chainpad-netflux @@ -357,7 +366,7 @@ proxy.mailboxes = { // Continue onReady(); }; - CpNetflux.start(cfg); + box.cpNf = CpNetflux.start(cfg); }; var initializeHistory = function (ctx) { @@ -480,11 +489,15 @@ proxy.mailboxes = { Object.keys(store.proxy.teams || {}).forEach(function (teamId) { var team = store.proxy.teams[teamId]; + if (!team) { return; } var teamMailbox = team.keys.mailbox || {}; if (!teamMailbox.channel) { return; } + var opts = { + owners: [Util.find(team, ['keys', 'drive', 'edPublic'])] + }; openChannel(ctx, 'team-'+teamId, teamMailbox, function () { //console.log('Mailbox team', teamId); - }); + }, opts); }); mailbox.post = function (box, type, content) { @@ -497,9 +510,12 @@ proxy.mailboxes = { }); }; - mailbox.open = function (key, m, cb, team) { + mailbox.open = function (key, m, cb, team, opts) { if (TYPES.indexOf(key) === -1 && !team) { return; } - openChannel(ctx, key, m, cb); + openChannel(ctx, key, m, cb, opts); + }; + mailbox.close = function (key, cb) { + leaveChannel(ctx, key, cb); }; mailbox.dismiss = function (data, cb) { diff --git a/www/common/outer/team.js b/www/common/outer/team.js index a0c785200..c495bc91c 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -126,6 +126,9 @@ define([ delete ctx.store.proxy.teams[teamId]; ctx.emit('LEAVE_TEAM', teamId, team.clients); ctx.updateMetadata(); + ctx.store.mailbox.close('team-'+teamId, function () { + // Close team mailbox + }); }; var getTeamChannelList = function (ctx, id) { @@ -494,8 +497,7 @@ define([ var roHash = Hash.getViewHashFromKeys(secret); var keyPair = Nacl.sign.keyPair(); // keyPair.secretKey , keyPair.publicKey - var curveSeed = Nacl.randomBytes(32); - var curvePair = Nacl.box.keyPair.fromSecretKey(curveSeed); + var curvePair = Nacl.box.keyPair(); var rosterSeed = Crypto.Team.createSeed(); var rosterKeys = Crypto.Team.deriveMemberKeys(rosterSeed, { @@ -612,7 +614,7 @@ define([ view: rosterKeys.viewKeyStr, } }; - ctx.store.proxy.teams[id] = { + var t = ctx.store.proxy.teams[id] = { owner: true, channel: secret.channel, hash: hash, @@ -629,6 +631,11 @@ define([ onReady(ctx, id, lm, roster, keys, cId, function () { Feedback.send('TEAM_CREATION'); + ctx.store.mailbox.open('team-'+id, t.keys.mailbox, function () { + // Team mailbox loaded + }, true, { + owners: t.keys.drive.edPublic + }); ctx.updateMetadata(); cb(); }); @@ -731,6 +738,11 @@ define([ team.rpc.removePins(waitFor(function (err) { if (err) { console.error(err); } })); + // Delete the mailbox + var mailboxChan = Util.find(teamData, ['keys', 'mailbox', 'channel']); + team.rpc.removeOwnedChannel(mailboxChan, waitFor(function (err) { + if (err) { console.error(err); } + })); // Delete the roster var rosterChan = Util.find(teamData, ['keys', 'roster', 'channel']); ctx.store.rpc.removeOwnedChannel(rosterChan, waitFor(function (err) { @@ -1577,15 +1589,12 @@ define([ }); }; - // XXX call mailbox.open when you create or join a team - // XXX close the mailbox hwne you leave the team var deriveMailbox = function (team) { if (!team) { return; } if (team.keys && team.keys.mailbox) { return team.keys.mailbox; } - var channel = team.channel; - if (!channel) { return; } - // XXX maybe use something else than channel? - var hash = Nacl.hash(Nacl.util.decodeUTF8(channel)); + var strSeed = Util.find(team, ['keys', 'roster', 'edit']); + if (!strSeed) { return; } + var hash = Nacl.hash(Nacl.util.decodeUTF8(strSeed)); var seed = hash.slice(0,32); var mailboxChannel = Util.uint8ArrayToHex(hash.slice(32,48)); var curvePair = Nacl.box.keyPair.fromSecretKey(seed); diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js index eac59462e..bdf1ae81e 100644 --- a/www/common/sframe-common-mailbox.js +++ b/www/common/sframe-common-mailbox.js @@ -106,7 +106,7 @@ define([ // Call the onMessage handlers var isNotification = function (type) { - return type === "notificatons" || /^team-/.test(type); + return type === "notifications" || /^team-/.test(type); }; var pushMessage = function (data, handler) { var todo = function (f) { @@ -188,6 +188,7 @@ define([ onMessageHandlers.push(function (data, el) { var type = data.type; if (types.indexOf(type) === -1 && !(teams && /^team-/.test(type))) { return; } + console.log('okokok'); cfg.onMessage(data, el); }); } diff --git a/www/common/toolbar.js b/www/common/toolbar.js index e55cdcf82..3afa55d61 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -1027,6 +1027,7 @@ MessengerUI, Messages) { Common.mailbox.subscribe(['notifications', 'team'], { onMessage: function (data, el) { + console.log(data, el, div); if (el) { $(div).prepend(el); } From 4faa0839f9e7d972d0c07b57b6ce64a2e1902f91 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 10 Jun 2020 12:29:29 +0200 Subject: [PATCH 06/49] Open the mailbox when joining a team --- www/common/outer/team.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/www/common/outer/team.js b/www/common/outer/team.js index c495bc91c..5c31621f7 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -773,6 +773,12 @@ define([ ctx.onReadyHandlers[id] = []; openChannel(ctx, team, id, function (obj) { if (!(obj && obj.error)) { console.debug('Team joined:' + id); } + var t = ctx.store.proxy.teams[id]; + ctx.store.mailbox.open('team-'+id, t.keys.mailbox, function () { + // Team mailbox loaded + }, true, { + owners: t.keys.drive.edPublic + }); ctx.updateMetadata(); cb(obj); }); From e755f88b6ae44a3e17248f0d6221499113c818db Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 10 Jun 2020 12:50:35 +0200 Subject: [PATCH 07/49] Translated using Weblate (English) Currently translated at 100.0% (1283 of 1283 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1282 of 1282 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 637b05bef..4d47b3c7c 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1377,5 +1377,7 @@ "code_editorTheme": "Editor theme", "toolbar_file": "File", "slide_backCol": "Background color", - "slide_textCol": "Text color" + "slide_textCol": "Text color", + "support_languagesPreamble": "This server's administrators speak the following languages:", + "settings_safeLinkDefault": "Safe Links are now turned on by default. Please use the Share menu to copy links rather than your browser's address bar." } From c01f62177f01500e484d1693b925d167e4f0c74e Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 10 Jun 2020 06:57:40 -0400 Subject: [PATCH 08/49] remove some hardcoded translations --- www/common/notifications.js | 2 -- www/support/inner.js | 1 - 2 files changed, 3 deletions(-) diff --git a/www/common/notifications.js b/www/common/notifications.js index 94c2dcb15..fc72517fd 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -388,8 +388,6 @@ define([ }; handlers['SAFE_LINKS_DEFAULT'] = function (common, data) { - Messages.settings_safeLinkDefault = "SAFE LINKS ARE NOW DEFAULT"; // XXX - var content = data.content; content.getFormatText = function () { return Messages.settings_safeLinkDefault; diff --git a/www/support/inner.js b/www/support/inner.js index 3d907421d..d956914c6 100644 --- a/www/support/inner.js +++ b/www/support/inner.js @@ -149,7 +149,6 @@ define([ }) ); - Messages.support_languagesPreamble = "This server's administrators speak the following languages:"; // XXX var $div = $( h('div.cp-support-language', [ Messages.support_languagesPreamble, From 30f6e92312c2bc7b3a7d89024033ccdd63d402cb Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 10 Jun 2020 10:49:29 -0400 Subject: [PATCH 09/49] export customizable footer links for use in the 'about menu' --- customize.dist/pages.js | 38 +++++++--------------- www/common/common-ui-elements.js | 56 +++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/customize.dist/pages.js b/customize.dist/pages.js index 6ba39e49a..b65faffc2 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -64,6 +64,12 @@ define([ Pages.versionString = "CryptPad v3.18.1 (Smilodon's revenge)"; + // used for the about menu + Pages.imprintLink = AppConfig.imprint ? footLink(imprintUrl, 'imprint') : undefined; + Pages.privacyLink = footLink(AppConfig.privacy, 'privacy'); + Pages.githubLink = footLink('https://github.com/xwiki-labs/cryptpad', null, 'GitHub'); + Pages.faqLink = footLink('/faq.html', 'faq_link'); + Pages.infopageFooter = function () { return h('footer', [ h('div.container', [ @@ -74,24 +80,14 @@ define([ languageSelector() ]) ], ''), - /*footerCol('footer_applications', [ - footLink('/drive/', 'main_drive'), - footLink('/pad/', 'main_richText'), - footLink('/code/', 'main_code'), - footLink('/slide/', 'main_slide'), - footLink('/poll/', 'main_poll'), - footLink('/kanban/', 'main_kanban'), - footLink('/whiteboard/', null, Msg.type.whiteboard) - ]),*/ footerCol('footer_product', [ - footLink('https://cryptpad.fr/what-is-cryptpad.html', 'topbar_whatIsCryptpad'), - footLink('/faq.html', 'faq_link'), - footLink('https://github.com/xwiki-labs/cryptpad', null, 'GitHub'), + footLink('/what-is-cryptpad.html', 'topbar_whatIsCryptpad'), + Pages.faqLink, + Pages.githubLink, footLink('https://opencollective.com/cryptpad/contribute/', 'footer_donate'), ]), footerCol('footer_aboutUs', [ - /*footLink('https://blog.cryptpad.fr', 'blog'), - footLink('https://labs.xwiki.com', null, 'XWiki Labs'),*/ + /*footLink('https://blog.cryptpad.fr', 'blog'), */ footLink('http://www.xwiki.com', null, 'XWiki SAS'), footLink('https://www.open-paas.org', null, 'OpenPaaS'), footLink('/about.html', 'footer_team'), @@ -99,15 +95,9 @@ define([ ]), footerCol('footer_legal', [ footLink('/terms.html', 'footer_tos'), - footLink(AppConfig.privacy, 'privacy'), - AppConfig.imprint ? footLink(imprintUrl, 'imprint') : undefined, + Pages.privacyLink, + Pages.imprintLink, ]), - /*footerCol('footer_contact', [ - footLink('https://riot.im/app/#/room/#cryptpad:matrix.org', null, 'Chat'), - footLink('https://twitter.com/cryptpad', null, 'Twitter'), - footLink('https://github.com/xwiki-labs/cryptpad', null, 'GitHub'), - footLink('/contact.html', null, 'Email') - ])*/ ]) ]), h('div.cp-version-footer', Pages.versionString) @@ -150,13 +140,9 @@ define([ h('a.navbar-brand', { href: '/index.html'}), button, h('div.collapse.navbar-collapse.justify-content-end#menuCollapse', [ - //h('a.nav-item.nav-link', { href: '/what-is-cryptpad.html'}, Msg.topbar_whatIsCryptpad), // Moved the FAQ - //h('a.nav-item.nav-link', { href: '/faq.html'}, Msg.faq_link), h('a.nav-item.nav-link', { href: 'https://blog.cryptpad.fr/'}, Msg.blog), h('a.nav-item.nav-link', { href: '/features.html'}, Msg.pricing), h('a.nav-item.nav-link', { href: '/privacy.html'}, Msg.privacy), - //h('a.nav-item.nav-link', { href: '/contact.html'}, Msg.contact), - //h('a.nav-item.nav-link', { href: '/about.html'}, Msg.about), ].concat(rightLinks)) ); }; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 4393d1201..6b433c805 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2303,29 +2303,47 @@ define([ var priv = metadataMgr.getPrivateData(); var origin = priv.origin; - Messages.help_faq = "Review our list of frequently asked questions"; // XXX - var faqLine = h('p', - h('a', { - target: '_blank', - rel: 'noreferrer noopener', - href: origin + '/faq.html', - }, Messages.help_faq) - ); + // TODO link to the most recent changelog/release notes + // https://github.com/xwiki-labs/cryptpad/releases/latest/ ? - // XXX link to the most recent changelog/release notes - // XXX FAQ - // XXX GitHub - // XXX privacy policy - // XXX legal notice + var note = function (content) { + return h('span.cp-info-menu-description', content); + }; - var content = h('div', [ - // CryptPad version number + Messages.info_imprintFlavour = "Legally mandated information about this service's operators can be found here."; // XXX + Messages.info_privacyFlavour = "Our privacy policy describes how we treat your data."; // XXX + Messages.info_faqFlavour = "Consult our FAQ for answers to common questions."; // XXX + + var template = function (line, link) { + if (!line || !link) { return; } + var p = $('

').html(line)[0]; + var model = link.cloneNode(true); + var sub = link.cloneNode(true); + +/* This is a hack to make relative URLs point to the main domain + instead of the sandbox domain. It will break if the admins have specified + some less common URL formats for their customizable links, such as if they've + used a protocal-relative absolute URL. The URL API isn't quite safe to use + because of IE (thanks, Bill). */ + var href = sub.getAttribute('href'); + if (/^\//.test(href)) { sub.setAttribute('href', origin + href); } + var a = p.querySelector('a'); + if (!a) { return; } + sub.innerText = a.innerText; + p.replaceChild(sub, a); + return p; + }; + + var legalLine = template(Messages.info_imprintFlavour, Pages.imprintLink); + var privacyLine = template(Messages.info_privacyFlavour, Pages.privacyLink); + var faqLine = template(Messages.info_faqFlavour, Pages.faqLink); + + var content = h('div.cp-info-menu-container', [ h('h6', Pages.versionString), - // First point users to our FAQ + h('hr'), + legalLine, + privacyLine, faqLine, - // Link to the support ticket form in case their - // question isn't answered by the FAQ - //supportLine, ]); var buttons = [ From 40d5acbd86500ef0ff8135b27caabd20593ebf0e Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 10 Jun 2020 11:22:00 -0400 Subject: [PATCH 10/49] remove the change display name option from the user admin menu --- www/common/common-ui-elements.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 6b433c805..f01bea6eb 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2306,10 +2306,6 @@ define([ // TODO link to the most recent changelog/release notes // https://github.com/xwiki-labs/cryptpad/releases/latest/ ? - var note = function (content) { - return h('span.cp-info-menu-description', content); - }; - Messages.info_imprintFlavour = "Legally mandated information about this service's operators can be found here."; // XXX Messages.info_privacyFlavour = "Our privacy policy describes how we treat your data."; // XXX Messages.info_faqFlavour = "Consult our FAQ for answers to common questions."; // XXX @@ -2317,7 +2313,6 @@ define([ var template = function (line, link) { if (!line || !link) { return; } var p = $('

').html(line)[0]; - var model = link.cloneNode(true); var sub = link.cloneNode(true); /* This is a hack to make relative URLs point to the main domain @@ -2435,13 +2430,14 @@ define([ } options.push({ tag: 'hr' }); // Add the change display name button if not in read only mode + /* if (config.changeNameButtonCls && config.displayChangeName && !AppConfig.disableProfile) { options.push({ tag: 'a', attributes: {'class': config.changeNameButtonCls + ' fa fa-user'}, content: h('span', Messages.user_rename) }); - } + }*/ if (accountName && !AppConfig.disableProfile) { options.push({ tag: 'a', From 85f85a38032d1851b4d0336df44c348d931a7893 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 10 Jun 2020 11:37:39 -0400 Subject: [PATCH 11/49] reorder admin menu items --- www/common/common-ui-elements.js | 116 ++++++++++++++++--------------- 1 file changed, 59 insertions(+), 57 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index f01bea6eb..b469dcb9b 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2386,15 +2386,21 @@ define([ content: $userAdminContent.html() }); } - options.push({ - tag: 'a', - attributes: { - 'target': '_blank', - 'href': origin+'/index.html', - 'class': 'fa fa-home' - }, - content: h('span', Messages.homePage) - }); + + if (accountName && !AppConfig.disableProfile) { + options.push({ + tag: 'a', + attributes: {'class': 'cp-toolbar-menu-profile fa fa-user-circle'}, + content: h('span', Messages.profileButton), + action: function () { + if (padType) { + window.open(origin+'/profile/'); + } else { + window.parent.location = origin+'/profile/'; + } + }, + }); + } if (padType !== 'drive' || (!accountName && priv.newSharedFolder)) { options.push({ tag: 'a', @@ -2428,30 +2434,6 @@ define([ content: h('span', Messages.type.contacts) }); } - options.push({ tag: 'hr' }); - // Add the change display name button if not in read only mode - /* - if (config.changeNameButtonCls && config.displayChangeName && !AppConfig.disableProfile) { - options.push({ - tag: 'a', - attributes: {'class': config.changeNameButtonCls + ' fa fa-user'}, - content: h('span', Messages.user_rename) - }); - }*/ - if (accountName && !AppConfig.disableProfile) { - options.push({ - tag: 'a', - attributes: {'class': 'cp-toolbar-menu-profile fa fa-user-circle'}, - content: h('span', Messages.profileButton), - action: function () { - if (padType) { - window.open(origin+'/profile/'); - } else { - window.parent.location = origin+'/profile/'; - } - }, - }); - } if (padType !== 'settings') { options.push({ tag: 'a', @@ -2466,6 +2448,7 @@ define([ }, }); } + options.push({ tag: 'hr' }); // Add administration panel link if the user is an admin if (priv.edPublic && Array.isArray(Config.adminKeys) && Config.adminKeys.indexOf(priv.edPublic) !== -1) { @@ -2496,30 +2479,6 @@ define([ }, }); } - options.push({ tag: 'hr' }); - if (Config.allowSubscriptions) { - options.push({ - tag: 'a', - attributes: { - 'target': '_blank', - 'href': priv.plan ? priv.accounts.upgradeURL : origin+'/features.html', - 'class': 'fa fa-star-o' - }, - content: h('span', priv.plan ? Messages.settings_cat_subscription : Messages.pricing) - }); - } - if (!priv.plan && !Config.removeDonateButton) { - options.push({ - tag: 'a', - attributes: { - 'target': '_blank', - 'rel': 'noopener', - 'href': priv.accounts.donateURL, - 'class': 'fa fa-gift' - }, - content: h('span', Messages.crowdfunding_button2) - }); - } if (AppConfig.surveyURL) { options.push({ tag: 'a', @@ -2547,6 +2506,49 @@ define([ }, }); + options.push({ + tag: 'a', + attributes: { + 'target': '_blank', + 'href': origin+'/index.html', + 'class': 'fa fa-home' + }, + content: h('span', Messages.homePage) + }); + // Add the change display name button if not in read only mode + /* + if (config.changeNameButtonCls && config.displayChangeName && !AppConfig.disableProfile) { + options.push({ + tag: 'a', + attributes: {'class': config.changeNameButtonCls + ' fa fa-user'}, + content: h('span', Messages.user_rename) + }); + }*/ + options.push({ tag: 'hr' }); + if (Config.allowSubscriptions) { + options.push({ + tag: 'a', + attributes: { + 'target': '_blank', + 'href': priv.plan ? priv.accounts.upgradeURL : origin+'/features.html', + 'class': 'fa fa-star-o' + }, + content: h('span', priv.plan ? Messages.settings_cat_subscription : Messages.pricing) + }); + } + if (!priv.plan && !Config.removeDonateButton) { + options.push({ + tag: 'a', + attributes: { + 'target': '_blank', + 'rel': 'noopener', + 'href': priv.accounts.donateURL, + 'class': 'fa fa-gift' + }, + content: h('span', Messages.crowdfunding_button2) + }); + } + options.push({ tag: 'hr' }); // Add login or logout button depending on the current status if (priv.loggedIn) { From 9aafd5f3c5594522b681b608386852e6625bbea8 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 10 Jun 2020 18:42:46 +0200 Subject: [PATCH 12/49] Add category and attachments to support tickets --- customize.dist/src/less2/include/support.less | 3 + www/support/inner.js | 3 +- www/support/ui.js | 135 +++++++++++++++++- 3 files changed, 132 insertions(+), 9 deletions(-) diff --git a/customize.dist/src/less2/include/support.less b/customize.dist/src/less2/include/support.less index 890ba810d..1d62157de 100644 --- a/customize.dist/src/less2/include/support.less +++ b/customize.dist/src/less2/include/support.less @@ -4,6 +4,9 @@ @msg-bg: #eee; @fromme-bg: #ddd; .cp-support-form-container { + div { + margin-bottom: 10px; + } [type="text"] { width: @sidebar_button-width; margin-bottom: 10px; diff --git a/www/support/inner.js b/www/support/inner.js index 3d907421d..089af5230 100644 --- a/www/support/inner.js +++ b/www/support/inner.js @@ -166,8 +166,6 @@ define([ var form = APP.support.makeForm(); - $div.find('button').before(form); - var id = Util.uid(); $div.find('button').click(function () { @@ -183,6 +181,7 @@ define([ $('.cp-sidebarlayout-category[data-category="tickets"]').click(); } }); + $div.find('button').before(form); return $div; }; diff --git a/www/support/ui.js b/www/support/ui.js index 04330734e..e95a8e8cf 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -6,8 +6,9 @@ define([ '/common/common-hash.js', '/common/common-util.js', '/common/clipboard.js', + '/common/common-ui-elements.js', '/customize/messages.js', -], function ($, ApiConfig, h, UI, Hash, Util, Clipboard, Messages) { +], function ($, ApiConfig, h, UI, Hash, Util, Clipboard, UIElements, Messages) { var send = function (ctx, id, type, data, dest) { var common = ctx.common; @@ -61,9 +62,14 @@ define([ }; var sendForm = function (ctx, id, form, dest) { - var $title = $(form).find('.cp-support-form-title'); - var $content = $(form).find('.cp-support-form-msg'); + var $form = $(form); + var $cat = $form.find('.cp-support-form-category'); + var $title = $form.find('.cp-support-form-title'); + var $content = $form.find('.cp-support-form-msg'); + var $attachments = $form.find('.cp-support-form-attachments'); + + var category = $cat.val().trim(); var title = $title.val().trim(); if (!title) { return void UI.alert(Messages.support_formTitleError); @@ -72,18 +78,38 @@ define([ if (!content) { return void UI.alert(Messages.support_formContentError); } + $cat.val(''); $content.val(''); $title.val(''); + var attachments = []; + $attachments.find('> span').each(function (i, el) { + var $el = $(el); + attachments.push({ + href: $el.attr('data-href'), + name: $el.attr('data-name') + }); + }); + send(ctx, id, 'TICKET', { + category: category, title: title, + attachments: attachments, message: content, }, dest); return true; }; - var makeForm = function (cb, title) { +Messages.support_cat_account = "User account"; // XXX +Messages.support_cat_data = "Loss of content"; // XXX +Messages.support_cat_bug = "Bug report"; // XXX +Messages.support_cat_other = "Other"; // XXX +Messages.support_category = "Category"; // XXX +Messages.support_attachments = "Attachments"; // XXX +Messages.support_addAttachment = "Add attachment"; // XXX + + var makeForm = function (ctx, cb, title) { var button; if (typeof(cb) === "function") { @@ -93,8 +119,34 @@ define([ var cancel = title ? h('button.btn.btn-secondary', Messages.cancel) : undefined; + var category = h('input.cp-support-form-category', { + type: 'hidden', + value: '' + }); + var categories = ['account', 'data', 'bug', 'other'].map(function (key) { + return { + tag: 'a', + content: h('span', Messages['support_cat_'+key]), + action: function () { + $(category).val(key); + } + }; + }); + var catContainer = h('div.cp-dropdown-container' + (title ? '.cp-hidden': '')); + var dropdownCfg = { + text: Messages.support_category, + options: categories, + container: $(catContainer), + isSelect: true + }; + var $drop = UIElements.createDropdown(dropdownCfg); + + var attachments, addAttachment; + var content = [ h('hr'), + category, + catContainer, h('input.cp-support-form-title' + (title ? '.cp-hidden' : ''), { placeholder: Messages.support_formTitle, type: 'text', @@ -104,11 +156,51 @@ define([ h('textarea.cp-support-form-msg', { placeholder: Messages.support_formMessage }), + h('label', Messages.support_attachments), + attachments = h('div.cp-support-form-attachments'), + addAttachment = h('button', Messages.support_addAttachment), h('hr'), button, cancel ]; + $(addAttachment).click(function () { + var $input = $('', { + 'type': 'file', + 'style': 'display: none;', + 'multiple': 'multiple', + 'accept': 'image/*' + }).on('change', function (e) { + var files = Util.slice(e.target.files); + files.forEach(function (file) { + var ev = {}; + ev.callback = function (data) { + var x, a; + var span = h('span', { + 'data-name': data.name, + 'data-href': data.url + }, [ + x = h('i.fa.fa-times'), + a = h('a', { + href: '#' + }, data.name) + ]); + $(x).click(function () { + $(span).remove(); + }); + $(a).click(function (e) { + e.preventDefault(); + ctx.common.openURL(data.url); + }); + + $(attachments).append(span); + }; + ctx.FM.handleFile(file, ev); + }); + }); + $input.click(); + }); + var form = h('div.cp-support-form-container', content); $(cancel).click(function () { @@ -125,6 +217,7 @@ define([ var privateData = metadataMgr.getPrivateData(); var ticketTitle = content.title + ' (#' + content.id + ')'; + var ticketCategory; var answer = h('button.btn.btn-primary.cp-support-answer', Messages.support_answer); var close = h('button.btn.btn-danger.cp-support-close', Messages.support_close); var hide = h('button.btn.btn-danger.cp-support-hide', Messages.support_remove); @@ -137,6 +230,7 @@ define([ var url; if (ctx.isAdmin) { + ticketCategory = Messages['support_cat_'+(content.category || 'other')] + ' - '; url = h('button.btn.btn-primary.fa.fa-clipboard'); $(url).click(function () { var link = privateData.origin + privateData.pathname + '#' + 'support-' + content.id; @@ -148,7 +242,7 @@ define([ var $ticket = $(h('div.cp-support-list-ticket', { 'data-id': content.id }, [ - h('h2', [ticketTitle, url]), + h('h2', [ticketCategory, ticketTitle, url]), actions ])); @@ -179,7 +273,7 @@ define([ $(answer).click(function () { $ticket.find('.cp-support-form-container').remove(); $(actions).hide(); - var form = makeForm(function () { + var form = makeForm(ctx, function () { var sent = sendForm(ctx, content.id, form, content.sender); if (sent) { $(actions).show(); @@ -215,6 +309,20 @@ define([ ev.stopPropagation(); }); + var attachments = (content.attachments || []).map(function (obj) { + if (!obj || !obj.name || !obj.href) { return; } + var a = h('a', { + href: '#' + }, obj.name) + $(a).click(function (e) { + e.preventDefault(); + ctx.common.openURL(obj.href); + }); + return h('span', [ + a + ]); + }); + var adminClass = (fromAdmin? '.cp-support-fromadmin': ''); var premiumClass = (fromPremium && !fromAdmin? '.cp-support-frompremium': ''); var name = Util.fixHTML(content.sender.name) || Messages.anonymous; @@ -226,6 +334,7 @@ define([ h('span.cp-support-message-time', content.time ? new Date(content.time).toLocaleString() : '') ]), h('pre.cp-support-message-content', content.message), + h('div', attachments), isAdmin ? userData : undefined, ]); }; @@ -257,10 +366,22 @@ define([ adminKeys: Array.isArray(ApiConfig.adminKeys)? ApiConfig.adminKeys.slice(): [], }; + var fmConfig = { + body: $('body'), + onUploaded: function (ev, data) { + if (ev.callback) { + ev.callback(data); + } + } + }; + ctx.FM = common.createFileManager(fmConfig); + ui.sendForm = function (id, form, dest) { return sendForm(ctx, id, form, dest); }; - ui.makeForm = makeForm; + ui.makeForm = function (cb, title) { + return makeForm(ctx, cb, title); + }; ui.makeTicket = function ($div, content, onHide) { return makeTicket(ctx, $div, content, onHide); }; From 54b5b5eae7beef4ae8eb56f5aca951a9cd88cb35 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 11 Jun 2020 13:30:52 +0200 Subject: [PATCH 13/49] Add dev button to delete last cp in oo --- www/common/onlyoffice/inner.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index 6218681c2..c4008052d 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -462,6 +462,20 @@ define([ }); } }; + var deleteLastCp = function () { + var hashes = content.hashes; + if (!hashes || !Object.keys(hashes).length) { return; } + i = i || 0; + var idx = Object.keys(hashes).map(Number).sort(function (a, b) { + return a-b; + }); + var lastIndex = idx[idx.length - 1 - i]; + delete content.hashes[lastIndex]; + APP.onLocal(); + APP.realtime.onSettle(function () { + UI.log(Messages.saved); + }); + }; var restoreLastCp = function () { content.saveLock = myOOId; APP.onLocal(); @@ -1584,6 +1598,14 @@ define([ $save.appendTo(toolbar.$bottomM); } if (window.CP_DEV_MODE || DISPLAY_RESTORE_BUTTON) { + common.createButton('', true, { + name: 'delete', + icon: 'fa-trash', + hiddenReadOnly: true + }).click(function () { + if (initializing) { return void console.error('initializing'); } + deleteLastCp(); + }).attr('title', 'Delete last checkpoint').appendTo(toolbar.$bottomM); common.createButton('', true, { name: 'restore', icon: 'fa-history', @@ -1609,6 +1631,7 @@ define([ } if (common.isLoggedIn()) { + window.CryptPad_deleteLastCp = deleteLastCp; var $importXLSX = common.createButton('import', true, { accept: accept, binary : ["ods", "xlsx", "odt", "docx", "odp", "pptx"] From bba1706ac5611574fb22077881a9baf8da739523 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 11 Jun 2020 13:34:00 +0200 Subject: [PATCH 14/49] lint compliance --- www/common/onlyoffice/inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index c4008052d..6f9c74f27 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -465,7 +465,7 @@ define([ var deleteLastCp = function () { var hashes = content.hashes; if (!hashes || !Object.keys(hashes).length) { return; } - i = i || 0; + var i = 0; var idx = Object.keys(hashes).map(Number).sort(function (a, b) { return a-b; }); From e7a6397084f5da42f27aeeab02384aac73b62533 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 11 Jun 2020 14:49:59 +0200 Subject: [PATCH 15/49] Add category filter and improve UI --- customize.dist/src/less2/include/support.less | 12 +++++ www/admin/inner.js | 17 +++++++ www/common/common-ui-elements.js | 4 +- www/support/app-support.less | 9 ++++ www/support/ui.js | 51 ++++++++++++------- 5 files changed, 73 insertions(+), 20 deletions(-) diff --git a/customize.dist/src/less2/include/support.less b/customize.dist/src/less2/include/support.less index 1d62157de..d83746b51 100644 --- a/customize.dist/src/less2/include/support.less +++ b/customize.dist/src/less2/include/support.less @@ -18,6 +18,18 @@ height: 300px; } } + .cp-support-attachments { + display: flex; + .fa { + cursor: pointer; + margin-right: 10px; + } + &> span { + border: 1px solid #ddd; + margin-right: 5px; + padding: 10px; + } + } .cp-support-container { .cp-support-list-ticket { display: flex; diff --git a/www/admin/inner.js b/www/admin/inner.js index 2ff62cf1f..90048e76d 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -185,6 +185,20 @@ define([ var $container = makeBlock('support-list'); var $div = $(h('div.cp-support-container')).appendTo($container); + var catContainer = h('div.cp-dropdown-container'); + $div.append(catContainer); + var category = 'all'; + var $drop = APP.support.makeCategoryDropdown(catContainer, function (key) { + category = key; + if (key === 'all') { + $div.find('.cp-support-list-ticket').show(); + return; + } + $div.find('.cp-support-list-ticket').hide(); + $div.find('.cp-support-list-ticket[data-cat="'+key+'"]').show(); + }, true); + $drop.setValue('all'); + var metadataMgr = common.getMetadataMgr(); var privateData = metadataMgr.getPrivateData(); var cat = privateData.category || ''; @@ -277,6 +291,9 @@ define([ UI.alert(Messages.error); }); }); + if (category !== 'all' && $ticket.attr('data-cat') !== category) { + $ticket.hide(); + } } $ticket.append(APP.support.makeMessage(content, hash)); reorder(); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 4393d1201..4d2f8b3c7 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2204,7 +2204,9 @@ define([ if (config.isSelect && value) { var $val = $innerblock.find('[data-value="'+value+'"]'); setActive($val); - $innerblock.scrollTop($val.position().top + $innerblock.scrollTop()); + try { + $innerblock.scrollTop($val.position().top + $innerblock.scrollTop()); + } catch (e) {} } if (config.feedback) { Feedback.send(config.feedback); } }; diff --git a/www/support/app-support.less b/www/support/app-support.less index 7684c054e..41af016fd 100644 --- a/www/support/app-support.less +++ b/www/support/app-support.less @@ -18,6 +18,15 @@ display: flex; flex-flow: column; + .cp-support-form-attachments { + .fa { + cursor: pointer; + } + &> span { + padding: 10px; + } + } + .cp-support-language-list { .cp-support-language { margin-left: 5px; diff --git a/www/support/ui.js b/www/support/ui.js index e95a8e8cf..e4d60e919 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -66,7 +66,7 @@ define([ var $cat = $form.find('.cp-support-form-category'); var $title = $form.find('.cp-support-form-title'); var $content = $form.find('.cp-support-form-msg'); - var $attachments = $form.find('.cp-support-form-attachments'); + var $attachments = $form.find('.cp-support-attachments'); var category = $cat.val().trim(); @@ -105,10 +105,32 @@ Messages.support_cat_account = "User account"; // XXX Messages.support_cat_data = "Loss of content"; // XXX Messages.support_cat_bug = "Bug report"; // XXX Messages.support_cat_other = "Other"; // XXX +Messages.support_cat_all = "All"; // XXX Messages.support_category = "Category"; // XXX Messages.support_attachments = "Attachments"; // XXX Messages.support_addAttachment = "Add attachment"; // XXX + var makeCategoryDropdown = function (ctx, container, onChange, all) { + var categories = ['account', 'data', 'bug', 'other']; + if (all) { categories.push('all'); } + categories = categories.map(function (key) { + return { + tag: 'a', + content: h('span', Messages['support_cat_'+key]), + action: function () { + onChange(key); + } + }; + }); + var dropdownCfg = { + text: Messages.support_category, + options: categories, + container: $(container), + isSelect: true + }; + return UIElements.createDropdown(dropdownCfg); + }; + var makeForm = function (ctx, cb, title) { var button; @@ -123,23 +145,10 @@ Messages.support_addAttachment = "Add attachment"; // XXX type: 'hidden', value: '' }); - var categories = ['account', 'data', 'bug', 'other'].map(function (key) { - return { - tag: 'a', - content: h('span', Messages['support_cat_'+key]), - action: function () { - $(category).val(key); - } - }; - }); var catContainer = h('div.cp-dropdown-container' + (title ? '.cp-hidden': '')); - var dropdownCfg = { - text: Messages.support_category, - options: categories, - container: $(catContainer), - isSelect: true - }; - var $drop = UIElements.createDropdown(dropdownCfg); + makeCategoryDropdown(ctx, catContainer, function (key) { + $(category).val(key); + }); var attachments, addAttachment; @@ -157,7 +166,7 @@ Messages.support_addAttachment = "Add attachment"; // XXX placeholder: Messages.support_formMessage }), h('label', Messages.support_attachments), - attachments = h('div.cp-support-form-attachments'), + attachments = h('div.cp-support-attachments'), addAttachment = h('button', Messages.support_addAttachment), h('hr'), button, @@ -240,6 +249,7 @@ Messages.support_addAttachment = "Add attachment"; // XXX } var $ticket = $(h('div.cp-support-list-ticket', { + 'data-cat': content.category, 'data-id': content.id }, [ h('h2', [ticketCategory, ticketTitle, url]), @@ -334,7 +344,7 @@ Messages.support_addAttachment = "Add attachment"; // XXX h('span.cp-support-message-time', content.time ? new Date(content.time).toLocaleString() : '') ]), h('pre.cp-support-message-content', content.message), - h('div', attachments), + h('div.cp-support-attachments', attachments), isAdmin ? userData : undefined, ]); }; @@ -382,6 +392,9 @@ Messages.support_addAttachment = "Add attachment"; // XXX ui.makeForm = function (cb, title) { return makeForm(ctx, cb, title); }; + ui.makeCategoryDropdown = function (container, onChange, all) { + return makeCategoryDropdown(ctx, container, onChange, all); + }; ui.makeTicket = function ($div, content, onHide) { return makeTicket(ctx, $div, content, onHide); }; From 9fbaa8f2a18d842dbf539a67f432ad6767e084ca Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 11 Jun 2020 16:33:30 +0200 Subject: [PATCH 16/49] Translated using Weblate (German) Currently translated at 99.9% (1282 of 1283 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index 8b0638aac..691e54aa4 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -1377,5 +1377,7 @@ "toolbar_insert": "Einfügen", "toolbar_savetodrive": "Als Bild speichern", "slide_backCol": "Hintergrundfarbe", - "slide_textCol": "Textfarbe" + "slide_textCol": "Textfarbe", + "support_languagesPreamble": "Die Administratoren dieses Servers sprechen die folgenden Sprachen:", + "settings_safeLinkDefault": "Sichere Links sind nun standardmäßig aktiviert. Bitte verwende zum Kopieren von Links das Menü Teilen und nicht die Adressleiste des Browsers." } From 15174a4cf36fadd30d3cb7a3206688aeee072511 Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 11 Jun 2020 16:33:30 +0200 Subject: [PATCH 17/49] Translated using Weblate (French) Currently translated at 100.0% (1283 of 1283 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index e1c72098c..aa8d9eda7 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1377,5 +1377,7 @@ "toolbar_savetodrive": "Sauvegarder image", "toolbar_insert": "Insérer", "toolbar_theme": "Thème", - "todo_move": "Votre liste de tâches est désormais dans le kanban {0} dans votre Drive." + "todo_move": "Votre liste de tâches est désormais dans le kanban {0} dans votre Drive.", + "settings_safeLinkDefault": "Les liens sécurisés sont désormais activés par défaut. Veuillez utiliser le menu Partager pour copier les liens plutôt que la barre d'adresse de votre navigateur.", + "support_languagesPreamble": "L'équipe de support parle les langues suivantes :" } From eed14750edfd320c473342cba1f05f93135055ee Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 11 Jun 2020 16:33:30 +0200 Subject: [PATCH 18/49] Translated using Weblate (Romanian) Currently translated at 44.1% (566 of 1283 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ro/ --- www/common/translations/messages.ro.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.ro.json b/www/common/translations/messages.ro.json index 6572c00e4..190f3250a 100644 --- a/www/common/translations/messages.ro.json +++ b/www/common/translations/messages.ro.json @@ -579,5 +579,6 @@ "fc_color": "Schimbă culoarea", "fm_morePads": "Mai mult", "uploadFolderButton": "Încarcă dosar", - "storageStatus": "Capacitate de stocare:
{0} utilizat din {1}" + "storageStatus": "Capacitate de stocare:
{0} utilizat din {1}", + "fc_collapseAll": "Restrânge" } From aa50352e1743e3ea18ca9e38ef3611d1b5b380b1 Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 11 Jun 2020 16:33:30 +0200 Subject: [PATCH 19/49] Translated using Weblate (English) Currently translated at 100.0% (1283 of 1283 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 4d47b3c7c..bce3ebd69 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1378,6 +1378,6 @@ "toolbar_file": "File", "slide_backCol": "Background color", "slide_textCol": "Text color", - "support_languagesPreamble": "This server's administrators speak the following languages:", + "support_languagesPreamble": "The support team speaks the following languages:", "settings_safeLinkDefault": "Safe Links are now turned on by default. Please use the Share menu to copy links rather than your browser's address bar." } From caac97df66649895b87ba6570a6b63479a12b7de Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 11 Jun 2020 11:47:36 -0400 Subject: [PATCH 20/49] update changelog, footer, and package.json for the 3.19.0 release --- CHANGELOG.md | 44 +++++++++++++++++++++++++++++++++++++++++ customize.dist/pages.js | 2 +- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfa69006a..89c9ca5f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,47 @@ +# Thylacine release (3.19.0) + +## Goals + +The intent of this release was to catch up on our backlog of bug fixes and minor usability improvements. + +## Update notes + +This release features an update to our clientside dependencies. + +To update to 3.19.0 from 3.18.1: + +1. Stop your server +2. Get the latest code with git +3. Get the latest clientside dependencies with `bower update` +4. Restart your server + +## Features + +* The most notable change in this release is that the use of "safe links" (introduced in our 3.11.0 release) has been made the new default for documents. This means that when you open a document that is stored in your drive your browser's address bar will not contain the encryption keys for the document, only an identifier used to look up those encryption keys which are stored in your drive. This makes it less likely that you'll leak access to your documents during video meetings, when sharing screenshots, or when using shared computers that store the history of pages you've viewed. + * To share access to documents with links, you'll need to use the _share menu_ which has recently been made more prominent in the platform's toolbars + * This setting is configurable, so you can still choose to disable the use of safe links via your settings page. +* We've updated the layout of the "user admin menu" which can be found in the top-right corner by clicking your avatar. It features an "About CryptPad" menu which displays the version of the instance you're using as well as some resources which are otherwise only available via the footer of static pages. +* We often receive support tickets in languages that we don't speak, which forces us to use translation services in order to answer questions. To address this issue, we've made it possible for admins to display a notice indicating which languages they speak. An example configuration is provided in `customize.dist/application_config.js`. +* We've integrated two PRs: + 1. [Only list premium features when subscriptions are enabled](https://github.com/xwiki-labs/cryptpad/pull/538) + 2. [Add privacy policy option](https://github.com/xwiki-labs/cryptpad/pull/537) +* We found it cumbersome to add new cards to the top of our Kanban columns, since we had to create a new card at the bottom and then drag it to the top. In response, we've broken up the rather large "new card" button into two buttons, one which adds a card at the top, and another which adds a new card at the bottom. +* We've made it easier to use tags for files in the drive: + 1. You can now select multiple files and apply a set of tags to all of them + 2. Hitting "enter" in an empty tag prompt field will submit the current list of tags +* Unregistered users were able to open up the "filepicker modal" in spreadsheets. It was already possible to embed an image which they'd already stored in their drive, but it was not clear why they were not able to upload a new image. We now display a disabled upload button with a tooltip to log in or register in order to upload images. +* Finally, we've updated the styles in our presentation editor to better match our recent toolbar redesign and the mermaidjs integration. + +## Bug fixes + +* We now preserve formatting in multi-line messages in team invitations. +* The slide editor exhibited some strange behaviour where the page would reload the first time you entered "present mode" after creating the document. We've also fixed some issues with printing. +* We now prevent the local resizing of images in the rich text editor while it is locked due to disconnection or the lack of edit rights. +* We've updated our marked.js dependency to the latest version in order to correct some minor rendering bugs. +* Unregistered users are now redirected to the login page when they visit the support page. +* We've removed the unsupported "rename" entry from the right-click menu in unregistered users drives. +* Lastly, we've added a "Hind" font to the spreadsheet editor which introduces basic support for Devanagari characters. + # Smilodon's revenge (3.18.1) Our next major release (3.19.0) is still a few weeks away. diff --git a/customize.dist/pages.js b/customize.dist/pages.js index b65faffc2..0e42b9a3a 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -62,7 +62,7 @@ define([ var imprintUrl = AppConfig.imprint && (typeof(AppConfig.imprint) === "boolean" ? '/imprint.html' : AppConfig.imprint); - Pages.versionString = "CryptPad v3.18.1 (Smilodon's revenge)"; + Pages.versionString = "CryptPad v3.19.0 (Thylacine)"; // used for the about menu Pages.imprintLink = AppConfig.imprint ? footLink(imprintUrl, 'imprint') : undefined; diff --git a/package-lock.json b/package-lock.json index 9840bd099..ed2097eff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cryptpad", - "version": "3.18.1", + "version": "3.19.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 56e512b22..be6f77978 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cryptpad", "description": "realtime collaborative visual editor with zero knowlege server", - "version": "3.18.1", + "version": "3.19.0", "license": "AGPL-3.0+", "repository": { "type": "git", From 3bd7742d20f295cbfb7204792ae00a1a24662aeb Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 11 Jun 2020 12:44:12 -0400 Subject: [PATCH 21/49] hide the kanban trash bar when it isn't in use --- www/kanban/app-kanban.less | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index a5eca13f4..880b1dd0b 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -421,14 +421,21 @@ } } #kanban-trash { - height: 60px; - font-size: 40px; + height: 0px; + font-size: 0px; + transition: height 400ms, font-size 400ms; + display: flex; align-items: center; justify-content: center; position: relative; width: 100%; //pointer-events: none; + + &.kanban-trash-active, &.kanban-trash-suggest { + height: 60px; + font-size: 40px; + } i { position: fixed; } From b7daa636bf9ed03fd5fa196595b80d2a694ec2ca Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 11 Jun 2020 13:06:51 -0400 Subject: [PATCH 22/49] fix a horizontal scrollbar issue I just introduced and explain why --- www/kanban/app-kanban.less | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 880b1dd0b..3777fa0a6 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -421,11 +421,17 @@ } } #kanban-trash { - height: 0px; + height: 1px; font-size: 0px; - transition: height 400ms, font-size 400ms; +/* CSS transitions are nice to look at, but it seems some interaction of "display: flex" here + makes the horizontal scrollbar stop working, so we need "display: none" for this state, but + CSS transitions are disabled when one state has "display: none". We can accomplish this in + js, but js animations are more prone to bugs and I'd rather live with a slight jank than + have the trash get stuck in some intermediary animation state under heavy use. --ansuz +*/ + display: none; // flex; + //transition: opacity 400ms, height 400ms, font-size 400ms; - display: flex; align-items: center; justify-content: center; position: relative; @@ -433,6 +439,7 @@ //pointer-events: none; &.kanban-trash-active, &.kanban-trash-suggest { + display: flex; height: 60px; font-size: 40px; } From 9b750cfc1bde05fc0485745e72f89ea172b77263 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2020 00:49:46 +0200 Subject: [PATCH 23/49] Translated using Weblate (German) Currently translated at 100.0% (1283 of 1283 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index 691e54aa4..01f06a9d4 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -1378,6 +1378,6 @@ "toolbar_savetodrive": "Als Bild speichern", "slide_backCol": "Hintergrundfarbe", "slide_textCol": "Textfarbe", - "support_languagesPreamble": "Die Administratoren dieses Servers sprechen die folgenden Sprachen:", + "support_languagesPreamble": "Das Support-Team spricht die folgenden Sprachen:", "settings_safeLinkDefault": "Sichere Links sind nun standardmäßig aktiviert. Bitte verwende zum Kopieren von Links das Menü Teilen und nicht die Adressleiste des Browsers." } From 86e733c620e270ee048ae9908699916986486e41 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2020 15:27:17 +0200 Subject: [PATCH 24/49] Translated using Weblate (English) Currently translated at 100.0% (1286 of 1286 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1286 of 1286 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1285 of 1285 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1284 of 1284 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index bce3ebd69..4f3a9d157 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -856,7 +856,7 @@ "help": { "title": "Getting started", "generic": { - "more": "Learn more about how CryptPad can work for you by reading our FAQ", + "more": "Learn more about how CryptPad can work for you by reading our FAQ.", "share": "Share this document with the Share button, and manage access rights with Access.", "save": "All your changes are synced automatically so you never need to save" }, @@ -1379,5 +1379,8 @@ "slide_backCol": "Background color", "slide_textCol": "Text color", "support_languagesPreamble": "The support team speaks the following languages:", - "settings_safeLinkDefault": "Safe Links are now turned on by default. Please use the Share menu to copy links rather than your browser's address bar." + "settings_safeLinkDefault": "Safe Links are now turned on by default. Please use the Share menu to copy links rather than your browser's address bar.", + "info_imprintFlavour": "Legal information about the administrators of this instance.", + "user_about": "About CryptPad", + "info_privacyFlavour": "Our privacy policy describes how we treat your data." } From e91997fe843af56fee55ca3d643d47609bfd710b Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 12 Jun 2020 09:39:41 -0400 Subject: [PATCH 25/49] remove some hardcoded translations --- www/common/common-ui-elements.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index b469dcb9b..da66b0976 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2306,10 +2306,6 @@ define([ // TODO link to the most recent changelog/release notes // https://github.com/xwiki-labs/cryptpad/releases/latest/ ? - Messages.info_imprintFlavour = "Legally mandated information about this service's operators can be found here."; // XXX - Messages.info_privacyFlavour = "Our privacy policy describes how we treat your data."; // XXX - Messages.info_faqFlavour = "Consult our FAQ for answers to common questions."; // XXX - var template = function (line, link) { if (!line || !link) { return; } var p = $('

').html(line)[0]; @@ -2331,7 +2327,7 @@ define([ var legalLine = template(Messages.info_imprintFlavour, Pages.imprintLink); var privacyLine = template(Messages.info_privacyFlavour, Pages.privacyLink); - var faqLine = template(Messages.info_faqFlavour, Pages.faqLink); + var faqLine = template(Messages.help.generic.more, Pages.faqLink); var content = h('div.cp-info-menu-container', [ h('h6', Pages.versionString), @@ -2494,7 +2490,6 @@ define([ }, }); } - Messages.user_about = 'About CryptPad'; // XXX options.push({ tag: 'a', attributes: { From b022f7cd8004414d63cd4bc2d26d5b5a75174dba Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2020 15:53:23 +0200 Subject: [PATCH 26/49] Translated using Weblate (French) Currently translated at 100.0% (1286 of 1286 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index aa8d9eda7..f38f3f5ef 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -111,7 +111,7 @@ "newButtonTitle": "Créer un nouveau pad", "uploadButton": "Importer des fichiers", "uploadFolderButton": "Importer un dossier", - "uploadButtonTitle": "Importer un nouveau fichier dans le dossier actuel", + "uploadButtonTitle": "Importer un nouveau fichier dans votre CryptDrive", "saveTemplateButton": "Sauver en tant que modèle", "saveTemplatePrompt": "Choisir un titre pour ce modèle", "templateSaved": "Modèle enregistré !", @@ -147,7 +147,7 @@ "filePicker_filter": "Filtrez les fichiers par leur nom", "or": "ou", "tags_title": "Mots-clés du pad (pour vous uniquement)", - "tags_add": "Modifier les mots-clés du pad", + "tags_add": "Modifier les mots-clés de la sélection", "tags_searchHint": "Commencez une recherche par # dans votre CryptDrive pour retrouver vos pads par mot-clé.", "tags_notShared": "Vos mots-clés ne sont pas partagés avec les autres utilisateurs", "tags_duplicate": "Mot-clé déjà présent : {0}", @@ -838,7 +838,7 @@ "help": { "title": "Pour bien démarrer", "generic": { - "more": "Apprenez-en davantage sur le fonctionnement de CryptPad en lisant notre FAQ", + "more": "Apprenez-en davantage sur le fonctionnement de CryptPad en lisant notre FAQ.", "share": "Partagez ce document avec le bouton Partager et gérez les droits d'accès avec le bouton Accès.", "save": "Tous les changements effectués sont enregistrés automatiquement" }, @@ -1379,5 +1379,8 @@ "toolbar_theme": "Thème", "todo_move": "Votre liste de tâches est désormais dans le kanban {0} dans votre Drive.", "settings_safeLinkDefault": "Les liens sécurisés sont désormais activés par défaut. Veuillez utiliser le menu Partager pour copier les liens plutôt que la barre d'adresse de votre navigateur.", - "support_languagesPreamble": "L'équipe de support parle les langues suivantes :" + "support_languagesPreamble": "L'équipe de support parle les langues suivantes :", + "info_privacyFlavour": "Description de la confidentialité de vos données.", + "user_about": "À propos de CryptPad", + "info_imprintFlavour": "Informations légales sur les administateurs de cette instance." } From 120a16ebbcf9e4222f2e50d89d913b9d53b718d0 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2020 15:53:23 +0200 Subject: [PATCH 27/49] Translated using Weblate (English) Currently translated at 100.0% (1286 of 1286 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 4f3a9d157..5cad912da 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -114,7 +114,7 @@ "newButtonTitle": "Create a new pad", "uploadButton": "Upload files", "uploadFolderButton": "Upload folder", - "uploadButtonTitle": "Upload a new file to the current folder", + "uploadButtonTitle": "Upload a new file to your CryptDrive", "saveTemplateButton": "Save as template", "saveTemplatePrompt": "Choose a title for the template", "templateSaved": "Template saved!", @@ -150,7 +150,7 @@ "filePicker_filter": "Filter files by name", "or": "or", "tags_title": "Tags (for you only)", - "tags_add": "Update this page's tags", + "tags_add": "Update the tags for selected pads", "tags_searchHint": "Start a search with # in your CryptDrive to find your tagged pads.", "tags_notShared": "Your tags are not shared with other users", "tags_duplicate": "Duplicate tag: {0}", From 3bc3c45485edd4ffc37f57020607a903c8ace33b Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 12 Jun 2020 14:09:16 -0400 Subject: [PATCH 28/49] use more space for tags in the kanban UI --- www/kanban/app-kanban.less | 12 +++++++----- www/kanban/inner.js | 34 ++++++++++++++++++++-------------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 3777fa0a6..83d66e232 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -312,22 +312,24 @@ display: inline-flex; align-items: baseline; flex: 1; - max-width: 80%; + //max-width: 80%; min-width: 150px; - + .cp-kanban-filterTags-toggle { + min-width: 100px; + } .cp-kanban-filterTags-reset { cursor: pointer; - margin-left: 10px; - flex-shrink: 0; .tools_unselectable(); + font-weight: bold; i { margin-right: 5px; } } - .cp-kanban-filterTags-name { + .cp-kanban-filterTags-reset, .cp-kanban-filterTags-name { flex-shrink: 0; } .cp-kanban-filterTags-list { + margin-right: 10px; margin-left: 10px; display: flex; flex-wrap: wrap; diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 84b7ea762..f845af6c7 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -874,14 +874,27 @@ define([ // Tags filter var existing = getExistingTags(kanban.options.boards); var list = h('div.cp-kanban-filterTags-list'); - var reset = h('span.cp-kanban-filterTags-reset', [h('i.fa.fa-times'), Messages.kanban_clearFilter]); + var reset = h('span.cp-kanban-filterTags-reset', [ + //h('i.fa.fa-times'), // XXX creates vertical alignment issues + Messages.kanban_clearFilter + ]); + var hint = h('span.cp-kanban-filterTags-name', Messages.kanban_tags); var tags = h('div.cp-kanban-filterTags', [ - h('span.cp-kanban-filterTags-name', Messages.kanban_tags), + h('span.cp-kanban-filterTags-toggle', [ + hint, + reset, + ]), list, - reset ]); var $reset = $(reset); var $list = $(list); + var $hint = $(hint); + + var setTagFilterState = function (bool) { + $hint.css('display', bool? 'none': 'inherit'); + $reset.css('display', bool? 'inherit': 'none'); + }; + setTagFilterState(); var getTags = function () { return $list.find('span.active').map(function () { @@ -890,11 +903,7 @@ define([ }; var commitTags = function () { var t = getTags(); - if (t.length) { - $reset.css('visibility', ''); - } else { - $reset.css('visibility', 'hidden'); - } + setTagFilterState(t.length); //framework._.sfCommon.setPadAttribute('tagsFilter', t); kanban.options.tags = t; kanban.setBoards(kanban.options.boards); @@ -938,14 +947,11 @@ define([ return $(this).data('tag') === t; }).addClass('active'); }); - if (tags.length) { - $reset.css('visibility', ''); - } else { - $reset.css('visibility', 'hidden'); - } + setTagFilterState(tags.length); //framework._.sfCommon.setPadAttribute('tagsFilter', tags); }; - $reset.css('visibility', 'hidden').click(function () { + setTagFilterState(); + $reset.click(function () { setTags([]); commitTags(); }); From 3d4821c7a219611bbe435d9eed1bad3e3d119df4 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2020 23:13:48 +0200 Subject: [PATCH 29/49] Added translation using Weblate (Arabic) --- www/common/translations/messages.ar.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 www/common/translations/messages.ar.json diff --git a/www/common/translations/messages.ar.json b/www/common/translations/messages.ar.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/www/common/translations/messages.ar.json @@ -0,0 +1 @@ +{} From f32cb251c78b38298edc8ee277844a64d24a20ce Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 12 Jun 2020 23:13:48 +0200 Subject: [PATCH 30/49] Translated using Weblate (German) Currently translated at 100.0% (1286 of 1286 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index 01f06a9d4..0ed8f0f91 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -109,7 +109,7 @@ "newButton": "Neu", "newButtonTitle": "Neues Pad erstellen", "uploadButton": "Hochladen", - "uploadButtonTitle": "Eine neue Datei in den aktuellen Ordner hochladen", + "uploadButtonTitle": "Eine neue Datei zum CryptDrive hochladen", "saveTemplateButton": "Als Vorlage speichern", "saveTemplatePrompt": "Bitte gib einen Titel für die Vorlage ein", "templateSaved": "Vorlage gespeichert!", @@ -145,7 +145,7 @@ "filePicker_filter": "Dateien nach Namen filtern", "or": "oder", "tags_title": "Tags (nur für dich)", - "tags_add": "Die Tags dieser Seite bearbeiten", + "tags_add": "Tags der ausgewählten Pads bearbeiten", "tags_searchHint": "Beginne die Suche in deinem CryptDrive mit #, um getaggte Dokumente zu finden.", "tags_notShared": "Deine Tags werden nicht mit anderen Benutzern geteilt", "tags_duplicate": "Doppeltes Tag: {0}", @@ -831,7 +831,7 @@ "help": { "title": "Mit CryptPad anfangen", "generic": { - "more": "Erfahre mehr über die Nutzung von CryptPad, indem du unsere FAQ liest", + "more": "Erfahre mehr über die Nutzung von CryptPad, indem du unsere FAQ liest.", "share": "Teile dieses Dokument mit der Schaltfläche Teilen und verwalte die Zugriffsrechte mit Zugriff.", "save": "Alle Änderungen werden automatisch synchronisiert. Du musst sie also nicht selbst speichern" }, @@ -1379,5 +1379,8 @@ "slide_backCol": "Hintergrundfarbe", "slide_textCol": "Textfarbe", "support_languagesPreamble": "Das Support-Team spricht die folgenden Sprachen:", - "settings_safeLinkDefault": "Sichere Links sind nun standardmäßig aktiviert. Bitte verwende zum Kopieren von Links das Menü Teilen und nicht die Adressleiste des Browsers." + "settings_safeLinkDefault": "Sichere Links sind nun standardmäßig aktiviert. Bitte verwende zum Kopieren von Links das Menü Teilen und nicht die Adressleiste des Browsers.", + "info_imprintFlavour": "Rechtliche Informationen über die Administratoren dieses Servers.", + "info_privacyFlavour": "Unsere Datenschutzerklärung beschreibt, wie wir deine Daten verarbeiten.", + "user_about": "Über CryptPad" } From 3936eed1af79a1c09661ac5ea0993aa1c605b51f Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 15 Jun 2020 08:44:28 -0400 Subject: [PATCH 31/49] remove some extraneous text from the tagPrompt --- www/common/common-interface.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 4ed2f413e..4eba3755c 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -328,11 +328,7 @@ define([ var input = dialog.textInput(); var tagger = dialog.frame([ - dialog.message([ - Messages.tags_add, - h('br'), - Messages.tags_searchHint, - ]), + dialog.message([ Messages.tags_add ]), input, h('center', h('small', Messages.tags_notShared)), dialog.nav(), From c6348f64198a5c49e8fb596b86d6b9bbd6473c1a Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 15 Jun 2020 09:13:17 -0400 Subject: [PATCH 32/49] remove a non-critical XXX note --- www/common/common-ui-elements.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index da66b0976..4f8ee71c5 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1569,7 +1569,6 @@ define([ button = $('