diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py index 29227c3188449734307e47ce28f783ea415c1a6e..a1b059b8891078fd3e56c429b0d61531e21a4c28 100644 --- a/common/lib/xmodule/setup.py +++ b/common/lib/xmodule/setup.py @@ -20,6 +20,7 @@ setup( "book = xmodule.backcompat_module:TranslateCustomTagDescriptor", "chapter = xmodule.seq_module:SequenceDescriptor", "combinedopenended = xmodule.combined_open_ended_module:CombinedOpenEndedDescriptor", + "conditional = xmodule.conditional_module:ConditionalDescriptor", "course = xmodule.course_module:CourseDescriptor", "customtag = xmodule.template_module:CustomTagDescriptor", "discuss = xmodule.backcompat_module:TranslateCustomTagDescriptor", diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index f33da6e3a43b98a59b207144cc05fda409c204f7..01e67d9f8bd2b80a0b02e1340e1b44e3afd32d25 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -398,6 +398,11 @@ class CapaModule(XModule): return False + def is_completed(self): + # used by conditional module + # return self.answer_available() + return self.lcp.done + def answer_available(self): ''' Is the user allowed to see an answer? ''' diff --git a/common/lib/xmodule/xmodule/conditional_module.py b/common/lib/xmodule/xmodule/conditional_module.py new file mode 100644 index 0000000000000000000000000000000000000000..c022c3742accca46720e30d1b816b1fa25cd6935 --- /dev/null +++ b/common/lib/xmodule/xmodule/conditional_module.py @@ -0,0 +1,88 @@ +import logging + +from xmodule.x_module import XModule +from xmodule.modulestore import Location +from xmodule.seq_module import SequenceDescriptor + +log = logging.getLogger('mitx.' + __name__) + +class ConditionalModule(XModule): + ''' + Blocks child module from showing unless certain conditions are met. + + Example: + + <conditional condition="require_completed" required="tag/url_name1&tag/url_name2"> + <video url_name="secret_video" /> + </conditional> + + ''' + + def __init__(self, system, location, definition, descriptor, instance_state=None, shared_state=None, **kwargs): + """ + In addition to the normal XModule init, provide: + + self.required_module_list = list of (tag, url_name) tuples of modules required by this one. + self.condition = string describing condition required + + """ + XModule.__init__(self, system, location, definition, descriptor, instance_state, shared_state, **kwargs) + self.contents = None + self.required_modules_list = [tuple(x.split('/',1)) for x in self.metadata.get('required','').split('&')] + self.condition = self.metadata.get('condition','') + log.debug('conditional module required=%s' % self.required_modules_list) + + def _get_required_modules(self): + self.required_modules = [] + for (tag, name) in self.required_modules_list: + loc = self.location.dict() + loc['category'] = tag + loc['name'] = name + module = self.system.get_module(loc) + self.required_modules.append(module) + log.debug('required_modules=%s' % (self.required_modules)) + + def is_condition_satisfied(self): + self._get_required_modules() + + if self.condition=='require_completed': + # all required modules must be completed, as determined by + # the modules .is_completed() method + for module in self.required_modules: + if not hasattr(module, 'is_completed'): + raise Exception('Error in conditional module: required module %s has no .is_completed() method' % module) + if not module.is_completed(): + log.debug('condition module: %s not completed' % module) + return False + else: + log.debug('condition module: %s IS completed' % module) + return True + else: + raise Exception('Error in conditional module: unknown condition "%s"' % self.condition) + + return True + + def get_html(self): + if not self.is_condition_satisfied(): + context = {'module': self, + } + return self.system.render_template('conditional_module.html', context) + + if self.contents is None: + self.contents = [child.get_html() for child in self.get_display_items()] + + # for now, just deal with one child + html = self.contents[0] + + log.debug('rendered conditional module %s' % str(self.location)) + + return html + +class ConditionalDescriptor(SequenceDescriptor): + module_class = ConditionalModule + + filename_extension = "xml" + + stores_state = True + has_score = False + \ No newline at end of file