Commit 6b931451 by Will Daly

Allow the user to confirm/cancel before submitting a response

parent 8c0e01b1
......@@ -40,6 +40,21 @@ describe("OpenAssessment.ResponseView", function() {
// View under test
var view = null;
// Control whether the confirmation stub
// simulates a user confirming the submission or cancelling it.
var stubConfirm = true;
/**
Set whether the user confirms or cancels the submission.
Args:
didConfirm(bool): If true, simulate that the user confirmed the submission;
otherwise, simulate that the user cancelled the submission.
**/
var setStubConfirm = function(didConfirm) {
stubConfirm = didConfirm;
};
beforeEach(function() {
// Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
......@@ -55,6 +70,18 @@ describe("OpenAssessment.ResponseView", function() {
var el = $('#openassessment-base').get(0);
view = new OpenAssessment.ResponseView(el, server, baseView);
view.installHandlers();
// Stub the confirmation step
// By default, we simulate the user confirming the submission.
// To instead simulate the user cancelling the submission,
// set `stubConfirm` to false.
setStubConfirm(true);
spyOn(view, 'confirmSubmission').andCallFake(function() {
return $.Deferred(function(defer) {
if (stubConfirm) { defer.resolve(); }
else { defer.reject(); }
});
});
});
it("updates submit/save buttons and save status when response text changes", function() {
......@@ -132,6 +159,19 @@ describe("OpenAssessment.ResponseView", function() {
expect(server.submit).toHaveBeenCalledWith('Test response');
});
it("allows the user to cancel before submitting", function() {
// Simulate the user cancelling the submission
setStubConfirm(false);
spyOn(server, 'submit').andCallThrough();
// Start a submission
view.response('Test response');
view.submit();
// Expect that the submission was not sent to the server
expect(server.submit).not.toHaveBeenCalled();
});
it("disables the submit button on submission", function() {
// Prevent the server's response from resolving,
// so we can see what happens before view gets re-rendered.
......@@ -159,6 +199,19 @@ describe("OpenAssessment.ResponseView", function() {
expect(view.submitEnabled()).toBe(true);
});
it("re-enables the submit button after cancelling", function() {
// Simulate the user cancelling the submission
setStubConfirm(false);
spyOn(server, 'submit').andCallThrough();
// Start a submission
view.response('Test response');
view.submit();
// Expect the submit button to be re-enabled
expect(view.submitEnabled()).toBe(true);
});
it("moves to the next step on duplicate submission error", function() {
// Simulate a "multiple submissions" server error
spyOn(server, 'submit').andCallFake(function() {
......
......@@ -216,32 +216,67 @@ OpenAssessment.ResponseView.prototype = {
// Immediately disable the submit button to prevent multiple submission
this.submitEnabled(false);
// Send the submission to the server
var submission = $('#submission__answer__value', this.element).val();
this.baseView.toggleActionError('response', null);
var view = this;
var baseView = this.baseView;
var moveToNextStep = function() {
view.load();
baseView.renderPeerAssessmentStep();
};
this.server.submit(submission)
.done(moveToNextStep)
this.confirmSubmission()
// On confirmation, send the submission to the server
// The callback returns a promise so we can attach
// additional callbacks after the confirmation.
// NOTE: in JQuery >=1.8, `pipe()` is deprecated in favor of `then()`,
// but we're using JQuery 1.7 in the LMS, so for now we're stuck with `pipe()`.
.pipe(function() {
var submission = $('#submission__answer__value', view.element).val();
baseView.toggleActionError('response', null);
// Send the submission to the server, returning the promise.
return view.server.submit(submission);
})
// If the submission was submitted successfully, move to the next step
.done($.proxy(view.moveToNextStep, view))
// Handle submission failure (either a server error or cancellation),
.fail(function(errCode, errMsg) {
// If the error is "multiple submissions", then we should move to the next
// step. Otherwise, the user will be stuck on the current step with no
// way to continue.
if (errCode == 'ENOMULTI') {
moveToNextStep();
}
if (errCode == 'ENOMULTI') { view.moveToNextStep(); }
else {
// Display the error
baseView.toggleActionError('submit', errMsg);
// If there is an error message, display it
if (errMsg) { baseView.toggleActionError('submit', errMsg); }
// Re-enable the submit button to allow the user to retry
// Re-enable the submit button so the user can retry
view.submitEnabled(true);
}
});
},
/**
Transition the user to the next step in the workflow.
**/
moveToNextStep: function() {
this.load();
this.baseView.renderPeerAssessmentStep();
},
/**
Make the user confirm before submitting a response.
Returns:
JQuery deferred object, which is:
* resolved if the user confirms the submission
* rejected if the user cancels the submission
**/
confirmSubmission: function() {
var msg = (
"You're about to submit your response for this assignment. " +
"After you submit this response, you can't change it or submit a new response."
);
// TODO -- UI for confirmation dialog instead of JS confirm
return $.Deferred(function(defer) {
if (confirm(msg)) { defer.resolve(); }
else { defer.reject(); }
});
}
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment