This commit is contained in:
DianaV 2026-09-11 11:16:39 +00:00 committed by GitHub
commit 352e84f300
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 328 additions and 95 deletions

View File

@ -157,6 +157,16 @@ define(req, function(AppConfig, Default, Language) {
}
};
// XXX
Messages.form_guestAuthorTitle = "Save your author link before sharing";
Messages.form_guestEditLinkDefinition = "This form's author link is the private link to modify questions and read responses.";
Messages.form_guestAuthorBody = "This author link is currently not stored anywhere since you are not logged in. To avoid loosing access in future please save this link now:";
Messages.form_guestAuthorBodyStored = "This author link is currently only stored on this device, please save it to avoid loosing access to your form.";
Messages.form_guestAuthorCopied = "Author link copied";
Messages.form_guestAuthorCopy = "Copy author link";
Messages.form_guestAuthorContinuePublic = "Continue to public link";
Messages.form_guestPublicTitle = "Copy your public link";
Messages.form_guestPublicBody = "Share this link with participants so they can fill out your form.";
return Messages;
});

View File

@ -119,15 +119,16 @@
.cp-creation-checkboxes {
min-width: 300px;
flex-flow: column;
align-items: baseline !important;
max-height: 150px;
min-height: 120px !important;
align-items: stretch !important;
max-height: 180px;
min-height: 140px !important;
justify-content: space-evenly;
flex: 1;
& > div {
display: flex;
width: 100%;
max-width: 100%;
min-width: 0;
margin: auto;
text-align: left;
}
@ -258,40 +259,76 @@
}
.cp-creation-teams {
display: none !important;
.cp-creation-teams-grid {
display: flex;
flex-wrap: wrap;
padding: 0 2px;
flex: 1;
display: flex;
align-items: center;
gap: 0.5rem;
min-width: 0;
width: 100%;
.cp-creation-store-label,
.cp-creation-help {
flex: none;
}
.cp-creation-team {
.avatar_main(25px);
width: 140px;
height: 35px;
display: flex;
justify-content: center;
.cp-creation-team-avatar {
.avatar_main(20px);
flex: none;
display: inline-flex;
align-items: center;
padding: 5px;
cursor: default;
font: @colortheme_app-font;
margin: 0 1px;
.tools_unselectable();
&.cp-selected {
background-color: @cp_creation-button-bg;
color: @cp_creation-button-fg;
justify-content: center;
svg, .lucide {
margin: 0;
}
.cp-creation-team-name {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.cp-creation-team-name {
flex: 1 1 0;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: left;
}
.cp-dropdown-container {
flex: 1 1 0;
width: 0;
min-width: 0;
button.btn {
width: 100%;
text-align: center;
line-height: 18px;
justify-content: flex-start;
overflow: hidden;
color: @cp_creation-fg;
background: @cp_forms-bg;
border: 1px solid @cp_forms-border;
text-transform: none;
.cp-dropdown-button-title {
flex: 1 1 0;
min-width: 0;
display: flex;
align-items: center;
justify-content: flex-start;
gap: 0.5rem;
overflow: hidden;
text-align: left;
}
}
.cp-dropdown-content {
left: 0;
right: 0;
width: 100%;
min-width: 0;
max-width: 100%;
box-sizing: border-box;
overflow-x: hidden;
li[role="menuitem"] {
overflow: hidden;
> a {
display: flex;
align-items: center;
gap: 0.5rem;
min-width: 0;
max-width: 100%;
overflow: hidden;
}
}
}
border: 1px solid @cp_creation-button-bg;
}
}

View File

@ -2814,55 +2814,79 @@ define([
}
// Team pad
var team;
// FIXME: broken wen cache is enabled
var teamExists = privateData.teams && Object.keys(privateData.teams).length;
var teamValue;
// storeInTeam can be
// * a team ID ==> store in the team drive, and the team will be the owner
// * -1 ==> store in the user drive, and the user will be the owner
// * undefined ==> ask
if (teamExists) {
var teams = Object.keys(privateData.teams).map(function (id) {
var data = privateData.teams[id];
var avatar = h('span.cp-creation-team-avatar.cp-avatar');
// We assume that teams always have a non-empty name, so we don't need a UID
common.displayAvatar($(avatar), data.avatar, data.name);
return h('div.cp-creation-team', {
'data-id': id,
title: data.name,
},[
avatar,
h('span.cp-creation-team-name', data.name)
]);
});
teams.unshift(h('div.cp-creation-team', {
'data-id': '-1',
title: Messages.settings_cat_drive
}, [
h('span.cp-creation-team-avatar', Icons.get('drive')),
h('span.cp-creation-team-name', Messages.settings_cat_drive)
]));
team = h('div.cp-creation-teams', [
Messages.team_pcsSelectLabel,
h('div.cp-creation-teams-grid', teams),
createHelper('#', Messages.team_pcsSelectHelp)
]);
var $team = $(team);
$team.find('.cp-creation-team').click(function () {
if ($(this).hasClass('cp-selected')) {
teamValue = undefined;
return void $(this).removeClass('cp-selected');
}
$team.find('.cp-creation-team').removeClass('cp-selected');
$(this).addClass('cp-selected');
teamValue = $(this).attr('data-id');
});
if (privateData.storeInTeam) {
$team.find('[data-id="'+privateData.storeInTeam+'"]').addClass('cp-selected');
teamValue = privateData.storeInTeam;
// * undefined ==> ask (CryptDrive / team / don't store); default CryptDrive
var team;
var teamValue = typeof(privateData.storeInTeam) === "undefined" ? '-1' : String(privateData.storeInTeam);
var getTeamLabel = function (val) {
if (val === '-1') { return Messages.settings_cat_drive; }
if (!val || val === 'none') { return Messages.autostore_hide; }
return privateData.teams?.[val]?.name || val;
};
var getTeamAvatar = function (val) {
if (val === '-1') {
return h('span.cp-creation-team-avatar', Icons.get('drive'));
}
}
if (!val || val === 'none') {
return h('span.cp-creation-team-avatar', Icons.get('close'));
}
var data = privateData.teams?.[val];
var avatar = h('span.cp-creation-team-avatar.cp-avatar');
if (data) {
common.displayAvatar($(avatar), data.avatar, data.name);
}
return avatar;
};
var teamOptions = [{
tag: 'a',
attributes: { 'data-value': '-1' },
content: [getTeamAvatar('-1'), h('span.cp-creation-team-name', getTeamLabel('-1'))]
}];
Object.keys(privateData.teams || {}).forEach(function (id) {
var data = privateData.teams[id];
if (!data) { return; }
teamOptions.push({
tag: 'a',
attributes: { 'data-value': id },
content: [getTeamAvatar(id), h('span.cp-creation-team-name', data.name)]
});
});
teamOptions.push({
tag: 'a',
attributes: { 'data-value': 'none' },
content: [getTeamAvatar('none'), h('span.cp-creation-team-name', getTeamLabel('none'))]
});
var $teamSelect = UIElements.createDropdown({
text: getTeamLabel(teamValue),
options: teamOptions,
isSelect: true,
caretDown: true,
initialValue: teamValue,
buttonTitle: getTeamLabel(teamValue),
common: common
});
var $teamBtn = $teamSelect.find('button').addClass('btn');
var setTeamButton = function (val) {
var label = getTeamLabel(val);
$teamBtn[0]?._tippy?.destroy();
$teamBtn.attr('title', label);
$teamBtn.find('.cp-dropdown-button-title').empty().append([
getTeamAvatar(val),
h('span.cp-creation-team-name', label)
]);
};
setTeamButton(teamValue);
$teamSelect.onChange.reg(function (text, value) {
teamValue = typeof(value) === "undefined" ? 'none' : String(value);
setTeamButton(teamValue);
});
team = h('div.cp-creation-teams', [
h('span.cp-creation-store-label', Messages.team_pcsSelectLabel),
$teamSelect[0],
// createHelper('#', Messages.team_pcsSelectHelp) - commented until the documentation is updated
]);
// Owned pads
@ -3145,9 +3169,16 @@ define([
var templateContent = $template.data('content') || undefined;
// Team
var team;
if (teamValue) {
team = privateData.teams[teamValue] || {};
team.id = Number(teamValue);
if (teamValue === 'none') {
team = false;
} else if (teamValue === '-1') {
team = { id: -1 };
} else if (teamValue) {
var selectedTeam = privateData.teams[teamValue] || {};
team = {
id: Number(teamValue),
edPublic: selectedTeam.edPublic
};
}
return {

View File

@ -1151,6 +1151,13 @@ define([
data.href = parsed.getUrl({present: parsed.present});
if (typeof (data.title) !== "string") { return cb('Missing title'); }
if (common.initialTeam === false) {
if (!data.forceSave) {
common.autoStore.onStoreRequest.fire({});
return void cb(null, { notStored: true });
}
delete common.initialTeam;
}
if (common.initialTeam) {
// If the value is -1, it means the user drive was selected from the pad creation screen

View File

@ -1179,6 +1179,11 @@ define([
openURL(url);
});
sframeChan.on('EV_OPEN_URL', openURL);
sframeChan.on('EV_OPEN_VIEW_URL', function () {
if (!hashes || !hashes.viewHash) { return; }
var a = window.open(Utils.Hash.hashToHref(hashes.viewHash, 'form'));
if (!a) { _sframeChan.event('EV_POPUP_BLOCKED'); }
});
sframeChan.on('Q_GET_PAD_METADATA', function (data, cb) {
if (!data || !data.channel) {
@ -1765,7 +1770,9 @@ define([
});
sframeChan.on('Q_SAVE_AS_TEMPLATE', function (data, cb) {
data.teamId = Cryptpad.initialTeam;
if (Cryptpad.initialTeam) {
data.teamId = Cryptpad.initialTeam;
}
Cryptpad.saveAsTemplate(Cryptget.put, data, cb);
});
@ -2279,12 +2286,8 @@ define([
});
});
});
sframeChan.on('EV_OPEN_VIEW_URL', function () {
var url = Utils.Hash.hashToHref(hashes.viewHash, 'form');
var a = window.open(url);
if (!a) {
sframeChan.event('EV_POPUP_BLOCKED');
}
sframeChan.on('EV_FORM_GUEST_SHARE_OPEN', function (data) {
initSecureModal('formGuestShare', data || {});
});
Handler.formCommandHandlers(sframeChan, Utils, nThen, Cryptpad);
@ -2537,8 +2540,12 @@ define([
if (cfg.integration) { rtConfig.metadata.selfdestruct = true; }
if (data.team) {
if (data.team === false) {
Cryptpad.initialTeam = false;
} else if (data.team) {
Cryptpad.initialTeam = data.team.id;
} else {
delete Cryptpad.initialTeam;
}
if (data.owned && data.team && data.team.edPublic) {
rtConfig.metadata.owners = [data.team.edPublic];

View File

@ -17,7 +17,6 @@ define([
'/common/common-hash.js',
'/common/common-interface.js',
'/common/common-ui-elements.js',
'/common/clipboard.js',
'/common/inner/common-mediatag.js',
'/common/hyperscript.js',
'/customize/messages.js',
@ -66,7 +65,6 @@ define([
Hash,
UI,
UIElements,
Clipboard,
MT,
h,
Messages,
@ -4908,14 +4906,35 @@ define([
Messages.form_geturl
]);
var preview = h('div.cp-forms-results-participant', [previewBtn, participantBtn]);
var shouldWarnGuestAuthor = function () {
if (framework._.sfCommon.isLoggedIn()) { return false; }
if (!APP.isEditor) { return false; }
return true;
};
var warnGuestAuthorThen = function (next) {
framework._.sfCommon.isPadStored(function (err, stored) {
sframeChan.event('EV_FORM_GUEST_SHARE_OPEN', {
next: next,
stored: Boolean(stored)
});
});
};
$(previewBtn).click(function () {
sframeChan.event('EV_OPEN_VIEW_URL');
if (!shouldWarnGuestAuthor()) {
return void sframeChan.event('EV_OPEN_VIEW_URL');
}
warnGuestAuthorThen('preview');
});
$(participantBtn).click(function () {
sframeChan.query('Q_COPY_VIEW_URL', null, function (err, success) {
if (success) { return void UI.log(Messages.shareSuccess); }
UI.warn(Messages.error);
});
if (!shouldWarnGuestAuthor()) {
sframeChan.query('Q_COPY_VIEW_URL', null, function (err, success) {
if (success) { return void UI.log(Messages.shareSuccess); }
UI.warn(Messages.error);
});
return;
}
warnGuestAuthorThen('public');
});
// Private / public status

View File

@ -106,4 +106,9 @@
}
}
}
.alertify .cp-form-guest-share-modal {
h4, h5, h6, p, textarea {
color: @cryptpad_text_col;
}
}
}

View File

@ -46,6 +46,123 @@ define([
};
var create = {};
create['formGuestShare'] = function (data) {
data = data || {};
require(['/common/clipboard.js'], function (Clipboard) {
var priv = metadataMgr.getPrivateData();
var hashes = priv.hashes || {};
var origin = priv.origin || '';
var editUrl = hashes.editHash ?
(origin + Hash.hashToHref(hashes.editHash, 'form')) : '';
var viewUrl = hashes.viewHash ?
(origin + Hash.hashToHref(hashes.viewHash, 'form')) : '';
var showPublic = function () {
if (!viewUrl) { return void hideIframe(); }
var frame;
var modal = UI.dialog.customModal(h('div.cp-form-guest-share-modal', [
h('h4', Messages.form_guestPublicTitle),
h('p', Messages.form_guestPublicBody),
UI.dialog.selectableArea(viewUrl, {
id: 'cp-form-guest-public-link',
rows: 2
})
]), {
onClose: function () {
if (displayed === frame) { hideIframe(); }
},
buttons: [{
className: 'cancel',
name: Messages.cancel,
onClick: function () {},
keys: [27]
}, {
className: 'primary',
name: Messages.form_geturl,
iconClass: 'copy',
onClick: function () {
Clipboard.copy(viewUrl, function (err) {
if (err) { return void UI.warn(Messages.error); }
UI.log(Messages.shareSuccess);
hideIframe();
});
return true;
},
keys: [13]
}]
});
frame = UI.openCustomModal(modal);
displayed = frame;
};
var showAuthor = function () {
if (!editUrl) {
if (data.next === 'public') { return void showPublic(); }
if (data.next === 'preview') {
sframeChan.event('EV_OPEN_VIEW_URL');
}
return void hideIframe();
}
var frame;
var stay;
var modal = UI.dialog.customModal(h('div.cp-form-guest-share-modal', [
h('h4', Messages.form_guestAuthorTitle),
h('p', Messages.form_guestEditLinkDefinition),
h('p', data.stored ?
Messages.form_guestAuthorBodyStored : Messages.form_guestAuthorBody),
UI.dialog.selectableArea(editUrl, {
id: 'cp-form-guest-author-link',
rows: 2
})
]), {
onClose: function () {
if (stay || displayed !== frame) { return; }
hideIframe();
},
buttons: [{
className: 'cancel',
name: Messages.cancel,
onClick: function () {},
keys: [27]
}, {
className: 'secondary',
name: Messages.form_guestAuthorCopy,
iconClass: 'copy',
onClick: function () {
Clipboard.copy(editUrl, function (err) {
if (err) { return void UI.warn(Messages.error); }
UI.log(Messages.form_guestAuthorCopied);
});
return true;
},
keys: []
}, {
className: 'primary',
name: data.next === 'public' ?
Messages.form_guestAuthorContinuePublic : Messages.continue,
onClick: function () {
if (data.next === 'public') {
stay = true;
if (frame && frame.closeModal) {
frame.closeModal(showPublic);
} else {
showPublic();
}
return true;
}
if (data.next === 'preview') {
sframeChan.event('EV_OPEN_VIEW_URL');
}
},
keys: [13]
}]
});
frame = UI.openCustomModal(modal);
displayed = frame;
};
showAuthor();
});
};
// Share modal
create['share'] = function (data) {