Merge branch into staging

This commit is contained in:
yflory 2025-03-24 16:00:20 +01:00
commit c3f6510179
6 changed files with 144 additions and 87 deletions

View File

@ -71,6 +71,7 @@
button {
height: @toolbar_line-height !important;
outline: 0;
border-radius: @variables_radius;
color: @toolbar-color;
.toolbar_button;
font: normal normal normal 14px/1 FontAwesome;

View File

@ -13,6 +13,8 @@ define(['/common/translations/messages.js'], function (Messages) {
// Replace the existing keys in your copied file here:
// Messages.button_newpad = "New Rich Text Document";
Messages.profile_remove_avatar = "Remove this avatar"; // XXX
return Messages;
});

View File

@ -360,7 +360,9 @@ app.use('/block/', function (req, res, next) {
// identified by base64-encoded public keys
// skip everything else, ie. /block/placeholder.txt
if (typeof(name) !== 'string' || name.length !== 44) {
return void next();
return void res.status(404).json({
error: "INVALID_ID",
});
}
var authorization = req.headers.authorization;

View File

@ -60,20 +60,9 @@ define(['/api/config'], function (ApiConfig) {
window.location.href = target.href;
};
// Local URLs don't require any warning and can navigate directly without user input.
if (target.host === host.host) { return void go(); }
// It's annoying to be prompted that you are leaving the platform to visit its docs
// but marking the docs domain as trusted undermines third-party admins' autonomy.
// If we ever abandon the cryptpad.fr domain someone could squat it and abuse this trust.
// If the docs domain is a subdomain of the current one then redirect automatically.
// We might make the docs domain configurable at some point in the future.
if (target.host === 'docs.cryptpad.org' && target.host.endsWith(host.host)) {
return void go();
}
// Everything else requires user input, so we load the platform's translations.
// Everything else may require user input, so we load the platform's translations.
// FIXME: this seems to infer language preferences from the browser instead of the user's account preferences
require([
'/customize/messages.js',
], function (Messages) {
@ -86,6 +75,18 @@ define(['/api/config'], function (ApiConfig) {
return void reject();
}
// Local URLs don't require any warning and can navigate directly without user input.
if (target.host === host.host) { return void go(); }
// It's annoying to be prompted that you are leaving the platform to visit its docs
// but marking the docs domain as trusted undermines third-party admins' autonomy.
// If we ever abandon the cryptpad.fr domain someone could squat it and abuse this trust.
// If the docs domain is a subdomain of the current one then redirect automatically.
// We might make the docs domain configurable at some point in the future.
if (target.host === 'docs.cryptpad.org' && target.host.endsWith(host.host)) {
return void go();
}
// The provided URL will navigate the user away from the outer domain.
var question = Messages._getKey('bounce_confirm', [host.hostname, target.href]);
// Confirm that they want to leave, then navigate or reject based on their choice.

View File

@ -6,6 +6,7 @@
@import (reference) '../../customize/src/less2/include/framework.less';
@import (reference) '../../customize/src/less2/include/sidebar-layout.less';
@import (reference) '../../customize/src/less2/include/variables.less';
&.cp-app-profile {
@ -21,36 +22,38 @@
display: none !important;
}
#cp-app-profile-header {
display: flex;
flex-flow: row wrap;
justify-content: center;
#cp-app-profile-rightside {
flex: 1;
display: flex;
flex-flow: column;
align-items: start;
max-width: 100%;
}
}
#cp-app-profile-avatar {
width: 300px;
//height: 350px;
margin: 10px;
margin-right: 20px;
text-align: center;
max-width: 300px;
max-height: 300px;
margin-bottom: 3.5rem;
&> span {
display: inline-block;
text-align: center;
height: 300px;
width: 300px;
border: 1px solid @cp_profile-border;
border-radius: 4px;
overflow: hidden;
position: relative;
.cp-app-profile-avatar-delete {
right: 0;
position: absolute;
opacity: 0.7;
opacity: 1;
&:hover {
opacity: 1;
opacity: 0.7;
}
}
}
@ -58,6 +61,7 @@
max-width: 100%;
max-height: 100%;
vertical-align: top;
border-radius: @variables_radius_L;
}
media-tag {
height: 100%;
@ -79,11 +83,18 @@
margin: 5px !important;
}
}
.cp-app-profile-resizer {
text-align: center;
}
#cp-app-profile-displayname, #cp-app-profile-link {
margin: 10px 0;
.cp-app-profile-displayname {
margin-top: 1rem;
}
.cp-app-profile-section:empty {
display: none;
}
.cp-app-profile-displayname, .cp-app-profile-link, .cp-app-profile-section {
margin-bottom: 1rem;
input {
width: 100%;
font-size: 20px;
@ -108,7 +119,8 @@
}
.cp-app-profile-link {
font-size: 25px;
vertical-align: middle;
display: inline;
overflow-wrap: anywhere;
}
.cp-app-profile-displayname, .cp-app-profile-link {
line-height: 40px;
@ -127,8 +139,19 @@
& > button:empty {
margin-left: 25px !important;
}
@media screen and (max-width: @browser_media-medium-screen) {
.cp-app-profile-link-code {
min-width: 0;
}
}
}
div.cp-app-profile-mute-container.cp-app-profile-section {
p {
margin-bottom: 0;
}
}
.cp-app-profile-friend {
display: flex;
align-items: center;
@ -146,22 +169,16 @@
#cp-app-profile-invite-button {
float: right;
}
.cp-app-profile-viewprofile-button {
margin-bottom: 5px !important;
}
#cp-app-profile-description {
position: relative;
font-size: 16px;
margin-bottom: 20px;
//margin-bottom: 20px;
.cp-app-profile-description-code {
display: none;
}
.cp-app-profile-description-rendered {
border: 1px solid @cp_profile-border;
padding: 0 15px;
&:empty {
display: none;
}
#cp-app-profile-description-info {
overflow-wrap: anywhere;
margin-top: 1rem;
}
.cp-app-profile-description-ok, .cp-app-profile-description-spin {
position: absolute;
@ -178,6 +195,7 @@
font-family: monospace;
font-size: 16px;
line-height: initial;
max-width: 31rem;
pre {
margin: 0;
font-family: inherit;
@ -194,7 +212,6 @@
justify-content: center;
}
.cp-app-profile-mute-container {
margin-top: 5px;
p {
margin-top: 5px;
font-size: 13px;

View File

@ -96,6 +96,7 @@ define([
var HEADER_ID = "cp-app-profile-header";
var HEADER_RIGHT_ID = "cp-app-profile-rightside";
var VIEW_PROFILE_BUTTON = 'cp-app-profile-viewprofile-button';
var PROFILE_SECTION = "cp-app-profile-section";
var common;
var sFrameChan;
@ -108,25 +109,32 @@ define([
var hash = common.getMetadataMgr().getPrivateData().hashes.viewHash;
var url = APP.origin + '/profile/#' + hash;
$('<button>', {
'class': 'btn '+VIEW_PROFILE_BUTTON,
}).text(Messages.profile_viewMyProfile).click(function () {
var $blockView = $('<div>', {class: PROFILE_SECTION}).appendTo($container);
var button = h('button.btn.' + VIEW_PROFILE_BUTTON, {
'aria-labelledby': 'cp-profile-view-button'
}, [
h('span#cp-profile-view-button', Messages.profile_viewMyProfile)
]);
$(button).click(function () {
window.open(url, '_blank');
}).appendTo($container);
}).appendTo($blockView);
$('<button>', {
'class': 'btn btn-primary '+VIEW_PROFILE_BUTTON,
}).append(h('i.fa.fa-shhare-alt'))
.append(h('span', Messages.shareButton))
.click(function () {
var $blockShare = $('<div>', {class: PROFILE_SECTION}).appendTo($container);
var button = h('button.btn.btn-primary.' + VIEW_PROFILE_BUTTON, {
'aria-labelledby': 'cp-profile-share-button'
}, [
h('i.fa.fa-share-alt', { 'aria-hidden': 'true' }),
h('span#cp-profile-share-button', Messages.shareButton)
]);
$(button).click(function () {
Clipboard.copy(url, (err) => {
if (!err) { UI.log(Messages.shareSuccess); }
});
}).appendTo($container);
}).appendTo($blockShare);
};
var addDisplayName = function ($container) {
var $block = $('<div>', {id: DISPLAYNAME_ID}).appendTo($container);
var $block = $('<div>', {'class': DISPLAYNAME_ID}).appendTo($container);
APP.$name = $('<span>', {'class': DISPLAYNAME_ID}).appendTo($block);
};
var refreshName = function (data) {
@ -134,7 +142,7 @@ define([
};
var addLink = function ($container) {
var $block = $('<div>', {id: LINK_ID}).appendTo($container);
var $block = $('<div>', {class: PROFILE_SECTION}).appendTo($container);
APP.$link = $('<a>', {
'class': LINK_ID,
@ -158,8 +166,8 @@ define([
}, Messages.profile_addLink);
APP.$linkEdit = $(button);
$block.append(button);
var save = h('button.btn.btn-primary', Messages.settings_save);
var text = h('input');
var save = h('button.btn.btn-primary', { 'aria-labelledby': 'cp-save-link' }, Messages.settings_save);
var text = h('input#cp-save-link');
var code = h('div.cp-app-profile-link-code', [
text,
save
@ -199,8 +207,9 @@ define([
var addFriendRequest = function ($container) {
if (!APP.readOnly || !APP.common.isLoggedIn()) { return; }
var $block = $('<div>', {class: PROFILE_SECTION}).appendTo($container);
APP.$friend = $(h('div.cp-app-profile-friend-container'));
$container.append(APP.$friend);
$block.append(APP.$friend);
};
var refreshFriendRequest = function (data) {
if (!APP.$friend) { return; }
@ -221,14 +230,16 @@ define([
if (friends[data.curvePublic]) {
// Add friend message
APP.$friend.append(h('p.cp-app-profile-friend', [
h('i.fa.fa-address-book'),
h('i.fa.fa-address-book', {'aria-hidden': 'true' }),
Messages._getKey('isContact', [name])
]));
if (!friends[data.curvePublic].notifications) { return; }
// Add unfriend button
var unfriendButton = h('button.btn.btn-primary.cp-app-profile-friend-request', [
h('i.fa.fa-user-times'),
Messages.contacts_remove
var unfriendButton = h('button.btn.btn-primary.cp-app-profile-friend-request', {
'aria-labelledby': 'cp-profile-unfriend-button'
}, [
h('i.fa.fa-user-times', {'aria-hidden': 'true' }),
h('span#cp-profile-unfriend-button', Messages.contacts_remove)
]);
$(unfriendButton).click(function () {
// Unfriend confirm
@ -246,7 +257,7 @@ define([
}
var button = h('button.btn.btn-success.cp-app-profile-friend-request', [
h('i.fa.fa-user-plus'),
h('i.fa.fa-user-plus', {'aria-hidden': 'true'}),
]);
var $button = $(button).appendTo(APP.$friend);
@ -261,9 +272,11 @@ define([
}
var addCancel = function () {
var cancelButton = h('button.btn.btn-danger.cp-app-profile-friend-request', [
h('i.fa.fa-user-times'),
Messages.cancel
var cancelButton = h('button.btn.btn-danger.cp-app-profile-friend-request', {
'aria-labelledby': 'cp-profile-cancel-button'
},[
h('i.fa.fa-user-times', {'aria-hidden': 'true' }),
h('span#cp-profile-cancel-button' , Messages.cancel)
]);
$(cancelButton).click(function () {
// Unfriend confirm
@ -305,7 +318,7 @@ define([
var addMuteButton = function ($container) {
if (!APP.readOnly || !APP.common.isLoggedIn()) { return; }
APP.$mute = $(h('div.cp-app-profile-mute-container'));
APP.$mute = $(h('div.cp-app-profile-mute-container.cp-app-profile-section'));
$container.append(APP.$mute);
};
var refreshMute = function (data) {
@ -317,7 +330,6 @@ define([
return;
}
// Add mute/unmute buttons
var $mute = APP.$mute;
var module = common.makeUniversal('messenger');
@ -326,9 +338,11 @@ define([
$mute.html('');
var isMuted = muted[data.curvePublic];
if (isMuted) {
var unmuteButton = h('button.btn.btn-secondary.cp-app-profile-friend-request', [
h('i.fa.fa-bell'),
Messages.contacts_unmute || 'unmute'
var unmuteButton = h('button.btn.btn-secondary.cp-app-profile-friend-request', {
'aria-labelledby': 'cp-profile-unmute-button'
}, [
h('i.fa.fa-bell', {'aria-hidden': 'true' }),
h('span#cp-profile-unmute-button', Messages.contacts_unmute || 'unmute')
]);
$(unmuteButton).click(function () {
module.execCommand('UNMUTE_USER', data.curvePublic, function (e) {
@ -338,10 +352,12 @@ define([
}).appendTo($mute);
return;
}
var muteButton = h('button.btn.btn-danger-outline.cp-app-profile-friend-request', [
h('i.fa.fa-bell-slash'),
Messages.contacts_mute || 'mute'
]);
var muteButton = h('button.btn.btn-danger-outline.cp-app-profile-friend-request', {
'aria-labelledby': 'cp-profile-mute-button'
}, [
h('i.fa.fa-bell-slash', {'aria-hidden': 'true' }),
h('span#cp-profile-mute-button', Messages.contacts_mute || 'mute')
]);
$(muteButton).click(function () {
module.execCommand('MUTE_USER', {
curvePublic: data.curvePublic,
@ -374,7 +390,7 @@ define([
var $delButton = $('<button>', {
'class': 'cp-app-profile-avatar-delete btn btn-danger fa fa-times',
title: Messages.fc_delete
title: Messages.profile_remove_avatar
});
$span.append($delButton);
$delButton.click(function () {
@ -419,10 +435,12 @@ define([
}
todo();
});
//upload profile photo button should be secondary
var $upButton = common.createButton('upload', false, data);
$upButton.removeClass('btn-primary').addClass('btn-secondary');
$upButton.removeProp('title');
$upButton.text(Messages.profile_upload);
$upButton.prepend($('<span>', {'class': 'fa fa-upload'}));
$upButton.prepend($('<i>', {'class': 'fa fa-upload', 'aria-hidden': 'true'}));
$block.append($upButton);
};
var refreshAvatar = function (data) {
@ -430,16 +448,21 @@ define([
};
var addDescription = function ($container) {
var $block = $('<div>', {id: DESCRIPTION_ID, class:'cp-sidebarlayout-element'}).appendTo($container);
var $block = $('<div>', {id: DESCRIPTION_ID, class: PROFILE_SECTION}).appendTo($container);
APP.$description = $('<div>', {
'id': 'cp-app-profile-description-info'
}).appendTo($block);
APP.$description = $('<div>', {'class': 'cp-app-profile-description-rendered'}).appendTo($block);
APP.$descriptionEdit = $();
if (APP.readOnly) { return; }
var button = h('button.btn.btn-primary', [
h('i.fa.fa-pencil'),
h('span', Messages.profile_addDescription)
]);
var button = h('button.btn.btn-secondary', {
'aria-labelledby': 'cp-profile-add-description-button'
}, [
h('i.fa.fa-pencil', {'aria-hidden': 'true' }),
h('span#cp-profile-add-description-button', Messages.profile_addDescription)
]);
APP.$descriptionEdit = $(button);
var save = h('button.btn.btn-primary', Messages.settings_save);
var text = h('textarea');
@ -454,6 +477,7 @@ define([
code
]);
$block.append(div);
$(div).insertBefore(APP.$description);
var cm = SFCodeMirror.create("gfm", CodeMirror, text);
var editor = APP.editor = cm.editor;
@ -462,6 +486,12 @@ define([
editor.setOption('styleActiveLine', true);
editor.setOption('readOnly', false);
cm.configureTheme(common, function () {});
editor.setOption("extraKeys", {
"Esc": function () {
cm.getInputField().blur();
$(save).focus();
}
});
var markdownTb = common.createMarkdownToolbar(editor);
$(code).prepend(markdownTb.toolbar);
@ -486,7 +516,8 @@ define([
});
};
var refreshDescription = function (data) {
var val = Marked.parse(data.description || "");
var descriptionData = data.description || "";
var val = Marked.parse(descriptionData);
APP.$description.html(val);
APP.$description.off('click');
APP.$description.click(function (e) {
@ -509,12 +540,14 @@ define([
if (!APP.readOnly) { return; }
if (!Messages.profile_copyKey) { return; }
var $div = $(h('div.cp-sidebarlayout-element')).appendTo($container);
var $div = $(h('div.cp-app-profile-section')).appendTo($container);
APP.$edPublic = $('<button>', {
'class': 'btn',
}).append(h('i.fa.fa-key'))
.append(h('span', Messages.profile_copyKey))
.click(function () {
'aria-labelledby': 'cp-profile-copy-key-button'
}).append([
h('i.fa.fa-key', {'aria-hidden': 'true' }),
h('span#cp-profile-copy-key-button', Messages.profile_copyKey)
]).click(function () {
if (!APP.getEdPublic) { return; }
APP.getEdPublic();
}).appendTo($div).hide();
@ -535,15 +568,16 @@ define([
var addCopyData = function ($container) {
if (!APP.isModerator) { return; }
var $div = $(h('div.cp-sidebarlayout-element')).appendTo($container);
APP.$copyData = $(h('button.btn.btn-secondary', [
h('i.fa.fa-clipboard'),
h('span', Messages.support_copyUserData)
var $block = $('<div>', {class:PROFILE_SECTION}).appendTo($container);
APP.$copyData = $(h('button.btn.btn-secondary', {
'aria-labelledby': 'cp-profile-copy-data-button'
}, [
h('i.fa.fa-clipboard', {'aria-hidden': 'true' }),
h('span#cp-profile-copy-data-button', Messages.support_copyUserData)
])).click(function () {
if (!APP.getCopyData) { return; }
APP.getCopyData();
}).appendTo($div).hide();
}).appendTo($block).hide();
};
var setCopyDataButton = function (data) {
if (!data.curvePublic) { return; }
@ -575,10 +609,10 @@ define([
addLink($rightside);
addFriendRequest($rightside);
addMuteButton($rightside);
addDescription(APP.$rightside);
addPublicKey($rightside);
addCopyData($rightside);
addViewButton($rightside);
addDescription($rightside);
APP.initialized = true;
createLeftside();
}