Move field definitions for XModules into mixin classes, so that descriptors and modules always have the same set of fields
This commit is contained in:
@@ -31,17 +31,19 @@ def group_from_value(groups, v):
|
||||
return g
|
||||
|
||||
|
||||
class ABTestModule(XModule):
|
||||
"""
|
||||
Implements an A/B test with an aribtrary number of competing groups
|
||||
"""
|
||||
|
||||
class ABTestFields(object):
|
||||
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_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)
|
||||
has_children = True
|
||||
|
||||
|
||||
class ABTestModule(ABTestFields, XModule):
|
||||
"""
|
||||
Implements an A/B test with an aribtrary number of competing groups
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
XModule.__init__(self, *args, **kwargs)
|
||||
|
||||
@@ -75,16 +77,11 @@ class ABTestModule(XModule):
|
||||
|
||||
# TODO (cpennington): Use Groups should be a first class object, rather than being
|
||||
# managed by ABTests
|
||||
class ABTestDescriptor(RawDescriptor, XmlDescriptor):
|
||||
class ABTestDescriptor(ABTestFields, RawDescriptor, XmlDescriptor):
|
||||
module_class = ABTestModule
|
||||
|
||||
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
|
||||
def definition_from_xml(cls, xml_object, system):
|
||||
"""
|
||||
|
||||
@@ -12,7 +12,12 @@ from xblock.core import Scope, String
|
||||
|
||||
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'),
|
||||
resource_string(__name__, 'js/src/collapsible.coffee'),
|
||||
resource_string(__name__, 'js/src/html/display.coffee'),
|
||||
@@ -23,7 +28,6 @@ class AnnotatableModule(XModule):
|
||||
css = {'scss': [resource_string(__name__, 'css/annotatable/display.scss')]}
|
||||
icon_class = 'annotatable'
|
||||
|
||||
data = String(help="XML data for the annotation", scope=Scope.content)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
XModule.__init__(self, *args, **kwargs)
|
||||
@@ -125,7 +129,7 @@ class AnnotatableModule(XModule):
|
||||
return self.system.render_template('annotatable.html', context)
|
||||
|
||||
|
||||
class AnnotatableDescriptor(RawDescriptor):
|
||||
class AnnotatableDescriptor(AnnotatableFields, RawDescriptor):
|
||||
module_class = AnnotatableModule
|
||||
stores_state = True
|
||||
template_dir_name = "annotatable"
|
||||
|
||||
@@ -83,13 +83,7 @@ class ComplexEncoder(json.JSONEncoder):
|
||||
return json.JSONEncoder.default(self, obj)
|
||||
|
||||
|
||||
class CapaModule(XModule):
|
||||
'''
|
||||
An XModule implementing LonCapa format problems, implemented by way of
|
||||
capa.capa_problem.LoncapaProblem
|
||||
'''
|
||||
icon_class = 'problem'
|
||||
|
||||
class CapaFields(object):
|
||||
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)
|
||||
due = String(help="Date that this problem is due by", scope=Scope.settings)
|
||||
@@ -103,6 +97,17 @@ class CapaModule(XModule):
|
||||
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)
|
||||
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'),
|
||||
resource_string(__name__, 'js/src/collapsible.coffee'),
|
||||
@@ -792,7 +797,7 @@ class CapaModule(XModule):
|
||||
'html': self.get_problem_html(encapsulate=False)}
|
||||
|
||||
|
||||
class CapaDescriptor(RawDescriptor):
|
||||
class CapaDescriptor(CapaFields, RawDescriptor):
|
||||
"""
|
||||
Module implementing problems in the LON-CAPA format,
|
||||
as implemented by capa.capa_problem
|
||||
@@ -800,9 +805,6 @@ class CapaDescriptor(RawDescriptor):
|
||||
|
||||
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
|
||||
has_score = True
|
||||
template_dir_name = 'problem'
|
||||
|
||||
@@ -27,7 +27,26 @@ VERSION_TUPLES = (
|
||||
DEFAULT_VERSION = 1
|
||||
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).
|
||||
It transitions between problems, and support arbitrary ordering.
|
||||
@@ -60,22 +79,6 @@ class CombinedOpenEndedModule(XModule):
|
||||
|
||||
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'),
|
||||
resource_string(__name__, 'js/src/collapsible.coffee'),
|
||||
resource_string(__name__, 'js/src/javascript_loader.coffee'),
|
||||
@@ -192,7 +195,7 @@ class CombinedOpenEndedModule(XModule):
|
||||
setattr(self,attribute, getattr(self.child_module,attribute))
|
||||
|
||||
|
||||
class CombinedOpenEndedDescriptor(RawDescriptor):
|
||||
class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor):
|
||||
"""
|
||||
Module for adding combined open ended questions
|
||||
"""
|
||||
|
||||
@@ -17,7 +17,11 @@ from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
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.
|
||||
|
||||
@@ -134,7 +138,7 @@ class ConditionalModule(XModule):
|
||||
return new_class
|
||||
|
||||
|
||||
class ConditionalDescriptor(SequenceDescriptor):
|
||||
class ConditionalDescriptor(ConditionalFields, SequenceDescriptor):
|
||||
"""Descriptor for conditional xmodule."""
|
||||
_tag_name = 'conditional'
|
||||
|
||||
@@ -145,7 +149,6 @@ class ConditionalDescriptor(SequenceDescriptor):
|
||||
stores_state = True
|
||||
has_score = False
|
||||
|
||||
show_tag_list = List(help="Poll answers", scope=Scope.content)
|
||||
|
||||
@staticmethod
|
||||
def parse_sources(xml_element, system, return_descriptor=False):
|
||||
|
||||
@@ -147,9 +147,7 @@ class TextbookList(List):
|
||||
return json_data
|
||||
|
||||
|
||||
class CourseDescriptor(SequenceDescriptor):
|
||||
module_class = SequenceModule
|
||||
|
||||
class CourseFields(object):
|
||||
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)
|
||||
enrollment_start = Date(help="Date that enrollment for this class is opened", scope=Scope.settings)
|
||||
@@ -207,6 +205,10 @@ class CourseDescriptor(SequenceDescriptor):
|
||||
# Explicit comparison to True because we always want to return a bool.
|
||||
hide_progress_tab = Boolean(help="DO NOT USE THIS", scope=Scope.settings)
|
||||
|
||||
|
||||
class CourseDescriptor(CourseFields, SequenceDescriptor):
|
||||
module_class = SequenceModule
|
||||
|
||||
template_dir_name = 'course'
|
||||
|
||||
|
||||
|
||||
@@ -6,17 +6,20 @@ from xmodule.raw_module import RawDescriptor
|
||||
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':
|
||||
[resource_string(__name__, 'js/src/time.coffee'),
|
||||
resource_string(__name__, 'js/src/discussion/display.coffee')]
|
||||
}
|
||||
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):
|
||||
context = {
|
||||
@@ -25,7 +28,7 @@ class DiscussionModule(XModule):
|
||||
return self.system.render_template('discussion/_discussion_module.html', context)
|
||||
|
||||
|
||||
class DiscussionDescriptor(RawDescriptor):
|
||||
class DiscussionDescriptor(DiscussionFields, RawDescriptor):
|
||||
module_class = DiscussionModule
|
||||
template_dir_name = "discussion"
|
||||
|
||||
@@ -35,8 +38,3 @@ class DiscussionDescriptor(RawDescriptor):
|
||||
metadata_translations = dict(RawDescriptor.metadata_translations)
|
||||
metadata_translations['id'] = 'discussion_id'
|
||||
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
|
||||
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
|
||||
perform any validation on its definition---just passes it along to the browser.
|
||||
@@ -15,8 +19,6 @@ class EditingDescriptor(MakoModuleDescriptor):
|
||||
"""
|
||||
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
|
||||
# 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.
|
||||
|
||||
@@ -21,10 +21,13 @@ log = logging.getLogger(__name__)
|
||||
# decides whether to create a staff or not-staff module.
|
||||
|
||||
|
||||
class ErrorModule(XModule):
|
||||
|
||||
class ErrorFields(object):
|
||||
contents = String(scope=Scope.content)
|
||||
error_msg = String(scope=Scope.content)
|
||||
display_name = String(scope=Scope.settings)
|
||||
|
||||
|
||||
class ErrorModule(ErrorFields, XModule):
|
||||
|
||||
def get_html(self):
|
||||
'''Show an error to staff.
|
||||
@@ -38,7 +41,7 @@ class ErrorModule(XModule):
|
||||
})
|
||||
|
||||
|
||||
class NonStaffErrorModule(XModule):
|
||||
class NonStaffErrorModule(ErrorFields, XModule):
|
||||
def get_html(self):
|
||||
'''Show an error to a student.
|
||||
TODO (vshnayder): proper style, divs, etc.
|
||||
@@ -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_class = ErrorModule
|
||||
|
||||
contents = String(scope=Scope.content)
|
||||
error_msg = String(scope=Scope.content)
|
||||
display_name = String(scope=Scope.settings)
|
||||
|
||||
@classmethod
|
||||
def _construct(self, system, contents, error_msg, location):
|
||||
|
||||
|
||||
@@ -11,10 +11,8 @@ from xblock.core import Scope, Integer, String
|
||||
|
||||
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
|
||||
required_level = Integer(default=4, scope=Scope.settings)
|
||||
required_sublevel = Integer(default=5, scope=Scope.settings)
|
||||
@@ -23,6 +21,11 @@ class FolditModule(XModule):
|
||||
show_basic_score = 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):
|
||||
XModule.__init__(self, *args, **kwargs)
|
||||
"""
|
||||
@@ -154,7 +157,7 @@ class FolditModule(XModule):
|
||||
|
||||
|
||||
|
||||
class FolditDescriptor(XmlDescriptor, EditingDescriptor):
|
||||
class FolditDescriptor(FolditFields, XmlDescriptor, EditingDescriptor):
|
||||
"""
|
||||
Module for adding Foldit problems to courses
|
||||
"""
|
||||
|
||||
@@ -20,7 +20,12 @@ from xblock.core import String, Scope
|
||||
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
|
||||
'''
|
||||
|
||||
@@ -44,9 +49,6 @@ class GraphicalSliderToolModule(XModule):
|
||||
}
|
||||
js_module_name = "GraphicalSliderTool"
|
||||
|
||||
render = String(scope=Scope.content)
|
||||
configuration = String(scope=Scope.content)
|
||||
|
||||
def get_html(self):
|
||||
""" Renders parameters to template. """
|
||||
|
||||
@@ -137,13 +139,10 @@ class GraphicalSliderToolModule(XModule):
|
||||
'">' + self.configuration + '</root>'))
|
||||
|
||||
|
||||
class GraphicalSliderToolDescriptor(MakoModuleDescriptor, XmlDescriptor):
|
||||
class GraphicalSliderToolDescriptor(GraphicalSliderToolFields, MakoModuleDescriptor, XmlDescriptor):
|
||||
module_class = GraphicalSliderToolModule
|
||||
template_dir_name = 'graphical_slider_tool'
|
||||
|
||||
render = String(scope=Scope.content)
|
||||
configuration = String(scope=Scope.content)
|
||||
|
||||
@classmethod
|
||||
def definition_from_xml(cls, xml_object, system):
|
||||
"""
|
||||
|
||||
@@ -17,7 +17,11 @@ from xmodule.xml_module import XmlDescriptor, name_to_pathname
|
||||
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'),
|
||||
resource_string(__name__, 'js/src/collapsible.coffee'),
|
||||
resource_string(__name__, 'js/src/html/display.coffee')
|
||||
@@ -26,13 +30,11 @@ class HtmlModule(XModule):
|
||||
js_module_name = "HTMLModule"
|
||||
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):
|
||||
return self.data
|
||||
|
||||
|
||||
class HtmlDescriptor(XmlDescriptor, EditingDescriptor):
|
||||
class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
|
||||
"""
|
||||
Module for putting raw html in a course
|
||||
"""
|
||||
@@ -41,8 +43,6 @@ class HtmlDescriptor(XmlDescriptor, EditingDescriptor):
|
||||
filename_extension = "xml"
|
||||
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_module_name = "HTMLEditingDescriptor"
|
||||
css = {'scss': [resource_string(__name__, 'css/editor/edit.scss'), resource_string(__name__, 'css/html/edit.scss')]}
|
||||
|
||||
@@ -95,7 +95,7 @@ class MongoKeyValueStore(KeyValueStore):
|
||||
else:
|
||||
return key.field_name in self._data
|
||||
else:
|
||||
raise InvalidScopeError(key.scope)
|
||||
return False
|
||||
|
||||
MongoUsage = namedtuple('MongoUsage', 'id, def_id')
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ from lxml import etree
|
||||
from xmodule.capa_module import ComplexEncoder
|
||||
from xmodule.progress import Progress
|
||||
from xmodule.stringify import stringify_children
|
||||
from xblock.core import List, Integer, String, Scope
|
||||
import openendedchild
|
||||
|
||||
from combined_open_ended_rubric import CombinedOpenEndedRubric
|
||||
|
||||
@@ -27,7 +27,17 @@ IS_GRADED = True
|
||||
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
|
||||
|
||||
js = {'coffee': [resource_string(__name__, 'js/src/peergrading/peer_grading.coffee'),
|
||||
@@ -39,14 +49,6 @@ class PeerGradingModule(XModule):
|
||||
|
||||
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):
|
||||
XModule.__init__(self, system, location, descriptor, model_data)
|
||||
|
||||
@@ -556,7 +558,7 @@ class PeerGradingModule(XModule):
|
||||
return json.dumps(state)
|
||||
|
||||
|
||||
class PeerGradingDescriptor(RawDescriptor):
|
||||
class PeerGradingDescriptor(PeerGradingFields, RawDescriptor):
|
||||
"""
|
||||
Module for adding peer grading questions
|
||||
"""
|
||||
|
||||
@@ -26,17 +26,7 @@ from xblock.core import Scope, String, Object, Boolean, List
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PollModule(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"
|
||||
|
||||
class PollFields(object):
|
||||
# Name of poll to use in links to this poll
|
||||
display_name = String(help="Display name for this module", scope=Scope.settings)
|
||||
|
||||
@@ -47,6 +37,20 @@ class PollModule(XModule):
|
||||
answers = List(help="Poll answers from xml", 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):
|
||||
"""Ajax handler.
|
||||
|
||||
@@ -135,7 +139,7 @@ class PollModule(XModule):
|
||||
'reset': str(self.descriptor.xml_attributes.get('reset', 'true')).lower()})
|
||||
|
||||
|
||||
class PollDescriptor(MakoModuleDescriptor, XmlDescriptor):
|
||||
class PollDescriptor(PollFields, MakoModuleDescriptor, XmlDescriptor):
|
||||
_tag_name = 'poll_question'
|
||||
_child_tag_name = 'answer'
|
||||
|
||||
@@ -143,11 +147,6 @@ class PollDescriptor(MakoModuleDescriptor, XmlDescriptor):
|
||||
template_dir_name = 'poll'
|
||||
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
|
||||
def definition_from_xml(cls, xml_object, system):
|
||||
"""Pull out the data into dictionary.
|
||||
|
||||
@@ -9,7 +9,11 @@ from xblock.core import Scope, Integer
|
||||
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.
|
||||
|
||||
@@ -31,9 +35,6 @@ class RandomizeModule(XModule):
|
||||
grading interaction is a tangle between super and subclasses of descriptors and
|
||||
modules.
|
||||
"""
|
||||
|
||||
choice = Integer(help="Which random child was chosen", scope=Scope.student_state)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
XModule.__init__(self, *args, **kwargs)
|
||||
|
||||
@@ -64,7 +65,6 @@ class RandomizeModule(XModule):
|
||||
self.child_descriptor = None
|
||||
self.child = None
|
||||
|
||||
|
||||
def get_child_descriptors(self):
|
||||
"""
|
||||
For grading--return just the chosen child.
|
||||
@@ -86,7 +86,7 @@ class RandomizeModule(XModule):
|
||||
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
|
||||
module_class = RandomizeModule
|
||||
|
||||
|
||||
@@ -18,7 +18,15 @@ log = logging.getLogger(__name__)
|
||||
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
|
||||
'''
|
||||
js = {'coffee': [resource_string(__name__,
|
||||
@@ -27,11 +35,6 @@ class SequenceModule(XModule):
|
||||
css = {'scss': [resource_string(__name__, 'css/sequence/display.scss')]}
|
||||
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):
|
||||
XModule.__init__(self, *args, **kwargs)
|
||||
@@ -114,11 +117,10 @@ class SequenceModule(XModule):
|
||||
return new_class
|
||||
|
||||
|
||||
class SequenceDescriptor(MakoModuleDescriptor, XmlDescriptor):
|
||||
class SequenceDescriptor(SequenceFields, MakoModuleDescriptor, XmlDescriptor):
|
||||
mako_template = 'widgets/sequence-edit.html'
|
||||
module_class = SequenceModule
|
||||
|
||||
has_children = True
|
||||
stores_state = True # For remembering where in the sequence the student is
|
||||
|
||||
js = {'coffee': [resource_string(__name__, 'js/src/sequence/edit.coffee')]}
|
||||
|
||||
@@ -15,11 +15,7 @@ from xblock.core import Float, String, Boolean, Scope
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TimeLimitModule(XModule):
|
||||
'''
|
||||
Wrapper module which imposes a time constraint for the completion of its child.
|
||||
'''
|
||||
|
||||
class TimeLimitFields(object):
|
||||
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)
|
||||
accomodation_code = String(help="A code indicating accommodations to be given the student", scope=Scope.student_state)
|
||||
@@ -27,6 +23,12 @@ class TimeLimitModule(XModule):
|
||||
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)
|
||||
|
||||
|
||||
class TimeLimitModule(TimeLimitFields, XModule):
|
||||
'''
|
||||
Wrapper module which imposes a time constraint for the completion of its child.
|
||||
'''
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
XModule.__init__(self, *args, **kwargs)
|
||||
|
||||
@@ -117,7 +119,7 @@ class TimeLimitModule(XModule):
|
||||
else:
|
||||
return "other"
|
||||
|
||||
class TimeLimitDescriptor(XMLEditingDescriptor, XmlDescriptor):
|
||||
class TimeLimitDescriptor(TimeLimitFields, XMLEditingDescriptor, XmlDescriptor):
|
||||
|
||||
module_class = TimeLimitModule
|
||||
|
||||
|
||||
@@ -19,7 +19,13 @@ import time
|
||||
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
|
||||
icon_class = 'video'
|
||||
|
||||
@@ -33,10 +39,6 @@ class VideoModule(XModule):
|
||||
css = {'scss': [resource_string(__name__, 'css/video/display.scss')]}
|
||||
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):
|
||||
XModule.__init__(self, *args, **kwargs)
|
||||
|
||||
@@ -151,7 +153,7 @@ class VideoModule(XModule):
|
||||
})
|
||||
|
||||
|
||||
class VideoDescriptor(RawDescriptor):
|
||||
class VideoDescriptor(VideoFields, RawDescriptor):
|
||||
module_class = VideoModule
|
||||
stores_state = True
|
||||
template_dir_name = "video"
|
||||
|
||||
@@ -19,7 +19,13 @@ import time
|
||||
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:
|
||||
|
||||
@@ -47,10 +53,6 @@ class VideoAlphaModule(XModule):
|
||||
css = {'scss': [resource_string(__name__, 'css/videoalpha/display.scss')]}
|
||||
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):
|
||||
XModule.__init__(self, *args, **kwargs)
|
||||
xmltree = etree.fromstring(self.data)
|
||||
@@ -147,7 +149,7 @@ class VideoAlphaModule(XModule):
|
||||
})
|
||||
|
||||
|
||||
class VideoAlphaDescriptor(RawDescriptor):
|
||||
class VideoAlphaDescriptor(VideoAlphaFields, RawDescriptor):
|
||||
module_class = VideoAlphaModule
|
||||
stores_state = True
|
||||
template_dir_name = "videoalpha"
|
||||
|
||||
@@ -82,7 +82,15 @@ class HTMLSnippet(object):
|
||||
.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.
|
||||
|
||||
Subclasses must at a minimum provide a definition for get_html in order
|
||||
@@ -99,11 +107,6 @@ class XModule(HTMLSnippet, XBlock):
|
||||
# in the module
|
||||
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):
|
||||
'''
|
||||
@@ -307,7 +310,7 @@ class ResourceTemplates(object):
|
||||
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
|
||||
could be a problem, an organizational element (a group of content), or a
|
||||
@@ -352,12 +355,6 @@ class XModuleDescriptor(HTMLSnippet, ResourceTemplates, XBlock):
|
||||
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
|
||||
# importing 2012 courses.
|
||||
# A set of metadata key conversions that we want to make
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
# XBlock:
|
||||
# Might change frequently, so put it in local-requirements.txt,
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user