|
- from jinja2 import contextfilter, environmentfilter
- from jinja2.ext import Extension
-
- from io import StringIO
- from lxml import etree
-
- @contextfilter
- def rellinktoabs(context, value):
- env = context.environment
-
- # get the path for this context
- rel_path = context['resource'].relative_path
- content_url = env.globals['content_url'](context, rel_path)
-
- # Note that this could be parsed w/ fragment_fromstring
- # (https://lxml.de/3.1/api/private/lxml.html-module.html#fragment_fromstring)
- # But is would require using create_parent, and stripping that
- # instead, or fragments_fromstring, but iterating over those
- # to strings. Not one is a solution to the problem.
- html = etree.HTML(value)
-
- # get all the fragment urls
- r = html.xpath("//a[@href[starts-with(.,'#')]]")
-
- for i in r:
- # prefix them w/ the content_url
- i.attrib['href'] = content_url + i.attrib['href']
-
- res = etree.tostring(html, encoding='unicode', method='html')
-
- # lxml.HTML wraps the html w/ html/body tags, strip them
- # if present
-
- startstr = '<html><body>'
- endstr = '</body></html>'
-
- startpos = 0
- endpos = None
- if res.startswith(startstr):
- startpos = len(startstr)
- if res.endswith(endstr):
- endpos = -len(endstr)
-
- res = res[startpos:endpos]
-
- return res
-
- # mostly copied from hyde.ext.templates.jinja.py Markdown
- # and using docs from:
- # https://jinja.palletsprojects.com/en/2.10.x/extensions/#example-extension
- # to get the filter installed
-
- class RelLinktoAbs(Extension):
- """
- A wrapper around the rellinktoabs filter for syntactic sugar.
- """
- tags = { 'rellinktoabs' }
-
- def __init__(self, env):
- super(RelLinktoAbs, self).__init__(env)
-
- env.filters['rellinktoabs'] = rellinktoabs
-
- def parse(self, parser):
- """
- Parses the statements and defers to the callback
- for rellinktoabs processing.
- """
-
- lineno = next(parser.stream).lineno
- body = parser.parse_statements(['name:endrellinktoabs'], drop_needle=True)
-
- return nodes.CallBlock(
- self.call_method('_render_rellinktoabs'),
- [], [], body).set_lineno(lineno)
-
- def _render_rellinktoabs(self, caller=None):
- """
- Calls the rellinktoabs filter to transform the output.
- """
- if not caller:
- return ''
- output = caller().strip()
- return rellinktoabs(self.environment, output)
|