Merge branch 'master' into asset-pipeline
This commit is contained in:
@@ -25,6 +25,7 @@ from mako.template import Template
|
||||
|
||||
from util import contextualize_text
|
||||
import inputtypes
|
||||
|
||||
from responsetypes import NumericalResponse, FormulaResponse, CustomResponse, SchematicResponse, MultipleChoiceResponse, StudentInputError, TrueFalseResponse, ExternalResponse,ImageResponse,OptionResponse
|
||||
|
||||
import calc
|
||||
@@ -166,7 +167,7 @@ class LoncapaProblem(object):
|
||||
problems_simple = self.extract_problems(self.tree)
|
||||
for response in problems_simple:
|
||||
grader = response_types[response.tag](response, self.context, self.system)
|
||||
results = grader.grade(answers) # call the responsetype instance to do the actual grading
|
||||
results = grader.get_score(answers) # call the responsetype instance to do the actual grading
|
||||
self.correct_map.update(results)
|
||||
return self.correct_map
|
||||
|
||||
@@ -239,7 +240,7 @@ class LoncapaProblem(object):
|
||||
# used to be
|
||||
# if problemtree.tag in html_special_response:
|
||||
|
||||
if hasattr(inputtypes, problemtree.tag):
|
||||
if problemtree.tag in inputtypes.get_input_xml_tags():
|
||||
# status is currently the answer for the problem ID for the input element,
|
||||
# but it will turn into a dict containing both the answer and any associated message
|
||||
# for the problem ID for the input element.
|
||||
@@ -266,9 +267,17 @@ class LoncapaProblem(object):
|
||||
# print "[courseware.capa.capa_problem.extract_html] msg = ",msg
|
||||
|
||||
# do the rendering
|
||||
#render_function = html_special_response[problemtree.tag]
|
||||
render_function = getattr(inputtypes, problemtree.tag)
|
||||
return render_function(problemtree, value, status, msg) # render the special response (textline, schematic,...)
|
||||
# This should be broken out into a helper function
|
||||
# that handles all input objects
|
||||
render_object = inputtypes.SimpleInput(system = self.system,
|
||||
xml = problemtree,
|
||||
state = {'value':value,
|
||||
'status': status,
|
||||
'id':problemtree.get('id'),
|
||||
'feedback':{'message':msg}
|
||||
},
|
||||
use = 'capa_input')
|
||||
return render_object.get_html() #function(problemtree, value, status, msg) # render the special response (textline, schematic,...)
|
||||
|
||||
tree=Element(problemtree.tag)
|
||||
for item in problemtree:
|
||||
|
||||
@@ -32,8 +32,121 @@ from lxml import etree
|
||||
|
||||
from mitxmako.shortcuts import render_to_string
|
||||
|
||||
def get_input_xml_tags():
|
||||
''' Eventually, this will be for all registered input types '''
|
||||
return SimpleInput.get_xml_tags()
|
||||
|
||||
class SimpleInput():# XModule
|
||||
''' Type for simple inputs -- plain HTML with a form element
|
||||
State is a dictionary with optional keys:
|
||||
* Value
|
||||
* ID
|
||||
* Status (answered, unanswered, unsubmitted)
|
||||
* Feedback (dictionary containing keys for hints, errors, or other
|
||||
feedback from previous attempt)
|
||||
'''
|
||||
|
||||
xml_tags = {} ## Maps tags to functions
|
||||
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return c.xml_tags.keys()
|
||||
|
||||
@classmethod
|
||||
def get_uses(c):
|
||||
return ['capa_input', 'capa_transform']
|
||||
|
||||
def get_html(self):
|
||||
return self.xml_tags[self.tag](self.xml, self.value, self.status, self.msg)
|
||||
|
||||
def __init__(self, system, xml, item_id = None, track_url=None, state=None, use = 'capa_input'):
|
||||
self.xml = xml
|
||||
self.tag = xml.tag
|
||||
if not state:
|
||||
state = {}
|
||||
## ID should only come from one place.
|
||||
## If it comes from multiple, we use state first, XML second, and parameter
|
||||
## third. Since we don't make this guarantee, we can swap this around in
|
||||
## the future if there's a more logical order.
|
||||
if item_id:
|
||||
self.id = item_id
|
||||
if xml.get('id'):
|
||||
self.id = xml.get('id')
|
||||
if 'id' in state:
|
||||
self.id = state['id']
|
||||
self.system = system
|
||||
|
||||
self.value = ''
|
||||
if 'value' in state:
|
||||
self.value = state['value']
|
||||
|
||||
self.msg = ''
|
||||
if 'feedback' in state and 'message' in state['feedback']:
|
||||
self.msg = state['feedback']['message']
|
||||
|
||||
self.status = 'unanswered'
|
||||
if 'status' in state:
|
||||
self.status = state['status']
|
||||
|
||||
## TODO
|
||||
# class SimpleTransform():
|
||||
# ''' Type for simple XML to HTML transforms. Examples:
|
||||
# * Math tags, which go from LON-CAPA-style m-tags to MathJAX
|
||||
# '''
|
||||
# xml_tags = {} ## Maps tags to functions
|
||||
|
||||
# @classmethod
|
||||
# def get_xml_tags(c):
|
||||
# return c.xml_tags.keys()
|
||||
|
||||
# @classmethod
|
||||
# def get_uses(c):
|
||||
# return ['capa_transform']
|
||||
|
||||
# def get_html(self):
|
||||
# return self.xml_tags[self.tag](self.xml, self.value, self.status, self.msg)
|
||||
|
||||
# def __init__(self, system, xml, item_id = None, track_url=None, state=None, use = 'capa_input'):
|
||||
# self.xml = xml
|
||||
# self.tag = xml.tag
|
||||
# if not state:
|
||||
# state = {}
|
||||
# if item_id:
|
||||
# self.id = item_id
|
||||
# if xml.get('id'):
|
||||
# self.id = xml.get('id')
|
||||
# if 'id' in state:
|
||||
# self.id = state['id']
|
||||
# self.system = system
|
||||
|
||||
# self.value = ''
|
||||
# if 'value' in state:
|
||||
# self.value = state['value']
|
||||
|
||||
# self.msg = ''
|
||||
# if 'feedback' in state and 'message' in state['feedback']:
|
||||
# self.msg = state['feedback']['message']
|
||||
|
||||
# self.status = 'unanswered'
|
||||
# if 'status' in state:
|
||||
# self.status = state['status']
|
||||
|
||||
|
||||
def register_render_function(fn, names=None, cls=SimpleInput):
|
||||
if names == None:
|
||||
SimpleInput.xml_tags[fn.__name__] = fn
|
||||
else:
|
||||
raise NotImplementedError
|
||||
def wrapped():
|
||||
return fn
|
||||
return wrapped
|
||||
|
||||
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@register_render_function
|
||||
def optioninput(element, value, status, msg=''):
|
||||
'''
|
||||
Select option input type.
|
||||
@@ -67,7 +180,7 @@ def optioninput(element, value, status, msg=''):
|
||||
return etree.XML(html)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@register_render_function
|
||||
def choicegroup(element, value, status, msg=''):
|
||||
'''
|
||||
Radio button inputs: multiple choice or true/false
|
||||
@@ -90,6 +203,7 @@ def choicegroup(element, value, status, msg=''):
|
||||
html=render_to_string("choicegroup.html", context)
|
||||
return etree.XML(html)
|
||||
|
||||
@register_render_function
|
||||
def textline(element, value, state, msg=""):
|
||||
eid=element.get('id')
|
||||
count = int(eid.split('_')[-2])-1 # HACK
|
||||
@@ -100,6 +214,7 @@ def textline(element, value, state, msg=""):
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@register_render_function
|
||||
def js_textline(element, value, status, msg=''):
|
||||
'''
|
||||
Plan: We will inspect element to figure out type
|
||||
@@ -125,6 +240,7 @@ def js_textline(element, value, status, msg=''):
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
## TODO: Make a wrapper for <codeinput>
|
||||
@register_render_function
|
||||
def textbox(element, value, status, msg=''):
|
||||
'''
|
||||
The textbox is used for code input. The message is the return HTML string from
|
||||
@@ -140,6 +256,7 @@ def textbox(element, value, status, msg=''):
|
||||
return etree.XML(html)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
@register_render_function
|
||||
def schematic(element, value, status, msg=''):
|
||||
eid = element.get('id')
|
||||
height = element.get('height')
|
||||
@@ -164,6 +281,7 @@ def schematic(element, value, status, msg=''):
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
### TODO: Move out of inputtypes
|
||||
@register_render_function
|
||||
def math(element, value, status, msg=''):
|
||||
'''
|
||||
This is not really an input type. It is a convention from Lon-CAPA, used for
|
||||
@@ -198,6 +316,7 @@ def math(element, value, status, msg=''):
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@register_render_function
|
||||
def solution(element, value, status, msg=''):
|
||||
'''
|
||||
This is not really an input type. It is just a <span>...</span> which is given an ID,
|
||||
@@ -218,6 +337,7 @@ def solution(element, value, status, msg=''):
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@register_render_function
|
||||
def imageinput(element, value, status, msg=''):
|
||||
'''
|
||||
Clickable image as an input field. Element should specify the image source, height, and width, eg
|
||||
@@ -253,4 +373,3 @@ def imageinput(element, value, status, msg=''):
|
||||
print '[courseware.capa.inputtypes.imageinput] context=',context
|
||||
html=render_to_string("imageinput.html", context)
|
||||
return etree.XML(html)
|
||||
|
||||
|
||||
@@ -47,10 +47,10 @@ def compare_with_tolerance(v1, v2, tol):
|
||||
return abs(v1-v2) <= tolerance
|
||||
|
||||
class GenericResponse(object):
|
||||
__metaclass__=abc.ABCMeta
|
||||
__metaclass__=abc.ABCMeta # abc = Abstract Base Class
|
||||
|
||||
@abc.abstractmethod
|
||||
def grade(self, student_answers):
|
||||
def get_score(self, student_answers):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
@@ -61,7 +61,7 @@ class GenericResponse(object):
|
||||
def preprocess_response(self):
|
||||
pass
|
||||
|
||||
#Every response type needs methods "grade" and "get_answers"
|
||||
#Every response type needs methods "get_score" and "get_answers"
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@@ -95,7 +95,7 @@ class MultipleChoiceResponse(GenericResponse):
|
||||
raise Exception("should have exactly one choice group per multiplechoicceresponse")
|
||||
self.answer_id=self.answer_id[0]
|
||||
|
||||
def grade(self, student_answers):
|
||||
def get_score(self, student_answers):
|
||||
if self.answer_id in student_answers and student_answers[self.answer_id] in self.correct_choices:
|
||||
return {self.answer_id:'correct'}
|
||||
else:
|
||||
@@ -132,7 +132,7 @@ class TrueFalseResponse(MultipleChoiceResponse):
|
||||
else:
|
||||
choice.set("name", "choice_"+choice.get("name"))
|
||||
|
||||
def grade(self, student_answers):
|
||||
def get_score(self, student_answers):
|
||||
correct = set(self.correct_choices)
|
||||
answers = set(student_answers.get(self.answer_id, []))
|
||||
|
||||
@@ -162,7 +162,7 @@ class OptionResponse(GenericResponse):
|
||||
print '[courseware.capa.responsetypes.OR.init] answer_fields=%s' % (self.answer_fields)
|
||||
self.context = context
|
||||
|
||||
def grade(self, student_answers):
|
||||
def get_score(self, student_answers):
|
||||
cmap = {}
|
||||
amap = self.get_answers()
|
||||
for aid in amap:
|
||||
@@ -194,7 +194,7 @@ class NumericalResponse(GenericResponse):
|
||||
except Exception, err:
|
||||
self.answer_id = None
|
||||
|
||||
def grade(self, student_answers):
|
||||
def get_score(self, student_answers):
|
||||
''' Display HTML for a numeric response '''
|
||||
student_answer = student_answers[self.answer_id]
|
||||
try:
|
||||
@@ -300,7 +300,7 @@ def sympy_check2():
|
||||
else:
|
||||
self.code = answer.text
|
||||
|
||||
def grade(self, student_answers):
|
||||
def get_score(self, student_answers):
|
||||
'''
|
||||
student_answers is a dict with everything from request.POST, but with the first part
|
||||
of each key removed (the string before the first "_").
|
||||
@@ -363,7 +363,7 @@ def sympy_check2():
|
||||
print "oops in customresponse (cfn) error %s" % err
|
||||
# print "context = ",self.context
|
||||
print traceback.format_exc()
|
||||
if settings.DEBUG: print "[courseware.capa.responsetypes.customresponse.grade] ret = ",ret
|
||||
if settings.DEBUG: print "[courseware.capa.responsetypes.customresponse.get_score] ret = ",ret
|
||||
if type(ret)==dict:
|
||||
correct[0] = 'correct' if ret['ok'] else 'incorrect'
|
||||
msg = ret['msg']
|
||||
@@ -428,7 +428,7 @@ class ExternalResponse(GenericResponse):
|
||||
|
||||
self.tests = xml.get('answer')
|
||||
|
||||
def grade(self, student_answers):
|
||||
def get_score(self, student_answers):
|
||||
submission = [student_answers[k] for k in sorted(self.answer_ids)]
|
||||
self.context.update({'submission':submission})
|
||||
|
||||
@@ -504,7 +504,7 @@ class FormulaResponse(GenericResponse):
|
||||
self.case_sensitive = False
|
||||
|
||||
|
||||
def grade(self, student_answers):
|
||||
def get_score(self, student_answers):
|
||||
variables=self.samples.split('@')[0].split(',')
|
||||
numsamples=int(self.samples.split('@')[1].split('#')[1])
|
||||
sranges=zip(*map(lambda x:map(float, x.split(",")),
|
||||
@@ -566,7 +566,7 @@ class SchematicResponse(GenericResponse):
|
||||
else:
|
||||
self.code = answer.text
|
||||
|
||||
def grade(self, student_answers):
|
||||
def get_score(self, student_answers):
|
||||
from capa_problem import global_context
|
||||
submission = [json.loads(student_answers[k]) for k in sorted(self.answer_ids)]
|
||||
self.context.update({'submission':submission})
|
||||
@@ -605,7 +605,7 @@ class ImageResponse(GenericResponse):
|
||||
self.ielements = xml.findall('imageinput')
|
||||
self.answer_ids = [ie.get('id') for ie in self.ielements]
|
||||
|
||||
def grade(self, student_answers):
|
||||
def get_score(self, student_answers):
|
||||
correct_map = {}
|
||||
expectedset = self.get_answers()
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
def contextualize_text(text, context): # private
|
||||
''' Takes a string with variables. E.g. $a+$b.
|
||||
Does a substitution of those variables from the context '''
|
||||
if not text: return text
|
||||
for key in sorted(context, lambda x,y:cmp(len(y),len(x))):
|
||||
text=text.replace('$'+key, str(context[key]))
|
||||
return text
|
||||
|
||||
@@ -13,8 +13,8 @@ from fs.osfs import OSFS
|
||||
from django.conf import settings
|
||||
from mitxmako.shortcuts import render_to_string
|
||||
|
||||
|
||||
from models import StudentModule
|
||||
from multicourse import multicourse_settings
|
||||
|
||||
import courseware.modules
|
||||
|
||||
@@ -31,6 +31,8 @@ class I4xSystem(object):
|
||||
self.track_function = track_function
|
||||
if not filestore:
|
||||
self.filestore = OSFS(settings.DATA_DIR)
|
||||
else:
|
||||
self.filestore = filestore
|
||||
self.render_function = render_function
|
||||
self.exception404 = Http404
|
||||
def __repr__(self):
|
||||
@@ -95,15 +97,15 @@ def render_x_module(user, request, xml_module, module_object_preload):
|
||||
state = smod.state
|
||||
|
||||
# get coursename if stored
|
||||
if 'coursename' in request.session: coursename = request.session['coursename']
|
||||
else: coursename = None
|
||||
coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
xp = multicourse_settings.get_course_xmlpath(coursename) # path to XML for the course
|
||||
|
||||
# Create a new instance
|
||||
ajax_url = settings.MITX_ROOT_URL + '/modx/'+module_type+'/'+module_id+'/'
|
||||
system = I4xSystem(track_function = make_track_function(request),
|
||||
render_function = lambda x: render_module(user, request, x, module_object_preload),
|
||||
ajax_url = ajax_url,
|
||||
filestore = None
|
||||
filestore = OSFS(settings.DATA_DIR + xp),
|
||||
)
|
||||
instance=module_class(system,
|
||||
etree.tostring(xml_module),
|
||||
|
||||
@@ -2,6 +2,8 @@ import logging
|
||||
import urllib
|
||||
import json
|
||||
|
||||
from fs.osfs import OSFS
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.context_processors import csrf
|
||||
from django.contrib.auth.models import User
|
||||
@@ -38,9 +40,7 @@ def gradebook(request):
|
||||
if 'course_admin' not in content_parser.user_groups(request.user):
|
||||
raise Http404
|
||||
|
||||
# TODO: This should be abstracted out. We repeat this logic many times.
|
||||
if 'coursename' in request.session: coursename = request.session['coursename']
|
||||
else: coursename = None
|
||||
coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
|
||||
student_objects = User.objects.all()[:100]
|
||||
student_info = [{'username' :s.username,
|
||||
@@ -68,8 +68,7 @@ def profile(request, student_id = None):
|
||||
|
||||
user_info = UserProfile.objects.get(user=student) # request.user.profile_cache #
|
||||
|
||||
if 'coursename' in request.session: coursename = request.session['coursename']
|
||||
else: coursename = None
|
||||
coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
|
||||
context={'name':user_info.name,
|
||||
'username':student.username,
|
||||
@@ -110,8 +109,7 @@ def render_section(request, section):
|
||||
if not settings.COURSEWARE_ENABLED:
|
||||
return redirect('/')
|
||||
|
||||
if 'coursename' in request.session: coursename = request.session['coursename']
|
||||
else: coursename = None
|
||||
coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
|
||||
try:
|
||||
dom = content_parser.section_file(user, section, coursename)
|
||||
@@ -251,8 +249,8 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
|
||||
ajax_url = settings.MITX_ROOT_URL + '/modx/'+module+'/'+id+'/'
|
||||
|
||||
# get coursename if stored
|
||||
if 'coursename' in request.session: coursename = request.session['coursename']
|
||||
else: coursename = None
|
||||
coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
xp = multicourse_settings.get_course_xmlpath(coursename) # path to XML for the course
|
||||
|
||||
# Grab the XML corresponding to the request from course.xml
|
||||
try:
|
||||
@@ -269,7 +267,7 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
|
||||
system = I4xSystem(track_function = make_track_function(request),
|
||||
render_function = None,
|
||||
ajax_url = ajax_url,
|
||||
filestore = None
|
||||
filestore = OSFS(settings.DATA_DIR + xp),
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -307,12 +305,12 @@ def quickedit(request, id=None):
|
||||
print "In deployed use, this will only edit on one server"
|
||||
print "We need a setting to disable for production where there is"
|
||||
print "a load balanacer"
|
||||
if not request.user.is_staff():
|
||||
if not request.user.is_staff:
|
||||
return redirect('/')
|
||||
|
||||
# get coursename if stored
|
||||
if 'coursename' in request.session: coursename = request.session['coursename']
|
||||
else: coursename = None
|
||||
coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
xp = multicourse_settings.get_course_xmlpath(coursename) # path to XML for the course
|
||||
|
||||
def get_lcp(coursename,id):
|
||||
# Grab the XML corresponding to the request from course.xml
|
||||
@@ -325,9 +323,8 @@ def quickedit(request, id=None):
|
||||
system = I4xSystem(track_function = make_track_function(request),
|
||||
render_function = None,
|
||||
ajax_url = ajax_url,
|
||||
filestore = None,
|
||||
coursename = coursename,
|
||||
role = 'staff' if request.user.is_staff else 'student', # TODO: generalize this
|
||||
filestore = OSFS(settings.DATA_DIR + xp),
|
||||
#role = 'staff' if request.user.is_staff else 'student', # TODO: generalize this
|
||||
)
|
||||
instance=courseware.modules.get_module_class(module)(system,
|
||||
xml,
|
||||
|
||||
@@ -42,6 +42,11 @@ else: # default to 6.002_Spring_2012
|
||||
#-----------------------------------------------------------------------------
|
||||
# wrapper functions around course settings
|
||||
|
||||
def get_coursename_from_request(request):
|
||||
if 'coursename' in request.session: coursename = request.session['coursename']
|
||||
else: coursename = None
|
||||
return coursename
|
||||
|
||||
def get_course_settings(coursename):
|
||||
if not coursename:
|
||||
if hasattr(settings,'COURSE_DEFAULT'):
|
||||
|
||||
@@ -1 +1,24 @@
|
||||
# multicourse/views.py
|
||||
import datetime
|
||||
import json
|
||||
import sys
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.context_processors import csrf
|
||||
from django.core.mail import send_mail
|
||||
from django.http import Http404
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
import courseware.capa.calc
|
||||
import track.views
|
||||
from multicourse import multicourse_settings
|
||||
|
||||
def mitxhome(request):
|
||||
''' Home page (link from main header). List of courses. '''
|
||||
if settings.ENABLE_MULTICOURSE:
|
||||
context = {'courseinfo' : multicourse_settings.COURSE_SETTINGS}
|
||||
return render_to_response("mitxhome.html", context)
|
||||
return info(request)
|
||||
|
||||
|
||||
@@ -61,12 +61,6 @@ def info(request):
|
||||
''' Info page (link from main header) '''
|
||||
return render_to_response("info.html", {})
|
||||
|
||||
def mitxhome(request):
|
||||
''' Home page (link from main header). List of courses. '''
|
||||
if settings.ENABLE_MULTICOURSE:
|
||||
return render_to_response("mitxhome.html", {})
|
||||
return info(request)
|
||||
|
||||
# From http://djangosnippets.org/snippets/1042/
|
||||
def parse_accept_header(accept):
|
||||
"""Parse the Accept header *accept*, returning a list with pairs of
|
||||
|
||||
89
templates/mathjax_include.html
Normal file
89
templates/mathjax_include.html
Normal file
@@ -0,0 +1,89 @@
|
||||
##
|
||||
## File: templates/mathjax_include.html
|
||||
##
|
||||
## Advanced mathjax using 2.0-latest CDN for Dynamic Math
|
||||
##
|
||||
## This enables ASCIIMathJAX, and is used by js_textbox
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
|
||||
// (function () {
|
||||
var QUEUE = MathJax.Hub.queue; // shorthand for the queue
|
||||
var math = null;
|
||||
var jaxset = {}; // associative array of the element jaxs for the math output.
|
||||
var mmlset = {}; // associative array of mathml from each jax
|
||||
|
||||
// constructs mathML of the specified jax element
|
||||
function toMathML(jax,callback) {
|
||||
var mml;
|
||||
try {
|
||||
mml = jax.root.toMathML("");
|
||||
} catch(err) {
|
||||
if (!err.restart) {throw err} // an actual error
|
||||
return MathJax.Callback.After([toMathML,jax,callback],err.restart);
|
||||
}
|
||||
MathJax.Callback(callback)(mml);
|
||||
}
|
||||
|
||||
// function to queue in MathJax to get put the MathML expression in in the right document element
|
||||
function UpdateMathML(jax,id) {
|
||||
toMathML(jax,function (mml) {
|
||||
// document.getElementById(id+'_fromjs').value=math.originalText+ "\n\n=>\n\n"+ mml;
|
||||
delem = document.getElementById("input_" + id + "_fromjs");
|
||||
if (delem) { delem.value=mml; };
|
||||
mmlset[id] = mml;
|
||||
})
|
||||
}
|
||||
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [
|
||||
["\\(","\\)"],
|
||||
['[mathjaxinline]','[/mathjaxinline]']
|
||||
],
|
||||
displayMath: [
|
||||
["\\[","\\]"],
|
||||
['[mathjax]','[/mathjax]']
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// The onchange event handler that typesets the
|
||||
// math entered by the user
|
||||
//
|
||||
window.UpdateMath = function (Am,id) {
|
||||
QUEUE.Push(["Text",jaxset[id],Am]);
|
||||
QUEUE.Push(UpdateMathML(jaxset[id],id));
|
||||
}
|
||||
|
||||
// })();
|
||||
|
||||
function DoUpdateMath(inputId) {
|
||||
var str = document.getElementById("input_"+inputId).value;
|
||||
|
||||
// make sure the input field is in the jaxset
|
||||
if ($.inArray(inputId,jaxset) == -1){
|
||||
//alert('missing '+inputId);
|
||||
if (document.getElementById("display_" + inputId)){
|
||||
MathJax.Hub.queue.Push(function () {
|
||||
math = MathJax.Hub.getAllJax("display_" + inputId)[0];
|
||||
if (math){
|
||||
jaxset[inputId] = math;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
UpdateMath(str,inputId)
|
||||
}
|
||||
|
||||
</script>
|
||||
<%block name="headextra"/>
|
||||
|
||||
<!-- This must appear after all mathjax-config blocks, so it is after the imports from the other templates -->
|
||||
<!-- TODO: move to settings -->
|
||||
<script type="text/javascript"
|
||||
src="http://cdn.mathjax.org/mathjax/2.0-latest/MathJax.js?config=TeX-MML-AM_HTMLorMML-full">
|
||||
</script>
|
||||
|
||||
@@ -28,10 +28,10 @@ $(document).ready(function(){
|
||||
<hr width="100%">
|
||||
<h3>Courses available:</h3>
|
||||
<ul>
|
||||
<li><a href=${ MITX_ROOT_URL }/courseware/6.002_Spring_2012/>6.002 (Spring 2012)</a></li>
|
||||
<li><a href=${ MITX_ROOT_URL }/courseware/8.02_Spring_2013/>8.02 (Spring 2013)</a></li>
|
||||
<li><a href=${ MITX_ROOT_URL }/courseware/8.01_Spring_2013/>8.01 (Spring 201x)</a></li>
|
||||
</ul>
|
||||
% for coursename, info in courseinfo.items():
|
||||
<li><a href=${ MITX_ROOT_URL }/courseware/${coursename}/>${info['title']} (${coursename})</a></li>
|
||||
% endfor
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
25
templates/optioninput.html
Normal file
25
templates/optioninput.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<form class="option-input">
|
||||
|
||||
<select name="input_${id}" id="input_${id}" >
|
||||
<option value="option_${id}_dummy_default"> </option>
|
||||
% for option_id, option_description in options.items():
|
||||
<option value="${option_id}"
|
||||
% if (option_id==value):
|
||||
selected="true"
|
||||
% endif
|
||||
> ${option_description}</option>
|
||||
% endfor
|
||||
</select>
|
||||
|
||||
<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>
|
||||
@@ -3,6 +3,15 @@
|
||||
% if problem['weight']:
|
||||
: ${ problem['weight'] } points
|
||||
% endif
|
||||
% if settings.QUICKEDIT:
|
||||
<span class="staff">
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<font size=-2><a href=${MITX_ROOT_URL}/quickedit/${id}>Quick
|
||||
Edit Problem</a></font></span>
|
||||
% endif
|
||||
</h2>
|
||||
|
||||
<section class="problem">
|
||||
|
||||
2
urls.py
2
urls.py
@@ -70,7 +70,7 @@ if settings.COURSEWARE_ENABLED:
|
||||
)
|
||||
|
||||
if settings.ENABLE_MULTICOURSE:
|
||||
urlpatterns += (url(r'^mitxhome$', 'util.views.mitxhome'),)
|
||||
urlpatterns += (url(r'^mitxhome$', 'multicourse.views.mitxhome'),)
|
||||
|
||||
if settings.QUICKEDIT:
|
||||
urlpatterns += (url(r'^quickedit/(?P<id>[^/]*)$', 'courseware.views.quickedit'),)
|
||||
|
||||
Reference in New Issue
Block a user