Commit c45a6019 by Jonathan Piacenti

Enable seamless use of steps that have no questions.

parent c6e60602
...@@ -125,6 +125,7 @@ class AnswerBlock(SubmittingXBlockMixin, AnswerMixin, QuestionMixin, StudioEdita ...@@ -125,6 +125,7 @@ class AnswerBlock(SubmittingXBlockMixin, AnswerMixin, QuestionMixin, StudioEdita
""" """
CATEGORY = 'pb-answer' CATEGORY = 'pb-answer'
STUDIO_LABEL = _(u"Long Answer") STUDIO_LABEL = _(u"Long Answer")
answerable = True
name = String( name = String(
display_name=_("Question ID (name)"), display_name=_("Question ID (name)"),
......
...@@ -56,6 +56,15 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -56,6 +56,15 @@ function MentoringWithStepsBlock(runtime, element) {
} }
} }
function postUpdateStep(response) {
activeStep = response.active_step;
if (activeStep === -1) {
updateNumAttempts();
} else {
updateControls();
}
}
function handleResults(response) { function handleResults(response) {
showFeedback(response); showFeedback(response);
...@@ -64,14 +73,7 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -64,14 +73,7 @@ function MentoringWithStepsBlock(runtime, element) {
// Otherwise, get UI ready for showing next step. // Otherwise, get UI ready for showing next step.
var handlerUrl = runtime.handlerUrl(element, 'update_active_step'); var handlerUrl = runtime.handlerUrl(element, 'update_active_step');
$.post(handlerUrl, JSON.stringify(activeStep+1)) $.post(handlerUrl, JSON.stringify(activeStep+1))
.success(function(response) { .success(postUpdateStep);
activeStep = response.active_step;
if (activeStep === -1) {
updateNumAttempts();
} else {
updateControls();
}
});
} }
function updateNumAttempts() { function updateNumAttempts() {
...@@ -138,6 +140,14 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -138,6 +140,14 @@ function MentoringWithStepsBlock(runtime, element) {
step.submit(handleResults); step.submit(handleResults);
} }
function markRead() {
var handlerUrl = runtime.handlerUrl(element, 'update_active_step');
$.post(handlerUrl, JSON.stringify(activeStep+1)).success(function (response) {
postUpdateStep(response);
updateDisplay();
});
}
function getResults() { function getResults() {
var step = steps[activeStep]; var step = steps[activeStep];
step.getResults(handleReviewResults); step.getResults(handleReviewResults);
...@@ -195,9 +205,18 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -195,9 +205,18 @@ function MentoringWithStepsBlock(runtime, element) {
showActiveStep(); showActiveStep();
validateXBlock(); validateXBlock();
updateNextLabel(); updateNextLabel();
var step = steps[activeStep];
if (step.hasQuestion()) {
nextDOM.attr('disabled', 'disabled'); nextDOM.attr('disabled', 'disabled');
} else {
nextDOM.removeAttr('disabled');
}
if (isLastStep() && reviewStep) { if (isLastStep() && reviewStep) {
if (step.hasQuestion()) {
reviewDOM.attr('disabled', 'disabled'); reviewDOM.attr('disabled', 'disabled');
} else {
reviewDOM.removeAttr('disabled')
}
reviewDOM.show(); reviewDOM.show();
} }
} }
...@@ -261,9 +280,14 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -261,9 +280,14 @@ function MentoringWithStepsBlock(runtime, element) {
nextDOM.show(); nextDOM.show();
nextDOM.removeAttr('disabled'); nextDOM.removeAttr('disabled');
} }
var step = steps[activeStep];
tryAgainDOM.hide(); tryAgainDOM.hide();
if (step.hasQuestion()) {
submitDOM.show(); submitDOM.show();
} else {
submitDOM.hide();
}
submitDOM.attr('disabled', 'disabled'); submitDOM.attr('disabled', 'disabled');
reviewLinkDOM.show(); reviewLinkDOM.show();
...@@ -302,8 +326,19 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -302,8 +326,19 @@ function MentoringWithStepsBlock(runtime, element) {
} else { } else {
submitDOM.removeAttr('disabled'); submitDOM.removeAttr('disabled');
} }
if (isLastStep()) { if (isLastStep() && step.hasQuestion()) {
nextDOM.hide(); nextDOM.hide();
} else if (isLastStep()) {
reviewDOM.one('click', markRead);
reviewDOM.removeAttr('disabled');
nextDOM.hide()
} else if (!step.hasQuestion()) {
nextDOM.one('click', markRead);
}
if (step.hasQuestion()) {
submitDOM.show();
} else {
submitDOM.hide();
} }
} }
......
...@@ -85,6 +85,10 @@ function MentoringStepBlock(runtime, element) { ...@@ -85,6 +85,10 @@ function MentoringStepBlock(runtime, element) {
getStepLabel: function() { getStepLabel: function() {
return $('.sb-step', element).data('next-button-label'); return $('.sb-step', element).data('next-button-label');
},
hasQuestion: function() {
return $('.sb-step', element).data('has-question')
} }
}; };
......
...@@ -90,6 +90,7 @@ class QuestionnaireAbstractBlock( ...@@ -90,6 +90,7 @@ class QuestionnaireAbstractBlock(
) )
editable_fields = ('question', 'message', 'weight', 'display_name', 'show_title') editable_fields = ('question', 'message', 'weight', 'display_name', 'show_title')
has_children = True has_children = True
answerable = True
@lazy @lazy
def html_id(self): def html_id(self):
......
...@@ -133,6 +133,10 @@ class MentoringStepBlock( ...@@ -133,6 +133,10 @@ class MentoringStepBlock(
AnswerRecapBlock, MentoringTableBlock, AnswerRecapBlock, MentoringTableBlock,
] ]
@property
def has_question(self):
return any(getattr(child, 'answerable', False) for child in self.steps)
@XBlock.json_handler @XBlock.json_handler
def submit(self, submissions, suffix=''): def submit(self, submissions, suffix=''):
log.info(u'Received submissions: {}'.format(submissions)) log.info(u'Received submissions: {}'.format(submissions))
......
<div class="sb-step" data-next-button-label="{{ self.next_button_label }}"> <div class="sb-step" data-next-button-label="{{ self.next_button_label }}" {% if self.has_question %} data-has-question="true" {% endif %}>
{% if show_title %} {% if show_title %}
<div class="title"> <div class="title">
<h3> <h3>
......
...@@ -211,6 +211,7 @@ class StepBuilderTest(MentoringAssessmentBaseTest): ...@@ -211,6 +211,7 @@ class StepBuilderTest(MentoringAssessmentBaseTest):
# It should be possible to visit the MRQ from here # It should be possible to visit the MRQ from here
self.wait_until_clickable(controls.next_question) self.wait_until_clickable(controls.next_question)
controls.next_question.click() controls.next_question.click()
self.html_section(step_builder, controls)
self.peek_at_multiple_response_question( self.peek_at_multiple_response_question(
None, step_builder, controls, extended_feedback=True, alternative_review=True None, step_builder, controls, extended_feedback=True, alternative_review=True
) )
...@@ -230,6 +231,24 @@ class StepBuilderTest(MentoringAssessmentBaseTest): ...@@ -230,6 +231,24 @@ class StepBuilderTest(MentoringAssessmentBaseTest):
self.expect_question_visible(None, step_builder) self.expect_question_visible(None, step_builder)
self.assertEqual(controls.next_question.get_attribute('value'), "Next Challenge") self.assertEqual(controls.next_question.get_attribute('value'), "Next Challenge")
def html_section(self, step_builder, controls, last=False):
self.wait_until_hidden(controls.submit)
target_control = controls.review if last else controls.next_question
self.wait_until_clickable(target_control)
target_control.click()
def test_html_last(self):
step_builder, controls = self.load_assessment_scenario("step_builder_html_last.xml")
# Step 1
# Submit free-form answer, go to next step
self.freeform_answer(None, step_builder, controls, 'This is the answer', CORRECT)
# Step 2
# Submit MCQ, go to next step
self.single_choice_question(None, step_builder, controls, 'Maybe not', INCORRECT)
self.html_section(step_builder, controls, last=True)
@data( @data(
{"max_attempts": 0, "extended_feedback": False}, # Unlimited attempts, no extended feedback {"max_attempts": 0, "extended_feedback": False}, # Unlimited attempts, no extended feedback
{"max_attempts": 1, "extended_feedback": True}, # Limited attempts, extended feedback {"max_attempts": 1, "extended_feedback": True}, # Limited attempts, extended feedback
...@@ -253,6 +272,9 @@ class StepBuilderTest(MentoringAssessmentBaseTest): ...@@ -253,6 +272,9 @@ class StepBuilderTest(MentoringAssessmentBaseTest):
# Submit rating, go to next step # Submit rating, go to next step
self.rating_question(None, step_builder, controls, "5 - Extremely good", CORRECT) self.rating_question(None, step_builder, controls, "5 - Extremely good", CORRECT)
# Step 4, html with no question.
self.html_section(step_builder, controls)
# Last step # Last step
# Submit MRQ, go to review # Submit MRQ, go to review
with patch.object(WorkbenchRuntime, 'publish') as patched_method: with patch.object(WorkbenchRuntime, 'publish') as patched_method:
...@@ -308,6 +330,8 @@ class StepBuilderTest(MentoringAssessmentBaseTest): ...@@ -308,6 +330,8 @@ class StepBuilderTest(MentoringAssessmentBaseTest):
# Submit rating, go to next step # Submit rating, go to next step
self.rating_question(None, step_builder, controls, "1 - Not good at all", INCORRECT) self.rating_question(None, step_builder, controls, "1 - Not good at all", INCORRECT)
# Step 4, read only. Go to next step.
self.html_section(step_builder, controls)
# Last step # Last step
# Submit MRQ, go to review # Submit MRQ, go to review
user_selection = ("Its elegance", "Its beauty", "Its gracefulness") user_selection = ("Its elegance", "Its beauty", "Its gracefulness")
...@@ -350,6 +374,7 @@ class StepBuilderTest(MentoringAssessmentBaseTest): ...@@ -350,6 +374,7 @@ class StepBuilderTest(MentoringAssessmentBaseTest):
self.freeform_answer(None, step_builder, controls, 'This is the answer', CORRECT) self.freeform_answer(None, step_builder, controls, 'This is the answer', CORRECT)
self.single_choice_question(None, step_builder, controls, 'Maybe not', INCORRECT) self.single_choice_question(None, step_builder, controls, 'Maybe not', INCORRECT)
self.rating_question(None, step_builder, controls, "5 - Extremely good", CORRECT) self.rating_question(None, step_builder, controls, "5 - Extremely good", CORRECT)
self.html_section(step_builder, controls)
self.multiple_response_question(None, step_builder, controls, ("Its beauty",), PARTIAL, last=True) self.multiple_response_question(None, step_builder, controls, ("Its beauty",), PARTIAL, last=True)
# The review tips for MCQ 2 and the MRQ should be shown: # The review tips for MCQ 2 and the MRQ should be shown:
...@@ -374,6 +399,7 @@ class StepBuilderTest(MentoringAssessmentBaseTest): ...@@ -374,6 +399,7 @@ class StepBuilderTest(MentoringAssessmentBaseTest):
self.single_choice_question(None, step_builder, controls, 'Yes', CORRECT) self.single_choice_question(None, step_builder, controls, 'Yes', CORRECT)
self.rating_question(None, step_builder, controls, "5 - Extremely good", CORRECT) self.rating_question(None, step_builder, controls, "5 - Extremely good", CORRECT)
user_selection = ("Its elegance", "Its beauty", "Its gracefulness") user_selection = ("Its elegance", "Its beauty", "Its gracefulness")
self.html_section(step_builder, controls)
self.multiple_response_question(None, step_builder, controls, user_selection, CORRECT, last=True) self.multiple_response_question(None, step_builder, controls, user_selection, CORRECT, last=True)
# If attempts remain and student got all answers right, show "complete" message # If attempts remain and student got all answers right, show "complete" message
...@@ -390,6 +416,7 @@ class StepBuilderTest(MentoringAssessmentBaseTest): ...@@ -390,6 +416,7 @@ class StepBuilderTest(MentoringAssessmentBaseTest):
) )
self.single_choice_question(None, step_builder, controls, 'Maybe not', INCORRECT) self.single_choice_question(None, step_builder, controls, 'Maybe not', INCORRECT)
self.rating_question(None, step_builder, controls, "1 - Not good at all", INCORRECT) self.rating_question(None, step_builder, controls, "1 - Not good at all", INCORRECT)
self.html_section(step_builder, controls)
self.multiple_response_question(None, step_builder, controls, ("Its beauty",), PARTIAL, last=True) self.multiple_response_question(None, step_builder, controls, ("Its beauty",), PARTIAL, last=True)
# The review tips will not be shown because no attempts remain: # The review tips will not be shown because no attempts remain:
......
...@@ -36,6 +36,10 @@ ...@@ -36,6 +36,10 @@
</pb-rating> </pb-rating>
</sb-step> </sb-step>
<sb-step display_name="Fourth Step">
<html_demo>Test test test</html_demo>
</sb-step>
<sb-step display_name="Last step"> <sb-step display_name="Last step">
<pb-mrq name="mrq_1_1" question="What do you like in this MRQ?" required_choices='["gracefulness","elegance","beauty"]' message="Question Feedback Message"> <pb-mrq name="mrq_1_1" question="What do you like in this MRQ?" required_choices='["gracefulness","elegance","beauty"]' message="Question Feedback Message">
<pb-choice value="elegance">Its elegance</pb-choice> <pb-choice value="elegance">Its elegance</pb-choice>
......
<step-builder url_name="step-builder" display_name="Step Builder"
max_attempts="1" extended_feedback="True">
<sb-step display_name="First step" next_button_label="Next Challenge">
<pb-answer name="goal" question="What is your goal?" />
</sb-step>
<sb-step display_name="Second step" next_button_label="Next Item">
<pb-mcq name="mcq_1_1" question="Do you like this MCQ?" correct_choices='["yes"]'>
<pb-choice value="yes">Yes</pb-choice>
<pb-choice value="maybenot">Maybe not</pb-choice>
<pb-choice value="understand">I don't understand</pb-choice>
<pb-tip values='["yes"]'>Great!</pb-tip>
<pb-tip values='["maybenot"]'>Ah, damn.</pb-tip>
<pb-tip values='["understand"]'><div id="test-custom-html">Really?</div></pb-tip>
</pb-mcq>
</sb-step>
<sb-step display_name="Last HTML step">
<html_demo>Bla bla bla</html_demo>
</sb-step>
<sb-review-step />
</step-builder>
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