Use "is-loading" to avoid duplicate form submit for code comment (#28143) (#28147)

Backport #28143 by @wxiaoguang

Compare by ignoring spaces:
https://github.com/go-gitea/gitea/pull/28143/files?diff=split&w=1

When the form is going to be submitted, add the "is-loading" class to
show an indicator and avoid user UI events.

When the request finishes (success / error), remove the "is-loading"
class to make user can interact the UI.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
(cherry picked from commit ffab076b72)
This commit is contained in:
Giteabot 2023-11-21 12:02:58 +08:00 committed by Earl Warren
parent e627592402
commit 2969745b0c
No known key found for this signature in database
GPG key ID: 0579CB2928A78A00

View file

@ -6,8 +6,9 @@ import {initDiffCommitSelect} from './repo-diff-commitselect.js';
import {validateTextareaNonEmpty} from './comp/ComboMarkdownEditor.js'; import {validateTextareaNonEmpty} from './comp/ComboMarkdownEditor.js';
import {initViewedCheckboxListenerFor, countAndUpdateViewedFiles, initExpandAndCollapseFilesButton} from './pull-view-file.js'; import {initViewedCheckboxListenerFor, countAndUpdateViewedFiles, initExpandAndCollapseFilesButton} from './pull-view-file.js';
import {initImageDiff} from './imagediff.js'; import {initImageDiff} from './imagediff.js';
import {showErrorToast} from '../modules/toast.js';
const {csrfToken, pageData} = window.config; const {csrfToken, pageData, i18n} = window.config;
function initRepoDiffReviewButton() { function initRepoDiffReviewButton() {
const $reviewBox = $('#review-box'); const $reviewBox = $('#review-box');
@ -50,26 +51,34 @@ function initRepoDiffConversationForm() {
return; return;
} }
const formData = new FormData($form[0]); if ($form.hasClass('is-loading')) return;
try {
$form.addClass('is-loading');
const formData = new FormData($form[0]);
// if the form is submitted by a button, append the button's name and value to the form data // if the form is submitted by a button, append the button's name and value to the form data
const submitter = e.originalEvent?.submitter; const submitter = e.originalEvent?.submitter;
const isSubmittedByButton = (submitter?.nodeName === 'BUTTON') || (submitter?.nodeName === 'INPUT' && submitter.type === 'submit'); const isSubmittedByButton = (submitter?.nodeName === 'BUTTON') || (submitter?.nodeName === 'INPUT' && submitter.type === 'submit');
if (isSubmittedByButton && submitter.name) { if (isSubmittedByButton && submitter.name) {
formData.append(submitter.name, submitter.value); formData.append(submitter.name, submitter.value);
} }
const formDataString = String(new URLSearchParams(formData)); const formDataString = String(new URLSearchParams(formData));
const $newConversationHolder = $(await $.post($form.attr('action'), formDataString)); const $newConversationHolder = $(await $.post($form.attr('action'), formDataString));
const {path, side, idx} = $newConversationHolder.data(); const {path, side, idx} = $newConversationHolder.data();
$form.closest('.conversation-holder').replaceWith($newConversationHolder); $form.closest('.conversation-holder').replaceWith($newConversationHolder);
if ($form.closest('tr').data('line-type') === 'same') { if ($form.closest('tr').data('line-type') === 'same') {
$(`[data-path="${path}"] .add-code-comment[data-idx="${idx}"]`).addClass('gt-invisible'); $(`[data-path="${path}"] .add-code-comment[data-idx="${idx}"]`).addClass('gt-invisible');
} else { } else {
$(`[data-path="${path}"] .add-code-comment[data-side="${side}"][data-idx="${idx}"]`).addClass('gt-invisible'); $(`[data-path="${path}"] .add-code-comment[data-side="${side}"][data-idx="${idx}"]`).addClass('gt-invisible');
}
$newConversationHolder.find('.dropdown').dropdown();
initCompReactionSelector($newConversationHolder);
} catch { // here the caught error might be a jQuery AJAX error (thrown by await $.post), which is not good to use for error message handling
showErrorToast(i18n.network_error);
} finally {
$form.removeClass('is-loading');
} }
$newConversationHolder.find('.dropdown').dropdown();
initCompReactionSelector($newConversationHolder);
}); });
$(document).on('click', '.resolve-conversation', async function (e) { $(document).on('click', '.resolve-conversation', async function (e) {