chiark / gitweb /
m.math: unique names for SVG paths and pages.
authorVladimír Vondruš <mosra@centrum.cz>
Wed, 1 Nov 2017 12:34:32 +0000 (13:34 +0100)
committerVladimír Vondruš <mosra@centrum.cz>
Wed, 1 Nov 2017 23:02:12 +0000 (00:02 +0100)
Makes the markup valid HTML5 and avoids strange issues with missing /
wrong paths due to conflicting IDs.

pelican-plugins/m/math.py

index 9ccae45ad4b187b492e2afeda16792b35f341e65..8ece82ee7df84e5e6741e3e49b67efcb0287bf95 100644 (file)
@@ -29,6 +29,8 @@ from docutils.parsers import rst
 from docutils.parsers.rst import directives
 from docutils.parsers.rst.roles import set_classes
 
+import pelican.signals
+
 from . import latex2svg
 
 latex2svg_params = latex2svg.default_params.copy()
@@ -45,18 +47,28 @@ latex2svg_params.update({
     'dvisvgm_cmd': 'dvisvgm --no-fonts -Z 1.25',
     })
 
-uncrap_src = re.compile(r"""<\?xml version='1.0' encoding='UTF-8'\?>
+patch_src = re.compile(r"""<\?xml version='1.0' encoding='UTF-8'\?>
 <!-- This file was generated by dvisvgm \d+\.\d+\.\d+ -->
 <svg (?P<attribs>.+) xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>
 """)
 
-uncrap_dst = r"""<svg{attribs} \g<attribs>>
+patch_dst = r"""<svg{attribs} \g<attribs>>
 <title>LaTeX Math</title>
 <description>
 {formula}
 </description>
 """
 
+unique_src = re.compile(r"""(?P<name> id|xlink:href)='(?P<ref>#?)(?P<id>g\d+-\d+|page\d+)'""")
+unique_dst = r"""\g<name>='\g<ref>eq{counter}-\g<id>'"""
+
+counter = 0
+
+def _patch(formula, out, attribs):
+    global counter
+    counter += 1
+    return unique_src.sub(unique_dst.format(counter=counter), patch_src.sub(patch_dst.format(attribs=attribs, formula=formula.replace('\\', '\\\\')), out['svg']))
+
 class Math(rst.Directive):
     option_spec = {'class': directives.class_option,
                    'name': directives.unchanged}
@@ -72,17 +84,21 @@ class Math(rst.Directive):
             if not block:
                 continue
 
+            out = latex2svg.latex2svg("$$" + block + "$$", params=latex2svg_params)
+
             container = nodes.container(**self.options)
             container['classes'] += ['m-math']
-            node = nodes.raw(self.block_text, uncrap_src.sub(
-                uncrap_dst.format(attribs='', formula=block.replace('\\', '\\\\')),
-                latex2svg.latex2svg("$$" + block + "$$", params=latex2svg_params)['svg']), format='html')
+            node = nodes.raw(self.block_text, _patch(block, out, ''), format='html')
             node.line = self.content_offset + 1
             self.add_name(node)
             container.append(node)
             _nodes.append(container)
         return _nodes
 
+def new_page(content):
+    global counter
+    counter = 0
+
 def math(role, rawtext, text, lineno, inliner, options={}, content=[]):
     # Otherwise the backslashes do quite a mess there
     i = rawtext.find('`')
@@ -95,18 +111,17 @@ def math(role, rawtext, text, lineno, inliner, options={}, content=[]):
         classes += ' ' + ' '.join(options['classes'])
         del options['classes']
 
-    out = latex2svg.latex2svg("$" + text + "$", params=latex2svg_params);
+    out = latex2svg.latex2svg("$" + text + "$", params=latex2svg_params)
 
     # CSS classes and styling for proper vertical alignment. Depth is relative
     # to font size, describes how below the line the text is. Scaling it back
     # to 12pt font, scaled by 125% as set above in the config.
     attribs = ' class="{}" style="vertical-align: -{:.1f}pt;"'.format(classes, out['depth']*12*1.25)
 
-    node = nodes.raw(rawtext, uncrap_src.sub(
-        uncrap_dst.format(attribs=attribs, formula=text.replace('\\', '\\\\')),
-        out['svg']), format='html', **options)
+    node = nodes.raw(rawtext, _patch(text, out, attribs), format='html', **options)
     return [node], []
 
 def register():
+    pelican.signals.content_object_init.connect(new_page)
     rst.directives.register_directive('math', Math)
     rst.roles.register_canonical_role('math', math)