Files
edx-platform/xmodule/template_block.py
Kyle McCormick 0b455e0336 build: commit XModule SCSS entrypoints of generating them (#32290)
`xmodule_assets` generated a series of SCSS "entrypoint"
files, where each entrypoint file imported from the
SCSS "sources" in xmodule/css.

This process was more complicated up until very
recently (see PRs in issue linked below for more
context). Now that the process is simpler, though,
there is no reason to generate the SCSS entrypoints;
we can just commit them to the repository instead!
So, we go from this:

    # GENERATED: SCSS entrypoints files for CMS
    common/static/xmodule/descriptors:
       AboutBlockStudio.scss
       AnnotatableBlockStudio.scss
       ...
    # GENERATED: SCSS entrypoints files for LMS
    common/static/xmodule/modules:
       AboutBlockPreview.scss
       AnnotatableBlockPreview.scss
       ...
    # VERSION CONTROLLED: SCSS source files
    xmodule/css:
      annotatable/...
      capa/...
      ...

to this:

    # VERSION CONTROLLED: All XModule SCSS
    xmodule/static/sass:
      # Source files
      include:
        annotatable/...
        capa/...
        ...
      # CMS entrypoint files
      cms:
        AboutBlockStudio.scss
        AnnotatableBlockStudio.scss
        ...
      # LMS source files
      lms:
        AboutBlockPreview.scss
        AnnotatableBlockPreview.scss
        ...

Also, we are able to remove all SCSS-related logic from the
`xmodule_assets` script and from the `HTMLSnippet` class.
XModule JS assets still need processing, but we will address
those in a separate series of PRs.

Part of: https://github.com/openedx/edx-platform/issues/32292
2023-06-16 08:51:03 -04:00

159 lines
4.8 KiB
Python

"""
Template block
"""
from string import Template
from xblock.core import XBlock
from lxml import etree
from pkg_resources import resource_filename
from web_fragments.fragment import Fragment
from xmodule.editing_block import EditingMixin
from xmodule.raw_block import RawMixin
from xmodule.util.xmodule_django import add_webpack_to_fragment
from xmodule.x_module import (
HTMLSnippet,
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,
HTMLSnippet,
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'
preview_view_js = {
'js': [],
'xmodule_js': resource_filename(__name__, 'js/src/xmodule.js'),
}
studio_view_js = {
'js': [resource_filename(__name__, 'js/src/raw/edit/xml.js')],
'xmodule_js': resource_filename(__name__, 'js/src/xmodule.js'),
}
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_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)
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))