Commit 8129f786 by ichuang Committed by Matthew Mongeau

second pass in capa cleanup:

  - each response can now render its own xhtml
  - cleaned up LoncapaProblem.extract_html
parent 19f915af
......@@ -33,26 +33,17 @@ def get_input_xml_tags():
class SimpleInput():# XModule
''' Type for simple inputs -- plain HTML with a form element
State is a dictionary with optional keys:
* Value
* ID
* Status (answered, unanswered, unsubmitted)
* Feedback (dictionary containing keys for hints, errors, or other
feedback from previous attempt)
'''
xml_tags = {} ## Maps tags to functions
@classmethod
def get_xml_tags(c):
return c.xml_tags.keys()
@classmethod
def get_uses(c):
return ['capa_input', 'capa_transform']
def get_html(self):
return self.xml_tags[self.tag](self.xml, self.value, self.status, self.system.render_template, self.msg)
def __init__(self, system, xml, item_id = None, track_url=None, state=None, use = 'capa_input'):
self.xml = xml
......@@ -83,49 +74,16 @@ class SimpleInput():# XModule
if 'status' in state:
self.status = state['status']
## TODO
# class SimpleTransform():
# ''' Type for simple XML to HTML transforms. Examples:
# * Math tags, which go from LON-CAPA-style m-tags to MathJAX
# '''
# xml_tags = {} ## Maps tags to functions
# @classmethod
# def get_xml_tags(c):
# return c.xml_tags.keys()
# @classmethod
# def get_uses(c):
# return ['capa_transform']
# def get_html(self):
# return self.xml_tags[self.tag](self.xml, self.value, self.status, self.msg)
# def __init__(self, system, xml, item_id = None, track_url=None, state=None, use = 'capa_input'):
# self.xml = xml
# self.tag = xml.tag
# if not state:
# state = {}
# if item_id:
# self.id = item_id
# if xml.get('id'):
# self.id = xml.get('id')
# if 'id' in state:
# self.id = state['id']
# self.system = system
# self.value = ''
# if 'value' in state:
# self.value = state['value']
# self.msg = ''
# if 'feedback' in state and 'message' in state['feedback']:
# self.msg = state['feedback']['message']
# self.status = 'unanswered'
# if 'status' in state:
# self.status = state['status']
@classmethod
def get_xml_tags(c):
return c.xml_tags.keys()
@classmethod
def get_uses(c):
return ['capa_input', 'capa_transform']
def get_html(self):
return self.xml_tags[self.tag](self.xml, self.value, self.status, self.system.render_template, self.msg)
def register_render_function(fn, names=None, cls=SimpleInput):
if names is None:
......@@ -136,9 +94,6 @@ def register_render_function(fn, names=None, cls=SimpleInput):
return fn
return wrapped
#-----------------------------------------------------------------------------
@register_render_function
......@@ -201,16 +156,16 @@ def choicegroup(element, value, status, render_template, msg=''):
return etree.XML(html)
@register_render_function
def textline(element, value, state, render_template, msg=""):
def textline(element, value, status, render_template, msg=""):
'''
Simple text line input, with optional size specification.
'''
if element.get('math') or element.get('dojs'): # 'dojs' flag is temporary, for backwards compatibility with 8.02x
return SimpleInput.xml_tags['textline_dynamath'](element,value,state,render_template,msg)
return SimpleInput.xml_tags['textline_dynamath'](element,value,status,render_template,msg)
eid=element.get('id')
count = int(eid.split('_')[-2])-1 # HACK
size = element.get('size')
context = {'id':eid, 'value':value, 'state':state, 'count':count, 'size': size, 'msg': msg}
context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size, 'msg': msg}
html = render_template("textinput.html", context)
return etree.XML(html)
......
......@@ -63,7 +63,8 @@ class GenericResponse(object):
- get_max_score : if defined, this is called to obtain the maximum score possible for this question
- setup_response : find and note the answer input field IDs for the response; called by __init__
- __unicode__ : unicode representation of this Response
- render_html : render this Response as HTML (must return XHTML compliant string)
- __unicode__ : unicode representation of this Response
Each response type may also specify the following attributes:
......@@ -114,9 +115,30 @@ class GenericResponse(object):
if self.max_inputfields==1:
self.answer_id = self.answer_ids[0] # for convenience
self.default_answer_map = {} # dict for default answer map (provided in input elements)
for entry in self.inputfields:
answer = entry.get('correct_answer')
if answer:
self.default_answer_map[entry.get('id')] = contextualize_text(answer, self.context)
if hasattr(self,'setup_response'):
self.setup_response()
def render_html(self,renderer):
'''
Return XHTML Element tree representation of this Response.
Arguments:
- renderer : procedure which produces HTML given an ElementTree
'''
tree = etree.Element('span') # render ourself as a <span> + our content
for item in self.xml:
item_xhtml = renderer(item) # call provided procedure to do the rendering
if item_xhtml is not None: tree.append(item_xhtml)
tree.tail = self.xml.tail
return tree
@abc.abstractmethod
def get_score(self, student_answers):
'''
......@@ -132,7 +154,6 @@ class GenericResponse(object):
'''
pass
#not an abstract method because plenty of responses will not want to preprocess anything, and we should not require that they override this method.
def setup_response(self):
pass
......@@ -485,17 +506,17 @@ def sympy_check2():
'''
Give correct answer expected for this response.
capa_problem handles correct_answers from entry objects like textline, and that
is what should be used when this response has multiple entry objects.
use default_answer_map from entry elements (eg textline),
when this response has multiple entry objects.
but for simplicity, if an "expect" attribute was given by the content author
ie <customresponse expect="foo" ...> then return it now.
ie <customresponse expect="foo" ...> then that.
'''
if len(self.answer_ids)>1:
return {}
return self.default_answer_map
if self.expect:
return {self.answer_ids[0] : self.expect}
return {}
return self.default_answer_map
#-----------------------------------------------------------------------------
......@@ -797,9 +818,8 @@ class SchematicResponse(GenericResponse):
return zip(sorted(self.answer_ids), self.context['correct'])
def get_answers(self):
# Since this is explicitly specified in the problem, this will
# be handled by capa_problem
return {}
# use answers provided in input elements
return self.default_answer_map
#-----------------------------------------------------------------------------
......
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