Merge pull request #71 from MITx/pmitros/modular-refactor
Pmitros/modular refactor
This commit is contained in:
@@ -66,10 +66,8 @@ class GenericResponse(object):
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
class MultipleChoiceResponse(GenericResponse):
|
||||
'''
|
||||
Example:
|
||||
|
||||
<multiplechoiceresponse direction="vertical" randomize="yes">
|
||||
# TODO: handle direction and randomize
|
||||
snippets = [{'snippet': '''<multiplechoiceresponse direction="vertical" randomize="yes">
|
||||
<choicegroup type="MultipleChoice">
|
||||
<choice location="random" correct="false"><span>`a+b`<br/></span></choice>
|
||||
<choice location="random" correct="true"><span><math>a+b^2</math><br/></span></choice>
|
||||
@@ -77,10 +75,7 @@ class MultipleChoiceResponse(GenericResponse):
|
||||
<choice location="bottom" correct="false"><math>a+b+d</math></choice>
|
||||
</choicegroup>
|
||||
</multiplechoiceresponse>
|
||||
|
||||
TODO: handle direction and randomize
|
||||
|
||||
'''
|
||||
'''}]
|
||||
def __init__(self, xml, context, system=None):
|
||||
self.xml = xml
|
||||
self.correct_choices = xml.xpath('//*[@id=$id]//choice[@correct="true"]',
|
||||
@@ -218,8 +213,9 @@ class NumericalResponse(GenericResponse):
|
||||
class CustomResponse(GenericResponse):
|
||||
'''
|
||||
Custom response. The python code to be run should be in <answer>...</answer>. Example:
|
||||
'''
|
||||
|
||||
<customresponse>
|
||||
snippets = [{'snippet': '''<customresponse>
|
||||
<startouttext/>
|
||||
<br/>
|
||||
Suppose that \(I(t)\) rises from \(0\) to \(I_S\) at a time \(t_0 \neq 0\)
|
||||
@@ -237,9 +233,10 @@ class CustomResponse(GenericResponse):
|
||||
if not(r=="IS*u(t-t0)"):
|
||||
correct[0] ='incorrect'
|
||||
</answer>
|
||||
</customresponse>
|
||||
</customresponse>'''}]
|
||||
|
||||
Alternatively, the check function can be defined in <script>...</script> Example:
|
||||
|
||||
'''Footnote: the check function can also be defined in <script>...</script> Example:
|
||||
|
||||
<script type="loncapa/python"><![CDATA[
|
||||
|
||||
|
||||
@@ -218,6 +218,7 @@ def section_file(user, section, coursename=None, dironly=False):
|
||||
Given a user and the name of a section, return that section.
|
||||
This is done specific to each course.
|
||||
If dironly=True then return the sections directory.
|
||||
TODO: This is a bit weird; dironly should be scrapped.
|
||||
'''
|
||||
filename = section+".xml"
|
||||
|
||||
|
||||
@@ -20,7 +20,9 @@ class Module(XModule):
|
||||
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["sequential", 'tab']
|
||||
obsolete_tags = ["sequential", 'tab']
|
||||
modern_tags = ["videosequence"]
|
||||
return obsolete_tags + modern_tags
|
||||
|
||||
def get_html(self):
|
||||
self.render()
|
||||
@@ -81,7 +83,8 @@ class Module(XModule):
|
||||
params={'items':self.contents,
|
||||
'id':self.item_id,
|
||||
'position': self.position,
|
||||
'titles':self.titles}
|
||||
'titles':self.titles,
|
||||
'tag':self.xmltree.tag}
|
||||
|
||||
# TODO/BUG: Destroy JavaScript should only be called for the active view
|
||||
# This calls it for all the views
|
||||
@@ -90,7 +93,7 @@ class Module(XModule):
|
||||
# IDs to sequences.
|
||||
destroy_js="".join([e['destroy_js'] for e in self.contents if 'destroy_js' in e])
|
||||
|
||||
if self.xmltree.tag == 'sequential':
|
||||
if self.xmltree.tag in ['sequential', 'videosequence']:
|
||||
self.init_js=js+render_to_string('seq_module.js',params)
|
||||
self.destroy_js=destroy_js
|
||||
self.content=render_to_string('seq_module.html',params)
|
||||
|
||||
@@ -13,7 +13,7 @@ class Module(XModule):
|
||||
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["vertical"]
|
||||
return ["vertical", "problemset"]
|
||||
|
||||
def get_html(self):
|
||||
return render_to_string('vert_module.html',{'items':self.contents})
|
||||
|
||||
@@ -17,6 +17,39 @@ class XModule(object):
|
||||
''' Tags in the courseware file guaranteed to correspond to the module '''
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
def get_usage_tags(c):
|
||||
''' We should convert to a real module system
|
||||
For now, this tells us whether we use this as an xmodule, a CAPA response type
|
||||
or a CAPA input type '''
|
||||
return ['xmodule']
|
||||
|
||||
def __init__(self, system = None, xml = None, item_id = None,
|
||||
json = None, track_url=None, state=None):
|
||||
''' In most cases, you must pass state or xml'''
|
||||
if not item_id:
|
||||
raise ValueError("Missing Index")
|
||||
if not xml and not json:
|
||||
raise ValueError("xml or json required")
|
||||
if not system:
|
||||
raise ValueError("System context required")
|
||||
|
||||
self.xml = xml
|
||||
self.json = json
|
||||
self.item_id = item_id
|
||||
self.state = state
|
||||
|
||||
if system:
|
||||
## These are temporary; we really should go
|
||||
## through self.system.
|
||||
self.ajax_url = system.ajax_url
|
||||
self.tracker = system.track_function
|
||||
self.filestore = system.filestore
|
||||
self.render_function = system.render_function
|
||||
self.system = system
|
||||
|
||||
### Functions used in the LMS
|
||||
|
||||
def get_completion(self):
|
||||
''' This is mostly unimplemented.
|
||||
It gives a progress indication -- e.g. 30 minutes of 1.5 hours watched. 3 of 5 problems done, etc. '''
|
||||
@@ -45,6 +78,12 @@ class XModule(object):
|
||||
'''
|
||||
return "Unimplemented"
|
||||
|
||||
# TODO:
|
||||
# def get_header_js(self):
|
||||
# ''' Filename of common js that needs to be included in the header
|
||||
# '''
|
||||
# raise NotImplementedError
|
||||
|
||||
def get_init_js(self):
|
||||
''' JavaScript code to be run when problem is shown. Be aware
|
||||
that this may happen several times on the same page
|
||||
@@ -63,17 +102,30 @@ class XModule(object):
|
||||
get is a dictionary-like object '''
|
||||
return ""
|
||||
|
||||
def __init__(self, system, xml, item_id, track_url=None, state=None):
|
||||
''' In most cases, you must pass state or xml'''
|
||||
self.xml = xml
|
||||
self.item_id = item_id
|
||||
self.state = state
|
||||
### Functions used in the CMS
|
||||
def get_xml(self):
|
||||
''' For conversions between JSON and legacy XML representations.
|
||||
'''
|
||||
if self.xml:
|
||||
return self.xml
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
if system:
|
||||
## These are temporary; we really should go
|
||||
## through self.system.
|
||||
self.ajax_url = system.ajax_url
|
||||
self.tracker = system.track_function
|
||||
self.filestore = system.filestore
|
||||
self.render_function = system.render_function
|
||||
self.system = system
|
||||
def get_json(self):
|
||||
''' For conversions between JSON and legacy XML representations.
|
||||
'''
|
||||
if self.json:
|
||||
raise NotImplementedError
|
||||
return self.json # TODO: Return context as well -- files, etc.
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
def handle_cms_json(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def render(self, size):
|
||||
''' Size: [thumbnail, small, full]
|
||||
Small ==> what we drag around
|
||||
Full ==> what we edit
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -60,7 +60,6 @@ def profile(request, student_id = None):
|
||||
if student_id == None:
|
||||
student = request.user
|
||||
else:
|
||||
print content_parser.user_groups(request.user)
|
||||
if 'course_admin' not in content_parser.user_groups(request.user):
|
||||
raise Http404
|
||||
student = User.objects.get( id = int(student_id))
|
||||
@@ -184,16 +183,28 @@ def index(request, course=None, chapter="Using the System", section="Hints"):
|
||||
log.exception("Unable to parse courseware xml")
|
||||
return render_to_response('courseware-error.html', {})
|
||||
|
||||
dom_module = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]/*[1]",
|
||||
#dom_module = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]/*[1]",
|
||||
dom_module = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]",
|
||||
course=course, chapter=chapter, section=section)
|
||||
|
||||
#print "DM", dom_module
|
||||
|
||||
if len(dom_module) == 0:
|
||||
module = None
|
||||
module_wrapper = None
|
||||
else:
|
||||
module = dom_module[0]
|
||||
module_wrapper = dom_module[0]
|
||||
|
||||
module_ids = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]//@id",
|
||||
course=course, chapter=chapter, section=section)
|
||||
if module_wrapper == None:
|
||||
module = None
|
||||
elif module_wrapper.get("src"):
|
||||
module = content_parser.section_file(user=user, section=module_wrapper.get("src"), coursename=course)
|
||||
else:
|
||||
module = etree.XML(etree.tostring(module_wrapper[0])) # Copy the element out of the tree
|
||||
|
||||
module_ids = []
|
||||
if module:
|
||||
module_ids = module.xpath("//@id",
|
||||
course=course, chapter=chapter, section=section)
|
||||
|
||||
if user.is_authenticated():
|
||||
module_object_preload = list(StudentModule.objects.filter(student=user,
|
||||
@@ -305,7 +316,7 @@ def quickedit(request, id=None):
|
||||
Maybe this should be moved into capa/views.py
|
||||
Or this should take a "module" argument, and the quickedit moved into capa_module.
|
||||
'''
|
||||
print "WARNING: UNDEPLOYABLE CODE. FOR DEV USE ONLY."
|
||||
print "WARNING: UNDEPLOYABLE CODE. FOR CONTENT DEV USE ONLY."
|
||||
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"
|
||||
|
||||
@@ -53,7 +53,7 @@ function disablePrev() {
|
||||
function ${ id }goto(i) {
|
||||
log_event("seq_goto", {'old':${id}loc, 'new':i,'id':'${id}'});
|
||||
|
||||
postJSON('${ MITX_ROOT_URL }/modx/sequential/${ id }/goto_position',
|
||||
postJSON('${ MITX_ROOT_URL }/modx/${tag}/${ id }/goto_position',
|
||||
{'position' : i });
|
||||
|
||||
if (${ id }loc!=-1)
|
||||
|
||||
Reference in New Issue
Block a user