diff --git a/public/javascripts/speed_grader.js b/public/javascripts/speed_grader.js index bee8181ed77..fde546710a5 100644 --- a/public/javascripts/speed_grader.js +++ b/public/javascripts/speed_grader.js @@ -114,6 +114,8 @@ let anonymizableStudentId let anonymizableAuthorId let isModerated +let commentSubmissionInProgress + let $window let $full_width_container let $left_side @@ -2860,6 +2862,13 @@ EG = { }, addSubmissionComment(draftComment) { + // Avoid submitting additional comments if a request is already in progress. + // This can happen if the user submits a comment and then switches students + // (which attempts to save a draft comment) before the request finishes. + if (commentSubmissionInProgress) { + return false + } + // This is to continue existing behavior of creating finalized comments by default if (draftComment === undefined) { draftComment = false @@ -2875,6 +2884,8 @@ EG = { // that means that they did not type a comment, attach a file or record any media. so dont do anything. return false } + + commentSubmissionInProgress = true const url = `${assignmentUrl}/${isAnonymous ? 'anonymous_' : ''}submissions/${ EG.currentStudent[anonymizableId] }` @@ -2909,11 +2920,13 @@ EG = { window.setTimeout(() => { $rightside_inner.scrollTo($rightside_inner[0].scrollHeight, 500) }) + commentSubmissionInProgress = false } const formError = (data, _xhr, _textStatus, _errorThrown) => { EG.handleGradingError(data) EG.revertFromFormSubmit({errorSubmitting: true}) + commentSubmissionInProgress = false } if ($add_a_comment.find("input[type='file']:visible").length) { @@ -3759,6 +3772,8 @@ export default { speedGraderJSONErrorFn ) + commentSubmissionInProgress = false + $.when(getGradingPeriods(), speedGraderJsonDfd).then(setupSpeedGrader) // run the stuff that just attaches event handlers and dom stuff, but does not need the jsonData diff --git a/spec/javascripts/jsx/speed_graderSpec.js b/spec/javascripts/jsx/speed_graderSpec.js index 7607b9bb715..d7aeb06ffb9 100644 --- a/spec/javascripts/jsx/speed_graderSpec.js +++ b/spec/javascripts/jsx/speed_graderSpec.js @@ -4630,6 +4630,48 @@ QUnit.module('SpeedGrader', rootHooks => { revertFromFormSubmit.restore() }) + + test('does not submit a comment request if one is already in progress', () => { + $.ajaxJSON.resetHistory() + + SpeedGrader.EG.addSubmissionComment('hello') + SpeedGrader.EG.addSubmissionComment('hello???') + strictEqual($.ajaxJSON.callCount, 1) + }) + + test('submits a comment request if the preceding request succeeded', () => { + $.ajaxJSON.resetHistory() + $.ajaxJSON.callsFake((_url, _method, _form, success, _error) => { + sinon.stub(SpeedGrader.EG, 'revertFromFormSubmit') + sinon.stub(window, 'setTimeout') + + success([]) + + window.setTimeout.restore() + SpeedGrader.EG.revertFromFormSubmit.restore() + }) + + SpeedGrader.EG.addSubmissionComment('ok') + SpeedGrader.EG.addSubmissionComment('ok!') + strictEqual($.ajaxJSON.callCount, 2) + }) + + test('submits a comment request if the preceding request failed', () => { + $.ajaxJSON.resetHistory() + $.ajaxJSON.callsFake((_url, _method, _form, _success, error) => { + sinon.stub(SpeedGrader.EG, 'revertFromFormSubmit') + sinon.stub(SpeedGrader.EG, 'handleGradingError') + + error() + + SpeedGrader.EG.handleGradingError.restore() + SpeedGrader.EG.revertFromFormSubmit.restore() + }) + + SpeedGrader.EG.addSubmissionComment('no') + SpeedGrader.EG.addSubmissionComment('noooooo') + strictEqual($.ajaxJSON.callCount, 2) + }) }) QUnit.module('#handleGradeSubmit', hooks => {