From 85f5c93d9203c92a4d7b80e402af8683719085d3 Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Thu, 19 Jul 2012 10:25:26 -0700 Subject: [PATCH] Added MultipleChoiceResponse, TrueFalseResponse, and choicegroup back in. --- common/lib/capa/capa/capa_problem.py | 2 +- common/lib/capa/capa/inputtypes.py | 42 +++++++++- common/lib/capa/capa/responsetypes.py | 81 ++++++++++++++++++- .../lib/capa/capa/templates/choicegroup.html | 6 +- 4 files changed, 125 insertions(+), 6 deletions(-) diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index 1709d987ac..5ccb98f090 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -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 diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index 351d51f6c1..d809f98ed2 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -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 tags should be immediate children of a , 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) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 46cb8a7ad7..1b205978af 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -315,6 +315,85 @@ class ChoiceResponse(LoncapaResponse): #----------------------------------------------------------------------------- +class MultipleChoiceResponse(LoncapaResponse): + # TODO: handle direction and randomize + snippets = [{'snippet': ''' + + `a+b`
+ a+b^2
+ a+b+c + a+b+d +
+
+ '''}] + + 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 stanzas in the 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 ] diff --git a/common/lib/capa/capa/templates/choicegroup.html b/common/lib/capa/capa/templates/choicegroup.html index ec0c5a3d1a..3beb45e073 100644 --- a/common/lib/capa/capa/templates/choicegroup.html +++ b/common/lib/capa/capa/templates/choicegroup.html @@ -1,12 +1,14 @@
% for choice_id, choice_description in choices: - -
+ % if not inline: +
+ % endif % endfor