diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py
index 095fa5a3cca0..22271d305b53 100644
--- a/common/lib/xmodule/setup.py
+++ b/common/lib/xmodule/setup.py
@@ -4,10 +4,8 @@
XMODULES = [
"book = xmodule.backcompat_module:TranslateCustomTagDescriptor",
- "customtag = xmodule.template_module:CustomTagDescriptor",
"discuss = xmodule.backcompat_module:TranslateCustomTagDescriptor",
"image = xmodule.backcompat_module:TranslateCustomTagDescriptor",
- "poll_question = xmodule.poll_module:PollDescriptor",
"section = xmodule.backcompat_module:SemanticSectionDescriptor",
"slides = xmodule.backcompat_module:TranslateCustomTagDescriptor",
"videodev = xmodule.backcompat_module:TranslateCustomTagDescriptor",
@@ -21,6 +19,7 @@
"conditional = xmodule.conditional_module:ConditionalBlock",
"course = xmodule.course_module:CourseBlock",
"course_info = xmodule.html_module:CourseInfoBlock",
+ "customtag = xmodule.template_module:CustomTagBlock",
"error = xmodule.error_module:ErrorBlock",
"hidden = xmodule.hidden_module:HiddenDescriptor",
"html = xmodule.html_module:HtmlBlock",
@@ -29,6 +28,7 @@
"library_sourced = xmodule.library_sourced_block:LibrarySourcedBlock",
"lti = xmodule.lti_module:LTIBlock",
"nonstaff_error = xmodule.error_module:NonStaffErrorBlock",
+ "poll_question = xmodule.poll_module:PollBlock",
"problem = xmodule.capa_module:ProblemBlock",
"problemset = xmodule.seq_module:SequenceBlock",
"randomize = xmodule.randomize_module:RandomizeBlock",
diff --git a/common/lib/xmodule/xmodule/poll_module.py b/common/lib/xmodule/xmodule/poll_module.py
index 519ee5280e94..6c739f4a91f6 100644
--- a/common/lib/xmodule/xmodule/poll_module.py
+++ b/common/lib/xmodule/xmodule/poll_module.py
@@ -14,19 +14,38 @@
from copy import deepcopy
from pkg_resources import resource_string
+from web_fragments.fragment import Fragment
+
from lxml import etree
from openedx.core.djangolib.markup import Text, HTML
from xblock.fields import Boolean, Dict, List, Scope, String # lint-amnesty, pylint: disable=wrong-import-order
-from xmodule.mako_module import MakoModuleDescriptor
+from xmodule.mako_module import MakoTemplateBlockBase
from xmodule.stringify import stringify_children
-from xmodule.x_module import XModule
-from xmodule.xml_module import XmlDescriptor
+from xmodule.util.xmodule_django import add_webpack_to_fragment
+from xmodule.x_module import (
+ HTMLSnippet,
+ ResourceTemplates,
+ shim_xmodule_js,
+ XModuleMixin,
+ XModuleDescriptorToXBlockMixin,
+ XModuleToXBlockMixin,
+)
+from xmodule.xml_module import XmlMixin
log = logging.getLogger(__name__)
_ = lambda text: text
-class PollFields(object): # lint-amnesty, pylint: disable=missing-class-docstring
+class PollBlock(
+ MakoTemplateBlockBase,
+ XmlMixin,
+ XModuleDescriptorToXBlockMixin,
+ XModuleToXBlockMixin,
+ HTMLSnippet,
+ ResourceTemplates,
+ XModuleMixin,
+): # pylint: disable=abstract-method
+ """Poll Module"""
# Name of poll to use in links to this poll
display_name = String(
help=_("The display name for this component."),
@@ -61,18 +80,33 @@ class PollFields(object): # lint-amnesty, pylint: disable=missing-class-docstri
default=''
)
+ resources_dir = None
+ uses_xmodule_styles_setup = True
-class PollModule(PollFields, XModule):
- """Poll Module"""
- js = {
+ preview_view_js = {
'js': [
resource_string(__name__, 'js/src/javascript_loader.js'),
resource_string(__name__, 'js/src/poll/poll.js'),
resource_string(__name__, 'js/src/poll/poll_main.js')
- ]
+ ],
+ 'xmodule_js': resource_string(__name__, 'js/src/xmodule.js'),
+ }
+ preview_view_css = {
+ 'scss': [
+ resource_string(__name__, 'css/poll/display.scss')
+ ],
+ }
+
+ # There is no studio_view() for this XBlock but this is needed to make the
+ # the static_content command happy.
+ studio_view_js = {
+ 'js': [],
+ 'xmodule_js': resource_string(__name__, 'js/src/xmodule.js')
+ }
+
+ studio_view_css = {
+ 'scss': []
}
- css = {'scss': [resource_string(__name__, 'css/poll/display.scss')]}
- js_module_name = "Poll"
def handle_ajax(self, dispatch, data): # lint-amnesty, pylint: disable=unused-argument
"""Ajax handler.
@@ -103,7 +137,7 @@ def handle_ajax(self, dispatch, data): # lint-amnesty, pylint: disable=unused-a
'total': sum(self.poll_answers.values())
})
elif dispatch == 'reset_poll' and self.voted and \
- self.descriptor.xml_attributes.get('reset', 'True').lower() != 'false':
+ self.xml_attributes.get('reset', 'True').lower() != 'false':
self.voted = False
# FIXME: fix this, when xblock will support mutable types.
@@ -117,16 +151,21 @@ def handle_ajax(self, dispatch, data): # lint-amnesty, pylint: disable=unused-a
else: # return error message
return json.dumps({'error': 'Unknown Command!'})
- def get_html(self):
- """Renders parameters to template."""
+ def student_view(self, _context):
+ """
+ Renders the student view.
+ """
+ fragment = Fragment()
params = {
'element_id': self.location.html_id(),
'element_class': self.location.block_type,
- 'ajax_url': self.system.ajax_url,
+ 'ajax_url': self.ajax_url,
'configuration_json': self.dump_poll(),
}
- self.content = self.system.render_template('poll.html', params) # lint-amnesty, pylint: disable=attribute-defined-outside-init
- return self.content
+ fragment.add_content(self.system.render_template('poll.html', params))
+ add_webpack_to_fragment(fragment, 'PollBlockPreview')
+ shim_xmodule_js(fragment, 'Poll')
+ return fragment
def dump_poll(self):
"""Dump poll information.
@@ -160,17 +199,12 @@ def dump_poll(self):
'poll_answer': self.poll_answer,
'poll_answers': self.poll_answers if self.voted else {},
'total': sum(self.poll_answers.values()) if self.voted else 0,
- 'reset': str(self.descriptor.xml_attributes.get('reset', 'true')).lower()
+ 'reset': str(self.xml_attributes.get('reset', 'true')).lower()
})
-
-class PollDescriptor(PollFields, MakoModuleDescriptor, XmlDescriptor): # lint-amnesty, pylint: disable=missing-class-docstring
_tag_name = 'poll_question'
_child_tag_name = 'answer'
- module_class = PollModule
- resources_dir = None
-
@classmethod
def definition_from_xml(cls, xml_object, system):
"""Pull out the data into dictionary.
diff --git a/common/lib/xmodule/xmodule/static_content.py b/common/lib/xmodule/xmodule/static_content.py
index eac98a2f75ce..58e03bd05ac5 100755
--- a/common/lib/xmodule/xmodule/static_content.py
+++ b/common/lib/xmodule/xmodule/static_content.py
@@ -26,8 +26,10 @@
from xmodule.html_module import AboutBlock, CourseInfoBlock, HtmlBlock, StaticTabBlock
from xmodule.library_content_module import LibraryContentBlock
from xmodule.lti_module import LTIBlock
+from xmodule.poll_module import PollBlock
from xmodule.seq_module import SequenceBlock
from xmodule.split_test_module import SplitTestBlock
+from xmodule.template_module import CustomTagBlock
from xmodule.word_cloud_module import WordCloudBlock
from xmodule.x_module import XModuleDescriptor, HTMLSnippet
@@ -74,9 +76,11 @@ class VideoBlock(HTMLSnippet): # lint-amnesty, pylint: disable=abstract-method
AnnotatableBlock,
ConditionalBlock,
CourseInfoBlock,
+ CustomTagBlock,
HtmlBlock,
LibraryContentBlock,
LTIBlock,
+ PollBlock,
ProblemBlock,
SequenceBlock,
SplitTestBlock,
diff --git a/common/lib/xmodule/xmodule/template_module.py b/common/lib/xmodule/xmodule/template_module.py
index d53856a2a913..a94cf457fa29 100644
--- a/common/lib/xmodule/xmodule/template_module.py
+++ b/common/lib/xmodule/xmodule/template_module.py
@@ -5,11 +5,32 @@
from string import Template
from lxml import etree
-from xmodule.raw_module import RawDescriptor
-from xmodule.x_module import XModule # lint-amnesty, pylint: disable=unused-import
-
-
-class CustomTagModule(XModule):
+from pkg_resources import resource_string
+from web_fragments.fragment import Fragment
+from xmodule.editing_module import EditingMixin
+from xmodule.raw_module import RawMixin
+from xmodule.util.xmodule_django import add_webpack_to_fragment
+from xmodule.x_module import (
+ HTMLSnippet,
+ ResourceTemplates,
+ shim_xmodule_js,
+ XModuleMixin,
+ XModuleDescriptorToXBlockMixin,
+ XModuleToXBlockMixin,
+)
+from xmodule.xml_module import XmlMixin
+
+
+class CustomTagBlock(
+ RawMixin,
+ XmlMixin,
+ EditingMixin,
+ XModuleDescriptorToXBlockMixin,
+ XModuleToXBlockMixin,
+ HTMLSnippet,
+ ResourceTemplates,
+ XModuleMixin,
+): # pylint: disable=abstract-method
"""
This module supports tags of the form
@@ -31,17 +52,35 @@ class CustomTagModule(XModule):
Renders to::
More information given in the text
"""
-
- def get_html(self):
- return self.descriptor.rendered_html
-
-
-class CustomTagDescriptor(RawDescriptor):
- """ Descriptor for custom tags. Loads the template when created."""
- module_class = CustomTagModule
resources_dir = None
template_dir_name = 'customtag'
+ preview_view_js = {
+ 'js': [],
+ 'xmodule_js': resource_string(__name__, 'js/src/xmodule.js'),
+ }
+ preview_view_css = {
+ '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')],
+ }
+
+ 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, 'CustomTagBlockStudio')
+ shim_xmodule_js(fragment, 'XMLEditingDescriptor')
+ return fragment
+
def render_template(self, system, xml_data):
'''Render the template, given the definition xml_data'''
xmltree = etree.fromstring(xml_data)
@@ -71,6 +110,14 @@ def render_template(self, system, xml_data):
def rendered_html(self):
return self.render_template(self.system, self.data)
+ def student_view(self, _context):
+ """
+ Renders the student view.
+ """
+ fragment = Fragment()
+ fragment.add_content(self.rendered_html)
+ return fragment
+
def export_to_file(self):
"""
Custom tags are special: since they're already pointers, we don't want
diff --git a/common/lib/xmodule/xmodule/tests/__init__.py b/common/lib/xmodule/xmodule/tests/__init__.py
index d8c76e34bb81..f8b531aa52e8 100644
--- a/common/lib/xmodule/xmodule/tests/__init__.py
+++ b/common/lib/xmodule/xmodule/tests/__init__.py
@@ -191,29 +191,6 @@ def test_load_class(self):
assert str(vc) == vc_str
-class LogicTest(unittest.TestCase):
- """Base class for testing xmodule logic."""
- descriptor_class = None
- raw_field_data = {}
-
- def setUp(self):
- super(LogicTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
- self.system = get_test_system()
- self.descriptor = Mock(name="descriptor", url_name='', category='test')
-
- self.xmodule_class = self.descriptor_class.module_class
- usage_key = self.system.course_id.make_usage_key(self.descriptor.category, 'test_loc')
- # ScopeIds has 4 fields: user_id, block_type, def_id, usage_id
- scope_ids = ScopeIds(1, self.descriptor.category, usage_key, usage_key)
- self.xmodule = self.xmodule_class(
- self.descriptor, self.system, DictFieldData(self.raw_field_data), scope_ids
- )
-
- def ajax_request(self, dispatch, data):
- """Call Xmodule.handle_ajax."""
- return json.loads(self.xmodule.handle_ajax(dispatch, data))
-
-
def map_references(value, field, actual_course_key):
"""
Map the references in value to actual_course_key and return value
diff --git a/common/lib/xmodule/xmodule/tests/test_poll.py b/common/lib/xmodule/xmodule/tests/test_poll.py
index f2e46aa184f7..631e8335e41d 100644
--- a/common/lib/xmodule/xmodule/tests/test_poll.py
+++ b/common/lib/xmodule/xmodule/tests/test_poll.py
@@ -1,24 +1,42 @@
# -*- coding: utf-8 -*-
"""Test for Poll Xmodule functional logic."""
+import json
+import unittest
from mock import Mock
-from xmodule.poll_module import PollDescriptor
+from xblock.field_data import DictFieldData
+from xblock.fields import ScopeIds
+from xmodule.poll_module import PollBlock
-from . import LogicTest
+from . import get_test_system
from .test_import import DummySystem
-class PollModuleTest(LogicTest):
+class PollBlockTest(unittest.TestCase):
"""Logic tests for Poll Xmodule."""
- descriptor_class = PollDescriptor
+
raw_field_data = {
'poll_answers': {'Yes': 1, 'Dont_know': 0, 'No': 0},
'voted': False,
'poll_answer': ''
}
+ def setUp(self):
+ super().setUp()
+ self.system = get_test_system()
+ usage_key = self.system.course_id.make_usage_key(PollBlock.category, 'test_loc')
+ # ScopeIds has 4 fields: user_id, block_type, def_id, usage_id
+ scope_ids = ScopeIds(1, PollBlock.category, usage_key, usage_key)
+ self.xmodule = PollBlock(
+ self.system, DictFieldData(self.raw_field_data), scope_ids
+ )
+
+ def ajax_request(self, dispatch, data):
+ """Call Xmodule.handle_ajax."""
+ return json.loads(self.xmodule.handle_ajax(dispatch, data))
+
def test_bad_ajax_request(self):
# Make sure that answer for incorrect request is error json.
response = self.ajax_request('bad_answer', {})
@@ -52,7 +70,7 @@ def test_poll_export_with_unescaped_characters_xml(self):
'''
- output = PollDescriptor.from_xml(sample_poll_xml, module_system, id_generator)
+ output = PollBlock.from_xml(sample_poll_xml, module_system, id_generator)
# Update the answer with invalid character.
invalid_characters_poll_answer = output.answers[0]
# Invalid less-than character.
diff --git a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
index 685fe0becc03..c742448ffa1a 100644
--- a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
+++ b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
@@ -34,7 +34,7 @@
from xmodule.conditional_module import ConditionalBlock
from xmodule.course_module import CourseBlock
from xmodule.html_module import HtmlBlock
-from xmodule.poll_module import PollDescriptor
+from xmodule.poll_module import PollBlock
from xmodule.randomize_module import RandomizeBlock
from xmodule.seq_module import SequenceBlock
from xmodule.tests import get_test_descriptor_system, get_test_system
@@ -57,7 +57,7 @@
LEAF_XMODULES = {
AnnotatableBlock: [{}],
HtmlBlock: [{}],
- PollDescriptor: [{'display_name': 'Poll Display Name'}],
+ PollBlock: [{'display_name': 'Poll Display Name'}],
WordCloudBlock: [{}],
}
@@ -76,7 +76,7 @@
# These modules are not editable in studio yet
NOT_STUDIO_EDITABLE = (
- PollDescriptor,
+ PollBlock,
)