Add an XBlock student_view to XModule
This just wraps XModule.get_html, and ignores javascript and css for now. [LMS-189]
This commit is contained in:
@@ -19,10 +19,45 @@ from xblock.core import String, Scope
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_RENDER="""
|
||||
<h2>Graphic slider tool: Dynamic range and implicit functions.</h2>
|
||||
|
||||
<p>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.</p>
|
||||
<p>Implicit functions like a circle can be plotted as 2 separate
|
||||
functions of the same color.</p>
|
||||
<div style="height:50px;">
|
||||
<slider var='r' style="width:400px;float:left;"/>
|
||||
<textbox var='r' style="float:left;width:60px;margin-left:15px;"/>
|
||||
</div>
|
||||
<plot style="margin-top:15px;margin-bottom:15px;"/>
|
||||
"""
|
||||
DEFAULT_CONFIGURATION="""
|
||||
<parameters>
|
||||
<param var="r" min="5" max="25" step="0.5" initial="12.5" />
|
||||
</parameters>
|
||||
<functions>
|
||||
<function color="red">Math.sqrt(r * r - x * x)</function>
|
||||
<function color="red">-Math.sqrt(r * r - x * x)</function>
|
||||
</functions>
|
||||
<plot>
|
||||
<xrange>
|
||||
<!-- dynamic range -->
|
||||
<min>-r</min>
|
||||
<max>r</max>
|
||||
</xrange>
|
||||
<num_points>1000</num_points>
|
||||
<xticks>-30, 6, 30</xticks>
|
||||
<yticks>-30, 6, 30</yticks>
|
||||
</plot>
|
||||
"""
|
||||
|
||||
|
||||
|
||||
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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
from .x_module import XModule, XModuleDescriptor
|
||||
|
||||
|
||||
class ModuleDescriptor(XModuleDescriptor):
|
||||
pass
|
||||
|
||||
|
||||
class Module(XModule):
|
||||
def get_html(self):
|
||||
return '<input type="hidden" class="schematic" name="{item_id}" height="480" width="640">'.format(item_id=self.item_id)
|
||||
160
common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
Normal file
160
common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
Normal file
@@ -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")
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -109,13 +109,6 @@ Progress
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Schematic
|
||||
=========
|
||||
|
||||
.. automodule:: xmodule.schematic_module
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Sequence
|
||||
========
|
||||
|
||||
|
||||
Reference in New Issue
Block a user