diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index 5a4930ff95..5c902f48c2 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -19,10 +19,45 @@ from xblock.core import String, Scope log = logging.getLogger(__name__) +DEFAULT_RENDER=""" +

Graphic slider tool: Dynamic range and implicit functions.

+ +

You can make the range of the x axis (but not ticks of x axis) of + functions depend on a parameter value. This can be useful when the + function domain needs to be variable.

+

Implicit functions like a circle can be plotted as 2 separate + functions of the same color.

+
+ + +
+ +""" +DEFAULT_CONFIGURATION=""" + + + + + Math.sqrt(r * r - x * x) + -Math.sqrt(r * r - x * x) + + + + + -r + r + + 1000 + -30, 6, 30 + -30, 6, 30 + +""" + + class GraphicalSliderToolFields(object): - render = String(scope=Scope.content) - configuration = String(scope=Scope.content) + render = String(scope=Scope.content, default=DEFAULT_RENDER) + configuration = String(scope=Scope.content, default=DEFAULT_CONFIGURATION) class GraphicalSliderToolModule(GraphicalSliderToolFields, XModule): diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py index 0536f5ef5e..a482a86fe7 100644 --- a/common/lib/xmodule/xmodule/html_module.py +++ b/common/lib/xmodule/xmodule/html_module.py @@ -27,7 +27,7 @@ class HtmlFields(object): # use display_name_with_default for those default="Blank HTML Page" ) - data = String(help="Html contents to display for this module", default="", scope=Scope.content) + data = String(help="Html contents to display for this module", default=u"", scope=Scope.content) source_code = String(help="Source code for LaTeX documents. This feature is not well-supported.", scope=Scope.settings) diff --git a/common/lib/xmodule/xmodule/schematic_module.py b/common/lib/xmodule/xmodule/schematic_module.py deleted file mode 100644 index 83bcc5351d..0000000000 --- a/common/lib/xmodule/xmodule/schematic_module.py +++ /dev/null @@ -1,11 +0,0 @@ - -from .x_module import XModule, XModuleDescriptor - - -class ModuleDescriptor(XModuleDescriptor): - pass - - -class Module(XModule): - def get_html(self): - return ''.format(item_id=self.item_id) diff --git a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py new file mode 100644 index 0000000000..d4df2e1054 --- /dev/null +++ b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py @@ -0,0 +1,160 @@ +""" +Tests for the wrapping layer that provides the XBlock API using XModule/Descriptor +functionality +""" + +from nose.tools import assert_equal +from unittest.case import SkipTest +from mock import Mock + +from xmodule.annotatable_module import AnnotatableDescriptor +from xmodule.capa_module import CapaDescriptor +from xmodule.course_module import CourseDescriptor +from xmodule.combined_open_ended_module import CombinedOpenEndedDescriptor +from xmodule.discussion_module import DiscussionDescriptor +from xmodule.gst_module import GraphicalSliderToolDescriptor +from xmodule.html_module import HtmlDescriptor +from xmodule.peer_grading_module import PeerGradingDescriptor +from xmodule.poll_module import PollDescriptor +from xmodule.video_module import VideoDescriptor +from xmodule.word_cloud_module import WordCloudDescriptor +from xmodule.crowdsource_hinter import CrowdsourceHinterDescriptor +from xmodule.videoalpha_module import VideoAlphaDescriptor +from xmodule.seq_module import SequenceDescriptor +from xmodule.conditional_module import ConditionalDescriptor +from xmodule.randomize_module import RandomizeDescriptor +from xmodule.vertical_module import VerticalDescriptor +from xmodule.wrapper_module import WrapperDescriptor + +LEAF_XMODULES = ( + AnnotatableDescriptor, + CapaDescriptor, + CombinedOpenEndedDescriptor, + DiscussionDescriptor, + GraphicalSliderToolDescriptor, + HtmlDescriptor, + PeerGradingDescriptor, + PollDescriptor, + VideoDescriptor, + # This is being excluded because it has dependencies on django + #VideoAlphaDescriptor, + WordCloudDescriptor, +) + + +CONTAINER_XMODULES = ( + CrowdsourceHinterDescriptor, + CourseDescriptor, + SequenceDescriptor, + ConditionalDescriptor, + RandomizeDescriptor, + VerticalDescriptor, + WrapperDescriptor, + CourseDescriptor, +) + + +class TestXBlockWrapper(object): + + @property + def leaf_module_runtime(self): + runtime = Mock() + runtime.render_template = lambda *args, **kwargs: unicode((args, kwargs)) + runtime.anonymous_student_id = 'anonymous_student_id' + runtime.open_ended_grading_interface = {} + runtime.seed = 5 + runtime.get = lambda x: getattr(runtime, x) + runtime.position = 2 + runtime.ajax_url = 'ajax_url' + runtime.xblock_model_data = lambda d: d._model_data + return runtime + + @property + def leaf_descriptor_runtime(self): + runtime = Mock() + runtime.render_template = lambda *args, **kwargs: unicode((args, kwargs)) + return runtime + + def leaf_descriptor(self, descriptor_cls): + return descriptor_cls( + self.leaf_descriptor_runtime, + {'location': 'i4x://org/course/catagory/name'} + ) + + def leaf_module(self, descriptor_cls): + return self.leaf_descriptor(descriptor_cls).xmodule(self.leaf_module_runtime) + + def container_module_runtime(self, depth): + runtime = self.leaf_module_runtime + if depth == 0: + runtime.get_module.side_effect = lambda x: self.leaf_module(HtmlDescriptor) + else: + runtime.get_module.side_effect = lambda x: self.container_module(VerticalDescriptor, depth-1) + return runtime + + @property + def container_descriptor_runtime(self): + runtime = Mock() + runtime.render_template = lambda *args, **kwargs: unicode((args, kwargs)) + return runtime + + def container_descriptor(self, descriptor_cls): + return descriptor_cls( + self.container_descriptor_runtime, + { + 'location': 'i4x://org/course/catagory/name', + 'children': range(3) + } + ) + + def container_module(self, descriptor_cls, depth): + return self.container_descriptor(descriptor_cls).xmodule(self.container_module_runtime(depth)) + +class TestStudentView(TestXBlockWrapper): + + # Test that for all of the leaf XModule Descriptors, + # the student_view wrapper returns the same thing in its content + # as get_html returns + def test_student_view_leaf_node(self): + for descriptor_cls in LEAF_XMODULES: + yield self.check_student_view_leaf_node, descriptor_cls + + # Check that when an xmodule is instantiated from descriptor_cls + # it generates the same thing from student_view that it does from get_html + def check_student_view_leaf_node(self, descriptor_cls): + xmodule = self.leaf_module(descriptor_cls) + assert_equal(xmodule.get_html(), xmodule.student_view(None).content) + + + # Test that for all container XModule Descriptors, + # their corresponding XModule renders the same thing using student_view + # as it does using get_html, under the following conditions: + # a) All of its descendents are xmodules + # b) Some of its descendents are xmodules and some are xblocks + # c) All of its descendents are xblocks + def test_student_view_container_node(self): + for descriptor_cls in CONTAINER_XMODULES: + yield self.check_student_view_container_node_xmodules_only, descriptor_cls + yield self.check_student_view_container_node_mixed, descriptor_cls + yield self.check_student_view_container_node_xblocks_only, descriptor_cls + + + # Check that when an xmodule is generated from descriptor_cls + # with only xmodule children, it generates the same html from student_view + # as it does using get_html + def check_student_view_container_node_xmodules_only(self, descriptor_cls): + xmodule = self.container_module(descriptor_cls, 2) + assert_equal(xmodule.get_html(), xmodule.student_view(None).content) + + # Check that when an xmodule is generated from descriptor_cls + # with mixed xmodule and xblock children, it generates the same html from student_view + # as it does using get_html + def check_student_view_container_node_mixed(self, descriptor_cls): + raise SkipTest("XBlock support in XDescriptor not yet fully implemented") + + # Check that when an xmodule is generated from descriptor_cls + # with only xblock children, it generates the same html from student_view + # as it does using get_html + def check_student_view_container_node_xblocks_only(self, descriptor_cls): + raise SkipTest("XBlock support in XModules not yet fully implemented") + diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 89f72e8099..47642e9f90 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -11,6 +11,7 @@ from xmodule.modulestore import inheritance, Location from xmodule.modulestore.exceptions import ItemNotFoundError, InsufficientSpecificationError, InvalidLocationError from xblock.core import XBlock, Scope, String, Integer, Float, ModelType +from xblock.fragment import Fragment from xmodule.modulestore.locator import BlockUsageLocator log = logging.getLogger(__name__) @@ -314,6 +315,19 @@ class XModule(XModuleFields, HTMLSnippet, XBlock): return "" + # ~~~~~~~~~~~~~~~ XBlock API Wrappers ~~~~~~~~~~~~~~~~ + def student_view(self, context): + """ + Return a fragment with the html from this XModule + + Doesn't yet add any of the javascript to the fragment, nor the css. + Also doesn't expect any javascript binding, yet. + + Makes no use of the context parameter + """ + return Fragment(self.get_html()) + + def policy_key(location): """ Get the key for a location in a policy file. (Since the policy file is @@ -906,8 +920,8 @@ class ModuleSystem(object): publish(event) - A function that allows XModules to publish events (such as grade changes) - xblock_model_data - A dict-like object containing the all data available to this - xblock + xblock_model_data - A function that constructs a model_data for an xblock from its + corresponding descriptor cache - A cache object with two methods: .get(key) returns an object from the cache or None. diff --git a/docs/source/xmodule.rst b/docs/source/xmodule.rst index d7552812a0..008a1303d2 100644 --- a/docs/source/xmodule.rst +++ b/docs/source/xmodule.rst @@ -109,13 +109,6 @@ Progress :members: :show-inheritance: -Schematic -========= - -.. automodule:: xmodule.schematic_module - :members: - :show-inheritance: - Sequence ========