diff --git a/src/moin/apps/frontend/views.py b/src/moin/apps/frontend/views.py index 1fff185d3..187c78134 100644 --- a/src/moin/apps/frontend/views.py +++ b/src/moin/apps/frontend/views.py @@ -2645,22 +2645,19 @@ class UserSettingsUIForm(Form): # if no flash message was added until here, we add a generic success message msg = _("Your changes have been saved.") response["flash"].append((msg, "info")) - repeat_flash_msg(msg, "info") - - if response["redirect"] is not None or not is_xhr: - # if we redirect or it is no XHR request, we just flash() the messages normally - for f in response["flash"]: - flash(*f) if is_xhr: # if it is a XHR request, render the part from the usersettings_ajax.html template # and send the response encoded as an JSON object response["form"] = render_template("usersettings_ajax.html", part=part, form=form) return jsonify(**response) - else: - # if it is not a XHR request but there is an redirect pending, we use a normal HTTP redirect - if response["redirect"] is not None: - return redirect(response["redirect"]) + + # if it is not a XHR request but there is an redirect pending, we use a normal HTTP redirect + if response["redirect"] is not None: + # if we redirect, we just flash() the messages normally + for f in response["flash"]: + flash(*f) + return redirect(response["redirect"]) # if the view did not return until here, we add the current form to the forms dict # and continue with rendering the normal template diff --git a/src/moin/static/css/common.css b/src/moin/static/css/common.css index f92bcd8ad..c7d057f4a 100644 --- a/src/moin/static/css/common.css +++ b/src/moin/static/css/common.css @@ -182,10 +182,15 @@ a.moin-nonexistent object { background: var(--bg-disabled); border: 3px dashed /* end of links */ /* misc highlighting */ -.moin-error:before { content: url("../img/icons/admon-warning.png"); float: left; height: 100%; padding: 0 1em; } -.moin-error { color: var(--error); background-color: var(--bg-error); +.moin-error:before { content: url("../img/icons/admon-warning.png"); float: left; height: 100%; padding: 0 .5em; } +.moin-error:not(input) { + color: var(--error); + background-color: var(--bg-error); border: 1px solid var(--border); - margin: 10px 30px 10px 30px; min-height: 64px; padding: 8px 8px 8px 8px; clear: both; display: inline-block; } + border-radius: 4px; + margin-top: .5em; + min-height: 12px; + padding: 8px 8px 8px 8px; clear: both; display: inline-block; } .moin-highlight { background-color: var(--bg-hilite); padding: 1px; } .moin-showhide { margin-left: 10px; } .moin-disabled { color: var(--disabled); } @@ -609,6 +614,8 @@ li.moin-selected-groups { font-size: 1em; font-weight: bold; } .moin-form .submit-buttons{ display: flex; column-gap: 8pt; justify-content: end; margin: 8pt 0; } +.moin-form input.moin-error { color: var(--error) } + #options dd { width: 10%; } #options dt { width: 60%; max-width: 40em; } #subscriptions textarea, diff --git a/src/moin/static/js/common.js b/src/moin/static/js/common.js index ea77bbf95..a18bfcdac 100644 --- a/src/moin/static/js/common.js +++ b/src/moin/static/js/common.js @@ -471,7 +471,6 @@ MoinMoin.prototype.enhanceUserSettings = function () { // send the form to the server $.post(form.attr('action'), form.serialize(), function (data) { - var i, f, newform; clearInterval(buttonDotAnimation); // if the response indicates a redirect, set the new location if (data.redirect) { @@ -480,7 +479,7 @@ MoinMoin.prototype.enhanceUserSettings = function () { return; } // get the new form element from the response - newform = $(data.form); + const newform = $(data.form); // set event handlers on the new form newform.submit(submitHandler); newform.change(changeHandler); @@ -488,7 +487,13 @@ MoinMoin.prototype.enhanceUserSettings = function () { newform.data('initialForm', newform.serialize()); // replace the old form with the new one form.replaceWith(newform); - if (ev.currentTarget.id === 'usersettings_ui' || ev.currentTarget.id === 'usersettings_personal') { + // check if form processing gave back an error; don't reload the page + // in case an error is present as this would cause validation error + // messages present in 'newform' to get lost. + const has_error = 'flash' in data && data.flash[0][1] === 'error'; + if ((ev.currentTarget.id === 'usersettings_ui' || ev.currentTarget.id === 'usersettings_personal') && + !has_error + ) { MoinMoin.prototype.saveFlashMessages(data.flash) // theme or language may have changed, show user the new theme/language location.reload(true); diff --git a/src/moin/templates/forms.html b/src/moin/templates/forms.html index 6d4af60b4..de956595e 100644 --- a/src/moin/templates/forms.html +++ b/src/moin/templates/forms.html @@ -12,7 +12,7 @@ {%- if field.errors %}
{%- for error in field.errors %} -

{{ error }}

+ {{ error }} {% endfor %}
{% endif %}