Commit 011ceb8e by Renzo Lucioni

Merge pull request #418 from edx/renzo/in-context-progress

Renzo/in context progress
parents 73e6e6f4 9af87e41
......@@ -309,7 +309,13 @@ class CapaModule(CapaFields, XModule):
d = self.get_score()
score = d['score']
total = d['total']
if total > 0:
if self.weight is not None:
# scale score and total by weight/total:
score = score * self.weight / total
total = self.weight
try:
return Progress(score, total)
except (TypeError, ValueError):
......@@ -321,11 +327,13 @@ class CapaModule(CapaFields, XModule):
"""
Return some html with data about the module
"""
progress = self.get_progress()
return self.system.render_template('problem_ajax.html', {
'element_id': self.location.html_id(),
'id': self.id,
'ajax_url': self.system.ajax_url,
'progress': Progress.to_js_status_str(self.get_progress())
'progress_status': Progress.to_js_status_str(progress),
'progress_detail': Progress.to_js_detail_str(progress),
})
def check_button_name(self):
......@@ -485,8 +493,7 @@ class CapaModule(CapaFields, XModule):
"""
Return html for the problem.
Adds check, reset, save buttons as necessary based on the problem config
and state.
Adds check, reset, save buttons as necessary based on the problem config and state.
"""
try:
......@@ -516,13 +523,12 @@ class CapaModule(CapaFields, XModule):
'reset_button': self.should_show_reset_button(),
'save_button': self.should_show_save_button(),
'answer_available': self.answer_available(),
'ajax_url': self.system.ajax_url,
'attempts_used': self.attempts,
'attempts_allowed': self.max_attempts,
'progress': self.get_progress(),
}
html = self.system.render_template('problem.html', context)
if encapsulate:
html = u'<div id="problem_{id}" class="problem" data-url="{ajax_url}">'.format(
id=self.location.html_id(), ajax_url=self.system.ajax_url
......@@ -584,6 +590,7 @@ class CapaModule(CapaFields, XModule):
result.update({
'progress_changed': after != before,
'progress_status': Progress.to_js_status_str(after),
'progress_detail': Progress.to_js_detail_str(after),
})
return json.dumps(result, cls=ComplexEncoder)
......@@ -614,6 +621,7 @@ class CapaModule(CapaFields, XModule):
Problem can be completely wrong.
Pressing RESET button makes this function to return False.
"""
# used by conditional module
return self.lcp.done
def is_attempted(self):
......@@ -757,6 +765,7 @@ class CapaModule(CapaFields, XModule):
"""
return {'html': self.get_problem_html(encapsulate=False)}
@staticmethod
def make_dict_of_responses(data):
"""
......
......@@ -3,6 +3,7 @@ h2 {
margin-bottom: 15px;
&.problem-header {
display: inline-block;
section.staff {
margin-top: 30px;
font-size: 80%;
......@@ -28,6 +29,13 @@ iframe[seamless]{
color: darken($error-red, 11%);
}
section.problem-progress {
display: inline-block;
color: #999;
font-size: em(16);
font-weight: 100;
padding-left: 5px;
}
section.problem {
@media print {
......
<section class='xmodule_display xmodule_CapaModule' data-type='Problem'>
<section id='problem_1'
class='problems-wrapper'
class='problems-wrapper'
data-problem-id='i4x://edX/101/problem/Problem1'
data-url='/problem/Problem1'>
</section>
......
<h2 class="problem-header">Problem Header</h2>
<section class='problem-progress'>
</section>
<section class="problem">
<p>Problem Content</p>
......
......@@ -77,6 +77,25 @@ describe 'Problem', ->
[@problem.updateMathML, @stubbedJax, $('#input_example_1').get(0)]
]
describe 'renderProgressState', ->
beforeEach ->
@problem = new Problem($('.xmodule_display'))
#@renderProgressState = @problem.renderProgressState
describe 'with a status of "none"', ->
it 'reports the number of points possible', ->
@problem.el.data('progress_status', 'none')
@problem.el.data('progress_detail', '0/1')
@problem.renderProgressState()
expect(@problem.$('.problem-progress').html()).toEqual "(1 point possible)"
describe 'with any other valid status', ->
it 'reports the current score', ->
@problem.el.data('progress_status', 'foo')
@problem.el.data('progress_detail', '1/1')
@problem.renderProgressState()
expect(@problem.$('.problem-progress').html()).toEqual "(1/1 points)"
describe 'render', ->
beforeEach ->
@problem = new Problem($('.xmodule_display'))
......
......@@ -35,15 +35,34 @@ class @Problem
@$('input.math').each (index, element) =>
MathJax.Hub.Queue [@refreshMath, null, element]
renderProgressState: =>
detail = @el.data('progress_detail')
status = @el.data('progress_status')
# i18n
progress = "(#{detail} points)"
if status == 'none' and detail? and detail.indexOf('/') > 0
a = detail.split('/')
possible = parseInt(a[1])
if possible == 1
# i18n
progress = "(#{possible} point possible)"
else
# i18n
progress = "(#{possible} points possible)"
@$('.problem-progress').html(progress)
updateProgress: (response) =>
if response.progress_changed
@el.attr progress: response.progress_status
@el.data('progress_status', response.progress_status)
@el.data('progress_detail', response.progress_detail)
@el.trigger('progressChanged')
@renderProgressState()
forceUpdate: (response) =>
@el.attr progress: response.progress_status
@el.data('progress_status', response.progress_status)
@el.data('progress_detail', response.progress_detail)
@el.trigger('progressChanged')
@renderProgressState()
queueing: =>
@queued_items = @$(".xqueue")
......@@ -113,7 +132,7 @@ class @Problem
@setupInputTypes()
@bind()
@queueing()
@forceUpdate response
# TODO add hooks for problem types here by inspecting response.html and doing
# stuff if a div w a class is found
......
......@@ -45,7 +45,7 @@ class @Sequence
new_progress = "NA"
_this = this
$('.problems-wrapper').each (index) ->
progress = $(this).attr 'progress'
progress = $(this).data 'progress_status'
new_progress = _this.mergeProgress progress, new_progress
@progressTable[@position] = new_progress
......
......@@ -1233,6 +1233,37 @@ class CapaModuleTest(unittest.TestCase):
mock_log.exception.assert_called_once_with('Got bad progress')
mock_log.reset_mock()
@patch('xmodule.capa_module.Progress')
def test_get_progress_calculate_progress_fraction(self, mock_progress):
"""
Check that score and total are calculated correctly for the progress fraction.
"""
module = CapaFactory.create()
module.weight = 1
module.get_progress()
mock_progress.assert_called_with(0, 1)
other_module = CapaFactory.create(correct=True)
other_module.weight = 1
other_module.get_progress()
mock_progress.assert_called_with(1, 1)
def test_get_html(self):
"""
Check that get_html() calls get_progress() with no arguments.
"""
module = CapaFactory.create()
module.get_progress = Mock(wraps=module.get_progress)
module.get_html()
module.get_progress.assert_called_once_with()
def test_get_problem(self):
"""
Check that get_problem() returns the expected dictionary.
"""
module = CapaFactory.create()
self.assertEquals(module.get_problem("data"), {'html': module.get_problem_html(encapsulate=False)})
class ComplexEncoderTest(unittest.TestCase):
def test_default(self):
......
......@@ -129,3 +129,45 @@ Feature: Answer problems
When I press the button with the label "Hide Answer(s)"
Then the button with the label "Show Answer(s)" does appear
And I should not see "4.14159" anywhere on the page
Scenario: I can see my score on a problem when I answer it and after I reset it
Given I am viewing a "<ProblemType>" problem
When I answer a "<ProblemType>" problem "<Correctness>ly"
Then I should see a score of "<Score>"
When I reset the problem
Then I should see a score of "<Points Possible>"
Examples:
| ProblemType | Correctness | Score | Points Possible |
| drop down | correct | 1/1 points | 1 point possible |
| drop down | incorrect | 1 point possible | 1 point possible |
| multiple choice | correct | 1/1 points | 1 point possible |
| multiple choice | incorrect | 1 point possible | 1 point possible |
| checkbox | correct | 1/1 points | 1 point possible |
| checkbox | incorrect | 1 point possible | 1 point possible |
| radio | correct | 1/1 points | 1 point possible |
| radio | incorrect | 1 point possible | 1 point possible |
| string | correct | 1/1 points | 1 point possible |
| string | incorrect | 1 point possible | 1 point possible |
| numerical | correct | 1/1 points | 1 point possible |
| numerical | incorrect | 1 point possible | 1 point possible |
| formula | correct | 1/1 points | 1 point possible |
| formula | incorrect | 1 point possible | 1 point possible |
| script | correct | 2/2 points | 2 points possible |
| script | incorrect | 2 points possible | 2 points possible |
Scenario: I can see my score on a problem to which I submit a blank answer
Given I am viewing a "<ProblemType>" problem
When I check a problem
Then I should see a score of "<Points Possible>"
Examples:
| ProblemType | Points Possible |
| drop down | 1 point possible |
| multiple choice | 1 point possible |
| checkbox | 1 point possible |
| radio | 1 point possible |
| string | 1 point possible |
| numerical | 1 point possible |
| formula | 1 point possible |
| script | 2 points possible |
......@@ -142,6 +142,11 @@ def button_with_label_present(_step, buttonname, doesnt_appear):
assert world.browser.is_text_present(buttonname, wait_time=5)
@step(u'I should see a score of "([^"]*)"$')
def see_score(_step, score):
assert world.browser.is_text_present(score)
@step(u'My "([^"]*)" answer is marked "([^"]*)"')
def assert_answer_mark(step, problem_type, correctness):
"""
......
<%namespace name='static' file='static_content.html'/>
<h2 class="problem-header">
${ problem['name'] }
% if problem['weight'] != 1 and problem['weight'] is not None:
: ${ problem['weight'] } points
% endif
</h2>
<section class="problem-progress">
</section>
<section class="problem">
${ problem['html'] }
......
<section id="problem_${element_id}" class="problems-wrapper" data-problem-id="${id}" data-url="${ajax_url}" progress="${progress}"></section>
<section id="problem_${element_id}" class="problems-wrapper" data-problem-id="${id}" data-url="${ajax_url}" data-progress_status="${progress_status}" data-progress_detail="${progress_detail}"></section>
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