From 758e76dc14eed847c983a6ff4ce595e0a37abd22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Tue, 9 Oct 2012 15:08:43 +0300 Subject: [PATCH 1/9] added js to input for cr --- common/lib/capa/capa/responsetypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index ab5eaf950c..462ce1dbb9 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -856,7 +856,7 @@ def sympy_check2(): """}] response_tag = 'customresponse' - allowed_inputfields = ['textline', 'textbox'] + allowed_inputfields = ['textline', 'textbox', 'javascriptinput'] def setup_response(self): xml = self.xml From 708c11a1ea66dd959497d1670142b6f00f1bcb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Tue, 9 Oct 2012 19:13:54 +0300 Subject: [PATCH 2/9] added input type --- common/lib/capa/capa/inputtypes.py | 17 +++++++++++++++++ .../capa/capa/templates/crystallography.html | 11 +++++++++++ 2 files changed, 28 insertions(+) create mode 100644 common/lib/capa/capa/templates/crystallography.html diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index 466adcbf01..41b98eacae 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -624,3 +624,20 @@ def imageinput(element, value, status, render_template, msg=''): } html = render_template("imageinput.html", context) return etree.XML(html) + + +#----------------------------------------------------------------------------- +@register_render_function +def crystallography(element, value, status, render_template, msg=''): + eid = element.get('id') + height = element.get('height') + width = element.get('width') + display_file = element.get('display_file') + context = { + 'id': eid, + 'width': width, + 'height': height, + 'display_file': display_file, + } + html = render_template("crystallography.html", context) + return etree.XML(html) \ No newline at end of file diff --git a/common/lib/capa/capa/templates/crystallography.html b/common/lib/capa/capa/templates/crystallography.html new file mode 100644 index 0000000000..104092a2ca --- /dev/null +++ b/common/lib/capa/capa/templates/crystallography.html @@ -0,0 +1,11 @@ + + +
+
+
+
+
+ + + +
From c4359b6f247060b90c9b974a6f8d14bf6b957bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Wed, 10 Oct 2012 19:35:09 +0300 Subject: [PATCH 3/9] added crystresponse --- common/lib/capa/capa/responsetypes.py | 56 ++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 462ce1dbb9..e1ca420d9b 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -856,7 +856,7 @@ def sympy_check2(): """}] response_tag = 'customresponse' - allowed_inputfields = ['textline', 'textbox', 'javascriptinput'] + allowed_inputfields = ['textline', 'textbox', 'crystallography'] def setup_response(self): xml = self.xml @@ -1762,6 +1762,57 @@ class ImageResponse(LoncapaResponse): def get_answers(self): return dict([(ie.get('id'), ie.get('rectangle')) for ie in self.ielements]) + +#----------------------------------------------------------------------------- + + +class CrystResponse(LoncapaResponse): + + response_tag = 'crystresponse' + hint_tag = 'crystresponse' + allowed_inputfields = ['crystallography'] + required_attributes = ['answer'] + max_inputfields = 1 + + def setup_response(self): + xml = self.xml + context = self.context + self.correct_answer = contextualize_text(xml.get('answer'), context) + # try: + # self.tolerance_xml = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default', + # id=xml.get('id'))[0] + # self.tolerance = contextualize_text(self.tolerance_xml, context) + # except Exception: + # self.tolerance = 0 + try: + self.answer_id = xml.xpath('//*[@id=$id]//crystallography/@id', + id=xml.get('id'))[0] + except Exception: + self.answer_id = None + + def get_score(self, student_answers): + '''Grade a numeric response ''' + student_answer = student_answers[self.answer_id] + try: + correct = compare_with_tolerance(evaluator(dict(), dict(), student_answer), + complex(self.correct_answer), self.tolerance) + # We should catch this explicitly. + # I think this is just pyparsing.ParseException, calc.UndefinedVariable: + # But we'd need to confirm + except: + raise StudentInputError("Invalid input: could not interpret '%s' as a number" % + cgi.escape(student_answer)) + + if correct: + return CorrectMap(self.answer_id, 'correct') + else: + return CorrectMap(self.answer_id, 'incorrect') + + # TODO: add check_hint_condition(self, hxml_set, student_answers) + + def get_answers(self): + return {self.answer_id: self.correct_answer} + #----------------------------------------------------------------------------- # TEMPORARY: List of all response subclasses # FIXME: To be replaced by auto-registration @@ -1779,4 +1830,5 @@ __all__ = [CodeResponse, ChoiceResponse, MultipleChoiceResponse, TrueFalseResponse, - JavascriptResponse] + JavascriptResponse, + CrystResponse] From 42bd9e8b9e02acc97c56549e41563b12bcf33444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Wed, 10 Oct 2012 19:36:03 +0300 Subject: [PATCH 4/9] added test information --- common/lib/capa/capa/templates/crystallography.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/lib/capa/capa/templates/crystallography.html b/common/lib/capa/capa/templates/crystallography.html index 104092a2ca..f621f414d1 100644 --- a/common/lib/capa/capa/templates/crystallography.html +++ b/common/lib/capa/capa/templates/crystallography.html @@ -6,6 +6,6 @@
- - + + From f374a33606f90b7e0b5c1c5371478a2beb289861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Wed, 10 Oct 2012 20:54:17 +0300 Subject: [PATCH 5/9] added not hidden field --- common/lib/capa/capa/templates/crystallography.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/lib/capa/capa/templates/crystallography.html b/common/lib/capa/capa/templates/crystallography.html index f621f414d1..76478ac8c4 100644 --- a/common/lib/capa/capa/templates/crystallography.html +++ b/common/lib/capa/capa/templates/crystallography.html @@ -7,5 +7,6 @@
- + + From c7654b4d1eff2cc2aa25cd1909a8e1280266d7b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Thu, 11 Oct 2012 18:33:49 +0300 Subject: [PATCH 6/9] cryst inputtypes template - same as textline + js files --- .../capa/capa/templates/crystallography.html | 57 ++++++++++++++++--- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/common/lib/capa/capa/templates/crystallography.html b/common/lib/capa/capa/templates/crystallography.html index 76478ac8c4..1fc638b356 100644 --- a/common/lib/capa/capa/templates/crystallography.html +++ b/common/lib/capa/capa/templates/crystallography.html @@ -1,12 +1,51 @@ +<% doinline = "inline" if inline else "" %> - -
-
-
+
+
-
- - - - +
+ + + % if state == 'unsubmitted': +
+ % elif state == 'correct': +
+ % elif state == 'incorrect': +
+ % elif state == 'incomplete': +
+ % endif + % if hidden: +
+ % endif + + + +

