Commit 54026886 by Lyla Fischer

multiple choice

parent c5598334
......@@ -14,8 +14,8 @@ from lxml.etree import Element
from mako.template import Template
from util import contextualize_text
from inputtypes import textline, schematic
from responsetypes import numericalresponse, formularesponse, customresponse, schematicresponse, StudentInputError
import inputtypes
from responsetypes import numericalresponse, formularesponse, customresponse, schematicresponse, multiplechoiceresponse, StudentInputError
import calc
import eia
......@@ -25,8 +25,9 @@ log = logging.getLogger("mitx.courseware")
response_types = {'numericalresponse':numericalresponse,
'formularesponse':formularesponse,
'customresponse':customresponse,
'schematicresponse':schematicresponse}
entry_types = ['textline', 'schematic']
'schematicresponse':schematicresponse,
'multiplechoiceresponse':multiplechoiceresponse}
entry_types = ['textline', 'schematic', 'choicegroup']
response_properties = ["responseparam", "answer"]
# How to convert from original XML to HTML
# We should do this with xlst later
......@@ -35,6 +36,7 @@ html_transforms = {'problem': {'tag':'div'},
"customresponse": {'tag':'span'},
"schematicresponse": {'tag':'span'},
"formularesponse": {'tag':'span'},
"multiplechoiceresponse": {'tag':'span'},
"text": {'tag':'span'}}
global_context={'random':random,
......@@ -48,29 +50,20 @@ global_context={'random':random,
html_problem_semantics = ["responseparam", "answer", "script"]
# These should be removed from HTML output, but keeping subelements
html_skip = ["numericalresponse", "customresponse", "schematicresponse", "formularesponse", "text"]
# These should be transformed
html_special_response = {"textline":textline.render,
"schematic":schematic.render}
class LoncapaProblem(object):
def __init__(self, filename, id=None, state=None, seed=None):
def __init__(self, filename, id, state=None, seed=None):
## Initialize class variables from state
self.seed = None
self.student_answers = dict()
self.correct_map = dict()
self.done = False
self.filename = filename
self.problem_id = id
if seed != None:
self.seed = seed
if id:
self.problem_id = id
else:
print "NO ID"
raise Exception("This should never happen (183)")
#self.problem_id = filename
if state:
if 'seed' in state:
self.seed = state['seed']
......@@ -82,7 +75,6 @@ class LoncapaProblem(object):
self.done = state['done']
# print self.seed
# TODO: Does this deplete the Linux entropy pool? Is this fast enough?
if not self.seed:
self.seed=struct.unpack('i', os.urandom(4))[0]
......@@ -175,7 +167,7 @@ class LoncapaProblem(object):
if problemtree.tag in html_problem_semantics:
return
if problemtree.tag in html_special_response:
if hasattr(inputtypes, problemtree.tag):
status = "unsubmitted"
if problemtree.get('id') in self.correct_map:
status = self.correct_map[problemtree.get('id')]
......@@ -184,7 +176,7 @@ class LoncapaProblem(object):
if self.student_answers and problemtree.get('id') in self.student_answers:
value = self.student_answers[problemtree.get('id')]
return html_special_response[problemtree.tag](problemtree, value, status) #TODO
return getattr(inputtypes, problemtree.tag)(problemtree, value, status) #TODO
tree=Element(problemtree.tag)
for item in problemtree:
......@@ -210,7 +202,6 @@ class LoncapaProblem(object):
# TODO: Fix. This loses Element().tail
#if problemtree.tag in html_skip:
# return tree
return [tree]
def preprocess_problem(self, tree, correct_map=dict(), answer_map=dict()): # private
......
from lxml.etree import Element
from lxml import etree
from mitxmako.shortcuts import render_to_response, render_to_string
from mitxmako.shortcuts import render_to_string
class textline(object):
@staticmethod
def render(element, value, state):
eid=element.get('id')
count = int(eid.split('_')[-2])-1 # HACK
size = element.get('size')
context = {'id':eid, 'value':value, 'state':state, 'count':count, 'size': size}
html=render_to_string("textinput.html", context)
return etree.XML(html)
#takes the xml tree as 'element', the student's previous answer as 'value', and the graded status as 'state'
class schematic(object):
@staticmethod
def render(element, value, state):
eid = element.get('id')
height = element.get('height')
width = element.get('width')
parts = element.get('parts')
analyses = element.get('analyses')
initial_value = element.get('initial_value')
submit_analyses = element.get('submit_analyses')
context = {
'id':eid,
'value':value,
'initial_value':initial_value,
'state':state,
'width':width,
'height':height,
'parts':parts,
'analyses':analyses,
'submit_analyses':submit_analyses,
}
html=render_to_string("schematicinput.html", context)
return etree.XML(html)
def choicegroup(element, value, state):
eid=element.get('id')
type="radio" #because right now, we are only doing multiple choice
choices={}
for choice in element:
assert choice.tag =="choice", "only <choice> tags should be immediate children of a <choicegroup>"
choices[choice.get("name")] = etree.tostring(choice[0])
context={'id':eid, 'value':value, 'state':state, 'type':type, 'choices':choices}
html=render_to_string("choicegroup.html", context)
return etree.XML(html)
def textline(element, value, state):
eid=element.get('id')
count = int(eid.split('_')[-2])-1 # HACK
size = element.get('size')
context = {'id':eid, 'value':value, 'state':state, 'count':count, 'size': size}
html=render_to_string("textinput.html", context)
return etree.XML(html)
def schematic(element, value, state):
eid = element.get('id')
height = element.get('height')
width = element.get('width')
parts = element.get('parts')
analyses = element.get('analyses')
initial_value = element.get('initial_value')
submit_analyses = element.get('submit_analyses')
context = {
'id':eid,
'value':value,
'initial_value':initial_value,
'state':state,
'width':width,
'height':height,
'parts':parts,
'analyses':analyses,
'submit_analyses':submit_analyses,
}
html=render_to_string("schematicinput.html", context)
return etree.XML(html)
......@@ -9,6 +9,8 @@ import traceback
from calc import evaluator, UndefinedVariable
from django.conf import settings
from util import contextualize_text
from lxml import etree
from lxml.etree import Element
import calc
import eia
......@@ -34,6 +36,32 @@ def compare_with_tolerance(v1, v2, tol):
tolerance = evaluator(dict(),dict(),tol)
return abs(v1-v2) <= tolerance
#Every response type needs methods "grade" and "get_answers"
class multiplechoiceresponse(object):
def __init__(self, xml, context):
self.xml = xml
self.correct_choices = xml.xpath('//*[@id=$id]//choice[@correct="true"]',
id=xml.get('id'))
self.correct_choices = [choice.get('name') for choice in self.correct_choices]
self.context = context
self.answer_id = xml.xpath('//*[@id=$id]//choicegroup/@id',
id=xml.get('id'))
assert len(self.answer_id) == 1, "should have exactly one choice group per multiplechoicceresponse"
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:
return {self.answer_id:'incorrect'}
def get_answers(self):
return {self.answer_id:self.correct_choices}
class numericalresponse(object):
def __init__(self, xml, context):
self.xml = xml
......
<form class="multiple-choice">
% for choice_id, choice_description in choices.items():
<label for="input_${id}_${choice_id}"> <input type="${type}" name="input_${id}" id="input_${id}_${choice_id}" value="${choice_id}"
% if value == choice_id:
checked="true"
% endif
/> ${choice_description} </label>
% endfor
<span id="answer_${id}"></span>
% if state == 'unsubmitted':
<span class="unanswered" style="display:inline-block;" id="status_${id}"></span>
% elif state == 'correct':
<span class="correct" id="status_${id}"></span>
% elif state == 'incorrect':
<span class="incorrect" id="status_${id}"></span>
% elif state == 'incomplete':
<span class="incorrect" id="status_${id}"></span>
% endif
</form>
......@@ -5,11 +5,23 @@ function ${ id }_load() {
update_schematics();
$('#check_${ id }').click(function() {
$("input.schematic").each(function(index,element){ element.schematic.update_value(); });
$("input.schematic").each(function(index,element){ element.schematic.update_value(); });
var submit_data={};
$.each($("[id^=input_${ id }_]"), function(index,value){
submit_data[value.id]=value.value;
if (value.type==="radio" || value.type==="checkbox"){
if (value.checked) {
console.log("adding a radio or checkbox value");
if (typeof submit_data[value.name] == 'undefined')
submit_data[value.name]=[]
submit_data[value.name]+=value.value;
}
}
else{
console.log("adding a standard value");
submit_data[value.id]=value.value;
}
});
console.log(submit_data)
postJSON('/modx/problem/${ id }/problem_check',
submit_data,
function(json) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment