Commit fb3ac5b8 by ichuang

second pass in capa cleanup:

  - each response can now render its own xhtml
  - cleaned up LoncapaProblem.extract_html
parent cdab3920
...@@ -33,26 +33,17 @@ def get_input_xml_tags(): ...@@ -33,26 +33,17 @@ def get_input_xml_tags():
class SimpleInput():# XModule class SimpleInput():# XModule
''' Type for simple inputs -- plain HTML with a form element ''' Type for simple inputs -- plain HTML with a form element
State is a dictionary with optional keys: State is a dictionary with optional keys:
* Value * Value
* ID * ID
* Status (answered, unanswered, unsubmitted) * Status (answered, unanswered, unsubmitted)
* Feedback (dictionary containing keys for hints, errors, or other * Feedback (dictionary containing keys for hints, errors, or other
feedback from previous attempt) feedback from previous attempt)
''' '''
xml_tags = {} ## Maps tags to functions 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'): def __init__(self, system, xml, item_id = None, track_url=None, state=None, use = 'capa_input'):
self.xml = xml self.xml = xml
...@@ -83,49 +74,16 @@ class SimpleInput():# XModule ...@@ -83,49 +74,16 @@ class SimpleInput():# XModule
if 'status' in state: if 'status' in state:
self.status = state['status'] self.status = state['status']
## TODO @classmethod
# class SimpleTransform(): def get_xml_tags(c):
# ''' Type for simple XML to HTML transforms. Examples: return c.xml_tags.keys()
# * 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_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): def register_render_function(fn, names=None, cls=SimpleInput):
if names is None: if names is None:
...@@ -136,9 +94,6 @@ def register_render_function(fn, names=None, cls=SimpleInput): ...@@ -136,9 +94,6 @@ def register_render_function(fn, names=None, cls=SimpleInput):
return fn return fn
return wrapped return wrapped
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
@register_render_function @register_render_function
...@@ -201,16 +156,16 @@ def choicegroup(element, value, status, render_template, msg=''): ...@@ -201,16 +156,16 @@ def choicegroup(element, value, status, render_template, msg=''):
return etree.XML(html) return etree.XML(html)
@register_render_function @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. 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 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') eid=element.get('id')
count = int(eid.split('_')[-2])-1 # HACK count = int(eid.split('_')[-2])-1 # HACK
size = element.get('size') 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) html = render_template("textinput.html", context)
return etree.XML(html) return etree.XML(html)
......
...@@ -63,7 +63,8 @@ class GenericResponse(object): ...@@ -63,7 +63,8 @@ class GenericResponse(object):
- get_max_score : if defined, this is called to obtain the maximum score possible for this question - 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__ - 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: Each response type may also specify the following attributes:
...@@ -114,9 +115,30 @@ class GenericResponse(object): ...@@ -114,9 +115,30 @@ class GenericResponse(object):
if self.max_inputfields==1: if self.max_inputfields==1:
self.answer_id = self.answer_ids[0] # for convenience 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'): if hasattr(self,'setup_response'):
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 @abc.abstractmethod
def get_score(self, student_answers): def get_score(self, student_answers):
''' '''
...@@ -132,7 +154,6 @@ class GenericResponse(object): ...@@ -132,7 +154,6 @@ class GenericResponse(object):
''' '''
pass 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): def setup_response(self):
pass pass
...@@ -485,17 +506,17 @@ def sympy_check2(): ...@@ -485,17 +506,17 @@ def sympy_check2():
''' '''
Give correct answer expected for this response. Give correct answer expected for this response.
capa_problem handles correct_answers from entry objects like textline, and that use default_answer_map from entry elements (eg textline),
is what should be used when this response has multiple entry objects. when this response has multiple entry objects.
but for simplicity, if an "expect" attribute was given by the content author 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: if len(self.answer_ids)>1:
return {} return self.default_answer_map
if self.expect: if self.expect:
return {self.answer_ids[0] : self.expect} return {self.answer_ids[0] : self.expect}
return {} return self.default_answer_map
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
...@@ -797,9 +818,8 @@ class SchematicResponse(GenericResponse): ...@@ -797,9 +818,8 @@ class SchematicResponse(GenericResponse):
return zip(sorted(self.answer_ids), self.context['correct']) return zip(sorted(self.answer_ids), self.context['correct'])
def get_answers(self): def get_answers(self):
# Since this is explicitly specified in the problem, this will # use answers provided in input elements
# be handled by capa_problem return self.default_answer_map
return {}
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
......
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