Commit 6a45664a by Tim Krones

Address review comments.

parent b285ea7e
...@@ -835,7 +835,7 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes ...@@ -835,7 +835,7 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes
) )
# User state # User state
step = Integer( active_step = Integer(
# Keep track of the student progress. # Keep track of the student progress.
default=0, default=0,
scope=Scope.user_state, scope=Scope.user_state,
...@@ -862,22 +862,23 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes ...@@ -862,22 +862,23 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes
def student_view(self, context): def student_view(self, context):
fragment = Fragment() fragment = Fragment()
child_content = u"" children_contents = []
for child_id in self.children: for child_id in self.children:
child = self.runtime.get_block(child_id) child = self.runtime.get_block(child_id)
if child is None: # child should not be None but it can happen due to bugs or permission issues if child is None: # child should not be None but it can happen due to bugs or permission issues
child_content += u"<p>[{}]</p>".format(self._(u"Error: Unable to load child component.")) child_content = u"<p>[{}]</p>".format(self._(u"Error: Unable to load child component."))
elif not isinstance(child, MentoringMessageBlock): elif not isinstance(child, MentoringMessageBlock):
child_fragment = self._render_child_fragment(child, context, view='mentoring_view') child_fragment = self._render_child_fragment(child, context, view='mentoring_view')
fragment.add_frag_resources(child_fragment) fragment.add_frag_resources(child_fragment)
child_content += child_fragment.content child_content = child_fragment.content
children_contents.append(child_content)
fragment.add_content(loader.render_template('templates/html/mentoring_with_steps.html', { fragment.add_content(loader.render_template('templates/html/mentoring_with_steps.html', {
'self': self, 'self': self,
'title': self.display_name, 'title': self.display_name,
'show_title': self.show_title, 'show_title': self.show_title,
'child_content': child_content, 'children_contents': children_contents,
})) }))
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder.css')) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder.css'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring_with_steps.js')) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring_with_steps.js'))
...@@ -909,16 +910,16 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes ...@@ -909,16 +910,16 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes
] ]
@XBlock.json_handler @XBlock.json_handler
def update_step(self, step, suffix=''): def update_active_step(self, new_value, suffix=''):
if step < len(self.steps): if new_value < len(self.steps):
self.step = step self.active_step = new_value
return { return {
'step': self.step 'active_step': self.active_step
} }
@XBlock.json_handler @XBlock.json_handler
def try_again(self, data, suffix=''): def try_again(self, data, suffix=''):
self.step = 0 self.active_step = 0
step_blocks = [self.runtime.get_block(child_id) for child_id in self.steps] step_blocks = [self.runtime.get_block(child_id) for child_id in self.steps]
...@@ -926,7 +927,7 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes ...@@ -926,7 +927,7 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes
step.reset() step.reset()
return { return {
'result': 'success' 'active_step': self.active_step
} }
def author_edit_view(self, context): def author_edit_view(self, context):
......
...@@ -3,24 +3,24 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -3,24 +3,24 @@ function MentoringWithStepsBlock(runtime, element) {
var steps = runtime.children(element).filter( var steps = runtime.children(element).filter(
function(c) { return c.element.className.indexOf('pb-mentoring-step') > -1; } function(c) { return c.element.className.indexOf('pb-mentoring-step') > -1; }
); );
var step = $('.mentoring', element).data('step'); var activeStep = $('.mentoring', element).data('active-step');
var active_child, checkmark, submitDOM, nextDOM, tryAgainDOM, submitXHR; var checkmark, submitDOM, nextDOM, tryAgainDOM, submitXHR;
function isLastChild() { function isLastStep() {
return (active_child === steps.length-1); return (activeStep === steps.length-1);
} }
function updateStep() { function updateActiveStep(newValue) {
var handlerUrl = runtime.handlerUrl(element, 'update_step'); var handlerUrl = runtime.handlerUrl(element, 'update_active_step');
$.post(handlerUrl, JSON.stringify(step+1)) $.post(handlerUrl, JSON.stringify(newValue))
.success(function(response) { .success(function(response) {
step = response.step; activeStep = response.active_step;
}); });
} }
function handleResults(response) { function handleResults(response) {
// Update step so next step is shown on page reload (even if user does not click "Next Step") // Update active step so next step is shown on page reload (even if user does not click "Next Step")
updateStep(); updateActiveStep(activeStep+1);
// Update UI // Update UI
if (response.completed === 'correct') { if (response.completed === 'correct') {
...@@ -36,16 +36,16 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -36,16 +36,16 @@ function MentoringWithStepsBlock(runtime, element) {
nextDOM.removeAttr("disabled"); nextDOM.removeAttr("disabled");
if (nextDOM.is(':visible')) { nextDOM.focus(); } if (nextDOM.is(':visible')) { nextDOM.focus(); }
if (isLastChild()) { if (isLastStep()) {
tryAgainDOM.removeAttr('disabled'); tryAgainDOM.removeAttr('disabled');
tryAgainDOM.show(); tryAgainDOM.show();
} }
} }
function submit() { function submit() {
// We do not handle submissions at this level, so just forward to "submit" method of current step // We do not handle submissions at this level, so just forward to "submit" method of active step
var child = steps[active_child]; var step = steps[activeStep];
child['submit'](handleResults); step.submit(handleResults);
} }
function hideAllSteps() { function hideAllSteps() {
...@@ -61,23 +61,21 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -61,23 +61,21 @@ function MentoringWithStepsBlock(runtime, element) {
hideAllSteps(); hideAllSteps();
} }
function displayNextChild() { function updateDisplay() {
cleanAll(); cleanAll();
findNextChild(); showActiveStep();
nextDOM.attr('disabled', 'disabled'); nextDOM.attr('disabled', 'disabled');
validateXBlock(); validateXBlock();
} }
function findNextChild() { function showActiveStep() {
// find the next real child block to display. HTMLBlock are always displayed var step = steps[activeStep];
++active_child; $(step.element).show();
var child = steps[active_child];
$(child.element).show();
} }
function onChange() { function onChange() {
// We do not allow users to modify answers belonging to a step after submitting them: // We do not allow users to modify answers belonging to a step after submitting them:
// Once an answer has been submitted (next button is enabled), // Once an answer has been submitted ("Next Step" button is enabled),
// start ignoring changes to the answer. // start ignoring changes to the answer.
if (nextDOM.attr('disabled')) { if (nextDOM.attr('disabled')) {
validateXBlock(); validateXBlock();
...@@ -85,17 +83,17 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -85,17 +83,17 @@ function MentoringWithStepsBlock(runtime, element) {
} }
function validateXBlock() { function validateXBlock() {
var is_valid = true; var isValid = true;
var child = steps[active_child]; var step = steps[activeStep];
if (child) { if (step) {
is_valid = child['validate'](); isValid = step.validate();
} }
if (!is_valid) { if (!isValid) {
submitDOM.attr('disabled', 'disabled'); submitDOM.attr('disabled', 'disabled');
} else { } else {
submitDOM.removeAttr('disabled'); submitDOM.removeAttr('disabled');
} }
if (isLastChild()) { if (isLastStep()) {
nextDOM.hide(); nextDOM.hide();
} }
} }
...@@ -103,19 +101,16 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -103,19 +101,16 @@ function MentoringWithStepsBlock(runtime, element) {
function initSteps(options) { function initSteps(options) {
for (var i=0; i < steps.length; i++) { for (var i=0; i < steps.length; i++) {
var step = steps[i]; var step = steps[i];
step['initChildren'](options); step.initChildren(options);
} }
} }
function handleTryAgain(result) { function handleTryAgain(result) {
if (result.result !== 'success') activeStep = result.active_step;
return; updateDisplay();
active_child = -1;
displayNextChild();
tryAgainDOM.hide(); tryAgainDOM.hide();
submitDOM.show(); submitDOM.show();
if (! isLastChild()) { if (! isLastStep()) {
nextDOM.show(); nextDOM.show();
} }
} }
...@@ -132,24 +127,22 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -132,24 +127,22 @@ function MentoringWithStepsBlock(runtime, element) {
checkmark = $('.assessment-checkmark', element); checkmark = $('.assessment-checkmark', element);
submitDOM = $(element).find('.submit .input-main'); submitDOM = $(element).find('.submit .input-main');
submitDOM.bind('click', submit); submitDOM.on('click', submit);
submitDOM.show(); submitDOM.show();
nextDOM = $(element).find('.submit .input-next'); nextDOM = $(element).find('.submit .input-next');
nextDOM.bind('click', displayNextChild); nextDOM.on('click', updateDisplay);
nextDOM.show(); nextDOM.show();
tryAgainDOM = $(element).find('.submit .input-try-again'); tryAgainDOM = $(element).find('.submit .input-try-again');
tryAgainDOM.bind('click', tryAgain); tryAgainDOM.on('click', tryAgain);
var options = { var options = {
onChange: onChange onChange: onChange
}; };
initSteps(options); initSteps(options);
active_child = step; updateDisplay();
active_child -= 1;
displayNextChild();
} }
initXBlockView(); initXBlockView();
......
...@@ -58,6 +58,12 @@ def _normalize_id(key): ...@@ -58,6 +58,12 @@ def _normalize_id(key):
return key return key
class Correctness(object):
CORRECT = 'correct'
PARTIAL = 'partial'
INCORRECT = 'incorrect'
class HtmlBlockShim(object): class HtmlBlockShim(object):
CATEGORY = 'html' CATEGORY = 'html'
STUDIO_LABEL = _(u"HTML") STUDIO_LABEL = _(u"HTML")
...@@ -127,18 +133,17 @@ class MentoringStepBlock( ...@@ -127,18 +133,17 @@ class MentoringStepBlock(
child.save() child.save()
# Update results stored for this step # Update results stored for this step
while self.student_results: self.reset()
self.student_results.pop()
for result in submit_results: for result in submit_results:
self.student_results.append(result) self.student_results.append(result)
# Compute "answer status" for this step # Compute "answer status" for this step
if all(result[1]['status'] == 'correct' for result in submit_results): if all(result[1]['status'] == 'correct' for result in submit_results):
completed = 'correct' completed = Correctness.CORRECT
elif all(result[1]['status'] == 'incorrect' for result in submit_results): elif all(result[1]['status'] == 'incorrect' for result in submit_results):
completed = 'incorrect' completed = Correctness.INCORRECT
else: else:
completed = 'partial' completed = Correctness.PARTIAL
return { return {
'message': 'Success!', 'message': 'Success!',
......
{% load i18n %} {% load i18n %}
<div class="mentoring themed-xblock" data-step="{{ self.step }}"> <div class="mentoring themed-xblock" data-active-step="{{ self.active_step }}">
{% if show_title and title %} {% if show_title and title %}
<div class="title"> <div class="title">
...@@ -8,7 +8,11 @@ ...@@ -8,7 +8,11 @@
{% endif %} {% endif %}
<div class="assessment-question-block"> <div class="assessment-question-block">
{{child_content|safe}}
{% for child_content in children_contents %}
{{ child_content|safe }}
{% endfor %}
<div class="submit"> <div class="submit">
<span class="assessment-checkmark fa icon-2x"></span> <span class="assessment-checkmark fa icon-2x"></span>
<input type="button" class="input-main" value="Submit" disabled="disabled" /> <input type="button" class="input-main" value="Submit" disabled="disabled" />
......
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