diff --git a/courseware/module_render.py b/courseware/module_render.py index 5c1c136155..1f4e784b2e 100644 --- a/courseware/module_render.py +++ b/courseware/module_render.py @@ -26,28 +26,10 @@ import track.views import courseware.content_parser as content_parser -import courseware.modules.capa_module -import courseware.modules.html_module -import courseware.modules.schematic_module -import courseware.modules.seq_module -import courseware.modules.template_module -import courseware.modules.vertical_module -import courseware.modules.video_module +import courseware.modules log = logging.getLogger("mitx.courseware") -## TODO: Add registration mechanism -modx_modules={'problem':courseware.modules.capa_module.LoncapaModule, - 'video':courseware.modules.video_module.VideoModule, - 'html':courseware.modules.html_module.HtmlModule, - 'vertical':courseware.modules.vertical_module.VerticalModule, - 'sequential':courseware.modules.seq_module.SequentialModule, - 'tab':courseware.modules.seq_module.SequentialModule, - 'schematic':courseware.modules.schematic_module.SchematicModule} - -for f in os.listdir(settings.DATA_DIR+'/custom_tags'): - modx_modules[f] = courseware.modules.template_module.TemplateModule - def object_cache(cache, user, module_type, module_id): # We don't look up on user -- all queries include user # Additional lookup would require a DB hit the way Django @@ -78,18 +60,18 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): ajax_url = '/modx/'+module+'/'+id+'/' - id_tag=modx_modules[module].id_attribute + id_tag=courseware.modules.get_module_class(module.id_attribute) # Grab the XML corresponding to the request from course.xml xml = content_parser.module_xml(content_parser.course_file(request.user), module, id_tag, id) # Create the module - instance=modx_modules[module](xml, - s.module_id, - ajax_url=ajax_url, - state=s.state, - track_function = make_track_function(request), - render_function = None) + instance=courseware.modules.get_module_class(module)(xml, + s.module_id, + ajax_url=ajax_url, + state=s.state, + track_function = make_track_function(request), + render_function = None) # Let the module handle the AJAX ajax_return=instance.handle_ajax(dispatch, request.POST) # Save the state back to the database @@ -104,7 +86,7 @@ def render_x_module(user, request, xml_module, module_object_preload): ''' Generic module for extensions. This renders to HTML. ''' # Check if problem has an instance in DB module_type=xml_module.tag - module_class=modx_modules[module_type] + module_class=courseware.modules.get_module_class(module_type) module_id=xml_module.get('id') #module_class.id_attribute) or "" # Grab state from database diff --git a/courseware/modules/__init__.py b/courseware/modules/__init__.py index e69de29bb2..4150088c22 100644 --- a/courseware/modules/__init__.py +++ b/courseware/modules/__init__.py @@ -0,0 +1,38 @@ +import os +import os.path + +from django.conf import settings + +import capa_module +import html_module +import schematic_module +import seq_module +import template_module +import vertical_module +import video_module + +# Import all files in modules directory, excluding backups (# and . in name) +# and __init__ +# +# Stick them in a list +modx_module_list = [] + +for f in os.listdir(os.path.dirname(__file__)): + if f!='__init__.py' and \ + f[-3:] == ".py" and \ + "." not in f[:-3] \ + and '#' not in f: + mod_path = 'courseware.modules.'+f[:-3] + mod = __import__(mod_path, fromlist = "courseware.modules") + if 'Module' in mod.__dict__: + modx_module_list.append(mod) + +# Convert list to a dictionary for lookup by tag +modx_modules = {} +for module in modx_module_list: + for tag in module.Module.get_xml_tags(): + modx_modules[tag] = module.Module + +def get_module_class(tag): + return modx_modules[tag] + diff --git a/courseware/modules/capa_module.py b/courseware/modules/capa_module.py index cd740d7dea..a9846abf58 100644 --- a/courseware/modules/capa_module.py +++ b/courseware/modules/capa_module.py @@ -26,15 +26,18 @@ import courseware.content_parser as content_parser log = logging.getLogger("mitx.courseware") -class LoncapaModule(XModule): +class Module(XModule): ''' Interface between capa_problem and x_module. Originally a hack meant to be refactored out, but it seems to be serving a useful prupose now. We can e.g .destroy and create the capa_problem on a reset. ''' - xml_tags = ["problem"] + id_attribute = "filename" + @classmethod + def get_xml_tags(c): + return ["problem"] def get_state(self): state = self.lcp.get_state() diff --git a/courseware/modules/html_module.py b/courseware/modules/html_module.py index f1ce14ec7e..92e29df938 100644 --- a/courseware/modules/html_module.py +++ b/courseware/modules/html_module.py @@ -7,14 +7,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule from lxml import etree -class HtmlModule(XModule): +class Module(XModule): id_attribute = 'filename' def get_state(self): return json.dumps({ }) - def get_xml_tags(): - return "html" + @classmethod + def get_xml_tags(c): + return ["html"] def get_html(self): if self.filename==None: diff --git a/courseware/modules/schematic_module.py b/courseware/modules/schematic_module.py index 0312321b4d..e253f1acc6 100644 --- a/courseware/modules/schematic_module.py +++ b/courseware/modules/schematic_module.py @@ -6,14 +6,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule -class SchematicModule(XModule): +class Module(XModule): id_attribute = 'id' def get_state(self): return json.dumps({ }) - def get_xml_tags(): - return "schematic" + @classmethod + def get_xml_tags(c): + return ["schematic"] def get_html(self): return ''.format(item_id=self.item_id) diff --git a/courseware/modules/seq_module.py b/courseware/modules/seq_module.py index 33c4088486..6ec74feace 100644 --- a/courseware/modules/seq_module.py +++ b/courseware/modules/seq_module.py @@ -13,7 +13,7 @@ from x_module import XModule # OBSOLETE: This obsoletes 'type' class_priority = ['video', 'problem'] -class SequentialModule(XModule): +class Module(XModule): ''' Layout module which lays out content in a temporal sequence ''' id_attribute = 'id' @@ -21,7 +21,8 @@ class SequentialModule(XModule): def get_state(self): return json.dumps({ 'position':self.position }) - def get_xml_tags(): + @classmethod + def get_xml_tags(c): return ["sequential", 'tab'] def get_html(self): diff --git a/courseware/modules/vertical_module.py b/courseware/modules/vertical_module.py index 6939c75cc9..c068cb9a76 100644 --- a/courseware/modules/vertical_module.py +++ b/courseware/modules/vertical_module.py @@ -7,14 +7,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule from lxml import etree -class VerticalModule(XModule): +class Module(XModule): id_attribute = 'id' def get_state(self): return json.dumps({ }) - def get_xml_tags(): - return "vertical" + @classmethod + def get_xml_tags(c): + return ["vertical"] def get_html(self): return render_to_string('vert_module.html',{'items':self.contents}) diff --git a/courseware/modules/video_module.py b/courseware/modules/video_module.py index b7e1e211dc..518413946c 100644 --- a/courseware/modules/video_module.py +++ b/courseware/modules/video_module.py @@ -11,7 +11,7 @@ from x_module import XModule log = logging.getLogger("mitx.courseware.modules") -class VideoModule(XModule): +class Module(XModule): #id_attribute = 'youtube' video_time = 0 @@ -28,9 +28,10 @@ class VideoModule(XModule): log.debug(u"STATE POSITION {0}".format(self.position)) return json.dumps({ 'position':self.position }) - def get_xml_tags(): + @classmethod + def get_xml_tags(c): '''Tags in the courseware file guaranteed to correspond to the module''' - return "video" + return ["video"] def video_list(self): l = self.youtube.split(',') diff --git a/courseware/modules/x_module.py b/courseware/modules/x_module.py index 4b45c4c7fc..1a2154256c 100644 --- a/courseware/modules/x_module.py +++ b/courseware/modules/x_module.py @@ -10,7 +10,8 @@ class XModule(object): ''' id_attribute='name' # An attribute guaranteed to be unique - def get_xml_tags(): + @classmethod + def get_xml_tags(c): ''' Tags in the courseware file guaranteed to correspond to the module ''' return []