Commit 111f7533 by Victor Shnayder

Display (unstyled) progress in problems inside sequences

* verticals not-in-sequences next
parent 53d0a6ad
......@@ -157,6 +157,8 @@ class LoncapaProblem(object):
def get_max_score(self):
'''
Return maximum score for this problem.
TODO (vshnayder): Is this fixed once the problem is instantiated? Can we compute it only once?
'''
maxscore = 0
for response, responder in self.responders.iteritems():
......
......@@ -207,15 +207,21 @@ class CapaModule(XModule):
return None
def get_html(self):
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_status': Progress.to_js_status_str(progress),
'progress_detail': Progress.to_js_detail_str(progress),
})
def get_problem_html(self, encapsulate=True):
'''Return html for the problem. Adds check, reset, save buttons
as necessary based on the problem config and state.'''
def get_problem_html(self):
"""
Return html for the problem. Adds check, reset, save buttons
as necessary based on the problem config and state.
"""
try:
html = self.lcp.get_html()
......@@ -286,33 +292,29 @@ class CapaModule(XModule):
'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 = '<div id="problem_{id}" class="problem" data-url="{ajax_url}">'.format(
id=self.location.html_id(), ajax_url=self.system.ajax_url) + html + "</div>"
return self.system.replace_urls(html, self.metadata['data_dir'])
def handle_ajax(self, dispatch, get):
'''
"""
This is called by courseware.module_render, to handle an AJAX call.
"get" is request.POST.
Returns a json dictionary:
{ 'progress_changed' : True/False,
'progress' : 'none'/'in_progress'/'done',
'progress_status' : 'none'/'in_progress'/'done',
'progress_detail' : 'NA' / '0/3' / '3/8' / '21/20'
<other request-specific values here > }
'''
"""
handlers = {
'problem_get': self.get_problem,
'problem_check': self.check_problem,
'problem_reset': self.reset_problem,
'problem_save': self.save_problem,
'problem_show': self.get_answer,
'score_update': self.update_score,
'score_update': self.update_score, # Callback for xqueue/grader, not the user's browser.
}
if dispatch not in handlers:
......@@ -324,6 +326,7 @@ class CapaModule(XModule):
d.update({
'progress_changed': after != before,
'progress_status': Progress.to_js_status_str(after),
'progress_detail': Progress.to_js_detail_str(after),
})
return json.dumps(d, cls=ComplexEncoder)
......@@ -414,7 +417,7 @@ class CapaModule(XModule):
Used if we want to reconfirm we have the right thing e.g. after
several AJAX calls.
'''
return {'html': self.get_problem_html(encapsulate=False)}
return {'html': self.get_problem_html()}
@staticmethod
def make_dict_of_responses(get):
......@@ -514,7 +517,7 @@ class CapaModule(XModule):
self.system.psychometrics_handler(self.get_instance_state())
# render problem into HTML
html = self.get_problem_html(encapsulate=False)
html = self.get_problem_html()
return {'success': success,
'contents': html,
......@@ -587,7 +590,7 @@ class CapaModule(XModule):
event_info['new_state'] = self.lcp.get_state()
self.system.track_function('reset_problem', event_info)
return {'html': self.get_problem_html(encapsulate=False)}
return {'html': self.get_problem_html()}
class CapaDescriptor(RawDescriptor):
......
......@@ -30,6 +30,10 @@ nav.sequence-nav {
pointer-events: none;
}
.student-progress {
display: block;
}
.sequence-list-wrapper {
position: relative;
z-index: 99;
......@@ -154,7 +158,7 @@ nav.sequence-nav {
background-image: url('../images/sequence-nav/list-unstarted.png');
}
&.progress-some, &.progress-in_progress {
&.progress-in_progress {
background-image: url('../images/sequence-nav/list-unfinished.png');
}
......
......@@ -19,7 +19,6 @@ class @Problem
@$('section.action input:button').click @refreshAnswers
@$('section.action input.check').click @check_fd
#@$('section.action input.check').click @check
@$('section.action input.reset').click @reset
@$('section.action input.show').click @show
@$('section.action input.save').click @save
......@@ -27,7 +26,8 @@ class @Problem
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')
queueing: =>
......
......@@ -18,11 +18,10 @@ class @Sequence
initProgress: ->
@progressTable = {} # "#problem_#{id}" -> progress
hookUpProgressEvent: ->
$('.problems-wrapper').bind 'progressChanged', @updateProgress
mergeProgress: (p1, p2) ->
mergeProgressStatus: (p1, p2) ->
# if either is "NA", return the other one
if p1 == "NA"
return p2
......@@ -41,25 +40,55 @@ class @Sequence
return "none"
updateOverallScore: (details) =>
# Given a list of "a/b" strings, compute the sum(a)/sum(b), and the corresponding percentage
gotten = 0
possible = 0
for d in details
if d? and d.indexOf('/') > 0
a = d.split('/')
got = parseInt(a[0])
pos = parseInt(a[1])
gotten += got
possible += pos
if possible > 0
s = (gotten / possible * 100).toFixed(1) + "%"
else
s = "0%"
s += " (" + gotten + '/' + possible + ")"
@el.find('.overall-progress').html(s)
updateProgress: =>
new_progress = "NA"
new_progress_status = "NA"
scores_list = @el.find('.progress-score-list')
scores_list.empty()
details = []
_this = this
$('.problems-wrapper').each (index) ->
progress = $(this).attr 'progress'
new_progress = _this.mergeProgress progress, new_progress
progress_status = $(this).data('progress_status')
new_progress_status = _this.mergeProgressStatus progress_status, new_progress_status
progress_detail = $(this).data('progress_detail')
scores_list.append("<li>" + progress_detail + "</li>")
details.push(progress_detail)
@progressTable[@position] = new_progress
@setProgress(new_progress, @link_for(@position))
@progressTable[@position] = new_progress_status
@setProgress(new_progress_status, @link_for(@position))
@updateOverallScore(details)
setProgress: (progress, element) ->
# If progress is "NA", don't add any css class
element.removeClass('progress-none')
.removeClass('progress-some')
.removeClass('progress-in_progress')
.removeClass('progress-done')
switch progress
when 'none' then element.addClass('progress-none')
when 'in_progress' then element.addClass('progress-some')
when 'in_progress' then element.addClass('progress-in_progress')
when 'done' then element.addClass('progress-done')
toggleArrows: =>
......@@ -95,6 +124,8 @@ class @Sequence
sequence_links = @$('#seq_content a.seqnav')
sequence_links.click @goto
# update score lists
@updateProgress()
goto: (event) =>
event.preventDefault()
......
......@@ -23,7 +23,9 @@ class VerticalModule(XModule):
})
def get_progress(self):
# TODO: Cache progress or children array?
"""
Combine the progress of all the children.
"""
children = self.get_children()
progresses = [child.get_progress() for child in children]
progress = reduce(Progress.add_counts, progresses, None)
......
<section id="problem_${element_id}" class="problems-wrapper" data-problem-id="${id}" data-url="${ajax_url}"></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>
<div id="sequence_${element_id}" class="sequence" data-id="${item_id}" data-position="${position}" data-course_modx_root="/course/modx" >
<div class="student-progress">
<div class="summary">
Overall: <span class="overall-progress"> </span>
</div>
<div class="details">
Scores:
<ul class="progress-score-list">
</ul>
</div>
</div>
<nav aria-label="Section Navigation" class="sequence-nav">
<div class="sequence-list-wrapper">
<ol id="sequence-list">
......
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