diff --git a/www/form/app-form.less b/www/form/app-form.less index 43e534e63..d1ca4da88 100644 --- a/www/form/app-form.less +++ b/www/form/app-form.less @@ -477,13 +477,19 @@ .cp-form-anon-answer { text-align: center; margin: 20px 0 30px 0; + .cp-form-required-radio.cp-radio-required { + background: fade(@cryptpad_text_col, 15%); + padding: 3px; + border: 2px solid @cryptpad_color_red; + color: @cp_form-invalid; + } .cp-form-anon-answer-input { - margin-top: 20px; display: flex; white-space: nowrap; align-items: center; input { margin-left: 10px; + display: inline-block; } } .cp-form-anon-answer-registered { diff --git a/www/form/inner.js b/www/form/inner.js index 2f7cdf7b1..e6e2af133 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -2723,7 +2723,7 @@ define([ var answer = obj.msg; var date = new Date(obj.time).toLocaleString(); var text, warning, badge; - if (!answer._userdata || !answer._userdata.name) { + if (!answer._userdata || (!answer._userdata.name && !answer._userdata.curvePublic)) { text = Messages._getKey('form_answerAnonymous', [date]); } else { var ud = answer._userdata; @@ -3022,69 +3022,81 @@ define([ if (!loggedIn && !content.answers.anonymous) { return; } - var cbox; - var anonName, $anonName; - cbox = UI.createCheckbox('cp-form-anonymous', - Messages.form_anonymousBox, true, {}); - var $cbox = $(cbox); - var $anonBox = $cbox.find('input'); + var $anonName; + var anonRadioOn = UI.createRadio('cp-form-anon', 'cp-form-anon-on', + Messages.form_anonymousBox, false, { + input: { value: 1 }, + }); + var anonOffContent = h('span'); + var anonRadioOff = UI.createRadio('cp-form-anon', 'cp-form-anon-off', + anonOffContent, false, { + input: { value: 0 }, + }); + var radioContainer = h('div.cp-form-required-radio', [ + anonRadioOn, + anonRadioOff, + ]); + var $radio = $(radioContainer); + + if (content.answers.makeAnonymous) { // If we make all answers anonymous, hide the checkbox and display a message - $cbox.hide(); - $anonBox.attr('disabled', 'disabled').prop('checked', true); + $radio.hide(); + $(anonRadioOn).find('input').prop('checked', true); setTimeout(function () { // We need to wait for cbox to be added into the DOM before using .after() - $cbox.after(h('div.alert.alert-info', Messages.form_anonAnswer)); + $radio.after(h('div.alert.alert-info', Messages.form_anonAnswer)); }); } else if (content.answers.anonymous) { // Answers aren't anonymous and guests are allowed // Guests can set a username and logged in users can answer anonymously - var $anon; if (!loggedIn) { - anonName = h('div.cp-form-anon-answer-input', [ + $(anonOffContent).append(h('span.cp-form-anon-answer-input', [ Messages.form_answerAs, h('input', { value: user.name || '', placeholder: Messages.form_anonName }) - ]); - $anonName = $(anonName).hide(); + ])); + $anonName = $(anonOffContent).find('input'); + var $off = $(anonRadioOff).find('input[type="radio"]'); + $anonName.on('click input', function () { + if (!Util.isChecked($off)) { $off.prop('checked', true); } + }); } else if (APP.cantAnon) { // You've already answered with your credentials - $cbox.hide(); - $anonBox.attr('disabled', 'disabled').prop('checked', false); + $(anonRadioOn).find('input').attr('disabled', 'disabled'); + $(anonRadioOff).find('input[type="radio"]').prop('checked', true); } - if (!anonName) { - anonName = h('div.cp-form-anon-answer-input', [ + if (!$anonName) { + $(anonOffContent).append(h('div.cp-form-anon-answer-input', [ Messages.form_answerAs, h('span.cp-form-anon-answer-registered', user.name || Messages.anonymous) - ]); + ])); } - if (!APP.cantAnon) { - $anon = $(anonName).hide(); - $anonBox.on('change', function () { - if (Util.isChecked($anonBox)) { $anon.hide(); } - else { $anon.show(); } + if (!$radio.find('input[type="radio"]:checked').length) { + $radio.addClass('cp-radio-required'); + $radio.find('input[type="radio"]').on('change', function () { + $radio.removeClass('cp-radio-required'); }); } } else { // Answers don't have to be anonymous and only logged in users can answer // ==> they have to answer with their keys so we know their name too - $cbox.hide(); - $anonBox.attr('disabled', 'disabled').prop('checked', false); + $(anonRadioOn).find('input').attr('disabled', 'disabled'); + $(anonRadioOff).find('input[type="radio"]').prop('checked', true); setTimeout(function () { // We need to wait for cbox to be added into the DOM before using .after() if (content.answers.cantEdit) { return; } - $cbox.after(h('div.alert.alert-info', Messages.form_authAnswer)); + $radio.after(h('div.alert.alert-info', Messages.form_authAnswer)); }); - anonName = h('div.cp-form-anon-answer-input', [ + $(anonOffContent).append(h('div.cp-form-anon-answer-input', [ Messages.form_answerAs, h('span.cp-form-anon-answer-registered', user.name || Messages.anonymous) - ]); + ])); } if (APP.hasAnswered && content.answers.cantEdit || APP.isClosed) { - $cbox.hide(); - anonName = undefined; + $radio.hide(); } var send = h('button.cp-open.btn.btn-primary', APP.hasAnswered ? Messages.form_update : Messages.form_submit); @@ -3098,12 +3110,18 @@ define([ evOnChange.fire(); }); var $send = $(send).click(function () { + if (!$radio.find('input[type="radio"]:checked').length) { + return UI.warn(Messages.error); + } + $send.attr('disabled', 'disabled'); var results = getFormResults(); if (!results) { return; } + var wantName = Util.isChecked($(anonRadioOff).find('input[type="radio"]')); + var user = metadataMgr.getUserData(); - if (!Util.isChecked($anonBox) && !content.answers.makeAnonymous) { + if (wantName && !content.answers.makeAnonymous) { results._userdata = loggedIn ? { avatar: user.avatar, name: user.name, @@ -3111,7 +3129,7 @@ define([ curvePublic: user.curvePublic, profile: user.profile } : { - name: $anonName ? $anonName.find('input').val() : user.name + name: $anonName ? $anonName.val() : user.name }; } @@ -3120,7 +3138,7 @@ define([ mailbox: content.answers, results: results, anonymous: content.answers.makeAnonymous || !loggedIn - || (Util.isChecked($anonBox) && !APP.cantAnon) // use ephemeral keys + || (!wantName && !APP.cantAnon) // use ephemeral keys }, function (err, data) { $send.attr('disabled', 'disabled'); if (err || (data && data.error)) { @@ -3130,6 +3148,11 @@ define([ console.error(err || data.error); return void UI.warn(Messages.error); } + if (results._userdata && loggedIn) { + $(anonRadioOn).find('input').attr('disabled', 'disabled'); + $(anonRadioOff).find('input[type="radio"]').prop('checked', true); + APP.cantAnon = true; + } evOnChange.fire(false, true); window.onbeforeunload = undefined; @@ -3139,8 +3162,7 @@ define([ APP.answeredInForm = false; showAnsweredPage(framework, content, { '_time': +new Date() }); if (content.answers.cantEdit) { - $cbox.hide(); - if ($anonName) { $anonName.hide(); } + $(radioContainer).hide(); } }); }); @@ -3248,10 +3270,9 @@ define([ return h('div.cp-form-send-container', [ invalid, errors, - cbox ? h('div.cp-form-anon-answer', [ - cbox, - anonName - ]) : undefined, + h('div.cp-form-anon-answer', [ + radioContainer + ]), reset, send ]); };