pelican_mathjax_markdown_extension.py 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. # -*- coding: utf-8 -*-
  2. """
  3. Pelican Mathjax Markdown Extension
  4. ==================================
  5. An extension for the Python Markdown module that enables
  6. the Pelican python blog to process mathjax. This extension
  7. gives Pelican the ability to use Mathjax as a "first class
  8. citizen" of the blog
  9. """
  10. import markdown
  11. from markdown.util import etree
  12. from markdown.util import AtomicString
  13. class PelicanMathJaxPattern(markdown.inlinepatterns.Pattern):
  14. """Pattern for matching mathjax"""
  15. def __init__(self, pelican_mathjax_extension, tag, pattern):
  16. super(PelicanMathJaxPattern,self).__init__(pattern)
  17. self.math_tag_class = pelican_mathjax_extension.getConfig('math_tag_class')
  18. self.pelican_mathjax_extension = pelican_mathjax_extension
  19. self.tag = tag
  20. def handleMatch(self, m):
  21. node = markdown.util.etree.Element(self.tag)
  22. node.set('class', self.math_tag_class)
  23. prefix = '\\(' if m.group('prefix') == '$' else m.group('prefix')
  24. suffix = '\\)' if m.group('suffix') == '$' else m.group('suffix')
  25. node.text = markdown.util.AtomicString(prefix + m.group('math') + suffix)
  26. # If mathjax was successfully matched, then JavaScript needs to be added
  27. # for rendering. The boolean below indicates this
  28. self.pelican_mathjax_extension.mathjax_needed = True
  29. return node
  30. class PelicanMathJaxTreeProcessor(markdown.treeprocessors.Treeprocessor):
  31. """Tree Processor for adding Mathjax JavaScript to the blog"""
  32. def __init__(self, pelican_mathjax_extension):
  33. self.pelican_mathjax_extension = pelican_mathjax_extension
  34. def run(self, root):
  35. # If no mathjax was present, then exit
  36. if (not self.pelican_mathjax_extension.mathjax_needed):
  37. return
  38. # Add the mathjax script to the html document
  39. mathjax_script = etree.Element('script')
  40. mathjax_script.set('type','text/javascript')
  41. mathjax_script.text = AtomicString(self.pelican_mathjax_extension.getConfig('mathjax_script'))
  42. root.append(mathjax_script)
  43. # Reset the boolean switch to false so that script is only added
  44. # to other pages if needed
  45. self.pelican_mathjax_extension.mathjax_needed = False
  46. class PelicanMathJaxExtension(markdown.Extension):
  47. """A markdown extension enabling mathjax processing in Markdown for Pelican"""
  48. def __init__(self, config):
  49. super(PelicanMathJaxExtension,self).__init__(config)
  50. # Regex to detect mathjax
  51. self.mathjax_inline_regex = r'(?P<prefix>\$)(?P<math>.+?)(?P<suffix>(?<!\s)\2)'
  52. self.mathjax_display_regex = r'(?P<prefix>(?:\$\$)|\\begin\{(.+?)\})(?P<math>.+?)(?P<suffix>\2|\\end\{\3\})'
  53. self.mathjax_needed = False
  54. def extendMarkdown(self, md, md_globals):
  55. # Process mathjax before escapes are processed since escape processing will
  56. # intefer with mathjax. The order in which the displayed and inlined math
  57. # is registered below matters
  58. md.inlinePatterns.add('mathjax_displayed', PelicanMathJaxPattern(self, 'div', self.mathjax_display_regex), '<escape')
  59. md.inlinePatterns.add('mathjax_inlined', PelicanMathJaxPattern(self, 'span', self.mathjax_inline_regex), '<escape')
  60. # If necessary, add the JavaScript Mathjax library to the document. This must
  61. # be last in the ordered dict (hence it is given the position '_end')
  62. md.treeprocessors.add('mathjax', PelicanMathJaxTreeProcessor(self), '_end')