Commit 92e99d7a by Calen Pennington

Move field definitions for XModules into mixin classes, so that descriptors and…

Move field definitions for XModules into mixin classes, so that descriptors and modules always have the same set of fields
parent f01c7f94
...@@ -31,17 +31,19 @@ def group_from_value(groups, v): ...@@ -31,17 +31,19 @@ def group_from_value(groups, v):
return g return g
class ABTestModule(XModule): class ABTestFields(object):
"""
Implements an A/B test with an aribtrary number of competing groups
"""
group_portions = Object(help="What proportions of students should go in each group", default={DEFAULT: 1}, scope=Scope.content) group_portions = Object(help="What proportions of students should go in each group", default={DEFAULT: 1}, scope=Scope.content)
group_assignments = Object(help="What group this user belongs to", scope=Scope.student_preferences, default={}) group_assignments = Object(help="What group this user belongs to", scope=Scope.student_preferences, default={})
group_content = Object(help="What content to display to each group", scope=Scope.content, default={DEFAULT: []}) group_content = Object(help="What content to display to each group", scope=Scope.content, default={DEFAULT: []})
experiment = String(help="Experiment that this A/B test belongs to", scope=Scope.content) experiment = String(help="Experiment that this A/B test belongs to", scope=Scope.content)
has_children = True has_children = True
class ABTestModule(ABTestFields, XModule):
"""
Implements an A/B test with an aribtrary number of competing groups
"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
XModule.__init__(self, *args, **kwargs) XModule.__init__(self, *args, **kwargs)
...@@ -75,16 +77,11 @@ class ABTestModule(XModule): ...@@ -75,16 +77,11 @@ class ABTestModule(XModule):
# TODO (cpennington): Use Groups should be a first class object, rather than being # TODO (cpennington): Use Groups should be a first class object, rather than being
# managed by ABTests # managed by ABTests
class ABTestDescriptor(RawDescriptor, XmlDescriptor): class ABTestDescriptor(ABTestFields, RawDescriptor, XmlDescriptor):
module_class = ABTestModule module_class = ABTestModule
template_dir_name = "abtest" template_dir_name = "abtest"
experiment = String(help="Experiment that this A/B test belongs to", scope=Scope.content)
group_portions = Object(help="What proportions of students should go in each group", default={})
group_content = Object(help="What content to display to each group", scope=Scope.content, default={DEFAULT: []})
has_children = True
@classmethod @classmethod
def definition_from_xml(cls, xml_object, system): def definition_from_xml(cls, xml_object, system):
""" """
......
...@@ -12,7 +12,12 @@ from xblock.core import Scope, String ...@@ -12,7 +12,12 @@ from xblock.core import Scope, String
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class AnnotatableModule(XModule):
class AnnotatableFields(object):
data = String(help="XML data for the annotation", scope=Scope.content)
class AnnotatableModule(AnnotatableFields, XModule):
js = {'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee'), js = {'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee'),
resource_string(__name__, 'js/src/collapsible.coffee'), resource_string(__name__, 'js/src/collapsible.coffee'),
resource_string(__name__, 'js/src/html/display.coffee'), resource_string(__name__, 'js/src/html/display.coffee'),
...@@ -23,7 +28,6 @@ class AnnotatableModule(XModule): ...@@ -23,7 +28,6 @@ class AnnotatableModule(XModule):
css = {'scss': [resource_string(__name__, 'css/annotatable/display.scss')]} css = {'scss': [resource_string(__name__, 'css/annotatable/display.scss')]}
icon_class = 'annotatable' icon_class = 'annotatable'
data = String(help="XML data for the annotation", scope=Scope.content)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
XModule.__init__(self, *args, **kwargs) XModule.__init__(self, *args, **kwargs)
...@@ -125,7 +129,7 @@ class AnnotatableModule(XModule): ...@@ -125,7 +129,7 @@ class AnnotatableModule(XModule):
return self.system.render_template('annotatable.html', context) return self.system.render_template('annotatable.html', context)
class AnnotatableDescriptor(RawDescriptor): class AnnotatableDescriptor(AnnotatableFields, RawDescriptor):
module_class = AnnotatableModule module_class = AnnotatableModule
stores_state = True stores_state = True
template_dir_name = "annotatable" template_dir_name = "annotatable"
......
...@@ -83,13 +83,7 @@ class ComplexEncoder(json.JSONEncoder): ...@@ -83,13 +83,7 @@ class ComplexEncoder(json.JSONEncoder):
return json.JSONEncoder.default(self, obj) return json.JSONEncoder.default(self, obj)
class CapaModule(XModule): class CapaFields(object):
'''
An XModule implementing LonCapa format problems, implemented by way of
capa.capa_problem.LoncapaProblem
'''
icon_class = 'problem'
attempts = StringyInteger(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.student_state) attempts = StringyInteger(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.student_state)
max_attempts = StringyInteger(help="Maximum number of attempts that a student is allowed", scope=Scope.settings) max_attempts = StringyInteger(help="Maximum number of attempts that a student is allowed", scope=Scope.settings)
due = String(help="Date that this problem is due by", scope=Scope.settings) due = String(help="Date that this problem is due by", scope=Scope.settings)
...@@ -103,6 +97,17 @@ class CapaModule(XModule): ...@@ -103,6 +97,17 @@ class CapaModule(XModule):
done = Boolean(help="Whether the student has answered the problem", scope=Scope.student_state) done = Boolean(help="Whether the student has answered the problem", scope=Scope.student_state)
display_name = String(help="Display name for this module", scope=Scope.settings) display_name = String(help="Display name for this module", scope=Scope.settings)
seed = StringyInteger(help="Random seed for this student", scope=Scope.student_state) seed = StringyInteger(help="Random seed for this student", scope=Scope.student_state)
weight = StringyFloat(help="How much to weight this problem by", scope=Scope.settings)
markdown = String(help="Markdown source of this module", scope=Scope.settings)
class CapaModule(CapaFields, XModule):
'''
An XModule implementing LonCapa format problems, implemented by way of
capa.capa_problem.LoncapaProblem
'''
icon_class = 'problem'
js = {'coffee': [resource_string(__name__, 'js/src/capa/display.coffee'), js = {'coffee': [resource_string(__name__, 'js/src/capa/display.coffee'),
resource_string(__name__, 'js/src/collapsible.coffee'), resource_string(__name__, 'js/src/collapsible.coffee'),
...@@ -792,7 +797,7 @@ class CapaModule(XModule): ...@@ -792,7 +797,7 @@ class CapaModule(XModule):
'html': self.get_problem_html(encapsulate=False)} 'html': self.get_problem_html(encapsulate=False)}
class CapaDescriptor(RawDescriptor): class CapaDescriptor(CapaFields, RawDescriptor):
""" """
Module implementing problems in the LON-CAPA format, Module implementing problems in the LON-CAPA format,
as implemented by capa.capa_problem as implemented by capa.capa_problem
...@@ -800,9 +805,6 @@ class CapaDescriptor(RawDescriptor): ...@@ -800,9 +805,6 @@ class CapaDescriptor(RawDescriptor):
module_class = CapaModule module_class = CapaModule
weight = StringyFloat(help="How much to weight this problem by", scope=Scope.settings)
markdown = String(help="Markdown source of this module", scope=Scope.settings)
stores_state = True stores_state = True
has_score = True has_score = True
template_dir_name = 'problem' template_dir_name = 'problem'
......
...@@ -27,7 +27,26 @@ VERSION_TUPLES = ( ...@@ -27,7 +27,26 @@ VERSION_TUPLES = (
DEFAULT_VERSION = 1 DEFAULT_VERSION = 1
DEFAULT_VERSION = str(DEFAULT_VERSION) DEFAULT_VERSION = str(DEFAULT_VERSION)
class CombinedOpenEndedModule(XModule):
class CombinedOpenEndedFields(object):
display_name = String(help="Display name for this module", default="Open Ended Grading", scope=Scope.settings)
current_task_number = Integer(help="Current task that the student is on.", default=0, scope=Scope.student_state)
task_states = List(help="List of state dictionaries of each task within this module.", scope=Scope.student_state)
state = String(help="Which step within the current task that the student is on.", default="initial", scope=Scope.student_state)
student_attempts = Integer(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.student_state)
ready_to_reset = Boolean(help="If the problem is ready to be reset or not.", default=False, scope=Scope.student_state)
attempts = Integer(help="Maximum number of attempts that a student is allowed.", default=1, scope=Scope.settings)
is_graded = Boolean(help="Whether or not the problem is graded.", default=False, scope=Scope.settings)
accept_file_upload = Boolean(help="Whether or not the problem accepts file uploads.", default=False, scope=Scope.settings)
skip_spelling_checks = Boolean(help="Whether or not to skip initial spelling checks.", default=True, scope=Scope.settings)
due = String(help="Date that this problem is due by", default=None, scope=Scope.settings)
graceperiod = String(help="Amount of time after the due date that submissions will be accepted", default=None, scope=Scope.settings)
max_score = Integer(help="Maximum score for the problem.", default=1, scope=Scope.settings)
version = Integer(help="Current version number", default=DEFAULT_VERSION, scope=Scope.settings)
data = String(help="XML data for the problem", scope=Scope.content)
class CombinedOpenEndedModule(CombinedOpenEndedFields, XModule):
""" """
This is a module that encapsulates all open ended grading (self assessment, peer assessment, etc). This is a module that encapsulates all open ended grading (self assessment, peer assessment, etc).
It transitions between problems, and support arbitrary ordering. It transitions between problems, and support arbitrary ordering.
...@@ -60,22 +79,6 @@ class CombinedOpenEndedModule(XModule): ...@@ -60,22 +79,6 @@ class CombinedOpenEndedModule(XModule):
icon_class = 'problem' icon_class = 'problem'
display_name = String(help="Display name for this module", default="Open Ended Grading", scope=Scope.settings)
current_task_number = Integer(help="Current task that the student is on.", default=0, scope=Scope.student_state)
task_states = List(help="List of state dictionaries of each task within this module.", scope=Scope.student_state)
state = String(help="Which step within the current task that the student is on.", default="initial", scope=Scope.student_state)
student_attempts = Integer(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.student_state)
ready_to_reset = Boolean(help="If the problem is ready to be reset or not.", default=False, scope=Scope.student_state)
attempts = Integer(help="Maximum number of attempts that a student is allowed.", default=1, scope=Scope.settings)
is_graded = Boolean(help="Whether or not the problem is graded.", default=False, scope=Scope.settings)
accept_file_upload = Boolean(help="Whether or not the problem accepts file uploads.", default=False, scope=Scope.settings)
skip_spelling_checks = Boolean(help="Whether or not to skip initial spelling checks.", default=True, scope=Scope.settings)
due = String(help="Date that this problem is due by", default= None, scope=Scope.settings)
graceperiod = String(help="Amount of time after the due date that submissions will be accepted", default=None, scope=Scope.settings)
max_score = Integer(help="Maximum score for the problem.", default=1, scope=Scope.settings)
version = Integer(help="Current version number", default=DEFAULT_VERSION, scope=Scope.settings)
data = String(help="XML data for the problem", scope=Scope.content)
js = {'coffee': [resource_string(__name__, 'js/src/combinedopenended/display.coffee'), js = {'coffee': [resource_string(__name__, 'js/src/combinedopenended/display.coffee'),
resource_string(__name__, 'js/src/collapsible.coffee'), resource_string(__name__, 'js/src/collapsible.coffee'),
resource_string(__name__, 'js/src/javascript_loader.coffee'), resource_string(__name__, 'js/src/javascript_loader.coffee'),
...@@ -192,7 +195,7 @@ class CombinedOpenEndedModule(XModule): ...@@ -192,7 +195,7 @@ class CombinedOpenEndedModule(XModule):
setattr(self,attribute, getattr(self.child_module,attribute)) setattr(self,attribute, getattr(self.child_module,attribute))
class CombinedOpenEndedDescriptor(RawDescriptor): class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor):
""" """
Module for adding combined open ended questions Module for adding combined open ended questions
""" """
......
...@@ -17,7 +17,11 @@ from xmodule.modulestore.exceptions import ItemNotFoundError ...@@ -17,7 +17,11 @@ from xmodule.modulestore.exceptions import ItemNotFoundError
log = logging.getLogger('mitx.' + __name__) log = logging.getLogger('mitx.' + __name__)
class ConditionalModule(XModule): class ConditionalFields(object):
show_tag_list = List(help="Poll answers", scope=Scope.content)
class ConditionalModule(ConditionalFields, XModule):
""" """
Blocks child module from showing unless certain conditions are met. Blocks child module from showing unless certain conditions are met.
...@@ -134,7 +138,7 @@ class ConditionalModule(XModule): ...@@ -134,7 +138,7 @@ class ConditionalModule(XModule):
return new_class return new_class
class ConditionalDescriptor(SequenceDescriptor): class ConditionalDescriptor(ConditionalFields, SequenceDescriptor):
"""Descriptor for conditional xmodule.""" """Descriptor for conditional xmodule."""
_tag_name = 'conditional' _tag_name = 'conditional'
...@@ -145,7 +149,6 @@ class ConditionalDescriptor(SequenceDescriptor): ...@@ -145,7 +149,6 @@ class ConditionalDescriptor(SequenceDescriptor):
stores_state = True stores_state = True
has_score = False has_score = False
show_tag_list = List(help="Poll answers", scope=Scope.content)
@staticmethod @staticmethod
def parse_sources(xml_element, system, return_descriptor=False): def parse_sources(xml_element, system, return_descriptor=False):
......
...@@ -147,9 +147,7 @@ class TextbookList(List): ...@@ -147,9 +147,7 @@ class TextbookList(List):
return json_data return json_data
class CourseDescriptor(SequenceDescriptor): class CourseFields(object):
module_class = SequenceModule
textbooks = TextbookList(help="List of pairs of (title, url) for textbooks used in this course", scope=Scope.content) textbooks = TextbookList(help="List of pairs of (title, url) for textbooks used in this course", scope=Scope.content)
wiki_slug = String(help="Slug that points to the wiki for this course", scope=Scope.content) wiki_slug = String(help="Slug that points to the wiki for this course", scope=Scope.content)
enrollment_start = Date(help="Date that enrollment for this class is opened", scope=Scope.settings) enrollment_start = Date(help="Date that enrollment for this class is opened", scope=Scope.settings)
...@@ -207,6 +205,10 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -207,6 +205,10 @@ class CourseDescriptor(SequenceDescriptor):
# Explicit comparison to True because we always want to return a bool. # Explicit comparison to True because we always want to return a bool.
hide_progress_tab = Boolean(help="DO NOT USE THIS", scope=Scope.settings) hide_progress_tab = Boolean(help="DO NOT USE THIS", scope=Scope.settings)
class CourseDescriptor(CourseFields, SequenceDescriptor):
module_class = SequenceModule
template_dir_name = 'course' template_dir_name = 'course'
......
...@@ -6,17 +6,20 @@ from xmodule.raw_module import RawDescriptor ...@@ -6,17 +6,20 @@ from xmodule.raw_module import RawDescriptor
from xblock.core import String, Scope from xblock.core import String, Scope
class DiscussionModule(XModule): class DiscussionFields(object):
discussion_id = String(scope=Scope.settings)
discussion_category = String(scope=Scope.settings)
discussion_target = String(scope=Scope.settings)
sort_key = String(scope=Scope.settings)
class DiscussionModule(DiscussionFields, XModule):
js = {'coffee': js = {'coffee':
[resource_string(__name__, 'js/src/time.coffee'), [resource_string(__name__, 'js/src/time.coffee'),
resource_string(__name__, 'js/src/discussion/display.coffee')] resource_string(__name__, 'js/src/discussion/display.coffee')]
} }
js_module_name = "InlineDiscussion" js_module_name = "InlineDiscussion"
discussion_id = String(scope=Scope.settings)
discussion_category = String(scope=Scope.settings)
discussion_target = String(scope=Scope.settings)
sort_key = String(scope=Scope.settings)
def get_html(self): def get_html(self):
context = { context = {
...@@ -25,7 +28,7 @@ class DiscussionModule(XModule): ...@@ -25,7 +28,7 @@ class DiscussionModule(XModule):
return self.system.render_template('discussion/_discussion_module.html', context) return self.system.render_template('discussion/_discussion_module.html', context)
class DiscussionDescriptor(RawDescriptor): class DiscussionDescriptor(DiscussionFields, RawDescriptor):
module_class = DiscussionModule module_class = DiscussionModule
template_dir_name = "discussion" template_dir_name = "discussion"
...@@ -35,8 +38,3 @@ class DiscussionDescriptor(RawDescriptor): ...@@ -35,8 +38,3 @@ class DiscussionDescriptor(RawDescriptor):
metadata_translations = dict(RawDescriptor.metadata_translations) metadata_translations = dict(RawDescriptor.metadata_translations)
metadata_translations['id'] = 'discussion_id' metadata_translations['id'] = 'discussion_id'
metadata_translations['for'] = 'discussion_target' metadata_translations['for'] = 'discussion_target'
discussion_id = String(scope=Scope.settings)
discussion_category = String(scope=Scope.settings)
discussion_target = String(scope=Scope.settings)
sort_key = String(scope=Scope.settings)
...@@ -6,7 +6,11 @@ import logging ...@@ -6,7 +6,11 @@ import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class EditingDescriptor(MakoModuleDescriptor): class EditingFields(object):
data = String(scope=Scope.content, default='')
class EditingDescriptor(EditingFields, MakoModuleDescriptor):
""" """
Module that provides a raw editing view of its data and children. It does not Module that provides a raw editing view of its data and children. It does not
perform any validation on its definition---just passes it along to the browser. perform any validation on its definition---just passes it along to the browser.
...@@ -15,8 +19,6 @@ class EditingDescriptor(MakoModuleDescriptor): ...@@ -15,8 +19,6 @@ class EditingDescriptor(MakoModuleDescriptor):
""" """
mako_template = "widgets/raw-edit.html" mako_template = "widgets/raw-edit.html"
data = String(scope=Scope.content, default='')
# cdodge: a little refactoring here, since we're basically doing the same thing # cdodge: a little refactoring here, since we're basically doing the same thing
# here as with our parent class, let's call into it to get the basic fields # here as with our parent class, let's call into it to get the basic fields
# set and then add our additional fields. Trying to keep it DRY. # set and then add our additional fields. Trying to keep it DRY.
......
...@@ -21,10 +21,13 @@ log = logging.getLogger(__name__) ...@@ -21,10 +21,13 @@ log = logging.getLogger(__name__)
# decides whether to create a staff or not-staff module. # decides whether to create a staff or not-staff module.
class ErrorModule(XModule): class ErrorFields(object):
contents = String(scope=Scope.content) contents = String(scope=Scope.content)
error_msg = String(scope=Scope.content) error_msg = String(scope=Scope.content)
display_name = String(scope=Scope.settings)
class ErrorModule(ErrorFields, XModule):
def get_html(self): def get_html(self):
'''Show an error to staff. '''Show an error to staff.
...@@ -38,7 +41,7 @@ class ErrorModule(XModule): ...@@ -38,7 +41,7 @@ class ErrorModule(XModule):
}) })
class NonStaffErrorModule(XModule): class NonStaffErrorModule(ErrorFields, XModule):
def get_html(self): def get_html(self):
'''Show an error to a student. '''Show an error to a student.
TODO (vshnayder): proper style, divs, etc. TODO (vshnayder): proper style, divs, etc.
...@@ -51,16 +54,12 @@ class NonStaffErrorModule(XModule): ...@@ -51,16 +54,12 @@ class NonStaffErrorModule(XModule):
}) })
class ErrorDescriptor(JSONEditingDescriptor): class ErrorDescriptor(ErrorFields, JSONEditingDescriptor):
""" """
Module that provides a raw editing view of broken xml. Module that provides a raw editing view of broken xml.
""" """
module_class = ErrorModule module_class = ErrorModule
contents = String(scope=Scope.content)
error_msg = String(scope=Scope.content)
display_name = String(scope=Scope.settings)
@classmethod @classmethod
def _construct(self, system, contents, error_msg, location): def _construct(self, system, contents, error_msg, location):
......
...@@ -11,10 +11,8 @@ from xblock.core import Scope, Integer, String ...@@ -11,10 +11,8 @@ from xblock.core import Scope, Integer, String
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class FolditModule(XModule):
css = {'scss': [resource_string(__name__, 'css/foldit/leaderboard.scss')]}
class FolditFields(object):
# default to what Spring_7012x uses # default to what Spring_7012x uses
required_level = Integer(default=4, scope=Scope.settings) required_level = Integer(default=4, scope=Scope.settings)
required_sublevel = Integer(default=5, scope=Scope.settings) required_sublevel = Integer(default=5, scope=Scope.settings)
...@@ -23,6 +21,11 @@ class FolditModule(XModule): ...@@ -23,6 +21,11 @@ class FolditModule(XModule):
show_basic_score = String(scope=Scope.settings, default='false') show_basic_score = String(scope=Scope.settings, default='false')
show_leaderboard = String(scope=Scope.settings, default='false') show_leaderboard = String(scope=Scope.settings, default='false')
class FolditModule(FolditFields, XModule):
css = {'scss': [resource_string(__name__, 'css/foldit/leaderboard.scss')]}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
XModule.__init__(self, *args, **kwargs) XModule.__init__(self, *args, **kwargs)
""" """
...@@ -154,7 +157,7 @@ class FolditModule(XModule): ...@@ -154,7 +157,7 @@ class FolditModule(XModule):
class FolditDescriptor(XmlDescriptor, EditingDescriptor): class FolditDescriptor(FolditFields, XmlDescriptor, EditingDescriptor):
""" """
Module for adding Foldit problems to courses Module for adding Foldit problems to courses
""" """
......
...@@ -20,7 +20,12 @@ from xblock.core import String, Scope ...@@ -20,7 +20,12 @@ from xblock.core import String, Scope
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class GraphicalSliderToolModule(XModule): class GraphicalSliderToolFields(object):
render = String(scope=Scope.content)
configuration = String(scope=Scope.content)
class GraphicalSliderToolModule(GraphicalSliderToolFields, XModule):
''' Graphical-Slider-Tool Module ''' Graphical-Slider-Tool Module
''' '''
...@@ -44,9 +49,6 @@ class GraphicalSliderToolModule(XModule): ...@@ -44,9 +49,6 @@ class GraphicalSliderToolModule(XModule):
} }
js_module_name = "GraphicalSliderTool" js_module_name = "GraphicalSliderTool"
render = String(scope=Scope.content)
configuration = String(scope=Scope.content)
def get_html(self): def get_html(self):
""" Renders parameters to template. """ """ Renders parameters to template. """
...@@ -137,13 +139,10 @@ class GraphicalSliderToolModule(XModule): ...@@ -137,13 +139,10 @@ class GraphicalSliderToolModule(XModule):
'">' + self.configuration + '</root>')) '">' + self.configuration + '</root>'))
class GraphicalSliderToolDescriptor(MakoModuleDescriptor, XmlDescriptor): class GraphicalSliderToolDescriptor(GraphicalSliderToolFields, MakoModuleDescriptor, XmlDescriptor):
module_class = GraphicalSliderToolModule module_class = GraphicalSliderToolModule
template_dir_name = 'graphical_slider_tool' template_dir_name = 'graphical_slider_tool'
render = String(scope=Scope.content)
configuration = String(scope=Scope.content)
@classmethod @classmethod
def definition_from_xml(cls, xml_object, system): def definition_from_xml(cls, xml_object, system):
""" """
......
...@@ -17,7 +17,11 @@ from xmodule.xml_module import XmlDescriptor, name_to_pathname ...@@ -17,7 +17,11 @@ from xmodule.xml_module import XmlDescriptor, name_to_pathname
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
class HtmlModule(XModule): class HtmlFields(object):
data = String(help="Html contents to display for this module", scope=Scope.content)
class HtmlModule(HtmlFields, XModule):
js = {'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee'), js = {'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee'),
resource_string(__name__, 'js/src/collapsible.coffee'), resource_string(__name__, 'js/src/collapsible.coffee'),
resource_string(__name__, 'js/src/html/display.coffee') resource_string(__name__, 'js/src/html/display.coffee')
...@@ -26,13 +30,11 @@ class HtmlModule(XModule): ...@@ -26,13 +30,11 @@ class HtmlModule(XModule):
js_module_name = "HTMLModule" js_module_name = "HTMLModule"
css = {'scss': [resource_string(__name__, 'css/html/display.scss')]} css = {'scss': [resource_string(__name__, 'css/html/display.scss')]}
data = String(help="Html contents to display for this module", scope=Scope.content)
def get_html(self): def get_html(self):
return self.data return self.data
class HtmlDescriptor(XmlDescriptor, EditingDescriptor): class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
""" """
Module for putting raw html in a course Module for putting raw html in a course
""" """
...@@ -41,8 +43,6 @@ class HtmlDescriptor(XmlDescriptor, EditingDescriptor): ...@@ -41,8 +43,6 @@ class HtmlDescriptor(XmlDescriptor, EditingDescriptor):
filename_extension = "xml" filename_extension = "xml"
template_dir_name = "html" template_dir_name = "html"
data = String(help="Html contents to display for this module", scope=Scope.content)
js = {'coffee': [resource_string(__name__, 'js/src/html/edit.coffee')]} js = {'coffee': [resource_string(__name__, 'js/src/html/edit.coffee')]}
js_module_name = "HTMLEditingDescriptor" js_module_name = "HTMLEditingDescriptor"
css = {'scss': [resource_string(__name__, 'css/editor/edit.scss'), resource_string(__name__, 'css/html/edit.scss')]} css = {'scss': [resource_string(__name__, 'css/editor/edit.scss'), resource_string(__name__, 'css/html/edit.scss')]}
......
...@@ -95,7 +95,7 @@ class MongoKeyValueStore(KeyValueStore): ...@@ -95,7 +95,7 @@ class MongoKeyValueStore(KeyValueStore):
else: else:
return key.field_name in self._data return key.field_name in self._data
else: else:
raise InvalidScopeError(key.scope) return False
MongoUsage = namedtuple('MongoUsage', 'id, def_id') MongoUsage = namedtuple('MongoUsage', 'id, def_id')
......
...@@ -5,7 +5,6 @@ from lxml import etree ...@@ -5,7 +5,6 @@ from lxml import etree
from xmodule.capa_module import ComplexEncoder from xmodule.capa_module import ComplexEncoder
from xmodule.progress import Progress from xmodule.progress import Progress
from xmodule.stringify import stringify_children from xmodule.stringify import stringify_children
from xblock.core import List, Integer, String, Scope
import openendedchild import openendedchild
from combined_open_ended_rubric import CombinedOpenEndedRubric from combined_open_ended_rubric import CombinedOpenEndedRubric
......
...@@ -27,7 +27,17 @@ IS_GRADED = True ...@@ -27,7 +27,17 @@ IS_GRADED = True
EXTERNAL_GRADER_NO_CONTACT_ERROR = "Failed to contact external graders. Please notify course staff." EXTERNAL_GRADER_NO_CONTACT_ERROR = "Failed to contact external graders. Please notify course staff."
class PeerGradingModule(XModule): class PeerGradingFields(object):
use_for_single_location = Boolean(help="Whether to use this for a single location or as a panel.", default=USE_FOR_SINGLE_LOCATION, scope=Scope.settings)
link_to_location = String(help="The location this problem is linked to.", default=LINK_TO_LOCATION, scope=Scope.settings)
is_graded = Boolean(help="Whether or not this module is scored.",default=IS_GRADED, scope=Scope.settings)
display_due_date_string = String(help="Due date that should be displayed.", default=None, scope=Scope.settings)
grace_period_string = String(help="Amount of grace to give on the due date.", default=None, scope=Scope.settings)
max_grade = Integer(help="The maximum grade that a student can receieve for this problem.", default=MAX_SCORE, scope=Scope.settings)
student_data_for_location = Object(help="Student data for a given peer grading problem.", default=json.dumps({}),scope=Scope.student_state)
class PeerGradingModule(PeerGradingFields, XModule):
_VERSION = 1 _VERSION = 1
js = {'coffee': [resource_string(__name__, 'js/src/peergrading/peer_grading.coffee'), js = {'coffee': [resource_string(__name__, 'js/src/peergrading/peer_grading.coffee'),
...@@ -39,14 +49,6 @@ class PeerGradingModule(XModule): ...@@ -39,14 +49,6 @@ class PeerGradingModule(XModule):
css = {'scss': [resource_string(__name__, 'css/combinedopenended/display.scss')]} css = {'scss': [resource_string(__name__, 'css/combinedopenended/display.scss')]}
use_for_single_location = Boolean(help="Whether to use this for a single location or as a panel.", default=USE_FOR_SINGLE_LOCATION, scope=Scope.settings)
link_to_location = String(help="The location this problem is linked to.", default=LINK_TO_LOCATION, scope=Scope.settings)
is_graded = Boolean(help="Whether or not this module is scored.",default=IS_GRADED, scope=Scope.settings)
display_due_date_string = String(help="Due date that should be displayed.", default=None, scope=Scope.settings)
grace_period_string = String(help="Amount of grace to give on the due date.", default=None, scope=Scope.settings)
max_grade = Integer(help="The maximum grade that a student can receieve for this problem.", default=MAX_SCORE, scope=Scope.settings)
student_data_for_location = Object(help="Student data for a given peer grading problem.", default=json.dumps({}),scope=Scope.student_state)
def __init__(self, system, location, descriptor, model_data): def __init__(self, system, location, descriptor, model_data):
XModule.__init__(self, system, location, descriptor, model_data) XModule.__init__(self, system, location, descriptor, model_data)
...@@ -556,7 +558,7 @@ class PeerGradingModule(XModule): ...@@ -556,7 +558,7 @@ class PeerGradingModule(XModule):
return json.dumps(state) return json.dumps(state)
class PeerGradingDescriptor(RawDescriptor): class PeerGradingDescriptor(PeerGradingFields, RawDescriptor):
""" """
Module for adding peer grading questions Module for adding peer grading questions
""" """
......
...@@ -26,17 +26,7 @@ from xblock.core import Scope, String, Object, Boolean, List ...@@ -26,17 +26,7 @@ from xblock.core import Scope, String, Object, Boolean, List
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class PollModule(XModule): class PollFields(object):
"""Poll Module"""
js = {
'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee')],
'js': [resource_string(__name__, 'js/src/poll/logme.js'),
resource_string(__name__, 'js/src/poll/poll.js'),
resource_string(__name__, 'js/src/poll/poll_main.js')]
}
css = {'scss': [resource_string(__name__, 'css/poll/display.scss')]}
js_module_name = "Poll"
# Name of poll to use in links to this poll # Name of poll to use in links to this poll
display_name = String(help="Display name for this module", scope=Scope.settings) display_name = String(help="Display name for this module", scope=Scope.settings)
...@@ -47,6 +37,20 @@ class PollModule(XModule): ...@@ -47,6 +37,20 @@ class PollModule(XModule):
answers = List(help="Poll answers from xml", scope=Scope.content, default=[]) answers = List(help="Poll answers from xml", scope=Scope.content, default=[])
question = String(help="Poll question", scope=Scope.content, default='') question = String(help="Poll question", scope=Scope.content, default='')
id = String(help="ID attribute for this module", scope=Scope.settings)
class PollModule(PollFields, XModule):
"""Poll Module"""
js = {
'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee')],
'js': [resource_string(__name__, 'js/src/poll/logme.js'),
resource_string(__name__, 'js/src/poll/poll.js'),
resource_string(__name__, 'js/src/poll/poll_main.js')]
}
css = {'scss': [resource_string(__name__, 'css/poll/display.scss')]}
js_module_name = "Poll"
def handle_ajax(self, dispatch, get): def handle_ajax(self, dispatch, get):
"""Ajax handler. """Ajax handler.
...@@ -135,7 +139,7 @@ class PollModule(XModule): ...@@ -135,7 +139,7 @@ class PollModule(XModule):
'reset': str(self.descriptor.xml_attributes.get('reset', 'true')).lower()}) 'reset': str(self.descriptor.xml_attributes.get('reset', 'true')).lower()})
class PollDescriptor(MakoModuleDescriptor, XmlDescriptor): class PollDescriptor(PollFields, MakoModuleDescriptor, XmlDescriptor):
_tag_name = 'poll_question' _tag_name = 'poll_question'
_child_tag_name = 'answer' _child_tag_name = 'answer'
...@@ -143,11 +147,6 @@ class PollDescriptor(MakoModuleDescriptor, XmlDescriptor): ...@@ -143,11 +147,6 @@ class PollDescriptor(MakoModuleDescriptor, XmlDescriptor):
template_dir_name = 'poll' template_dir_name = 'poll'
stores_state = True stores_state = True
answers = List(help="Poll answers", scope=Scope.content, default=[])
question = String(help="Poll question", scope=Scope.content, default='')
display_name = String(help="Display name for this module", scope=Scope.settings)
id = String(help="ID attribute for this module", scope=Scope.settings)
@classmethod @classmethod
def definition_from_xml(cls, xml_object, system): def definition_from_xml(cls, xml_object, system):
"""Pull out the data into dictionary. """Pull out the data into dictionary.
......
...@@ -9,7 +9,11 @@ from xblock.core import Scope, Integer ...@@ -9,7 +9,11 @@ from xblock.core import Scope, Integer
log = logging.getLogger('mitx.' + __name__) log = logging.getLogger('mitx.' + __name__)
class RandomizeModule(XModule): class RandomizeFields(object):
choice = Integer(help="Which random child was chosen", scope=Scope.student_state)
class RandomizeModule(RandomizeFields, XModule):
""" """
Chooses a random child module. Chooses the same one every time for each student. Chooses a random child module. Chooses the same one every time for each student.
...@@ -31,9 +35,6 @@ class RandomizeModule(XModule): ...@@ -31,9 +35,6 @@ class RandomizeModule(XModule):
grading interaction is a tangle between super and subclasses of descriptors and grading interaction is a tangle between super and subclasses of descriptors and
modules. modules.
""" """
choice = Integer(help="Which random child was chosen", scope=Scope.student_state)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
XModule.__init__(self, *args, **kwargs) XModule.__init__(self, *args, **kwargs)
...@@ -64,7 +65,6 @@ class RandomizeModule(XModule): ...@@ -64,7 +65,6 @@ class RandomizeModule(XModule):
self.child_descriptor = None self.child_descriptor = None
self.child = None self.child = None
def get_child_descriptors(self): def get_child_descriptors(self):
""" """
For grading--return just the chosen child. For grading--return just the chosen child.
...@@ -86,7 +86,7 @@ class RandomizeModule(XModule): ...@@ -86,7 +86,7 @@ class RandomizeModule(XModule):
return self.child.get_icon_class() if self.child else 'other' return self.child.get_icon_class() if self.child else 'other'
class RandomizeDescriptor(SequenceDescriptor): class RandomizeDescriptor(RandomizeFields, SequenceDescriptor):
# the editing interface can be the same as for sequences -- just a container # the editing interface can be the same as for sequences -- just a container
module_class = RandomizeModule module_class = RandomizeModule
......
...@@ -18,7 +18,15 @@ log = logging.getLogger(__name__) ...@@ -18,7 +18,15 @@ log = logging.getLogger(__name__)
class_priority = ['video', 'problem'] class_priority = ['video', 'problem']
class SequenceModule(XModule): class SequenceFields(object):
has_children = True
# NOTE: Position is 1-indexed. This is silly, but there are now student
# positions saved on prod, so it's not easy to fix.
position = Integer(help="Last tab viewed in this sequence", scope=Scope.student_state)
class SequenceModule(SequenceFields, XModule):
''' Layout module which lays out content in a temporal sequence ''' Layout module which lays out content in a temporal sequence
''' '''
js = {'coffee': [resource_string(__name__, js = {'coffee': [resource_string(__name__,
...@@ -27,11 +35,6 @@ class SequenceModule(XModule): ...@@ -27,11 +35,6 @@ class SequenceModule(XModule):
css = {'scss': [resource_string(__name__, 'css/sequence/display.scss')]} css = {'scss': [resource_string(__name__, 'css/sequence/display.scss')]}
js_module_name = "Sequence" js_module_name = "Sequence"
has_children = True
# NOTE: Position is 1-indexed. This is silly, but there are now student
# positions saved on prod, so it's not easy to fix.
position = Integer(help="Last tab viewed in this sequence", scope=Scope.student_state)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
XModule.__init__(self, *args, **kwargs) XModule.__init__(self, *args, **kwargs)
...@@ -114,11 +117,10 @@ class SequenceModule(XModule): ...@@ -114,11 +117,10 @@ class SequenceModule(XModule):
return new_class return new_class
class SequenceDescriptor(MakoModuleDescriptor, XmlDescriptor): class SequenceDescriptor(SequenceFields, MakoModuleDescriptor, XmlDescriptor):
mako_template = 'widgets/sequence-edit.html' mako_template = 'widgets/sequence-edit.html'
module_class = SequenceModule module_class = SequenceModule
has_children = True
stores_state = True # For remembering where in the sequence the student is stores_state = True # For remembering where in the sequence the student is
js = {'coffee': [resource_string(__name__, 'js/src/sequence/edit.coffee')]} js = {'coffee': [resource_string(__name__, 'js/src/sequence/edit.coffee')]}
......
...@@ -15,11 +15,7 @@ from xblock.core import Float, String, Boolean, Scope ...@@ -15,11 +15,7 @@ from xblock.core import Float, String, Boolean, Scope
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class TimeLimitModule(XModule): class TimeLimitFields(object):
'''
Wrapper module which imposes a time constraint for the completion of its child.
'''
beginning_at = Float(help="The time this timer was started", scope=Scope.student_state) beginning_at = Float(help="The time this timer was started", scope=Scope.student_state)
ending_at = Float(help="The time this timer will end", scope=Scope.student_state) ending_at = Float(help="The time this timer will end", scope=Scope.student_state)
accomodation_code = String(help="A code indicating accommodations to be given the student", scope=Scope.student_state) accomodation_code = String(help="A code indicating accommodations to be given the student", scope=Scope.student_state)
...@@ -27,6 +23,12 @@ class TimeLimitModule(XModule): ...@@ -27,6 +23,12 @@ class TimeLimitModule(XModule):
duration = Float(help="The length of this timer", scope=Scope.settings) duration = Float(help="The length of this timer", scope=Scope.settings)
suppress_toplevel_navigation = Boolean(help="Whether the toplevel navigation should be suppressed when viewing this module", scope=Scope.settings) suppress_toplevel_navigation = Boolean(help="Whether the toplevel navigation should be suppressed when viewing this module", scope=Scope.settings)
class TimeLimitModule(TimeLimitFields, XModule):
'''
Wrapper module which imposes a time constraint for the completion of its child.
'''
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
XModule.__init__(self, *args, **kwargs) XModule.__init__(self, *args, **kwargs)
...@@ -117,7 +119,7 @@ class TimeLimitModule(XModule): ...@@ -117,7 +119,7 @@ class TimeLimitModule(XModule):
else: else:
return "other" return "other"
class TimeLimitDescriptor(XMLEditingDescriptor, XmlDescriptor): class TimeLimitDescriptor(TimeLimitFields, XMLEditingDescriptor, XmlDescriptor):
module_class = TimeLimitModule module_class = TimeLimitModule
......
...@@ -19,7 +19,13 @@ import time ...@@ -19,7 +19,13 @@ import time
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class VideoModule(XModule): class VideoFields(object):
data = String(help="XML data for the problem", scope=Scope.content)
position = Integer(help="Current position in the video", scope=Scope.student_state, default=0)
display_name = String(help="Display name for this module", scope=Scope.settings)
class VideoModule(VideoFields, XModule):
video_time = 0 video_time = 0
icon_class = 'video' icon_class = 'video'
...@@ -33,10 +39,6 @@ class VideoModule(XModule): ...@@ -33,10 +39,6 @@ class VideoModule(XModule):
css = {'scss': [resource_string(__name__, 'css/video/display.scss')]} css = {'scss': [resource_string(__name__, 'css/video/display.scss')]}
js_module_name = "Video" js_module_name = "Video"
data = String(help="XML data for the problem", scope=Scope.content)
position = Integer(help="Current position in the video", scope=Scope.student_state, default=0)
display_name = String(help="Display name for this module", scope=Scope.settings)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
XModule.__init__(self, *args, **kwargs) XModule.__init__(self, *args, **kwargs)
...@@ -151,7 +153,7 @@ class VideoModule(XModule): ...@@ -151,7 +153,7 @@ class VideoModule(XModule):
}) })
class VideoDescriptor(RawDescriptor): class VideoDescriptor(VideoFields, RawDescriptor):
module_class = VideoModule module_class = VideoModule
stores_state = True stores_state = True
template_dir_name = "video" template_dir_name = "video"
...@@ -19,7 +19,13 @@ import time ...@@ -19,7 +19,13 @@ import time
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class VideoAlphaModule(XModule): class VideoAlphaFields(object):
data = String(help="XML data for the problem", scope=Scope.content)
position = Integer(help="Current position in the video", scope=Scope.student_state, default=0)
display_name = String(help="Display name for this module", scope=Scope.settings)
class VideoAlphaModule(VideoAlphaFields, XModule):
""" """
XML source example: XML source example:
...@@ -47,10 +53,6 @@ class VideoAlphaModule(XModule): ...@@ -47,10 +53,6 @@ class VideoAlphaModule(XModule):
css = {'scss': [resource_string(__name__, 'css/videoalpha/display.scss')]} css = {'scss': [resource_string(__name__, 'css/videoalpha/display.scss')]}
js_module_name = "VideoAlpha" js_module_name = "VideoAlpha"
data = String(help="XML data for the problem", scope=Scope.content)
position = Integer(help="Current position in the video", scope=Scope.student_state, default=0)
display_name = String(help="Display name for this module", scope=Scope.settings)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
XModule.__init__(self, *args, **kwargs) XModule.__init__(self, *args, **kwargs)
xmltree = etree.fromstring(self.data) xmltree = etree.fromstring(self.data)
...@@ -147,7 +149,7 @@ class VideoAlphaModule(XModule): ...@@ -147,7 +149,7 @@ class VideoAlphaModule(XModule):
}) })
class VideoAlphaDescriptor(RawDescriptor): class VideoAlphaDescriptor(VideoAlphaFields, RawDescriptor):
module_class = VideoAlphaModule module_class = VideoAlphaModule
stores_state = True stores_state = True
template_dir_name = "videoalpha" template_dir_name = "videoalpha"
...@@ -82,7 +82,15 @@ class HTMLSnippet(object): ...@@ -82,7 +82,15 @@ class HTMLSnippet(object):
.format(self.__class__)) .format(self.__class__))
class XModule(HTMLSnippet, XBlock): class XModuleFields(object):
display_name = String(
help="Display name for this module",
scope=Scope.settings,
default=None,
)
class XModule(XModuleFields, HTMLSnippet, XBlock):
''' Implements a generic learning module. ''' Implements a generic learning module.
Subclasses must at a minimum provide a definition for get_html in order Subclasses must at a minimum provide a definition for get_html in order
...@@ -99,11 +107,6 @@ class XModule(HTMLSnippet, XBlock): ...@@ -99,11 +107,6 @@ class XModule(HTMLSnippet, XBlock):
# in the module # in the module
icon_class = 'other' icon_class = 'other'
display_name = String(
help="Display name for this module",
scope=Scope.settings,
default=None,
)
def __init__(self, system, location, descriptor, model_data): def __init__(self, system, location, descriptor, model_data):
''' '''
...@@ -307,7 +310,7 @@ class ResourceTemplates(object): ...@@ -307,7 +310,7 @@ class ResourceTemplates(object):
return templates return templates
class XModuleDescriptor(HTMLSnippet, ResourceTemplates, XBlock): class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock):
""" """
An XModuleDescriptor is a specification for an element of a course. This An XModuleDescriptor is a specification for an element of a course. This
could be a problem, an organizational element (a group of content), or a could be a problem, an organizational element (a group of content), or a
...@@ -352,12 +355,6 @@ class XModuleDescriptor(HTMLSnippet, ResourceTemplates, XBlock): ...@@ -352,12 +355,6 @@ class XModuleDescriptor(HTMLSnippet, ResourceTemplates, XBlock):
FoldIt, which posts grade-changing updates through a separate API. FoldIt, which posts grade-changing updates through a separate API.
""" """
display_name = String(
help="Display name for this module",
scope=Scope.settings,
default=None,
)
# VS[compat]. Backwards compatibility code that can go away after # VS[compat]. Backwards compatibility code that can go away after
# importing 2012 courses. # importing 2012 courses.
# A set of metadata key conversions that we want to make # A set of metadata key conversions that we want to make
......
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
# XBlock: # XBlock:
# Might change frequently, so put it in local-requirements.txt, # Might change frequently, so put it in local-requirements.txt,
# but conceptually is an external package, so it is in a separate repo. # but conceptually is an external package, so it is in a separate repo.
-e git+ssh://git@github.com/MITx/xmodule-debugger@6d5c2443#egg=XBlock -e git+ssh://git@github.com/MITx/xmodule-debugger@5026e686#egg=XBlock
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