|  | 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)
 |