The Webpack configuration file for built-in XBlock JS used to be generated at build time and git-ignored. It lived at common/static/xmodule/webpack.xmodule.config.js. It was generated because the JS that it referred to was also generated at build-time, and the filenames of those JS modules were not static. Now that its contents have been made entirely static [1], there is no reason we need to continue generating this Webpack configuration file. So, we check it into edx-platform under the name ./webpack.builtinblocks.config.js. We choose to put it in the repo's root directory because the paths contained in the config file are relative to the repo's root. This allows us to behead both the xmodule/static_content.py (`xmodule_assets`) script andthe `process_xmodule_assets` paver task, a major step in removing the need for Python in the edx-platform asset build [2]. It also allows us to delete the `HTMLSnippet` class and all associated attributes, which were exclusively used by xmodule/static_content.py.. We leave `xmodule_assets` and `process_xmodule_assets` in as stubs for now in order to avoid breaking external code (like Tutor) which calls Paver; the entire pavelib/assets.py function will be eventually removed soon anyway [3]. Further, to avoid extraneous refactoring, we keep one method of `HTMLSnippet` around on a few of its former subclasses: `get_html`. This method was originally part of the XModule framework; now, it is left over on a few classes as a simple internal helper method. References: 1. https://github.com/openedx/edx-platform/pull/32480 2. https://github.com/openedx/edx-platform/issues/31800 3. https://github.com/openedx/edx-platform/issues/31895 Part of: https://github.com/openedx/edx-platform/issues/32481
148 lines
4.6 KiB
Python
148 lines
4.6 KiB
Python
"""
|
|
Template block
|
|
"""
|
|
|
|
from string import Template
|
|
from xblock.core import XBlock
|
|
|
|
from lxml import etree
|
|
from web_fragments.fragment import Fragment
|
|
from xmodule.editing_block import EditingMixin
|
|
from xmodule.raw_block import RawMixin
|
|
from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_sass_to_fragment
|
|
from xmodule.x_module import (
|
|
ResourceTemplates,
|
|
shim_xmodule_js,
|
|
XModuleMixin,
|
|
XModuleToXBlockMixin,
|
|
)
|
|
from xmodule.xml_block import XmlMixin
|
|
|
|
from openedx.core.djangolib.markup import Text
|
|
|
|
|
|
class CustomTagTemplateBlock( # pylint: disable=abstract-method
|
|
RawMixin,
|
|
XmlMixin,
|
|
EditingMixin,
|
|
XModuleToXBlockMixin,
|
|
ResourceTemplates,
|
|
XModuleMixin,
|
|
):
|
|
"""
|
|
A block which provides templates for CustomTagBlock. The template name
|
|
is set on the `impl` attribute of CustomTagBlock. See below for more details
|
|
on how to use it.
|
|
"""
|
|
|
|
|
|
@XBlock.needs('mako')
|
|
class CustomTagBlock(CustomTagTemplateBlock): # pylint: disable=abstract-method
|
|
"""
|
|
This block supports tags of the form
|
|
<customtag option="val" option2="val2" impl="tagname"/>
|
|
|
|
In this case, $tagname should refer to a file in data/custom_tags, which
|
|
contains a Python string.Template formatted template that uses ${option} and
|
|
${option2} for the content.
|
|
|
|
For instance:
|
|
|
|
data/mycourse/custom_tags/book::
|
|
More information given in <a href="/book/${page}">the text</a>
|
|
|
|
course.xml::
|
|
...
|
|
<customtag page="234" impl="book"/>
|
|
...
|
|
|
|
Renders to::
|
|
More information given in <a href="/book/234">the text</a>
|
|
"""
|
|
resources_dir = None
|
|
template_dir_name = 'customtag'
|
|
|
|
def studio_view(self, _context):
|
|
"""
|
|
Return the studio view.
|
|
"""
|
|
fragment = Fragment(
|
|
self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
|
|
)
|
|
add_sass_to_fragment(fragment, 'CustomTagBlockEditor.scss')
|
|
add_webpack_js_to_fragment(fragment, 'CustomTagBlockEditor')
|
|
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)
|
|
if 'impl' in xmltree.attrib:
|
|
template_name = xmltree.attrib['impl']
|
|
else:
|
|
# VS[compat] backwards compatibility with old nested customtag structure
|
|
child_impl = xmltree.find('impl')
|
|
if child_impl is not None:
|
|
template_name = child_impl.text
|
|
else:
|
|
# TODO (vshnayder): better exception type
|
|
raise Exception("Could not find impl attribute in customtag {}"
|
|
.format(self.location))
|
|
|
|
params = dict(list(xmltree.items()))
|
|
|
|
# cdodge: look up the template as a module
|
|
template_loc = self.location.replace(category='custom_tag_template', name=template_name)
|
|
|
|
template_block = system.get_block(template_loc)
|
|
template_block_data = template_block.data
|
|
template = Template(template_block_data)
|
|
return template.safe_substitute(params)
|
|
|
|
@property
|
|
def rendered_html(self):
|
|
return self.render_template(self.runtime, 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
|
|
to export them in a file with yet another layer of indirection.
|
|
"""
|
|
return False
|
|
|
|
|
|
class TranslateCustomTagBlock( # pylint: disable=abstract-method
|
|
XModuleToXBlockMixin,
|
|
XModuleMixin,
|
|
):
|
|
"""
|
|
Converts olx of the form `<$custom_tag attr="" attr=""/>` to CustomTagBlock
|
|
of the form `<customtag attr="" attr="" impl="$custom_tag"/>`.
|
|
"""
|
|
resources_dir = None
|
|
|
|
@classmethod
|
|
def parse_xml(cls, node, runtime, _keys, _id_generator):
|
|
"""
|
|
Transforms the xml_data from <$custom_tag attr="" attr=""/> to
|
|
<customtag attr="" attr="" impl="$custom_tag"/>
|
|
"""
|
|
|
|
runtime.error_tracker(Text('WARNING: the <{tag}> tag is deprecated. '
|
|
'Instead, use <customtag impl="{tag}" attr1="..." attr2="..."/>. ')
|
|
.format(tag=node.tag))
|
|
|
|
tag = node.tag
|
|
node.tag = 'customtag'
|
|
node.attrib['impl'] = tag
|
|
|
|
return runtime.process_xml(etree.tostring(node))
|