diff --git a/djangoapps/courseware/capa/capa_problem.py b/djangoapps/courseware/capa/capa_problem.py index 05509acc35..4bd97776d4 100644 --- a/djangoapps/courseware/capa/capa_problem.py +++ b/djangoapps/courseware/capa/capa_problem.py @@ -15,7 +15,7 @@ from mako.template import Template from util import contextualize_text import inputtypes -from responsetypes import NumericalResponse, FormulaResponse, CustomResponse, SchematicResponse, MultipleChoiceResponse, StudentInputError +from responsetypes import NumericalResponse, FormulaResponse, CustomResponse, SchematicResponse, MultipleChoiceResponse, StudentInputError, TrueFalseResponse import calc import eia @@ -26,7 +26,8 @@ response_types = {'numericalresponse':NumericalResponse, 'formularesponse':FormulaResponse, 'customresponse':CustomResponse, 'schematicresponse':SchematicResponse, - 'multiplechoiceresponse':MultipleChoiceResponse} + 'multiplechoiceresponse':MultipleChoiceResponse, + 'truefalseresponse':TrueFalseResponse} entry_types = ['textline', 'schematic', 'choicegroup'] response_properties = ["responseparam", "answer"] # How to convert from original XML to HTML @@ -92,6 +93,10 @@ class LoncapaProblem(object): self.preprocess_problem(self.tree, correct_map=self.correct_map, answer_map = self.student_answers) self.context = self.extract_context(self.tree, seed=self.seed) + for response in self.tree.xpath('//'+"|//".join(response_types)): + responder = response_types[response.tag](response, self.context) + responder.preprocess_response() + def get_state(self): ''' Stored per-user session data neeeded to: @@ -129,7 +134,6 @@ class LoncapaProblem(object): grader = response_types[response.tag](response, self.context) results = grader.grade(answers) self.correct_map.update(results) - return self.correct_map def get_question_answers(self): @@ -181,7 +185,7 @@ class LoncapaProblem(object): tree=Element(problemtree.tag) for item in problemtree: subitems = self.extract_html(item) - if subitems: + if len(subitems): for subitem in subitems: tree.append(subitem) for (key,value) in problemtree.items(): diff --git a/djangoapps/courseware/capa/inputtypes.py b/djangoapps/courseware/capa/inputtypes.py index 8002932b66..460ff7a5eb 100644 --- a/djangoapps/courseware/capa/inputtypes.py +++ b/djangoapps/courseware/capa/inputtypes.py @@ -7,7 +7,12 @@ from mitxmako.shortcuts import render_to_string def choicegroup(element, value, state): eid=element.get('id') - type="radio" #because right now, we are only doing multiple choice + if element.get('type') == "MultipleChoice": + type="radio" + elif element.get('type') == "TrueFalse": + type="checkbox" + else: + type="radio" choices={} for choice in element: assert choice.tag =="choice", "only tags should be immediate children of a " diff --git a/djangoapps/courseware/capa/responsetypes.py b/djangoapps/courseware/capa/responsetypes.py index 153bcd16d6..9fde05d8d9 100644 --- a/djangoapps/courseware/capa/responsetypes.py +++ b/djangoapps/courseware/capa/responsetypes.py @@ -5,6 +5,7 @@ import numpy import random import scipy import traceback +import copy from calc import evaluator, UndefinedVariable from django.conf import settings @@ -36,9 +37,17 @@ def compare_with_tolerance(v1, v2, tol): tolerance = evaluator(dict(),dict(),tol) return abs(v1-v2) <= tolerance +class GenericResponse(object): + def grade(self, student_answers): + pass + def get_answers(self): + pass + def preprocess_response(self): + pass + #Every response type needs methods "grade" and "get_answers" -class MultipleChoiceResponse(object): +class MultipleChoiceResponse(GenericResponse): def __init__(self, xml, context): self.xml = xml self.correct_choices = xml.xpath('//*[@id=$id]//choice[@correct="true"]', @@ -52,8 +61,6 @@ class MultipleChoiceResponse(object): self.answer_id=self.answer_id[0] def grade(self, student_answers): - answers={} - if self.answer_id in student_answers and student_answers[self.answer_id] in self.correct_choices: return {self.answer_id:'correct'} else: @@ -61,8 +68,32 @@ class MultipleChoiceResponse(object): def get_answers(self): return {self.answer_id:self.correct_choices} - -class NumericalResponse(object): + + def preprocess_response(self): + for response in self.xml.xpath("choicegroup"): + response.set("type", "MultipleChoice") + +class TrueFalseResponse(MultipleChoiceResponse): + def preprocess_response(self): + for response in self.xml.xpath("choicegroup"): + response.set("type", "TrueFalse") + + def grade(self, student_answers): + correct = copy.deepcopy(self.correct_choices) + if self.answer_id in student_answers and student_answers[self.answer_id]: + for answer in student_answers[self.answer_id]: + if answer in correct: + correct.remove(answer) + else: + return {self.answer_id:'incorrect'} + if len(correct) != 0: + return {self.answer_id:'incorrect'} + else: + return{self.answer_id:'correct'} + else: + return {self.answer_id:'incorrect'} + +class NumericalResponse(GenericResponse): def __init__(self, xml, context): self.xml = xml self.correct_answer = contextualize_text(xml.get('answer'), context) @@ -91,7 +122,7 @@ class NumericalResponse(object): def get_answers(self): return {self.answer_id:self.correct_answer} -class CustomResponse(object): +class CustomResponse(GenericResponse): def __init__(self, xml, context): self.xml = xml ## CRITICAL TODO: Should cover all entrytypes @@ -122,7 +153,7 @@ class CustomResponse(object): class StudentInputError(Exception): pass -class FormulaResponse(object): +class FormulaResponse(GenericResponse): def __init__(self, xml, context): self.xml = xml self.correct_answer = contextualize_text(xml.get('answer'), context) @@ -192,7 +223,7 @@ class FormulaResponse(object): def get_answers(self): return {self.answer_id:self.correct_answer} -class SchematicResponse(object): +class SchematicResponse(GenericResponse): def __init__(self, xml, context): self.xml = xml self.answer_ids = xml.xpath('//*[@id=$id]//schematic/@id', diff --git a/djangoapps/courseware/module_render.py b/djangoapps/courseware/module_render.py index 38f9e0211b..273c0ff19a 100644 --- a/djangoapps/courseware/module_render.py +++ b/djangoapps/courseware/module_render.py @@ -83,7 +83,10 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): track_function = make_track_function(request), render_function = None) # Let the module handle the AJAX - ajax_return=instance.handle_ajax(dispatch, request.POST) + post_data="" + if request.raw_post_data: + post_data = json.loads(request.raw_post_data) + ajax_return=instance.handle_ajax(dispatch, post_data) # Save the state back to the database s.state=instance.get_state() if instance.get_score(): diff --git a/djangoapps/courseware/modules/capa_module.py b/djangoapps/courseware/modules/capa_module.py index 86958dcf1c..d57e2d0786 100644 --- a/djangoapps/courseware/modules/capa_module.py +++ b/djangoapps/courseware/modules/capa_module.py @@ -270,8 +270,6 @@ class Module(XModule): for key in get: answers['_'.join(key.split('_')[1:])]=get[key] -# print "XXX", answers, get - event_info['answers']=answers # Too late. Cannot submit diff --git a/static/js/video_player.js b/static/js/video_player.js index 5b3b9377a9..b03d0f42af 100644 --- a/static/js/video_player.js +++ b/static/js/video_player.js @@ -42,7 +42,7 @@ function postJSON(url, data, callback) { $.ajax({type:'POST', url: url, dataType: 'json', - data: data, + data: JSON.stringify(data), success: callback, headers : {'X-CSRFToken':getCookie('csrftoken')} }); @@ -52,7 +52,7 @@ function postJSONAsync(url, data, callback) { $.ajax({type:'POST', url: url, dataType: 'json', - data: data, + data: JSON.stringify(data), success: callback, headers : {'X-CSRFToken':getCookie('csrftoken')}, async:true diff --git a/templates/choicegroup.html b/templates/choicegroup.html index 5e281c330b..938ce5b535 100644 --- a/templates/choicegroup.html +++ b/templates/choicegroup.html @@ -2,7 +2,7 @@ % for choice_id, choice_description in choices.items(): diff --git a/templates/problem.js b/templates/problem.js index 65b91c01fd..24b46bd2a1 100644 --- a/templates/problem.js +++ b/templates/problem.js @@ -8,12 +8,17 @@ function ${ id }_load() { $("input.schematic").each(function(index,element){ element.schematic.update_value(); }); var submit_data={}; $.each($("[id^=input_${ id }_]"), function(index,value){ - if (value.type==="radio" || value.type==="checkbox"){ + if (value.type==="checkbox"){ if (value.checked) { if (typeof submit_data[value.name] == 'undefined'){ - submit_data[value.name]=[] + submit_data[value.name]=[]; } - submit_data[value.name]+=value.value; + submit_data[value.name].push(value.value); + } + } + if (value.type==="radio"){ + if (value.checked) { + submit_data[value.name]= value.value; } } else{ @@ -21,18 +26,18 @@ function ${ id }_load() { } }); postJSON('/modx/problem/${ id }/problem_check', - submit_data, - function(json) { - switch(json.success) { - case 'incorrect': // Worked, but answer not - case 'correct': - ${ id }_load(); - //alert("!!"+json.success); - break; - default: - alert(json.success); - } - }); + submit_data, + function(json) { + switch(json.success) { + case 'incorrect': // Worked, but answer not + case 'correct': + ${ id }_load(); + //alert("!!"+json.success); + break; + default: + alert(json.success); + } + }); log_event('problem_check', submit_data); });