Added MultipleChoiceResponse, TrueFalseResponse, and choicegroup back in.
This commit is contained in:
@@ -39,7 +39,7 @@ import responsetypes
|
||||
# dict of tagname, Response Class -- this should come from auto-registering
|
||||
response_tag_dict = dict([(x.response_tag,x) for x in responsetypes.__all__])
|
||||
|
||||
entry_types = ['textline', 'schematic', 'textbox', 'imageinput', 'optioninput', 'radiogroup', 'checkboxgroup']
|
||||
entry_types = ['textline', 'schematic', 'textbox', 'imageinput', 'optioninput', 'choicegroup', 'radiogroup', 'checkboxgroup']
|
||||
solution_types = ['solution'] # extra things displayed after "show answers" is pressed
|
||||
response_properties = ["responseparam", "answer"] # these get captured as student responses
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ Module containing the problem elements which render into input objects
|
||||
- textline
|
||||
- textbox (change this to textarea?)
|
||||
- schemmatic
|
||||
- choicegroup
|
||||
- radiogroup
|
||||
- checkboxgroup
|
||||
- imageinput (for clickable image)
|
||||
@@ -146,6 +147,39 @@ def optioninput(element, value, status, render_template, msg=''):
|
||||
html = render_template("optioninput.html", context)
|
||||
return etree.XML(html)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# TODO: consolidate choicegroup, radiogroup, checkboxgroup after discussion of
|
||||
# desired semantics.
|
||||
@register_render_function
|
||||
def choicegroup(element, value, status, render_template, msg=''):
|
||||
'''
|
||||
Radio button inputs: multiple choice or true/false
|
||||
|
||||
TODO: allow order of choices to be randomized, following lon-capa spec. Use "location" attribute,
|
||||
ie random, top, bottom.
|
||||
'''
|
||||
eid=element.get('id')
|
||||
if element.get('type') == "MultipleChoice":
|
||||
type="radio"
|
||||
elif element.get('type') == "TrueFalse":
|
||||
type="checkbox"
|
||||
else:
|
||||
type="radio"
|
||||
choices=[]
|
||||
for choice in element:
|
||||
if not choice.tag=='choice':
|
||||
raise Exception("[courseware.capa.inputtypes.choicegroup] Error only <choice> tags should be immediate children of a <choicegroup>, found %s instead" % choice.tag)
|
||||
ctext = ""
|
||||
ctext += ''.join([etree.tostring(x) for x in choice]) # TODO: what if choice[0] has math tags in it?
|
||||
if choice.text is not None:
|
||||
ctext += choice.text # TODO: fix order?
|
||||
choices.append((choice.get("name"),ctext))
|
||||
context={'id':eid, 'value':value, 'state':status, 'input_type':type, 'choices':choices, 'inline':True, 'name_array_suffix':''}
|
||||
html = render_template("choicegroup.html", context)
|
||||
return etree.XML(html)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
def extract_choices(element):
|
||||
'''
|
||||
@@ -169,6 +203,8 @@ def extract_choices(element):
|
||||
|
||||
return choices
|
||||
|
||||
# TODO: consolidate choicegroup, radiogroup, checkboxgroup after discussion of
|
||||
# desired semantics.
|
||||
@register_render_function
|
||||
def radiogroup(element, value, status, render_template, msg=''):
|
||||
'''
|
||||
@@ -179,11 +215,13 @@ def radiogroup(element, value, status, render_template, msg=''):
|
||||
|
||||
choices = extract_choices(element)
|
||||
|
||||
context = { 'id':eid, 'value':value, 'state':status, 'input_type': 'radio', 'choices':choices }
|
||||
context = { 'id':eid, 'value':value, 'state':status, 'input_type': 'radio', 'choices':choices, 'inline': False, 'name_array_suffix': '[]' }
|
||||
|
||||
html = render_template("choicegroup.html", context)
|
||||
return etree.XML(html)
|
||||
|
||||
# TODO: consolidate choicegroup, radiogroup, checkboxgroup after discussion of
|
||||
# desired semantics.
|
||||
@register_render_function
|
||||
def checkboxgroup(element, value, status, render_template, msg=''):
|
||||
'''
|
||||
@@ -194,7 +232,7 @@ def checkboxgroup(element, value, status, render_template, msg=''):
|
||||
|
||||
choices = extract_choices(element)
|
||||
|
||||
context = { 'id':eid, 'value':value, 'state':status, 'input_type': 'checkbox', 'choices':choices }
|
||||
context = { 'id':eid, 'value':value, 'state':status, 'input_type': 'checkbox', 'choices':choices, 'inline': False, 'name_array_suffix': '[]' }
|
||||
|
||||
html = render_template("choicegroup.html", context)
|
||||
return etree.XML(html)
|
||||
|
||||
@@ -315,6 +315,85 @@ class ChoiceResponse(LoncapaResponse):
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
class MultipleChoiceResponse(LoncapaResponse):
|
||||
# TODO: handle direction and randomize
|
||||
snippets = [{'snippet': '''<multiplechoiceresponse direction="vertical" randomize="yes">
|
||||
<choicegroup type="MultipleChoice">
|
||||
<choice location="random" correct="false"><span>`a+b`<br/></span></choice>
|
||||
<choice location="random" correct="true"><span><math>a+b^2</math><br/></span></choice>
|
||||
<choice location="random" correct="false"><math>a+b+c</math></choice>
|
||||
<choice location="bottom" correct="false"><math>a+b+d</math></choice>
|
||||
</choicegroup>
|
||||
</multiplechoiceresponse>
|
||||
'''}]
|
||||
|
||||
response_tag = 'multiplechoiceresponse'
|
||||
max_inputfields = 1
|
||||
allowed_inputfields = ['choicegroup']
|
||||
|
||||
def setup_response(self):
|
||||
self.mc_setup_response() # call secondary setup for MultipleChoice questions, to set name attributes
|
||||
|
||||
# define correct choices (after calling secondary setup)
|
||||
xml = self.xml
|
||||
cxml = xml.xpath('//*[@id=$id]//choice[@correct="true"]',id=xml.get('id'))
|
||||
self.correct_choices = [choice.get('name') for choice in cxml]
|
||||
|
||||
def mc_setup_response(self):
|
||||
'''
|
||||
Initialize name attributes in <choice> stanzas in the <choicegroup> in this response.
|
||||
'''
|
||||
i=0
|
||||
for response in self.xml.xpath("choicegroup"):
|
||||
rtype = response.get('type')
|
||||
if rtype not in ["MultipleChoice"]:
|
||||
response.set("type", "MultipleChoice") # force choicegroup to be MultipleChoice if not valid
|
||||
for choice in list(response):
|
||||
if choice.get("name") is None:
|
||||
choice.set("name", "choice_"+str(i))
|
||||
i+=1
|
||||
else:
|
||||
choice.set("name", "choice_"+choice.get("name"))
|
||||
|
||||
def get_score(self, student_answers):
|
||||
'''
|
||||
grade student response.
|
||||
'''
|
||||
# log.debug('%s: student_answers=%s, correct_choices=%s' % (unicode(self),student_answers,self.correct_choices))
|
||||
if self.answer_id in student_answers and student_answers[self.answer_id] in self.correct_choices:
|
||||
return CorrectMap(self.answer_id,'correct')
|
||||
else:
|
||||
return CorrectMap(self.answer_id,'incorrect')
|
||||
|
||||
def get_answers(self):
|
||||
return {self.answer_id:self.correct_choices}
|
||||
|
||||
class TrueFalseResponse(MultipleChoiceResponse):
|
||||
|
||||
response_tag = 'truefalseresponse'
|
||||
|
||||
def mc_setup_response(self):
|
||||
i=0
|
||||
for response in self.xml.xpath("choicegroup"):
|
||||
response.set("type", "TrueFalse")
|
||||
for choice in list(response):
|
||||
if choice.get("name") is None:
|
||||
choice.set("name", "choice_"+str(i))
|
||||
i+=1
|
||||
else:
|
||||
choice.set("name", "choice_"+choice.get("name"))
|
||||
|
||||
def get_score(self, student_answers):
|
||||
correct = set(self.correct_choices)
|
||||
answers = set(student_answers.get(self.answer_id, []))
|
||||
|
||||
if correct == answers:
|
||||
return CorrectMap( self.answer_id , 'correct')
|
||||
|
||||
return CorrectMap(self.answer_id ,'incorrect')
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
class OptionResponse(LoncapaResponse):
|
||||
'''
|
||||
TODO: handle direction and randomize
|
||||
@@ -1179,5 +1258,5 @@ class ImageResponse(LoncapaResponse):
|
||||
# TEMPORARY: List of all response subclasses
|
||||
# FIXME: To be replaced by auto-registration
|
||||
|
||||
__all__ = [ CodeResponse, NumericalResponse, FormulaResponse, CustomResponse, SchematicResponse, ExternalResponse, ImageResponse, OptionResponse, SymbolicResponse, StringResponse, ChoiceResponse ]
|
||||
__all__ = [ CodeResponse, NumericalResponse, FormulaResponse, CustomResponse, SchematicResponse, ExternalResponse, ImageResponse, OptionResponse, SymbolicResponse, StringResponse, ChoiceResponse, MultipleChoiceResponse, TrueFalseResponse ]
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<form class="choicegroup">
|
||||
|
||||
% for choice_id, choice_description in choices:
|
||||
<label for="input_${id}_${choice_id}"> <input type="${input_type}" name="input_${id}[]" id="input_${id}_${choice_id}" value="${choice_id}"
|
||||
<label for="input_${id}_${choice_id}"> <input type="${input_type}" name="input_${id}${name_array_suffix}" id="input_${id}_${choice_id}" value="${choice_id}"
|
||||
% if choice_id in value:
|
||||
checked="true"
|
||||
% endif
|
||||
/> ${choice_description} </label>
|
||||
<br/>
|
||||
% if not inline:
|
||||
<br/>
|
||||
% endif
|
||||
% endfor
|
||||
<span id="answer_${id}"></span>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user