Commit 80a1b837 by Will Daly

Merge pull request #132 from edx/will/finish-ui-messages

Will/finish ui messages
parents 9a79aef7 e3e90829
......@@ -12,11 +12,3 @@
</h2>
</header>
</li>
\ No newline at end of file
......@@ -64,6 +64,7 @@
</header>
</li>
{% endfor %}
</ol>
</div>
</div>
......
......@@ -106,9 +106,14 @@
</fieldset>
<div class="peer-assessment__actions">
<div class="message message--error message--error-server">
<h3 class="message__title">We could not submit your assessment</h3>
<div class="message__content"></div>
</div>
<ul class="list list--actions">
<li class="list--actions__item">
<button type="submit" id="peer-assessment--001__assessment__submit" class="action action--submit">
<button type="submit" id="peer-assessment--001__assessment__submit" class="action action--submit is--disabled">
<span class="copy">{{ submit_button_text }}</span>
<i class="ico icon-caret-right"></i>
</button>
......
......@@ -32,29 +32,46 @@
</div>
<div class="step__content">
<!-- @talbs: This is some more ugly placeholder stuff that you can replace -->
<div id="response__save_status">{{ save_status }}</div>
<form id="response__submission" class="response__submission">
<div id="response__save_status" class="response__submission__status">
<h3 class="response__submission__status__title">
<span class="sr">Your Working Submission Status:</span>
{{ save_status }}
</h3>
</div>
<ol class="list list--fields response__submission__content">
<li class="field field--textarea submission__answer" id="submission__answer">
<label class="sr" for="submission__answer__value">Please provide your response to the question.</label>
<textarea id="submission__answer__value" placeholder="">{{ saved_response }}</textarea>
<span class="tip">You may continue to work on your response until you submit it.</span>
</li>
</ol>
<ul class="list list--actions response__submission__actions">
<div class="response__submission__actions">
<ul class="list list--actions">
<li class="list--actions__item">
<button type="submit" id="submission__save" class="action action--save submission__save">Save Your Progress</button>
<span class="tip">You may continue to work on your response until you submit it.</span>
<button type="submit" id="submission__save" class="action action--save submission__save is--disabled">Save Your Progress</button>
</li>
</ul>
<div class="message message--error message--error-server">
<h3 class="message__title">We could not save your progress</h3>
<div class="message__content"></div>
</div>
</div>
</form>
</div>
<div class="step__actions">
<div class="message message--error message--error-server">
<h3 class="message__title">We could not submit your response</h3>
<div class="message__content"></div>
</div>
<ul class="list list--actions">
<li class="list--actions__item">
<a aria-role="button" href="#" id="step--response__submit" class="action action--submit step--response__submit">
<a aria-role="button" href="#" id="step--response__submit" class="action action--submit step--response__submit is--disabled">
<span class="copy">Submit your response and move to the next step</span>
<i class="ico icon-caret-right"></i>
</a>
......
......@@ -76,9 +76,13 @@
</fieldset>
<div class="self-assessment__actions">
<div class="message message--error message--error-server">
<h3 class="message__title">We could not submit your assessment</h3>
<div class="message__content"></div>
</div>
<ul class="list list--actions">
<li class="list--actions__item">
<button type="submit" id="self-assessment--001__assessment__submit" class="action action--submit">
<button type="submit" id="self-assessment--001__assessment__submit" class="action action--submit is--disabled">
<span class="copy">{% trans "Submit Your Assessment" %}</span>
<i class="ico icon-caret-right"></i>
</button>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -68,9 +68,22 @@ OpenAssessment.BaseUI.prototype = {
var sel = $('#openassessment__response', ui.element);
sel.replaceWith(html);
// If we have a saved submission, enable the submit button
ui.responseChanged();
// Install change handler for textarea (to enable submission button)
$('#submission__answer__value', ui.element).keyup(
function(eventData) { ui.responseChanged(); }
);
// Install a click handler for submission
$('#step--response__submit', ui.element).click(
function(eventObject) { ui.submit(); }
function(eventObject) {
// Override default form submission
eventObject.preventDefault();
ui.submit();
}
);
// Install a click handler for the save button
......@@ -83,12 +96,21 @@ OpenAssessment.BaseUI.prototype = {
);
}
).fail(function(errMsg) {
// TODO: display to the user
console.log(errMsg);
ui.showLoadError('response');
});
},
/**
Enable/disable the submission and save buttons based on whether
the user has entered a response.
**/
responseChanged: function() {
var blankSubmission = ($('#submission__answer__value', this.element).val() === '');
$('#step--response__submit', this.element).toggleClass('is--disabled', blankSubmission);
$('#submission__save', this.element).toggleClass('is--disabled', blankSubmission);
},
/**
Render the peer-assessment step.
Args:
......@@ -102,6 +124,17 @@ OpenAssessment.BaseUI.prototype = {
var sel = $('#openassessment__peer-assessment', ui.element);
sel.replaceWith(html);
// Install a change handler for rubric options to enable/disable the submit button
$("#peer-assessment--001__assessment", ui.element).change(
function() {
var numChecked = $('input[type=radio]:checked', this).length;
var numAvailable = $('.field--radio.assessment__rubric__question', this).length;
$("#peer-assessment--001__assessment__submit", ui.element).toggleClass(
'is--disabled', numChecked != numAvailable
);
}
);
// Install a click handler for assessment
$('#peer-assessment--001__assessment__submit', ui.element).click(
function(eventObject) {
......@@ -114,8 +147,7 @@ OpenAssessment.BaseUI.prototype = {
);
}
).fail(function(errMsg) {
// TODO: display to the user
console.log(errMsg);
ui.showLoadError('peer-assessment');
});
},
......@@ -131,6 +163,17 @@ OpenAssessment.BaseUI.prototype = {
function(html) {
$('#openassessment__self-assessment', ui.element).replaceWith(html);
// Install a change handler for rubric options to enable/disable the submit button
$("#self-assessment--001__assessment", ui.element).change(
function() {
var numChecked = $('input[type=radio]:checked', this).length;
var numAvailable = $('.field--radio.assessment__rubric__question', this).length;
$("#self-assessment--001__assessment__submit", ui.element).toggleClass(
'is--disabled', numChecked != numAvailable
);
}
);
// Install a click handler for the submit button
$('#self-assessment--001__assessment__submit', ui.element).click(
function(eventObject) {
......@@ -143,8 +186,7 @@ OpenAssessment.BaseUI.prototype = {
);
}
).fail(function(errMsg) {
// TODO: display to the user
console.log(errMsg);
ui.showLoadError('self-assessment');
});
},
......@@ -161,8 +203,7 @@ OpenAssessment.BaseUI.prototype = {
$('#openassessment__grade', ui.element).replaceWith(html);
}
).fail(function(errMsg) {
// TODO: display to the user
console.log(errMsg);
ui.showLoadError('grade', errMsg);
});
},
......@@ -174,14 +215,13 @@ OpenAssessment.BaseUI.prototype = {
var submission = $('#submission__answer__value', this.element).val();
var ui = this;
$('#response__save_status', this.element).html('Saving...');
this.toggleActionError('save', null);
this.server.save(submission).done(function() {
// Update the "saved" icon
$('#response__save_status', this.element).html("Saved but not submitted");
}).fail(function(errMsg) {
// TODO: display to the user
console.log(errMsg);
$("#response__save_status", ui.element).html('Error');
ui.toggleActionError('save', errMsg);
});
},
/**
......@@ -191,6 +231,7 @@ OpenAssessment.BaseUI.prototype = {
// Send the submission to the server
var submission = $('#submission__answer__value', this.element).val();
var ui = this;
this.toggleActionError('response', null);
this.server.submit(submission).done(
// When we have successfully sent the submission, expand the next step
function(studentId, attemptNum) {
......@@ -198,8 +239,7 @@ OpenAssessment.BaseUI.prototype = {
ui.renderPeerAssessmentStep(true);
}
).fail(function(errCode, errMsg) {
// TODO: display to the user in a classier way
alert(errMsg);
ui.toggleActionError('submit', errMsg);
});
},
......@@ -219,6 +259,7 @@ OpenAssessment.BaseUI.prototype = {
// Send the assessment to the server
var ui = this;
this.toggleActionError('peer', null);
this.server.peerAssess(submissionId, optionsSelected, feedback).done(
function() {
// When we have successfully sent the assessment,
......@@ -228,8 +269,7 @@ OpenAssessment.BaseUI.prototype = {
ui.renderGradeStep(false);
}
).fail(function(errMsg) {
// TODO: display to the user
console.log(errMsg);
ui.toggleActionError('peer', errMsg);
});
},
......@@ -248,6 +288,7 @@ OpenAssessment.BaseUI.prototype = {
// Send the assessment to the server
var ui = this;
this.toggleActionError('self', null);
this.server.selfAssess(submissionId, optionsSelected).done(
function() {
// When we have successfully sent the assessment,
......@@ -256,9 +297,52 @@ OpenAssessment.BaseUI.prototype = {
ui.renderGradeStep(true);
}
).fail(function(errMsg) {
// TODO: display to user
console.log(errMsg);
ui.toggleActionError('self', errMsg);
});
},
/**
Report an error to the user.
Args:
type (str): Which type of error. Options are "save", submit", "peer", and "self".
msg (str or null): The error message to display.
If null, hide the error message (with one exception: loading errors are never hidden once displayed)
**/
toggleActionError: function(type, msg) {
var container = null;
if (type == 'save') { container = '.response__submission__actions'; }
else if (type == 'submit') { container = '.step__actions'; }
else if (type == 'peer') { container = '.peer-assessment__actions'; }
else if (type == 'self') { container = '.self-assessment__actions'; }
// If we don't have anywhere to put the message, just log it to the console
if (container === null) {
if (msg !== null) { console.log(msg); }
}
else {
// Insert the error message
var msgHtml = (msg === null) ? "" : msg;
$(container + " .message__content").html('<p>' + msg + '</p>');
// Toggle the error class
$(container).toggleClass('has--error', msg !== null);
}
},
/**
Report an error loading a step.
Args:
step (str): the step that could not be loaded.
**/
showLoadError: function(step) {
var container = '#openassessment__' + step;
$(container).toggleClass('has--error', true);
$(container + ' .step__status__value i').removeClass().addClass('icon-warning-sign');
$(container + ' .step__status__value').html('Unable to Load');
}
};
......
......@@ -210,6 +210,10 @@
// step actions
.step__actions {
@include transition(background-color $tmg-f1 ease-in-out 0s);
border-radius: ($baseline-v/5);
padding: ($baseline-v/2) ($baseline-h/2);
background: transparent;
text-align: center;
@include media($bp-ds) {
......@@ -232,6 +236,61 @@
@extend %btn--primary;
@extend %action-4;
}
// STATE: has error
&.has--error {
@include row();
background: tint($color-error, 90%);
.message {
display: block;
margin-bottom: ($baseline-v/2);
@include media($bp-ds) {
@include span-columns(3 of 6);
margin-bottom: 0;
text-align: left;
}
@include media($bp-dm) {
@include span-columns(6 of 12);
margin-bottom: 0;
text-align: left;
}
@include media($bp-dl) {
@include span-columns(6 of 12);
margin-bottom: 0;
text-align: left;
}
@include media($bp-dx) {
@include span-columns(6 of 12);
margin-bottom: 0;
text-align: left;
}
}
.list--actions {
display: block;
@include media($bp-ds) {
@include span-columns(3 of 6);
}
@include media($bp-dm) {
@include span-columns(6 of 12);
}
@include media($bp-dl) {
@include span-columns(6 of 12);
}
@include media($bp-dx) {
@include span-columns(6 of 12);
}
}
}
}
// STATE: step is loading
......@@ -344,16 +403,29 @@
}
}
// STATE: step is saved
&.is--saved {
// STATE: has error
&.has--error {
.step__counter:before {
border-color: rgba($color-error, 0.5);
color: $color-error;
}
.step__status__value {
background: $color-primary;
background: $color-error;
.copy {
color: $white-t;
}
}
.step__label {
color: $color-error;
}
.message {
}
}
}
......@@ -363,10 +435,25 @@
// --------------------
.message {
.message__title {
@extend %hd-6;
}
// CASE: has actions
&.has-actions {
.message__content {
@extend %copy-4;
}
}
// TYPE: error
.message--error {
.message__title {
color: $color-error;
}
.message__content {
color: tint($color-error, 33%);
}
}
......@@ -380,6 +467,25 @@
}
// --------------------
// errors
// --------------------
// CASE: default error display (hidden)
.message--error {
@extend %trans-opacity;
display: none;
opacity: 0.0;
}
// CASE: error is shown
.has--error {
.message--error {
display: block;
opacity: 1.0;
}
}
// --------------------
// problem
......@@ -422,16 +528,16 @@
// response form
.response__submission {
padding: ($baseline-v/2);
margin-top: ($baseline-v*2.5);
position: relative;
padding: ($baseline-v*0.75);
background: $color-decorative-tertiary;
border-radius: ($baseline-v/10);
.submission__answer {
margin-bottom: ($baseline-v/2);
}
}
.response__submission__content {
margin-bottom: ($baseline-v/2);
label {
@extend %text-sr;
}
......@@ -439,71 +545,112 @@
textarea {
@extend %ui-content-longanswer;
min-height: ($baseline-v*10);
margin-bottom: ($baseline-v/2);
}
}
.response__submission__status {
position: absolute;
top: -($baseline-v*1.5);
right: 0;
background: $color-decorative-tertiary;
padding: ($baseline-v/2) ($baseline-h/2);
margin-bottom: ($baseline-v/2);
}
.response__submission__status__title {
@extend %hd-7;
@extend %t-weight3;
color: $copy-supplemental-color;
}
.response__submission__actions {
@include transition(background-color $tmg-f1 ease-in-out 0s);
border-radius: ($baseline-v/5);
padding: ($baseline-v/2) ($baseline-h/2);
background: transparent;
.action--submit, .tip {
.action--save {
@extend %btn--secondary;
@extend %action-4;
display: block;
width: 100%;
margin-bottom: ($baseline-v/2);
text-align: center;
@include media($bp-ds) {
display: inline-block;
vertical-align: middle;
width: auto;
margin-right: ($baseline-v/2);
}
@include media($bp-dm) {
display: inline-block;
vertical-align: middle;
width: auto;
margin-right: ($baseline-v/2);
}
@include media($bp-dl) {
display: inline-block;
vertical-align: middle;
width: auto;
margin-right: ($baseline-v/2);
}
@include media($bp-dx) {
display: inline-block;
vertical-align: middle;
width: auto;
margin-right: ($baseline-v/2);
}
}
.action--save {
@extend %btn--secondary;
@extend %action-4;
// STATE: has error
&.has--error {
@include row();
background: tint($color-error, 90%);
.message {
display: block;
text-align: center;
@include media($bp-ds) {
display: inline-block;
margin-right: ($baseline-v/2);
@include span-columns(3 of 6);
text-align: left;
}
@include media($bp-dm) {
display: inline-block;
margin-right: ($baseline-v/2);
@include span-columns(6 of 12);
margin-bottom: 0;
text-align: left;
}
@include media($bp-dl) {
display: inline-block;
margin-right: ($baseline-v/2);
@include span-columns(6 of 12);
text-align: left;
}
@include media($bp-dx) {
display: inline-block;
margin-right: ($baseline-v/2);
@include span-columns(6 of 12);
text-align: left;
}
}
.tip {
@extend %copy-5;
color: $copy-supplemental-color;
.list--actions {
display: block;
margin-bottom: ($baseline-v/2);
@include media($bp-ds) {
@include span-columns(3 of 6);
margin-bottom: 0;
}
@include media($bp-dm) {
@include span-columns(6 of 12);
margin-bottom: 0;
}
@include media($bp-dl) {
@include span-columns(6 of 12);
margin-bottom: 0;
}
@include media($bp-dx) {
@include span-columns(6 of 12);
margin-bottom: 0;
}
}
}
}
}
......@@ -615,6 +762,10 @@
// step actions
.peer-assessment__actions {
@include transition(background-color $tmg-f1 ease-in-out 0s);
border-radius: ($baseline-v/5);
padding: ($baseline-v/2) ($baseline-h/2);
background: transparent;
text-align: center;
@include media($bp-ds) {
......@@ -637,6 +788,61 @@
@extend %btn--primary;
@extend %action-4;
}
// STATE: has error
&.has--error {
@include row();
background: tint($color-error, 90%);
.message {
display: block;
margin-bottom: ($baseline-v/2);
@include media($bp-ds) {
@include span-columns(3 of 6);
margin-bottom: 0;
text-align: left;
}
@include media($bp-dm) {
@include span-columns(6 of 12);
margin-bottom: 0;
text-align: left;
}
@include media($bp-dl) {
@include span-columns(6 of 12);
margin-bottom: 0;
text-align: left;
}
@include media($bp-dx) {
@include span-columns(6 of 12);
margin-bottom: 0;
text-align: left;
}
}
.list--actions {
display: block;
@include media($bp-ds) {
@include span-columns(3 of 6);
}
@include media($bp-dm) {
@include span-columns(6 of 12);
}
@include media($bp-dl) {
@include span-columns(6 of 12);
}
@include media($bp-dx) {
@include span-columns(6 of 12);
}
}
}
}
}
......@@ -702,6 +908,10 @@
// step actions
.self-assessment__actions {
@include transition(background-color $tmg-f1 ease-in-out 0s);
border-radius: ($baseline-v/5);
padding: ($baseline-v/2) ($baseline-h/2);
background: transparent;
text-align: center;
@include media($bp-ds) {
......@@ -724,6 +934,61 @@
@extend %btn--primary;
@extend %action-4;
}
// STATE: has error
&.has--error {
@include row();
background: tint($color-error, 90%);
.message {
display: block;
margin-bottom: ($baseline-v/2);
@include media($bp-ds) {
@include span-columns(3 of 6);
margin-bottom: 0;
text-align: left;
}
@include media($bp-dm) {
@include span-columns(6 of 12);
margin-bottom: 0;
text-align: left;
}
@include media($bp-dl) {
@include span-columns(6 of 12);
margin-bottom: 0;
text-align: left;
}
@include media($bp-dx) {
@include span-columns(6 of 12);
margin-bottom: 0;
text-align: left;
}
}
.list--actions {
display: block;
@include media($bp-ds) {
@include span-columns(3 of 6);
}
@include media($bp-dm) {
@include span-columns(6 of 12);
}
@include media($bp-dl) {
@include span-columns(6 of 12);
}
@include media($bp-dx) {
@include span-columns(6 of 12);
}
}
}
}
}
......
......@@ -75,7 +75,7 @@
text-decoration: none;
}
&.disabled, &[disabled] {
&.disabled, &[disabled], &.is--disabled {
cursor: default;
pointer-events: none;
}
......@@ -135,8 +135,8 @@
}
}
&.disabled, &.is-disabled, &[disabled] {
opacity: 0.5;
&.disabled, &.is--disabled, &[disabled] {
opacity: 0.4;
}
}
......@@ -169,8 +169,8 @@
}
}
&.disabled, &.is-disabled, &[disabled] {
opacity: 0.5;
&.disabled, &.is--disabled, &[disabled] {
opacity: 0.4;
}
}
......
......@@ -41,6 +41,12 @@
textarea {
width: 100%;
}
.tip {
display: block;
@extend %copy-5;
color: $copy-supplemental-color;
}
}
}
......@@ -153,7 +153,7 @@
%copy-5 {
@include font-size(13);
@include lh(12);
@include lh(13);
font-family: $f-copy;
}
......
......@@ -14,7 +14,7 @@ class SaveResponseTest(XBlockHandlerTestCase):
def test_default_saved_response_blank(self, xblock):
resp = self.request(xblock, 'render_submission', json.dumps({}))
self.assertIn('<textarea id="submission__answer__value" placeholder=""></textarea>', resp)
self.assertIn('<div id="response__save_status">Not saved</div>', resp)
self.assertIn('Not saved', resp)
@ddt.file_data('data/save_responses.json')
@scenario('data/save_scenario.xml', user_id="Perleman")
......@@ -32,7 +32,7 @@ class SaveResponseTest(XBlockHandlerTestCase):
submitted=submission_text
)
self.assertIn(expected_html, resp.decode('utf-8'))
self.assertIn('<div id="response__save_status">Saved but not submitted</div>', resp)
self.assertIn('Saved but not submitted', resp)
@scenario('data/save_scenario.xml', user_id="Valchek")
def test_overwrite_saved_response(self, xblock):
......
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