+ % if state == 'unsubmitted': + unanswered + % elif state == 'correct': + correct + % elif state == 'incorrect': + incorrect + % elif state == 'incomplete': + incomplete + % endif +

+ +

+ + % if msg: + ${msg|n} + % endif +% if state in ['unsubmitted', 'correct', 'incorrect', 'incomplete'] or hidden: +
+% endif
From dfb9b49c4dad9c3fa8be5e79e0ebc4057ea1ee85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Thu, 11 Oct 2012 18:37:10 +0300 Subject: [PATCH 7/9] added new inputtypes to list, due to that check button appears --- common/lib/capa/capa/capa_problem.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index 9a5a15a696..d9f0156e6f 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -53,7 +53,8 @@ entry_types = ['textline', 'radiogroup', 'checkboxgroup', 'filesubmission', - 'javascriptinput',] + 'javascriptinput', + 'crystallography',] # extra things displayed after "show answers" is pressed solution_types = ['solution'] From 2b200b6e206a94f3556d8f648c7052aa404dd62d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Thu, 11 Oct 2012 18:40:05 +0300 Subject: [PATCH 8/9] changed cryst inputtype to be similar to textline --- common/lib/capa/capa/inputtypes.py | 41 +++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index 41b98eacae..4aaf9cabfb 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -630,14 +630,41 @@ def imageinput(element, value, status, render_template, msg=''): @register_render_function def crystallography(element, value, status, render_template, msg=''): eid = element.get('id') + if eid is None: + msg = 'cryst has no id: it probably appears outside of a known response type' + msg += "\nSee problem XML source line %s" % getattr(element, 'sourceline', '') + raise Exception(msg) height = element.get('height') width = element.get('width') display_file = element.get('display_file') - context = { - 'id': eid, - 'width': width, - 'height': height, - 'display_file': display_file, - } + + count = int(eid.split('_')[-2]) - 1 # HACK + size = element.get('size') + # if specified, then textline is hidden and id is stored in div of name given by hidden + hidden = element.get('hidden', '') + # Escape answers with quotes, so they don't crash the system! + escapedict = {'"': '"'} + value = saxutils.escape(value, escapedict) + + context = {'id': eid, + 'value': value, + 'state': status, + 'count': count, + 'size': size, + 'msg': msg, + 'hidden': hidden, + 'inline': element.get('inline', ''), + 'width': width, + 'height': height, + 'display_file': display_file, + } + html = render_template("crystallography.html", context) - return etree.XML(html) \ No newline at end of file + try: + xhtml = etree.XML(html) + except Exception as err: + # TODO: needs to be self.system.DEBUG - but can't access system + if True: + log.debug('[inputtypes.textline] failed to parse XML for:\n%s' % html) + raise + return xhtml From 64565692ab6d13e8fec50324ece1c1bef5f899a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Thu, 11 Oct 2012 18:41:25 +0300 Subject: [PATCH 9/9] removed obsolete crystalresponse --- common/lib/capa/capa/responsetypes.py | 54 +-------------------------- 1 file changed, 1 insertion(+), 53 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index e1ca420d9b..3a7e9799ca 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -1762,57 +1762,6 @@ class ImageResponse(LoncapaResponse): def get_answers(self): return dict([(ie.get('id'), ie.get('rectangle')) for ie in self.ielements]) - -#----------------------------------------------------------------------------- - - -class CrystResponse(LoncapaResponse): - - response_tag = 'crystresponse' - hint_tag = 'crystresponse' - allowed_inputfields = ['crystallography'] - required_attributes = ['answer'] - max_inputfields = 1 - - def setup_response(self): - xml = self.xml - context = self.context - self.correct_answer = contextualize_text(xml.get('answer'), context) - # try: - # self.tolerance_xml = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default', - # id=xml.get('id'))[0] - # self.tolerance = contextualize_text(self.tolerance_xml, context) - # except Exception: - # self.tolerance = 0 - try: - self.answer_id = xml.xpath('//*[@id=$id]//crystallography/@id', - id=xml.get('id'))[0] - except Exception: - self.answer_id = None - - def get_score(self, student_answers): - '''Grade a numeric response ''' - student_answer = student_answers[self.answer_id] - try: - correct = compare_with_tolerance(evaluator(dict(), dict(), student_answer), - complex(self.correct_answer), self.tolerance) - # We should catch this explicitly. - # I think this is just pyparsing.ParseException, calc.UndefinedVariable: - # But we'd need to confirm - except: - raise StudentInputError("Invalid input: could not interpret '%s' as a number" % - cgi.escape(student_answer)) - - if correct: - return CorrectMap(self.answer_id, 'correct') - else: - return CorrectMap(self.answer_id, 'incorrect') - - # TODO: add check_hint_condition(self, hxml_set, student_answers) - - def get_answers(self): - return {self.answer_id: self.correct_answer} - #----------------------------------------------------------------------------- # TEMPORARY: List of all response subclasses # FIXME: To be replaced by auto-registration @@ -1830,5 +1779,4 @@ __all__ = [CodeResponse, ChoiceResponse, MultipleChoiceResponse, TrueFalseResponse, - JavascriptResponse, - CrystResponse] + JavascriptResponse]