diff --git a/common/lib/xmodule/xmodule/crowdsource_hinter.py b/common/lib/xmodule/xmodule/crowdsource_hinter.py index 6c868cb621..bac6982085 100644 --- a/common/lib/xmodule/xmodule/crowdsource_hinter.py +++ b/common/lib/xmodule/xmodule/crowdsource_hinter.py @@ -13,7 +13,7 @@ from pkg_resources import resource_string from lxml import etree from xmodule.x_module import XModule -from xmodule.xml_module import XmlDescriptor +from xmodule.raw_module import RawDescriptor from xblock.core import Scope, String, Integer, Boolean, Dict, List from capa.responsetypes import FormulaResponse, StudentInputError @@ -150,10 +150,10 @@ class CrowdsourceHinterModule(CrowdsourceHinterFields, XModule): # errors don't make a difference. out = str(responder.hash_answers(answer, self.formula_test_values)) except StudentInputError: - # I'm not sure what's the best thing to do here. - # I'll return the empty string, for now. - # That way, all invalid hints are clustered together. - return '' + # I'm not sure what's the best thing to do here. I'm returning + # None, for now, so that the calling function has a chance to catch + # the error without having to import StudentInputError. + return None return out def handle_ajax(self, dispatch, data): @@ -197,6 +197,10 @@ class CrowdsourceHinterModule(CrowdsourceHinterFields, XModule): return # Make a signature of the answer, for formula responses. signature = self.answer_signature(answer) + if signature == None: + # Sometimes, signature conversion may fail. + log.exception('Signature conversion failed: ' + str(answer)) + return # Look for a hint to give. # Make a local copy of self.hints - this means we only need to do one json unpacking. # (This is because xblocks storage makes the following command a deep copy.) @@ -261,7 +265,7 @@ class CrowdsourceHinterModule(CrowdsourceHinterFields, XModule): if signature in self.hints: # Go through each hint, and add to index_to_hints for hint_id in hints_offered: - if (hint_id is not None) and (hint_id not in answer_to_hints[signature]): + if (hint_id is not None) and (hint_id not in answer_to_hints[answer]): try: answer_to_hints[answer][hint_id] = self.hints[signature][str(hint_id)][0] except KeyError: @@ -335,10 +339,7 @@ class CrowdsourceHinterModule(CrowdsourceHinterFields, XModule): temp_dict[signature] = {str(self.hint_pk): [hint, 1]} # Add the signature to signature_to_ans, if it's not there yet. # This allows instructors to see a human-readable answer that corresponds to each signature. - if answer not in self.signature_to_ans: - local_sta = self.signature_to_ans - local_sta[signature] = answer - self.signature_to_ans = local_sta + self.add_signature(signature, answer) self.hint_pk += 1 if self.moderate == 'True': self.mod_queue = temp_dict @@ -349,8 +350,18 @@ class CrowdsourceHinterModule(CrowdsourceHinterFields, XModule): self.previous_answers = [] return {'message': 'Thank you for your hint!'} + def add_signature(self, signature, answer): + """ + Add a signature to self.signature_to_ans. If the signature already + exists, do nothing. + """ + if signature not in self.signature_to_ans: + local_sta = self.signature_to_ans + local_sta[signature] = answer + self.signature_to_ans = local_sta -class CrowdsourceHinterDescriptor(CrowdsourceHinterFields, XmlDescriptor): + +class CrowdsourceHinterDescriptor(CrowdsourceHinterFields, RawDescriptor): module_class = CrowdsourceHinterModule stores_state = True diff --git a/common/lib/xmodule/xmodule/js/src/crowdsource_hinter/display.coffee b/common/lib/xmodule/xmodule/js/src/crowdsource_hinter/display.coffee index 3df970a618..2e4d0e2c3b 100644 --- a/common/lib/xmodule/xmodule/js/src/crowdsource_hinter/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/crowdsource_hinter/display.coffee @@ -48,8 +48,8 @@ class @Hinter vote: (eventObj) => target = @$(eventObj.currentTarget) - parent_div_selector = '#previous-answer-' + @jq_escape(target.attr('data-answer')) - all_pks = @$(parent_div_selector).attr('data-all-pks') + parent_div = $('.previous-answer[data-answer="'+target.attr('data-answer')+'"]') + all_pks = parent_div.attr('data-all-pks') console.debug(all_pks) post_json = {'answer': target.attr('data-answer'), 'hint': target.data('hintno'), 'pk_list': all_pks} $.postWithPrefix "#{@url}/vote", post_json, (response) => @@ -57,8 +57,9 @@ class @Hinter submit_hint: (eventObj) => target = @$(eventObj.currentTarget) - textarea_id = '#custom-hint-' + @jq_escape(target.attr('data-answer')) - post_json = {'answer': target.attr('data-answer'), 'hint': @$(textarea_id).val()} + textarea = $('.custom-hint[data-answer="'+target.attr('data-answer')+'"]') + console.debug(textarea) + post_json = {'answer': target.attr('data-answer'), 'hint': @$(textarea).val()} $.postWithPrefix "#{@url}/submit_hint",post_json, (response) => @render(response.contents) diff --git a/common/templates/hinter_display.html b/common/templates/hinter_display.html index d349a17fc5..4f40113265 100644 --- a/common/templates/hinter_display.html +++ b/common/templates/hinter_display.html @@ -23,10 +23,19 @@ Help your classmates by writing hints for this problem. Start by picking one of your previous incorrect answers from below:
+ <% + def unspace(string): + """ + HTML id's can't have spaces in them. This little function + removes spaces. + """ + return ''.join(string.split()) + %> +