Commit 9fdbdd3b by Calen Pennington

Merge pull request #71 from MITx/pmitros/modular-refactor

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