multiple choice
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -1,40 +1,49 @@
|
||||
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
|
||||
|
||||
21
templates/choicegroup.html
Normal file
21
templates/choicegroup.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<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) {
|
||||
|
||||
Reference in New Issue
Block a user