Commit bc879077 by Tim Krones

Display score (percentage) and count of correct/partial/incorrect answers.

parent ca1e9f95
...@@ -869,6 +869,12 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes ...@@ -869,6 +869,12 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes
""" Get the usage_ids of all of this XBlock's children that are "Questions" """ """ Get the usage_ids of all of this XBlock's children that are "Questions" """
return list(chain.from_iterable(self.runtime.get_block(step_id).steps for step_id in self.steps)) return list(chain.from_iterable(self.runtime.get_block(step_id).steps for step_id in self.steps))
def get_questions(self):
""" Get all questions associated with this block, cached if possible. """
if getattr(self, "_questions_cache", None) is None:
self._questions_cache = [self.runtime.get_block(question_id) for question_id in self.questions]
return self._questions_cache
@property @property
def steps(self): def steps(self):
""" """
...@@ -880,6 +886,21 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes ...@@ -880,6 +886,21 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes
child_isinstance(self, child_id, MentoringStepBlock) child_isinstance(self, child_id, MentoringStepBlock)
] ]
def get_steps(self):
""" Get the step children of this block, cached if possible. """
if getattr(self, "_steps_cache", None) is None:
self._steps_cache = [self.runtime.get_block(child_id) for child_id in self.steps]
return self._steps_cache
def answer_mapper(self, answer_status):
steps = self.get_steps()
answer_map = []
for step in steps:
for answer in step.student_results:
if answer[1]['status'] == answer_status:
answer_map.append({'id': answer[0], 'details': answer[1]})
return answer_map
@property @property
def has_review_step(self): def has_review_step(self):
from .step import ReviewStepBlock from .step import ReviewStepBlock
...@@ -900,6 +921,27 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes ...@@ -900,6 +921,27 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes
assessment_message = _("Note: you have used all attempts. Continue to the next unit") assessment_message = _("Note: you have used all attempts. Continue to the next unit")
return '<p>{}</p>'.format(assessment_message) return '<p>{}</p>'.format(assessment_message)
@property
def score(self):
questions = self.get_questions()
total_child_weight = sum(float(question.weight) for question in questions)
if total_child_weight == 0:
return Score(0, 0, [], [], [])
steps = self.get_steps()
questions_map = {question.name: question for question in questions}
points_earned = 0
for step in steps:
for question_name, question_results in step.student_results:
question = questions_map.get(question_name)
if question: # Under what conditions would this evaluate to False?
points_earned += question_results['score'] * question.weight
score = points_earned / total_child_weight
correct = self.answer_mapper(CORRECT)
incorrect = self.answer_mapper(INCORRECT)
partially_correct = self.answer_mapper(PARTIAL)
return Score(score, int(round(score * 100)), correct, incorrect, partially_correct)
def get_message_content(self, message_type, or_default=False): def get_message_content(self, message_type, or_default=False):
for child_id in self.children: for child_id in self.children:
if child_isinstance(self, child_id, MentoringMessageBlock): if child_isinstance(self, child_id, MentoringMessageBlock):
...@@ -938,6 +980,7 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes ...@@ -938,6 +980,7 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes
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'))
fragment.add_resource(loader.load_unicode('templates/html/mentoring_attempts.html'), "text/html") fragment.add_resource(loader.load_unicode('templates/html/mentoring_attempts.html'), "text/html")
fragment.add_resource(loader.load_unicode('templates/html/mentoring_assessment_templates.html'), "text/html")
self.include_theme_files(fragment) self.include_theme_files(fragment)
...@@ -986,6 +1029,15 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes ...@@ -986,6 +1029,15 @@ class MentoringWithExplicitStepsBlock(BaseMentoringBlock, StudioContainerWithNes
} }
@XBlock.json_handler @XBlock.json_handler
def get_score(self, data, suffix):
return {
'score': self.score.percentage,
'correct_answers': len(self.score.correct),
'incorrect_answers': len(self.score.incorrect),
'partially_correct_answers': len(self.score.partially_correct),
}
@XBlock.json_handler
def try_again(self, data, suffix=''): def try_again(self, data, suffix=''):
self.active_step = 0 self.active_step = 0
......
...@@ -4,8 +4,10 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -4,8 +4,10 @@ function MentoringWithStepsBlock(runtime, element) {
function(c) { return c.element.className.indexOf('sb-step') > -1; } function(c) { return c.element.className.indexOf('sb-step') > -1; }
); );
var activeStep = $('.mentoring', element).data('active-step'); var activeStep = $('.mentoring', element).data('active-step');
var gradeTemplate = _.template($('#xblock-grade-template').html());
var attemptsTemplate = _.template($('#xblock-attempts-template').html()); var attemptsTemplate = _.template($('#xblock-attempts-template').html());
var reviewStep, checkmark, submitDOM, nextDOM, reviewDOM, tryAgainDOM, assessmentMessageDOM, attemptsDOM, submitXHR; var reviewStep, checkmark, submitDOM, nextDOM, reviewDOM, tryAgainDOM,
assessmentMessageDOM, gradeDOM, attemptsDOM, submitXHR;
function isLastStep() { function isLastStep() {
return (activeStep === steps.length-1); return (activeStep === steps.length-1);
...@@ -43,11 +45,25 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -43,11 +45,25 @@ function MentoringWithStepsBlock(runtime, element) {
}); });
} }
function updateGrade() {
var handlerUrl = runtime.handlerUrl(element, 'get_score');
$.post(handlerUrl, JSON.stringify({}))
.success(function(response) {
gradeDOM.data('score', response.score);
gradeDOM.data('correct_answer', response.correct_answers);
gradeDOM.data('incorrect_answer', response.incorrect_answers);
gradeDOM.data('partially_correct_answer', response.partially_correct_answers);
});
}
function handleResults(response) { function handleResults(response) {
// Update active 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")
updateActiveStep(activeStep+1); updateActiveStep(activeStep+1);
if (response.update_attempts) {
// If step submitted was last step of this mentoring block, update grade and number of attempts used
if (response.attempt_complete) {
updateNumAttempts(); updateNumAttempts();
updateGrade();
} }
// Update UI // Update UI
...@@ -96,6 +112,7 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -96,6 +112,7 @@ function MentoringWithStepsBlock(runtime, element) {
checkmark.removeClass('checkmark-incorrect icon-exclamation fa-exclamation'); checkmark.removeClass('checkmark-incorrect icon-exclamation fa-exclamation');
hideAllSteps(); hideAllSteps();
assessmentMessageDOM.html(''); assessmentMessageDOM.html('');
gradeDOM.html('');
attemptsDOM.html(''); attemptsDOM.html('');
} }
...@@ -117,12 +134,14 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -117,12 +134,14 @@ function MentoringWithStepsBlock(runtime, element) {
} }
function showAssessmentMessage() { function showAssessmentMessage() {
var data = $('.grade', element).data(); var data = gradeDOM.data();
assessmentMessageDOM.html(data.assessment_message); assessmentMessageDOM.html(data.assessment_message);
} }
function showReviewStep() { function showReviewStep() {
reviewStep.show(); reviewStep.show();
var data = gradeDOM.data();
gradeDOM.html(gradeTemplate(data));
submitDOM.hide(); submitDOM.hide();
nextDOM.hide(); nextDOM.hide();
reviewDOM.hide(); reviewDOM.hide();
...@@ -226,6 +245,7 @@ function MentoringWithStepsBlock(runtime, element) { ...@@ -226,6 +245,7 @@ function MentoringWithStepsBlock(runtime, element) {
tryAgainDOM.on('click', tryAgain); tryAgainDOM.on('click', tryAgain);
assessmentMessageDOM = $('.assessment-message', element); assessmentMessageDOM = $('.assessment-message', element);
gradeDOM = $('.grade', element);
attemptsDOM = $('.attempts', element); attemptsDOM = $('.attempts', element);
var options = { var options = {
......
...@@ -154,7 +154,7 @@ class MentoringStepBlock( ...@@ -154,7 +154,7 @@ class MentoringStepBlock(
'message': 'Success!', 'message': 'Success!',
'completed': completed, 'completed': completed,
'results': submit_results, 'results': submit_results,
'update_attempts': self.is_last_step 'attempt_complete': self.is_last_step
} }
def reset(self): def reset(self):
......
...@@ -17,6 +17,10 @@ ...@@ -17,6 +17,10 @@
<div class="grade" <div class="grade"
data-assessment_message="{{ self.assessment_message }}" data-assessment_message="{{ self.assessment_message }}"
data-score="{{ self.score.percentage }}"
data-correct_answer="{{ self.score.correct|length }}"
data-incorrect_answer="{{ self.score.incorrect|length }}"
data-partially_correct_answer="{{ self.score.partially_correct|length }}">
</div> </div>
<div class="submit"> <div class="submit">
......
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