diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py index 1f73ab2ad5..a72db037ed 100644 --- a/common/lib/xmodule/setup.py +++ b/common/lib/xmodule/setup.py @@ -20,13 +20,13 @@ XMODULES = [ "videodev = xmodule.backcompat_module:TranslateCustomTagDescriptor", "videosequence = xmodule.seq_module:SequenceDescriptor", "custom_tag_template = xmodule.raw_module:RawDescriptor", - "annotatable = xmodule.annotatable_module:AnnotatableDescriptor", "hidden = xmodule.hidden_module:HiddenDescriptor", "raw = xmodule.raw_module:RawDescriptor", "lti = xmodule.lti_module:LTIDescriptor", ] XBLOCKS = [ "about = xmodule.html_module:AboutBlock", + "annotatable = xmodule.annotatable_module:AnnotatableBlock", "conditional = xmodule.conditional_module:ConditionalBlock", "course_info = xmodule.html_module:CourseInfoBlock", "html = xmodule.html_module:HtmlBlock", diff --git a/common/lib/xmodule/xmodule/annotatable_module.py b/common/lib/xmodule/xmodule/annotatable_module.py index d30c737864..16e6b1771f 100644 --- a/common/lib/xmodule/xmodule/annotatable_module.py +++ b/common/lib/xmodule/xmodule/annotatable_module.py @@ -5,11 +5,22 @@ import textwrap from lxml import etree from pkg_resources import resource_string +from web_fragments.fragment import Fragment from xblock.fields import Scope, String from openedx.core.djangolib.markup import HTML, Text -from xmodule.raw_module import RawDescriptor -from xmodule.x_module import XModule +from xmodule.editing_module import EditingMixin +from xmodule.raw_module import RawMixin +from xmodule.util.xmodule_django import add_webpack_to_fragment +from xmodule.xml_module import XmlMixin +from xmodule.x_module import ( + HTMLSnippet, + ResourceTemplates, + shim_xmodule_js, + XModuleMixin, + XModuleDescriptorToXBlockMixin, + XModuleToXBlockMixin, +) log = logging.getLogger(__name__) @@ -18,7 +29,20 @@ log = logging.getLogger(__name__) _ = lambda text: text -class AnnotatableFields(object): +class AnnotatableBlock( + RawMixin, + XmlMixin, + EditingMixin, + XModuleDescriptorToXBlockMixin, + XModuleToXBlockMixin, + HTMLSnippet, + ResourceTemplates, + XModuleMixin, +): + """ + Annotatable XBlock. + """ + data = String( help=_("XML data for the annotation"), scope=Scope.content, @@ -47,29 +71,41 @@ class AnnotatableFields(object): default=_('Annotation'), ) + uses_xmodule_styles_setup = True -class AnnotatableModule(AnnotatableFields, XModule): - js = { + preview_view_js = { 'js': [ resource_string(__name__, 'js/src/html/display.js'), resource_string(__name__, 'js/src/annotatable/display.js'), resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), - ] + ], + 'xmodule_js': resource_string(__name__, 'js/src/xmodule.js'), } - js_module_name = "Annotatable" - css = {'scss': [resource_string(__name__, 'css/annotatable/display.scss')]} + preview_view_css = { + 'scss': [ + resource_string(__name__, 'css/annotatable/display.scss'), + ], + } + + studio_view_js = { + 'js': [ + resource_string(__name__, 'js/src/raw/edit/xml.js'), + ], + 'xmodule_js': resource_string(__name__, 'js/src/xmodule.js'), + } + studio_view_css = { + 'scss': [ + resource_string(__name__, 'css/codemirror/codemirror.scss'), + ], + } + studio_js_module_name = "XMLEditingDescriptor" + mako_template = "widgets/raw-edit.html" + icon_class = 'annotatable' + resources_dir = None - def __init__(self, *args, **kwargs): - super(AnnotatableModule, self).__init__(*args, **kwargs) - - xmltree = etree.fromstring(self.data) - - self.instructions = self._extract_instructions(xmltree) - self.content = etree.tostring(xmltree, encoding='unicode') - self.element_id = self.location.html_id() - self.highlight_colors = ['yellow', 'orange', 'purple', 'blue', 'green'] + HIGHLIGHT_COLORS = ['yellow', 'orange', 'purple', 'blue', 'green'] def _get_annotation_class_attr(self, index, el): """ Returns a dict with the CSS class attribute to set on the annotation @@ -82,7 +118,7 @@ class AnnotatableModule(AnnotatableFields, XModule): color = el.get(highlight_key) if color is not None: - if color in self.highlight_colors: + if color in self.HIGHLIGHT_COLORS: cls.append('highlight-' + color) attr['_delete'] = highlight_key attr['value'] = ' '.join(cls) @@ -127,7 +163,11 @@ class AnnotatableModule(AnnotatableFields, XModule): def _render_content(self): """ Renders annotatable content with annotation spans and returns HTML. """ - xmltree = etree.fromstring(self.content) + + xmltree = etree.fromstring(self.data) + content = etree.tostring(xmltree, encoding='unicode') + + xmltree = etree.fromstring(content) xmltree.tag = 'div' if 'display_name' in xmltree.attrib: del xmltree.attrib['display_name'] @@ -150,17 +190,37 @@ class AnnotatableModule(AnnotatableFields, XModule): def get_html(self): """ Renders parameters to template. """ + + xmltree = etree.fromstring(self.data) + instructions = self._extract_instructions(xmltree) + context = { - 'display_name': self.display_name_with_default_escaped, - 'element_id': self.element_id, - 'instructions_html': self.instructions, + 'display_name': self.display_name_with_default, + 'element_id': self.location.html_id(), + 'instructions_html': instructions, 'content_html': self._render_content() } return self.system.render_template('annotatable.html', context) + def student_view(self, context): + """ + Renders the output that a student will see. + """ + fragment = Fragment() + fragment.add_content(self.get_html()) + add_webpack_to_fragment(fragment, 'AnnotatableBlockPreview') + shim_xmodule_js(fragment, 'Annotatable') -class AnnotatableDescriptor(AnnotatableFields, RawDescriptor): - module_class = AnnotatableModule - mako_template = "widgets/raw-edit.html" - resources_dir = None + return fragment + + def studio_view(self, _context): + """ + Return the studio view. + """ + fragment = Fragment( + self.system.render_template(self.mako_template, self.get_context()) + ) + add_webpack_to_fragment(fragment, 'AnnotatableBlockStudio') + shim_xmodule_js(fragment, self.studio_js_module_name) + return fragment diff --git a/common/lib/xmodule/xmodule/static_content.py b/common/lib/xmodule/xmodule/static_content.py index 607c3e90d8..1a68b8cb99 100755 --- a/common/lib/xmodule/xmodule/static_content.py +++ b/common/lib/xmodule/xmodule/static_content.py @@ -20,6 +20,7 @@ import six from docopt import docopt from path import Path as path +from xmodule.annotatable_module import AnnotatableBlock from xmodule.capa_module import ProblemBlock from xmodule.conditional_module import ConditionalBlock from xmodule.html_module import AboutBlock, CourseInfoBlock, HtmlBlock, StaticTabBlock @@ -67,6 +68,7 @@ class VideoBlock(HTMLSnippet): # Should only be used for XModules being converted to XBlocks. XBLOCK_CLASSES = [ AboutBlock, + AnnotatableBlock, ConditionalBlock, CourseInfoBlock, HtmlBlock, diff --git a/common/lib/xmodule/xmodule/tests/test_annotatable_module.py b/common/lib/xmodule/xmodule/tests/test_annotatable_module.py index 05c6b51aba..b2f1a61e6f 100644 --- a/common/lib/xmodule/xmodule/tests/test_annotatable_module.py +++ b/common/lib/xmodule/xmodule/tests/test_annotatable_module.py @@ -9,12 +9,12 @@ from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from xblock.field_data import DictFieldData from xblock.fields import ScopeIds -from xmodule.annotatable_module import AnnotatableModule +from xmodule.annotatable_module import AnnotatableBlock from . import get_test_system -class AnnotatableModuleTestCase(unittest.TestCase): +class AnnotatableBlockTestCase(unittest.TestCase): sample_xml = ''' Read the text. @@ -33,9 +33,8 @@ class AnnotatableModuleTestCase(unittest.TestCase): ''' def setUp(self): - super(AnnotatableModuleTestCase, self).setUp() - self.annotatable = AnnotatableModule( - Mock(), + super().setUp() + self.annotatable = AnnotatableBlock( get_test_system(), DictFieldData({'data': self.sample_xml}), ScopeIds(None, None, None, BlockUsageLocator(CourseLocator('org', 'course', 'run'), 'category', 'name')) @@ -68,7 +67,7 @@ class AnnotatableModuleTestCase(unittest.TestCase): def test_annotation_class_attr_with_valid_highlight(self): xml = 'test' - for color in self.annotatable.highlight_colors: + for color in self.annotatable.HIGHLIGHT_COLORS: el = etree.fromstring(xml.format(highlight=color)) value = 'annotatable-span highlight highlight-{highlight}'.format(highlight=color) diff --git a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py index f8c625af60..a68e3fbeff 100644 --- a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py +++ b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py @@ -30,7 +30,7 @@ from xblock.core import XBlock from xblock.field_data import DictFieldData from xblock.fields import ScopeIds -from xmodule.annotatable_module import AnnotatableDescriptor +from xmodule.annotatable_module import AnnotatableBlock from xmodule.conditional_module import ConditionalBlock from xmodule.course_module import CourseDescriptor from xmodule.html_module import HtmlBlock @@ -55,7 +55,7 @@ from xmodule.x_module import ( # to a list of sample field values to test with. # TODO: Add more types of sample data LEAF_XMODULES = { - AnnotatableDescriptor: [{}], + AnnotatableBlock: [{}], HtmlBlock: [{}], PollDescriptor: [{'display_name': 'Poll Display Name'}], WordCloudBlock: [{}], diff --git a/lms/templates/annotatable.html b/lms/templates/annotatable.html index 49c2e8677b..7d7015d272 100644 --- a/lms/templates/annotatable.html +++ b/lms/templates/annotatable.html @@ -3,7 +3,7 @@
% if display_name is not UNDEFINED and display_name is not None: -

${display_name}

+

${display_name | h}

% endif