pelican_mathjax_markdown_extension.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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 root
  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. return root
  47. class PelicanMathJaxExtension(markdown.Extension):
  48. """A markdown extension enabling mathjax processing in Markdown for Pelican"""
  49. def __init__(self, config):
  50. try:
  51. # Needed for markdown versions >= 2.5
  52. self.config['mathjax_script'] = ['', 'Mathjax JavaScript script']
  53. self.config['math_tag_class'] = ['math', 'The class of the tag in which mathematics is wrapped']
  54. super(PelicanMathJaxExtension,self).__init__(**config)
  55. except AttributeError:
  56. # Markdown versions < 2.5
  57. config['mathjax_script'] = [config['mathjax_script'], 'Mathjax JavaScript script']
  58. config['math_tag_class'] = [config['math_tag_class'], 'The class of the tag in which mathematic is wrapped']
  59. super(PelicanMathJaxExtension,self).__init__(config)
  60. # Used as a flag to determine if javascript
  61. # needs to be injected into a document
  62. self.mathjax_needed = False
  63. def extendMarkdown(self, md, md_globals):
  64. # Regex to detect mathjax
  65. mathjax_inline_regex = r'(?P<prefix>\$)(?P<math>.+?)(?P<suffix>(?<!\s)\2)'
  66. mathjax_display_regex = r'(?P<prefix>\$\$|\\begin\{(.+?)\})(?P<math>.+?)(?P<suffix>\2|\\end\{\3\})'
  67. # Process mathjax before escapes are processed since escape processing will
  68. # intefer with mathjax. The order in which the displayed and inlined math
  69. # is registered below matters
  70. md.inlinePatterns.add('mathjax_displayed', PelicanMathJaxPattern(self, 'div', mathjax_display_regex), '<escape')
  71. md.inlinePatterns.add('mathjax_inlined', PelicanMathJaxPattern(self, 'span', mathjax_inline_regex), '<escape')
  72. # If necessary, add the JavaScript Mathjax library to the document. This must
  73. # be last in the ordered dict (hence it is given the position '_end')
  74. md.treeprocessors.add('mathjax', PelicanMathJaxTreeProcessor(self), '_end')