From 4680de12eecb025ef7e81fc8b484a96456bd8804 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 3 Feb 2020 15:14:52 +0100 Subject: [PATCH 1/5] New UI for the corner popup --- customize.dist/src/less2/include/corner.less | 111 +++++++++++++------ www/common/common-interface.js | 52 ++++++--- www/common/common-ui-elements.js | 98 +++++++++------- www/common/sframe-common.js | 3 + www/pad/inner.js | 6 +- 5 files changed, 177 insertions(+), 93 deletions(-) diff --git a/customize.dist/src/less2/include/corner.less b/customize.dist/src/less2/include/corner.less index 0740586aa..d267f3683 100644 --- a/customize.dist/src/less2/include/corner.less +++ b/customize.dist/src/less2/include/corner.less @@ -4,9 +4,9 @@ --LessLoader_require: LessLoader_currentFile(); }; & { - @corner-button-ok: #2c9b00; - @corner-button-cancel: #990000; @corner-link: #ffff7a; + @corner-blue: @colortheme_logo-1; + @corner-white: @colortheme_base; @keyframes appear { 0% { @@ -27,21 +27,23 @@ .cp-corner-container { position: absolute; - right: 0; - bottom: 0; - width: 300px; - height: 200px; - border-top-left-radius: 200px; - padding: 15px; - text-align: right; - background-color: @colortheme_logo-1; - color: @colortheme_base; + right: 10px; + bottom: 10px; + width: 350px; + padding: 10px; + background-color: @corner-blue; + border: 1px solid @corner-blue; + color: @corner-white; z-index: 9999; transform-origin: bottom right; animation: appear 0.8s ease-in-out; - box-shadow: 0 0 10px 0 @colortheme_logo-1; - //transform: scale(0.1); - //transform: scale(1); + //box-shadow: 0 0 10px 0 @corner-blue; + + &.cp-corner-alt { + background-color: @corner-white; + border: 1px solid @corner-blue; + color: @corner-blue; + } h1, h2, h3 { font-size: 1.5em; @@ -64,7 +66,7 @@ line-height: 15px; display: none; &:hover { - color: darken(@colortheme_base, 15%); + color: darken(@corner-white, 15%); } } .cp-corner-minimize { @@ -86,46 +88,93 @@ } } &.cp-corner-big { - width: 400px; - height: 250px; + width: 500px; + } + + .cp-corner-dontshow { + cursor: pointer; + .fa { + margin-right: 0.3em; + font-size: 1.1em; + } + &:hover { + color: darken(@corner-white, 10%); + } + } + &.cp-corner-alt { + .cp-corner-dontshow { + &:hover { + color: lighten(@corner-blue, 10%); + } + } } .cp-corner-actions { min-height: 30px; - margin: 15px auto; - display: inline-block; + margin: 10px auto; + display: block; + text-align: right; } .cp-corner-footer { - font-style: italic; font-size: 0.8em; } .cp-corner-footer, .cp-corner-text { a { - color: @corner-link; + color: @corner-white; + text-decoration: underline; &:hover { - color: darken(@corner-link, 20%); + color: darken(@corner-white, 10%); } } } + &.cp-corner-alt a { + color: @corner-blue; + &:hover { + color: lighten(@corner-blue, 10%); + } + } button { - border: 0px; padding: 5px; - color: @colortheme_base; - margin-left: 5px; + color: @corner-white; + margin-left: 10px; outline: none; + text-transform: uppercase; + border: 1px solid @corner-white; + .fa, .cptools { + margin-right: 0.3em; + } + &.cp-corner-primary { + background-color: @corner-white; + color: @corner-blue; + &:hover { + background-color: lighten(@corner-blue, 50%); + border-color: lighten(@corner-blue, 50%); + } + } + &.cp-corner-cancel { + background-color: @corner-blue; + color: @corner-white; + &:hover { + background-color: darken(@corner-blue, 10%); + } + } + } + &.cp-corner-alt button { + border-color: @corner-blue; &.cp-corner-primary { - background-color: @corner-button-ok; - font-weight: bold; + background-color: @corner-blue; + color: @corner-white; &:hover { - background-color: lighten(@corner-button-ok, 10%); + background-color: darken(@corner-blue, 10%); + border-color: darken(@corner-blue, 10%); } } &.cp-corner-cancel { - background-color: @corner-button-cancel; - margin-left: 10px; + background-color: @corner-white; + color: @corner-blue; &:hover { - background-color: lighten(@corner-button-cancel, 10%); + background-color: lighten(@corner-blue, 50%); } } } diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 1d681d6e9..04f806d4f 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -1050,39 +1050,36 @@ define([ return radio; }; + var corner = { + queue: [], + state: false + }; UI.cornerPopup = function (text, actions, footer, opts) { opts = opts || {}; - var minimize = h('div.cp-corner-minimize.fa.fa-window-minimize'); - var maximize = h('div.cp-corner-maximize.fa.fa-window-maximize'); + var dontShowAgain = h('div.cp-corner-dontshow', [ + h('span.fa.fa-times'), + Messages.dontShowAgain || "Don't show again" // XXX + ]); + var popup = h('div.cp-corner-container', [ - minimize, - maximize, - h('div.cp-corner-filler', { style: "width:110px;" }), - h('div.cp-corner-filler', { style: "width:80px;" }), - h('div.cp-corner-filler', { style: "width:60px;" }), - h('div.cp-corner-filler', { style: "width:40px;" }), - h('div.cp-corner-filler', { style: "width:20px;" }), setHTML(h('div.cp-corner-text'), text), h('div.cp-corner-actions', actions), - setHTML(h('div.cp-corner-footer'), footer) + setHTML(h('div.cp-corner-footer'), footer), + opts.dontShowAgain ? dontShowAgain : undefined ]); var $popup = $(popup); - $(minimize).click(function () { - $popup.addClass('cp-minimized'); - }); - $(maximize).click(function () { - $popup.removeClass('cp-minimized'); - }); - if (opts.hidden) { $popup.addClass('cp-minimized'); } if (opts.big) { $popup.addClass('cp-corner-big'); } + if (opts.alt) { + $popup.addClass('cp-corner-alt'); + } var hide = function () { $popup.hide(); @@ -1092,9 +1089,28 @@ define([ }; var deletePopup = function () { $popup.remove(); + if (!corner.queue.length) { + corner.state = false; + return; + } + setTimeout(function () { + $('body').append(corner.queue.pop()); + }, 5000); }; - $('body').append(popup); + $(dontShowAgain).click(function () { + deletePopup(); + if (typeof(opts.dontShowAgain) === "function") { + opts.dontShowAgain(); + } + }); + + if (corner.state) { + corner.queue.push(popup); + } else { + corner.state = true; + $('body').append(popup); + } return { popup: popup, diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index b5e5aa90a..8bfa02e3a 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -4097,52 +4097,68 @@ define([ }; var crowdfundingState = false; - UIElements.displayCrowdfunding = function (common) { + UIElements.displayCrowdfunding = function (common, force) { if (crowdfundingState) { return; } - if (AppConfig.disableCrowdfundingMessages) { return; } var priv = common.getMetadataMgr().getPrivateData(); + + + var todo = function () { + crowdfundingState = true; + // Display the popup + var text = Messages.crowdfunding_popup_text; + var yes = h('button.cp-corner-primary', [ + h('span.fa.fa-external-link'), + 'OpenCollective' + ]); + var no = h('button.cp-corner-cancel', Messages.crowdfunding_popup_no); + var actions = h('div', [no, yes]); + + var dontShowAgain = function () { + common.setAttribute(['general', 'crowdfunding'], false); + Feedback.send('CROWDFUNDING_NEVER'); + }; + + var modal = UI.cornerPopup(text, actions, null, { + big: true, + alt: true, + dontShowAgain: dontShowAgain + }); + + $(yes).click(function () { + modal.delete(); + common.openURL(priv.accounts.donateURL); + Feedback.send('CROWDFUNDING_YES'); + }); + $(modal.popup).find('a').click(function (e) { + e.stopPropagation(); + e.preventDefault(); + modal.delete(); + common.openURL(priv.accounts.donateURL); + Feedback.send('CROWDFUNDING_LINK'); + }); + $(no).click(function () { + modal.delete(); + Feedback.send('CROWDFUNDING_NO'); + }); + }; + + if (force) { + crowdfundingState = true; + return void todo(); + } + + if (AppConfig.disableCrowdfundingMessages) { return; } if (priv.plan) { return; } crowdfundingState = true; - setTimeout(function () { - common.getAttribute(['general', 'crowdfunding'], function (err, val) { - if (err || val === false) { return; } - common.getSframeChannel().query('Q_GET_PINNED_USAGE', null, function (err, obj) { - var quotaMb = obj.quota / (1024 * 1024); - if (quotaMb < 10) { return; } - // Display the popup - var text = Messages.crowdfunding_popup_text; - var yes = h('button.cp-corner-primary', Messages.crowdfunding_popup_yes); - var no = h('button.cp-corner-primary', Messages.crowdfunding_popup_no); - var never = h('button.cp-corner-cancel', Messages.crowdfunding_popup_never); - var actions = h('div', [yes, no, never]); - - var modal = UI.cornerPopup(text, actions, null, {big: true}); - - $(yes).click(function () { - modal.delete(); - common.openURL(priv.accounts.donateURL); - Feedback.send('CROWDFUNDING_YES'); - }); - $(modal.popup).find('a').click(function (e) { - e.stopPropagation(); - e.preventDefault(); - modal.delete(); - common.openURL(priv.accounts.donateURL); - Feedback.send('CROWDFUNDING_LINK'); - }); - $(no).click(function () { - modal.delete(); - Feedback.send('CROWDFUNDING_NO'); - }); - $(never).click(function () { - modal.delete(); - common.setAttribute(['general', 'crowdfunding'], false); - Feedback.send('CROWDFUNDING_NEVER'); - }); - }); + common.getAttribute(['general', 'crowdfunding'], function (err, val) { + if (err || val === false) { return; } + common.getSframeChannel().query('Q_GET_PINNED_USAGE', null, function (err, obj) { + var quotaMb = obj.quota / (1024 * 1024); + if (quotaMb < 10) { return; } + todo(); }); - }, 5000); + }); }; var storePopupState = false; @@ -4164,7 +4180,7 @@ define([ var hide = h('button.cp-corner-cancel', Messages.autostore_hide); var store = h('button.cp-corner-primary', Messages.autostore_store); - var actions = h('div', [store, hide]); + var actions = h('div', [hide, store]); var initialHide = data && data.autoStore && data.autoStore === -1; var modal = UI.cornerPopup(text, actions, footer, {hidden: initialHide}); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 026021d1d..a651bfa31 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -83,6 +83,9 @@ define([ }; // UI + window.CryptPad_UI = UI; + window.CryptPad_UIElements = UIElements; + window.CryptPad_common = funcs; funcs.createUserAdminMenu = callWithCommon(UIElements.createUserAdminMenu); funcs.initFilePicker = callWithCommon(UIElements.initFilePicker); funcs.openFilePicker = callWithCommon(UIElements.openFilePicker); diff --git a/www/pad/inner.js b/www/pad/inner.js index 78f027182..52ae7325a 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -736,12 +736,12 @@ define([ }); framework._.sfCommon.isPadStored(function (err, val) { - if (!val) { return; } + //if (!val) { return; } var b64images = $inner.find('img[src^="data:image"]:not(.cke_reset)'); - if (b64images.length && framework._.sfCommon.isLoggedIn()) { + if (true || b64images.length && framework._.sfCommon.isLoggedIn()) { var no = h('button.cp-corner-cancel', Messages.cancel); var yes = h('button.cp-corner-primary', Messages.ok); - var actions = h('div', [yes, no]); + var actions = h('div', [no, yes]); var modal = UI.cornerPopup(Messages.pad_base64, actions, '', {big: true}); $(no).click(function () { modal.delete(); From d065a3d11685ccb63b47fb02d415645a2f28ea1d Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 4 Feb 2020 15:19:12 +0100 Subject: [PATCH 2/5] Add transparency --- customize.dist/src/less2/include/corner.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/customize.dist/src/less2/include/corner.less b/customize.dist/src/less2/include/corner.less index d267f3683..6cf365c2e 100644 --- a/customize.dist/src/less2/include/corner.less +++ b/customize.dist/src/less2/include/corner.less @@ -31,7 +31,7 @@ bottom: 10px; width: 350px; padding: 10px; - background-color: @corner-blue; + background-color: fade(@corner-blue, 95%); border: 1px solid @corner-blue; color: @corner-white; z-index: 9999; @@ -40,7 +40,7 @@ //box-shadow: 0 0 10px 0 @corner-blue; &.cp-corner-alt { - background-color: @corner-white; + background-color: fade(@corner-white, 95%); border: 1px solid @corner-blue; color: @corner-blue; } From 653d58433e116a8a104a1e3873806bc817957c88 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 5 Feb 2020 12:16:04 +0100 Subject: [PATCH 3/5] Add link to profile in notifications --- .../src/less2/include/notifications.less | 9 +++++++ www/common/sframe-common-mailbox.js | 24 +++++++++++++++++-- www/notifications/app-notifications.less | 9 +++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/customize.dist/src/less2/include/notifications.less b/customize.dist/src/less2/include/notifications.less index 1e4430db2..a24ad32d3 100644 --- a/customize.dist/src/less2/include/notifications.less +++ b/customize.dist/src/less2/include/notifications.less @@ -8,6 +8,7 @@ @notif-height: 50px; .cp-notifications-container { max-width: 300px; + width: 300px; display: flex; flex-flow: column; & hr { @@ -16,6 +17,14 @@ .cp-notification { min-height: @notif-height; display: flex; + .cp-avatar { + .avatar_main(30px); + padding: 0 5px; + cursor: pointer; + &:hover { + background-color: rgba(0,0,0,0.1); + } + } .cp-notification-content { flex: 1; align-items: stretch; diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js index 35bf5df70..c10a45ff3 100644 --- a/www/common/sframe-common-mailbox.js +++ b/www/common/sframe-common-mailbox.js @@ -1,12 +1,13 @@ define([ 'jquery', '/common/common-util.js', + '/common/common-hash.js', '/common/common-interface.js', '/common/common-ui-elements.js', '/common/notifications.js', '/common/hyperscript.js', '/customize/messages.js', -], function ($, Util, UI, UIElements, Notifications, h, Messages) { +], function ($, Util, Hash, UI, UIElements, Notifications, h, Messages) { var Mailbox = {}; Mailbox.create = function (Common) { @@ -53,9 +54,28 @@ define([ }; var createElement = mailbox.createElement = function (data) { var notif; + var avatar; + var type = Util.find(data, ['content', 'msg', 'type']); + var userData = ['FRIEND_REQUEST'].indexOf(type) !== -1 ? Util.find(data, ['content', 'msg', 'content']) + : Util.find(data, ['content', 'msg', 'content', 'user']); + if (userData && typeof(userData) === "object" && userData.profile) { + avatar = h('span.cp-avatar'); + Common.displayAvatar($(avatar), userData.avatar, userData.displayName || userData.name); + $(avatar).click(function (e) { + e.stopPropagation(); + Common.openURL(Hash.hashToHref(userData.profile, 'profile')); + }); + } else { + console.warn(data); + + } notif = h('div.cp-notification', { 'data-hash': data.content.hash - }, [h('div.cp-notification-content', h('p', formatData(data)))]); + }, [ + avatar, + h('div.cp-notification-content', + h('p', formatData(data))) + ]); if (typeof(data.content.getFormatText) === "function") { $(notif).find('.cp-notification-content p').html(data.content.getFormatText()); diff --git a/www/notifications/app-notifications.less b/www/notifications/app-notifications.less index dfc1da7f7..5199ae5b6 100644 --- a/www/notifications/app-notifications.less +++ b/www/notifications/app-notifications.less @@ -1,5 +1,6 @@ @import (reference) '../../customize/src/less2/include/framework.less'; @import (reference) '../../customize/src/less2/include/sidebar-layout.less'; +@import (reference) '../../customize/src/less2/include/avatar.less'; &.cp-app-notifications { @@ -86,6 +87,14 @@ display: block; } } + .cp-avatar { + .avatar_main(48px); + padding: 0 10px; + cursor: pointer; + &:hover { + background-color: rgba(0,0,0,0.1); + } + } &.cp-app-notification-archived { background-color: #f1f1f1; } From 2ee38ccc42af2a626c5661938041015823a80cae Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 5 Feb 2020 13:33:32 +0100 Subject: [PATCH 4/5] lint compliance --- www/common/common-messaging.js | 12 ++- www/common/common-ui-elements.js | 57 ++------------ www/common/notifications.js | 18 ++++- www/common/outer/async-store.js | 32 +++----- www/common/outer/mailbox-handlers.js | 114 ++++++++++++++++----------- www/common/outer/mailbox.js | 14 +++- www/common/outer/team.js | 14 +--- www/common/sframe-common-mailbox.js | 7 +- www/pad/inner.js | 4 +- 9 files changed, 126 insertions(+), 146 deletions(-) diff --git a/www/common/common-messaging.js b/www/common/common-messaging.js index feb3d79d3..15d0408f7 100644 --- a/www/common/common-messaging.js +++ b/www/common/common-messaging.js @@ -53,10 +53,18 @@ define([ return list; }; + Msg.declineFriendRequest = function (store, data, cb) { + store.mailbox.sendTo('DECLINE_FRIEND_REQUEST', {}, { + channel: data.notifications, + curvePublic: data.curvePublic + }, function (obj) { + cb(obj); + }); + }; Msg.acceptFriendRequest = function (store, data, cb) { var friend = getFriend(store.proxy, data.curvePublic) || {}; var myData = createData(store.proxy, friend.channel || data.channel); - store.mailbox.sendTo('ACCEPT_FRIEND_REQUEST', myData, { + store.mailbox.sendTo('ACCEPT_FRIEND_REQUEST', { user: myData }, { channel: data.notifications, curvePublic: data.curvePublic }, function (obj) { @@ -110,7 +118,7 @@ define([ var proxy = store.proxy; var friend = proxy.friends[curvePublic]; if (!friend) { return void cb({error: 'ENOENT'}); } - if (!friend.notifications || !friend.channel) { return void cb({error: 'EINVAL'}); } + if (!friend.notifications) { return void cb({error: 'EINVAL'}); } store.mailbox.sendTo('UNFRIEND', { curvePublic: proxy.curvePublic diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 8bfa02e3a..c60ef652d 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -212,15 +212,7 @@ define([ common.mailbox.sendTo("RM_OWNER", { channel: channel, title: data.title, - pending: pending, - user: { - displayName: user.name, - avatar: user.avatar, - profile: user.profile, - notifications: user.notifications, - curvePublic: user.curvePublic, - edPublic: priv.edPublic - } + pending: pending }, { channel: friend.notifications, curvePublic: friend.curvePublic @@ -363,15 +355,7 @@ define([ channel: channel, href: data.href, password: data.password, - title: data.title, - user: { - displayName: user.name, - avatar: user.avatar, - profile: user.profile, - notifications: user.notifications, - curvePublic: user.curvePublic, - edPublic: priv.edPublic - } + title: data.title }, { channel: friend.notifications, curvePublic: friend.curvePublic @@ -4335,7 +4319,8 @@ define([ UIElements.displayFriendRequestModal = function (common, data) { var msg = data.content.msg; - var text = Messages._getKey('contacts_request', [Util.fixHTML(msg.content.displayName)]); + var userData = msg.content.user; + var text = Messages._getKey('contacts_request', [Util.fixHTML(userData.displayName)]); var todo = function (yes) { common.getSframeChannel().query("Q_ANSWER_FRIEND_REQUEST", { @@ -4362,7 +4347,6 @@ define([ UIElements.displayAddOwnerModal = function (common, data) { var priv = common.getMetadataMgr().getPrivateData(); - var user = common.getMetadataMgr().getUserData(); var sframeChan = common.getSframeChannel(); var msg = data.content.msg; @@ -4397,15 +4381,7 @@ define([ href: msg.content.href, password: msg.content.password, title: msg.content.title, - answer: yes, - user: { - displayName: user.name, - avatar: user.avatar, - profile: user.profile, - notifications: user.notifications, - curvePublic: user.curvePublic, - edPublic: priv.edPublic - } + answer: yes }, { channel: msg.content.user.notifications, curvePublic: msg.content.user.curvePublic @@ -4486,7 +4462,6 @@ define([ }; UIElements.displayAddTeamOwnerModal = function (common, data) { var priv = common.getMetadataMgr().getPrivateData(); - var user = common.getMetadataMgr().getUserData(); var sframeChan = common.getSframeChannel(); var msg = data.content.msg; @@ -4503,15 +4478,7 @@ define([ common.mailbox.sendTo("ADD_OWNER_ANSWER", { teamChannel: msg.content.teamChannel, title: msg.content.title, - answer: yes, - user: { - displayName: user.name, - avatar: user.avatar, - profile: user.profile, - notifications: user.notifications, - curvePublic: user.curvePublic, - edPublic: priv.edPublic - } + answer: yes }, { channel: msg.content.user.notifications, curvePublic: msg.content.user.curvePublic @@ -4627,8 +4594,6 @@ define([ }; UIElements.displayInviteTeamModal = function (common, data) { - var priv = common.getMetadataMgr().getPrivateData(); - var user = common.getMetadataMgr().getUserData(); var msg = data.content.msg; var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous; @@ -4649,15 +4614,7 @@ define([ common.mailbox.sendTo("INVITE_TO_TEAM_ANSWER", { answer: yes, teamChannel: msg.content.team.channel, - teamName: teamName, - user: { - displayName: user.name, - avatar: user.avatar, - profile: user.profile, - notifications: user.notifications, - curvePublic: user.curvePublic, - edPublic: priv.edPublic - } + teamName: teamName }, { channel: msg.content.user.notifications, curvePublic: msg.content.user.curvePublic diff --git a/www/common/notifications.js b/www/common/notifications.js index 192d2b4c6..8546f2787 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -29,7 +29,9 @@ define([ handlers['FRIEND_REQUEST'] = function (common, data) { var content = data.content; var msg = content.msg; - var name = Util.fixHTML(msg.content.displayName) || Messages.anonymous; + var userData = msg.content.user || msg.content; + var name = Util.fixHTML(userData.displayName) || Messages.anonymous; + msg.content = { user: userData }; // Display the notification content.getFormatText = function () { @@ -37,7 +39,7 @@ define([ }; // Check authenticity - if (msg.author !== msg.content.curvePublic) { return; } + if (msg.author !== userData.curvePublic) { return; } // if not archived, add handlers if (!content.archived) { @@ -51,7 +53,11 @@ define([ handlers['FRIEND_REQUEST_ACCEPTED'] = function (common, data) { var content = data.content; var msg = content.msg; - var name = Util.fixHTML(msg.content.name) || Messages.anonymous; + var userData = typeof(msg.content.user) === "object" ? msg.content.user : { + displayName: msg.content.name, + curvePublic: msg.content.user + }; + var name = Util.fixHTML(userData.displayName) || Messages.anonymous; content.getFormatText = function () { return Messages._getKey('friendRequest_accepted', [name]); }; @@ -63,7 +69,11 @@ define([ handlers['FRIEND_REQUEST_DECLINED'] = function (common, data) { var content = data.content; var msg = content.msg; - var name = Util.fixHTML(msg.content.name) || Messages.anonymous; + var userData = typeof(msg.content.user) === "object" ? msg.content.user : { + displayName: msg.content.name, + curvePublic: msg.content.user + }; + var name = Util.fixHTML(userData.displayName) || Messages.anonymous; content.getFormatText = function () { return Messages._getKey('friendRequest_declined', [name]); }; diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 51c04066f..c544754ba 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1267,15 +1267,15 @@ define([ // If we accept the request, add the friend to the list if (value) { - Messaging.acceptFriendRequest(store, msg.content, function (obj) { + Messaging.acceptFriendRequest(store, msg.content.user, function (obj) { if (obj && obj.error) { return void cb(obj); } Messaging.addToFriendList({ proxy: store.proxy, realtime: store.realtime, pinPads: function (data, cb) { Store.pinPads(null, data, cb); }, - }, msg.content, function (err) { + }, msg.content.user, function (err) { if (store.messenger) { - store.messenger.onFriendAdded(msg.content); + store.messenger.onFriendAdded(msg.content.user); } broadcast([], "UPDATE_METADATA"); if (err) { return void cb({error: err}); } @@ -1285,12 +1285,7 @@ define([ return; } // Otherwise, just remove the notification - store.mailbox.sendTo('DECLINE_FRIEND_REQUEST', { - displayName: store.proxy['cryptpad.username'] - }, { - channel: msg.content.notifications, - curvePublic: msg.content.curvePublic - }, function (obj) { + Messaging.declineFriendRequest(store, msg.content.user, function (obj) { broadcast([], "UPDATE_METADATA"); cb(obj); }); @@ -1312,8 +1307,9 @@ define([ store.proxy.friends_pending[data.curvePublic] = +new Date(); broadcast([], "UPDATE_METADATA"); - var myData = Messaging.createData(store.proxy); - store.mailbox.sendTo('FRIEND_REQUEST', myData, { + store.mailbox.sendTo('FRIEND_REQUEST', { + user: Messaging.createData(store.proxy) + }, { channel: data.notifications, curvePublic: data.curvePublic }, function (obj) { @@ -1649,11 +1645,8 @@ define([ // If send is true, send the request to the owner. if (owner) { if (data.send) { - var myData = Messaging.createData(store.proxy); - delete myData.channel; store.mailbox.sendTo('REQUEST_PAD_ACCESS', { - channel: data.channel, - user: myData + channel: data.channel }, { channel: owner.notifications, curvePublic: owner.curvePublic @@ -1687,13 +1680,10 @@ define([ } })) { return void cb({error: 'ENOTFOUND'}); } - var myData = Messaging.createData(store.proxy); - delete myData.channel; store.mailbox.sendTo("GIVE_PAD_ACCESS", { channel: channel, href: href, - title: title, - user: myData + title: title }, { channel: data.user.notifications, curvePublic: data.user.curvePublic @@ -1727,13 +1717,11 @@ define([ } // Tell all the owners that the pad was deleted from the server var curvePublic = store.proxy.curvePublic; - var myData = Messaging.createData(store.proxy, false); m.forEach(function (obj) { var mb = JSON.parse(obj); if (mb.curvePublic === curvePublic) { return; } store.mailbox.sendTo('OWNED_PAD_REMOVED', { - channel: channel, - user: myData + channel: channel }, { channel: mb.notifications, curvePublic: mb.curvePublic diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 253157361..d66ff516e 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -4,6 +4,7 @@ define([ '/common/common-util.js', ], function (Messaging, Hash, Util) { + // Random timeout between 10 and 30 times your sync time (lag + chainpad sync) var getRandomTimeout = function (ctx) { var lag = ctx.store.realtime.getLag().lag || 0; return (Math.max(0, lag) + 300) * 20 * (0.5 + Math.random()); @@ -22,9 +23,11 @@ define([ // Store the friend request displayed to avoid duplicates var friendRequest = {}; handlers['FRIEND_REQUEST'] = function (ctx, box, data, cb) { + // Old format: data was stored directly in "content" + var userData = data.msg.content.user || data.msg.content; // Check if the request is valid (send by the correct user) - if (data.msg.author !== data.msg.content.curvePublic) { + if (data.msg.author !== userData.curvePublic) { return void cb(true); } @@ -40,7 +43,8 @@ define([ if (Messaging.getFriend(ctx.store.proxy, data.msg.author) || ctx.store.proxy.friends_pending[data.msg.author]) { delete ctx.store.proxy.friends_pending[data.msg.author]; - Messaging.acceptFriendRequest(ctx.store, data.msg.content, function (obj) { + + Messaging.acceptFriendRequest(ctx.store, userData, function (obj) { if (obj && obj.error) { return void cb(); } @@ -48,10 +52,10 @@ define([ proxy: ctx.store.proxy, realtime: ctx.store.realtime, pinPads: ctx.pinPads - }, data.msg.content, function (err) { - if (err) { console.error(err); } + }, userData, function (err) { + if (err) { return void console.error(err); } if (ctx.store.messenger) { - ctx.store.messenger.onFriendAdded(data.msg.content); + ctx.store.messenger.onFriendAdded(userData); } }); ctx.updateMetadata(); @@ -63,96 +67,110 @@ define([ cb(); }; removeHandlers['FRIEND_REQUEST'] = function (ctx, box, data) { - if (friendRequest[data.content.curvePublic]) { - delete friendRequest[data.content.curvePublic]; + var userData = data.content.user || data.content; + if (friendRequest[userData.curvePublic]) { + delete friendRequest[userData.curvePublic]; } }; + // The DECLINE and ACCEPT messages act on the contacts data + // They are processed with a random timeout to avoid having + // multiple workers trying to add or remove the contacts at + // the same time. Once processed, they are dismissed. + // We must dismiss them and send another message to our own + // mailbox for the UI part otherwise it would automatically + // accept or decline future requests from the same user + // until the message is manually dismissed. + var friendRequestDeclined = {}; handlers['DECLINE_FRIEND_REQUEST'] = function (ctx, box, data, cb) { + // Old format: data was stored directly in "content" + var userData = data.msg.content.user || data.msg.content; + if (!userData.curvePublic) { userData.curvePublic = data.msg.author; } + + // Our friend request was declined. setTimeout(function () { - // Our friend request was declined. - if (!ctx.store.proxy.friends_pending[data.msg.author]) { return; } + // Only dismissed once in the timeout to make sure we won't lose + // the data if we close the worker before adding the friend + cb(true); + // Make sure we really sent it + if (!ctx.store.proxy.friends_pending[data.msg.author]) { return; } // Remove the pending message and display the "declined" state in the UI delete ctx.store.proxy.friends_pending[data.msg.author]; + ctx.updateMetadata(); if (friendRequestDeclined[data.msg.author]) { return; } + friendRequestDeclined[data.msg.author] = true; box.sendMessage({ type: 'FRIEND_REQUEST_DECLINED', - content: { - user: data.msg.author, - name: data.msg.content.displayName - } - }, function () { - if (friendRequestDeclined[data.msg.author]) { - // TODO remove our message because another one was sent first? - } - friendRequestDeclined[data.msg.author] = true; - }); + content: { user: userData } + }, function () {}); }, getRandomTimeout(ctx)); - cb(true); }; + // UI for declined friend request handlers['FRIEND_REQUEST_DECLINED'] = function (ctx, box, data, cb) { ctx.updateMetadata(); - if (friendRequestDeclined[data.msg.content.user]) { return void cb(true); } - friendRequestDeclined[data.msg.content.user] = true; + var curve = data.msg.content.user.curvePublic || data.msg.content.user; + if (friendRequestDeclined[curve]) { return void cb(true); } + friendRequestDeclined[curve] = true; cb(); }; removeHandlers['FRIEND_REQUEST_DECLINED'] = function (ctx, box, data) { - if (friendRequestDeclined[data.content.user]) { - delete friendRequestDeclined[data.content.user]; - } + var curve = data.content.user.curvePublic || data.content.user; + if (friendRequestDeclined[curve]) { delete friendRequestDeclined[curve]; } }; var friendRequestAccepted = {}; handlers['ACCEPT_FRIEND_REQUEST'] = function (ctx, box, data, cb) { + // Old format: data was stored directly in "content" + var userData = data.msg.content.user || data.msg.content; + // Our friend request was accepted. setTimeout(function () { + // Only dismissed once in the timeout to make sure we won't lose + // the data if we close the worker before adding the friend + cb(true); + // Make sure we really sent it if (!ctx.store.proxy.friends_pending[data.msg.author]) { return; } + // Remove the pending state. It will also us to send a new request in case of error + delete ctx.store.proxy.friends_pending[data.msg.author]; + // And add the friend Messaging.addToFriendList({ proxy: ctx.store.proxy, realtime: ctx.store.realtime, pinPads: ctx.pinPads - }, data.msg.content, function (err) { - if (err) { console.error(err); } - delete ctx.store.proxy.friends_pending[data.msg.author]; - if (ctx.store.messenger) { - ctx.store.messenger.onFriendAdded(data.msg.content); - } + }, userData, function (err) { + if (err) { return void console.error(err); } + // Load the chat if contacts app loaded + if (ctx.store.messenger) { ctx.store.messenger.onFriendAdded(userData); } + // Update the userlist ctx.updateMetadata(); // If you have a profile page open, update it if (ctx.store.modules['profile']) { ctx.store.modules['profile'].update(); } - if (friendRequestAccepted[data.msg.author]) { return; } // Display the "accepted" state in the UI + if (friendRequestAccepted[data.msg.author]) { return; } + friendRequestAccepted[data.msg.author] = true; box.sendMessage({ type: 'FRIEND_REQUEST_ACCEPTED', - content: { - user: data.msg.author, - name: data.msg.content.displayName - } - }, function () { - if (friendRequestAccepted[data.msg.author]) { - // TODO remove our message because another one was sent first? - } - friendRequestAccepted[data.msg.author] = true; - }); + content: { user: userData } + }, function () {}); }); }, getRandomTimeout(ctx)); - cb(true); }; + // UI for accepted friend request handlers['FRIEND_REQUEST_ACCEPTED'] = function (ctx, box, data, cb) { ctx.updateMetadata(); - if (friendRequestAccepted[data.msg.content.user]) { return void cb(true); } - friendRequestAccepted[data.msg.content.user] = true; + var curve = data.msg.content.user.curvePublic || data.msg.content.user; + if (friendRequestAccepted[curve]) { return void cb(true); } + friendRequestAccepted[curve] = true; cb(); }; removeHandlers['FRIEND_REQUEST_ACCEPTED'] = function (ctx, box, data) { - if (friendRequestAccepted[data.content.user]) { - delete friendRequestAccepted[data.content.user]; - } + var curve = data.content.user.curvePublic || data.content.user; + if (friendRequestAccepted[curve]) { delete friendRequestAccepted[curve]; } }; handlers['UNFRIEND'] = function (ctx, box, data, cb) { diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index b84e98dd7..ce9bbe850 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -2,11 +2,12 @@ define([ '/common/common-util.js', '/common/common-hash.js', '/common/common-realtime.js', + '/common/common-messaging.js', '/common/notify.js', '/common/outer/mailbox-handlers.js', '/bower_components/chainpad-netflux/chainpad-netflux.js', '/bower_components/chainpad-crypto/crypto.js', -], function (Util, Hash, Realtime, Notify, Handlers, CpNetflux, Crypto) { +], function (Util, Hash, Realtime, Messaging, Notify, Handlers, CpNetflux, Crypto) { var Mailbox = {}; var TYPES = [ @@ -96,6 +97,12 @@ proxy.mailboxes = { var crypto = Crypto.Mailbox.createEncryptor(keys); + // Always send your data + if (typeof(msg) === "object" && !msg.user) { + var myData = Messaging.createData(ctx.store.proxy, false); + msg.user = myData; + } + var text = JSON.stringify({ type: type, content: msg @@ -187,6 +194,11 @@ proxy.mailboxes = { history: [], // All the hashes loaded from the server in corretc order content: {}, // Content of the messages that should be displayed sendMessage: function (msg) { // To send a message to our box + // Always send your data + if (typeof(msg) === "object" && !msg.user) { + var myData = Messaging.createData(ctx.store.proxy, false); + msg.user = myData; + } try { msg = JSON.stringify(msg); } catch (e) { diff --git a/www/common/outer/team.js b/www/common/outer/team.js index ce79a800f..24952f5c9 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -909,13 +909,11 @@ define([ })); }).nThen(function (waitFor) { // Send mailbox to offer ownership - var myData = Messaging.createData(ctx.store.proxy, false); ctx.store.mailbox.sendTo("ADD_OWNER", { teamChannel: teamData.channel, chatChannel: Util.find(teamData, ['keys', 'chat', 'channel']), rosterChannel: Util.find(teamData, ['keys', 'roster', 'channel']), - title: teamData.metadata.name, - user: myData + title: teamData.metadata.name }, { channel: user.notifications, curvePublic: user.curvePublic @@ -969,12 +967,10 @@ define([ })); }).nThen(function (waitFor) { // Send mailbox to offer ownership - var myData = Messaging.createData(ctx.store.proxy, false); ctx.store.mailbox.sendTo("RM_OWNER", { teamChannel: teamData.channel, title: teamData.metadata.name, - pending: isPendingOwner, - user: myData + pending: isPendingOwner }, { channel: user.notifications, curvePublic: user.curvePublic @@ -1104,11 +1100,9 @@ define([ if (!team) { return void cb ({error: 'ENOENT'}); } // Send mailbox to offer ownership - var myData = Messaging.createData(ctx.store.proxy, false); ctx.store.mailbox.sendTo("TEAM_EDIT_RIGHTS", { state: state, - teamData: getInviteData(ctx, teamId, state), - user: myData + teamData: getInviteData(ctx, teamId, state) }, { channel: user.notifications, curvePublic: user.curvePublic @@ -1175,7 +1169,6 @@ define([ team.roster.add(obj, function (err) { if (err && err !== 'NO_CHANGE') { return void cb({error: err}); } ctx.store.mailbox.sendTo('INVITE_TO_TEAM', { - user: Messaging.createData(ctx.store.proxy, false), team: getInviteData(ctx, teamId) }, { channel: user.notifications, @@ -1202,7 +1195,6 @@ define([ if (!userData || !userData.notifications) { return cb(); } ctx.store.mailbox.sendTo('KICKED_FROM_TEAM', { pending: data.pending, - user: Messaging.createData(ctx.store.proxy, false), teamChannel: getInviteData(ctx, teamId).channel, teamName: getInviteData(ctx, teamId).metadata.name }, { diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js index c10a45ff3..a5602fc3f 100644 --- a/www/common/sframe-common-mailbox.js +++ b/www/common/sframe-common-mailbox.js @@ -55,9 +55,7 @@ define([ var createElement = mailbox.createElement = function (data) { var notif; var avatar; - var type = Util.find(data, ['content', 'msg', 'type']); - var userData = ['FRIEND_REQUEST'].indexOf(type) !== -1 ? Util.find(data, ['content', 'msg', 'content']) - : Util.find(data, ['content', 'msg', 'content', 'user']); + var userData = Util.find(data, ['content', 'msg', 'content', 'user']); if (userData && typeof(userData) === "object" && userData.profile) { avatar = h('span.cp-avatar'); Common.displayAvatar($(avatar), userData.avatar, userData.displayName || userData.name); @@ -65,9 +63,6 @@ define([ e.stopPropagation(); Common.openURL(Hash.hashToHref(userData.profile, 'profile')); }); - } else { - console.warn(data); - } notif = h('div.cp-notification', { 'data-hash': data.content.hash diff --git a/www/pad/inner.js b/www/pad/inner.js index 52ae7325a..3f6e717ce 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -736,9 +736,9 @@ define([ }); framework._.sfCommon.isPadStored(function (err, val) { - //if (!val) { return; } + if (!val) { return; } var b64images = $inner.find('img[src^="data:image"]:not(.cke_reset)'); - if (true || b64images.length && framework._.sfCommon.isLoggedIn()) { + if (b64images.length && framework._.sfCommon.isLoggedIn()) { var no = h('button.cp-corner-cancel', Messages.cancel); var yes = h('button.cp-corner-primary', Messages.ok); var actions = h('div', [no, yes]); From 78795a3b4d247e24d524e63fb5e95d657262f18f Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 5 Feb 2020 14:54:23 +0100 Subject: [PATCH 5/5] Login or register in profile for anonymous users --- customize.dist/src/less2/include/corner.less | 4 +++- www/profile/inner.js | 23 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/customize.dist/src/less2/include/corner.less b/customize.dist/src/less2/include/corner.less index 6cf365c2e..feec62165 100644 --- a/customize.dist/src/less2/include/corner.less +++ b/customize.dist/src/less2/include/corner.less @@ -137,7 +137,9 @@ button { padding: 5px; color: @corner-white; - margin-left: 10px; + &:not(:first-child) { + margin-left: 10px; + } outline: none; text-transform: uppercase; border: 1px solid @corner-white; diff --git a/www/profile/inner.js b/www/profile/inner.js index 0f4a17746..773b21206 100644 --- a/www/profile/inner.js +++ b/www/profile/inner.js @@ -570,6 +570,29 @@ define([ return; } + if (!common.isLoggedIn()) { + var login = h('button.cp-corner-primary', Messages.login_login); + var register = h('button.cp-corner-primary', Messages.login_register); + var cancel = h('button.cp-corner-cancel', Messages.cancel); + var actions = h('div', [cancel, register, login]); + var modal = UI.cornerPopup(Messages.profile_login || "You need to log in to add this user to your contacts", actions, '', {alt: true}); // XXX + $(register).click(function () { + common.setLoginRedirect(function () { + common.gotoURL('/register/'); + }); + modal.delete(); + }); + $(login).click(function () { + common.setLoginRedirect(function () { + common.gotoURL('/login/'); + }); + modal.delete(); + }); + $(cancel).click(function () { + modal.delete(); + }); + } + var listmapConfig = { data: {}, common: common,