Commit bf7aef1b by Dave St.Germain

Convert CAPA inputtype statuses from strings to objects, in order to

simplify css class management and internationalization of status strings
(potentially) displayed to the user.
parent 963f5685
......@@ -60,7 +60,47 @@ log = logging.getLogger(__name__)
#########################################################################
registry = TagRegistry()
registry = TagRegistry() # pylint: disable=C0103
class Status(object):
"""
Problem status
attributes: classname, display_name
"""
css_classes = {
# status: css class
'unsubmitted': 'unanswered',
'incomplete': 'incorrect',
'queued': 'processing',
}
__slots__ = ('classname', '_status', 'display_name')
def __init__(self, status, gettext_func=unicode):
self.classname = self.css_classes.get(status, status)
_ = gettext_func
names = {
'correct': _('correct'),
'incorrect': _('incorrect'),
'incomplete': _('incomplete'),
'unanswered': _('unanswered'),
'unsubmitted': _('unanswered'),
'queued': _('processing'),
}
self.display_name = names.get(status, unicode(status))
self._status = status or ''
def __str__(self):
return self._status
def __unicode__(self):
return self._status.decode('utf8')
def __repr__(self):
return 'Status(%r)' % self._status
def __eq__(self, other):
return self._status == str(other)
class Attribute(object):
......@@ -259,9 +299,7 @@ class InputTypeBase(object):
context = {
'id': self.input_id,
'value': self.value,
'status': self.status,
'status_class': self.status_class,
'status_display': self.status_display,
'status': Status(self.status, self.capa_system.i18n.ugettext),
'msg': self.msg,
'STATIC_URL': self.capa_system.STATIC_URL,
}
......@@ -271,34 +309,6 @@ class InputTypeBase(object):
context.update(self._extra_context())
return context
@property
def status_class(self):
"""
Return the CSS class for the associated status.
"""
statuses = {
'unsubmitted': 'unanswered',
'incomplete': 'incorrect',
'queued': 'processing',
}
return statuses.get(self.status, self.status)
@property
def status_display(self):
"""
Return the human-readable and translated word for the associated status.
"""
_ = self.capa_system.i18n.ugettext
statuses = {
'correct': _('correct'),
'incorrect': _('incorrect'),
'incomplete': _('incomplete'),
'unanswered': _('unanswered'),
'unsubmitted': _('unanswered'),
'queued': _('queued'),
}
return statuses.get(self.status, self.status)
def _extra_context(self):
"""
Subclasses can override this to return extra context that should be passed to their templates for rendering.
......
......@@ -52,13 +52,7 @@
<input type="hidden" class="value" name="input_${id}" id="input_${id}" value="${value|h}" />
% endif
% if status == 'unsubmitted':
<span class="unanswered" style="display:inline-block;" id="status_${id}" aria-describedby="input_${id}"><span class="sr">Status: Unanswered</span></span>
% elif status == 'incomplete':
<span class="incorrect" id="status_${id}" aria-describedby="input_${id}"><span class="sr">Status: Incorrect</span></span>
% elif status == 'incorrect' and not has_options_value:
<span class="incorrect" id="status_${id}" aria-describedby="input_${id}"><span class="sr">Status: Incorrect</span></span>
% endif
<span class="status ${status.classname}" id="status_${id}" aria-describedby="input_${id}"><span class="sr">${status.display_name}</span></span>
<p id="answer_${id}" class="answer answer-annotation"></p>
</div>
......
<div id="chemicalequationinput_${id}" class="chemicalequationinput">
<div class="script_placeholder" data-src="${previewer}"/>
<div class="${status_class}" id="status_${id}">
<div class="${status.classname}" id="status_${id}">
<input type="text" name="input_${id}" id="input_${id}" aria-label="${label}" aria-describedby="answer_${id}" data-input-id="${id}" value="${value|h}"
% if size:
......@@ -11,7 +11,7 @@
<p class="status" aria-describedby="input_${id}">
${value|h} -
${status_display}
${status.display_name}
</p>
<div id="input_${id}_preview" class="equation"></div>
......
<form class="choicegroup capa_inputtype" id="inputtype_${id}">
<div class="indicator_container">
% if input_type == 'checkbox' or not value:
<span class="status ${status_class if show_correctness != 'never' else 'unanswered'}"
<span class="status ${status.classname if show_correctness != 'never' else 'unanswered'}"
id="status_${id}"
aria-describedby="inputtype_${id}">
<span class="sr">
......@@ -11,7 +11,7 @@
%endif
%endfor
-
${status_display}
${status.display_name}
</span>
</span>
% endif
......@@ -51,7 +51,7 @@
% if input_type == 'radio' and ( (isinstance(value, basestring) and (choice_id == value)) or (not isinstance(value, basestring) and choice_id in value) ):
% if status in ('correct', 'incorrect') and not show_correctness=='never':
<span class="sr status">${choice_description|h} - ${status_display}</span>
<span class="sr status">${choice_description|h} - ${status.display_name}</span>
% endif
% endif
</label>
......
......@@ -10,7 +10,7 @@
<div class="script_placeholder" data-src="/static/js/capa/choicetextinput.js"/>
<div class="indicator_container">
% if input_type == 'checkbox' or not element_checked:
<span class="status ${status_class}" id="status_${id}"></span>
<span class="status ${status.classname}" id="status_${id}"></span>
% endif
</div>
......
......@@ -17,10 +17,10 @@
<div class="grader-status" tabindex="-1">
<span id="status_${id}"
class="${status_class}"
class="${status.classname}"
aria-describedby="input_${id}"
>
<span class="status sr">${status_display}</span>
<span class="status sr">${status.display_name}</span>
</span>
% if status == 'queued':
<span style="display:none;" class="xqueue" id="${id}">${queue_len}</span>
......@@ -30,7 +30,7 @@
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
% endif
<p class="debug">${status_display}</p>
<p class="debug">${status.display_name}</p>
</div>
<span id="answer_${id}"></span>
......
......@@ -9,29 +9,14 @@
<div class="script_placeholder" data-src="/static/js/sylvester.js"></div>
<div class="script_placeholder" data-src="/static/js/crystallography.js"></div>
% if status == 'unsubmitted':
<div class="unanswered" id="status_${id}">
% elif status == 'correct':
<div class="correct" id="status_${id}">
% elif status == 'incorrect':
<div class="incorrect" id="status_${id}">
% elif status == 'incomplete':
<div class="incorrect" id="status_${id}">
% endif
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="status ${status.classname}" id="status_${id}">
<input type="text" name="input_${id}" aria-describedby="answer_${id}" id="input_${id}" value="${value|h}" style="display:none;"/>
<p class="status" aria-describedby="input_${id}">
% if status == 'unsubmitted':
unanswered
% elif status == 'correct':
correct
% elif status == 'incorrect':
incorrect
% elif status == 'incomplete':
incomplete
% endif
${status.display_name}
</p>
<p id="answer_${id}" class="answer"></p>
......
......@@ -2,14 +2,8 @@
<div class="script_placeholder" data-src="/static/js/capa/protex/protex.nocache.js?raw"/>
<div class="script_placeholder" data-src="${applet_loader}"/>
% if status == 'unsubmitted':
<div class="unanswered" id="status_${id}">
% elif status == 'correct':
<div class="correct" id="status_${id}">
% elif status == 'incorrect':
<div class="incorrect" id="status_${id}">
% elif status == 'incomplete':
<div class="incomplete" id="status_${id}">
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
<div id="protex_container"></div>
......@@ -17,15 +11,7 @@
<input type="hidden" name="input_${id}" id="input_${id}" aria-describedby="answer_${id}" value="${value|h}"/>
<p class="status" aria-describedby="input_${id}">
% if status == 'unsubmitted':
unanswered
% elif status == 'correct':
correct
% elif status == 'incorrect':
incorrect
% elif status == 'incomplete':
incomplete
% endif
${status.display_name}
</p>
<p id="answer_${id}" class="answer"></p>
......
......@@ -8,14 +8,8 @@
<div class="script_placeholder" data-src="${STATIC_URL}js/capa/drag_and_drop.js"></div>
% if status == 'unsubmitted':
<div class="unanswered" id="status_${id}">
% elif status == 'correct':
<div class="correct" id="status_${id}">
% elif status == 'incorrect':
<div class="incorrect" id="status_${id}">
% elif status == 'incomplete':
<div class="incorrect" id="status_${id}">
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
......@@ -23,15 +17,7 @@
style="display:none;"/>
<p class="status" aria-describedby="input_${id}">
% if status == 'unsubmitted':
unanswered
% elif status == 'correct':
correct
% elif status == 'incorrect':
incorrect
% elif status == 'incomplete':
incomplete
% endif
${status.display_name}
</p>
<p id="answer_${id}" class="answer"></p>
......
......@@ -2,14 +2,8 @@
<div class="script_placeholder" data-src="/static/js/capa/genex/genex.nocache.js?raw"/>
<div class="script_placeholder" data-src="${applet_loader}"/>
% if status == 'unsubmitted':
<div class="unanswered" id="status_${id}">
% elif status == 'correct':
<div class="correct" id="status_${id}">
% elif status == 'incorrect':
<div class="incorrect" id="status_${id}">
% elif status == 'incomplete':
<div class="incomplete" id="status_${id}">
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
<div id="genex_container"></div>
......@@ -18,15 +12,7 @@
<input type="hidden" name="input_${id}" aria-describedby="answer_${id}" id="input_${id}" value="${value|h}"/>
<p class="status" aria-describedby="input_${id}">
% if status == 'unsubmitted':
unanswered
% elif status == 'correct':
correct
% elif status == 'incorrect':
incorrect
% elif status == 'incomplete':
incomplete
% endif
${status.display_name}
</p>
<p id="answer_${id}" class="answer"></p>
......
<section id="editamoleculeinput_${id}" class="editamoleculeinput">
<div class="script_placeholder" data-src="${applet_loader}"/>
% if status == 'unsubmitted':
<div class="unanswered" id="status_${id}">
% elif status == 'correct':
<div class="correct" id="status_${id}">
% elif status == 'incorrect':
<div class="incorrect" id="status_${id}">
% elif status == 'incomplete':
<div class="incorrect" id="status_${id}">
% endif
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
<div id="applet_${id}" class="applet" data-molfile-src="${file}" style="display:block;width:500px;height:400px">
</div>
......@@ -23,15 +17,7 @@
<p id="answer_${id}" class="answer"></p>
<p class="status" aria-describedby="input_${id}">
% if status == 'unsubmitted':
unanswered
% elif status == 'correct':
correct
% elif status == 'incorrect':
incorrect
% elif status == 'incomplete':
incomplete
% endif
${status.display_name}
</p>
<br/> <br/>
......
<section id="filesubmission_${id}" class="filesubmission">
<div class="grader-status file">
% if status == 'unsubmitted':
<span class="unanswered" style="display:inline-block;" id="status_${id}">Unanswered</span>
% elif status == 'correct':
<span class="correct" id="status_${id}">Correct</span>
% elif status == 'incorrect':
<span class="incorrect" id="status_${id}">Incorrect</span>
% elif status == 'queued':
<span class="processing" id="status_${id}">Queued</span>
<span style="display:none;" class="xqueue" id="${id}" >${queue_len}</span>
<span class="${status.classname}" id="status_${id}">${status.display_name}</span>
% if status == 'queued':
<span style="display:none;" class="xqueue" id="${id}">${queue_len}</span>
% endif
<p class="debug">${status}</p>
......
<% doinline = 'style="display:inline-block;vertical-align:top"' if inline else "" %>
<section id="formulaequationinput_${id}" class="inputtype formulaequationinput" ${doinline}>
<div class="${status_class}" id="status_${id}">
<div class="${status.classname}" id="status_${id}">
<input type="text" name="input_${id}" id="input_${id}"
data-input-id="${id}" value="${value|h}"
aria-label="${label}"
......@@ -20,7 +20,7 @@
% else:
${label}
%endif
</span> - ${status_display}
</span> - ${status.display_name}
</p>
<div id="input_${id}_preview" class="equation">
......
......@@ -39,38 +39,11 @@
(new ImageInput('${id}'));
</script>
% if status == 'unsubmitted':
<span
class="unanswered"
style="display: inline-block;"
class="status ${status.classname}"
id="status_${id}"
aria-describedby="input_${id}"
>
<span class="sr">Status: unanswered</span>
<span class="sr">${status.display_name}</span>
</span>
% elif status == 'correct':
<span
class="correct"
id="status_${id}"
aria-describedby="input_${id}"
>
<span class="sr">Status: correct</span>
</span>
% elif status == 'incorrect':
<span
class="incorrect"
id="status_${id}"
aria-describedby="input_${id}"
>
<span class="sr">Status: incorrect</span>
</span>
% elif status == 'incomplete':
<span
class="incorrect"
id="status_${id}"
aria-describedby="input_${id}"
>
<span class="sr">Status: incorrect</span>
</span>
% endif
</div>
......@@ -17,14 +17,8 @@
<div class="script_placeholder" data-src="${jschannel_loader}"/>
<div class="script_placeholder" data-src="${jsinput_loader}"/>
% if status == 'unsubmitted':
<div class="unanswered" id="status_${id}">
% elif status == 'correct':
<div class="correct" id="status_${id}">
% elif status == 'incorrect':
<div class="incorrect" id="status_${id}">
% elif status == 'incomplete':
<div class="incorrect" id="status_${id}">
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
<iframe name="iframe_${id}"
......@@ -44,15 +38,7 @@
<p id="answer_${id}" class="answer"></p>
<p class="status">
% if status == 'unsubmitted':
unanswered
% elif status == 'correct':
correct
% elif status == 'incorrect':
incorrect
% elif status == 'incomplete':
incomplete
% endif
${status.display_name}
</p>
<br/> <br/>
......
......@@ -18,23 +18,9 @@
<textarea style="display:none" id="input_${id}_fromjs" name="input_${id}_fromjs"></textarea>
% endif
% if status == 'unsubmitted':
<span class="unanswered" style="display:inline-block;" id="status_${id}" aria-describedby="input_${id}">
<span class="sr">Status: unanswered</span>
<span class="status ${status.classname}" id="status_${id}" aria-describedby="input_${id}">
<span class="sr">${status.display_name</span>
</span>
% elif status == 'correct':
<span class="correct" id="status_${id}" aria-describedby="input_${id}">
<span class="sr">Status: correct</span>
</span>
% elif status == 'incorrect':
<span class="incorrect" id="status_${id}" aria-describedby="input_${id}">
<span class="sr">Status: incorrect</span>
</span>
% elif status == 'incomplete':
<span class="incorrect" id="status_${id}" aria-describedby="input_${id}">
<span class="sr">Status: incorrect</span>
</span>
% endif
% if msg:
<br/>
<span class="debug">${msg|n}</span>
......
......@@ -18,10 +18,10 @@
<div class="grader-status" tabindex="-1">
<span id="status_${id}"
class="${status_class}"
class="${status.classname}"
aria-describedby="input_${id}"
>
<span class="status sr">${status_display}</span>
<span class="status sr">${status.display_name}</span>
</span>
% if status == 'queued':
<span style="display:none;" class="xqueue" id="${id}">${queue_len}</span>
......@@ -31,7 +31,7 @@
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
% endif
<p class="debug">${status_display}</p>
<p class="debug">${status.display_name}</p>
</div>
<span id="answer_${id}"></span>
......
......@@ -13,10 +13,10 @@
</select>
<span id="answer_${id}"></span>
<span class="status ${status_class}"
<span class="status ${status.classname}"
id="status_${id}"
aria-describedby="input_${id}">
<span class="sr">${value|h} - ${status_display}</span>
<span class="sr">${value|h} - ${status.display_name}</span>
</span>
% if msg:
......
<span>
<div>
<div class="script_placeholder" data-src="${setup_script}"/>
<input type="hidden"
class="schematic"
......@@ -16,23 +16,7 @@
/>
<span id="answer_${id}"></span>
% if status == 'unsubmitted':
<span class="ui-icon ui-icon-bullet" style="display:inline-block;" id="status_${id}" aria-describedby="input_${id}">
<span class="sr">Status: unsubmitted</span>
<span class="status ${status.classname}" id="status_${id}" aria-describedby="input_${id}">
<span class="sr">${status.display_name}</span>
</span>
% elif status == 'correct':
<span class="ui-icon ui-icon-check" style="display:inline-block;" id="status_${id}" aria-describedby="input_${id}">
<span class="sr">Status: correct</span>
</span>
% elif status == 'incorrect':
<span class="ui-icon ui-icon-close" style="display:inline-block;" id="status_${id}" aria-describedby="input_${id}">
<span class="sr">Status: incorrect</span>
</span>
% elif status == 'incomplete':
<span class="ui-icon ui-icon-close" style="display:inline-block;" id="status_${id}" aria-describedby="input_${id}">
<span class="sr">Status: incomplete</span>
</span>
% endif
</span>
</div>
......@@ -8,7 +8,7 @@
% endif
% if status in ('unsubmitted', 'correct', 'incorrect', 'incomplete'):
<div class="${status_class} ${doinline}" id="status_${id}">
<div class="${status.classname} ${doinline}" id="status_${id}">
% endif
% if hidden:
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
......@@ -38,7 +38,7 @@
${label}
%endif
-
${status_display}
${status.display_name}
</p>
<p id="answer_${id}" class="answer" aria-hidden="true"></p>
......
......@@ -11,14 +11,8 @@
<div class="script_placeholder" data-src="/static/js/vsepr/vsepr.js"></div>
% if status == 'unsubmitted':
<div class="unanswered" id="status_${id}">
% elif status == 'correct':
<div class="correct" id="status_${id}">
% elif status == 'incorrect':
<div class="incorrect" id="status_${id}">
% elif status == 'incomplete':
<div class="incorrect" id="status_${id}">
% if status in ['unsubmitted', 'correct', 'incorrect', 'incomplete']:
<div class="${status.classname}" id="status_${id}">
% endif
<input type="text" name="input_${id}" id="input_${id}" aria-describedby="answer_${id}" value="${value|h}"
......@@ -26,15 +20,7 @@
/>
<p class="status" aria-describedby="input_${id}">
% if status == 'unsubmitted':
unanswered
% elif status == 'correct':
correct
% elif status == 'incorrect':
incorrect
% elif status == 'incomplete':
incomplete
% endif
${status.display_name}
</p>
<p id="answer_${id}" class="answer"></p>
......
......@@ -7,6 +7,7 @@ import os.path
import fs.osfs
from capa.capa_problem import LoncapaProblem, LoncapaSystem
from capa.inputtypes import Status
from mock import Mock, MagicMock
import xml.sax.saxutils as saxutils
......@@ -47,6 +48,7 @@ def test_capa_system():
render_template=tst_render_template,
seed=0,
STATIC_URL='/dummy-static/',
STATUS_CLASS=Status,
xqueue={'interface': xqueue_interface, 'construct_callback': calledback_url, 'default_queuename': 'testqueue', 'waittime': 10},
)
return the_system
......
......@@ -153,9 +153,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
# the solution
expected_textline_context = {
'STATIC_URL': '/dummy-static/',
'status': 'unsubmitted',
'status_class': 'unanswered',
'status_display': u'unanswered',
'status': the_system.STATUS_CLASS('unsubmitted'),
'label': '',
'value': '',
'preprocessor': None,
......
......@@ -4,7 +4,8 @@ class @HTMLModule
@el = $(@element)
JavascriptLoader.executeModuleScripts(@el)
Collapsible.setCollapsibles(@el)
MathJax.Hub.Queue ["Typeset", MathJax.Hub, @el[0]]
if MathJax?
MathJax.Hub.Queue ["Typeset", MathJax.Hub, @el[0]]
$: (selector) ->
$(selector, @el)
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