OLD | NEW |
(Empty) | |
| 1 """ |
| 2 POST-PROCESSORS |
| 3 ============================================================================= |
| 4 |
| 5 Markdown also allows post-processors, which are similar to preprocessors in |
| 6 that they need to implement a "run" method. However, they are run after core |
| 7 processing. |
| 8 |
| 9 """ |
| 10 |
| 11 from __future__ import absolute_import |
| 12 from __future__ import unicode_literals |
| 13 from . import util |
| 14 from . import odict |
| 15 import re |
| 16 |
| 17 |
| 18 def build_postprocessors(md_instance, **kwargs): |
| 19 """ Build the default postprocessors for Markdown. """ |
| 20 postprocessors = odict.OrderedDict() |
| 21 postprocessors["raw_html"] = RawHtmlPostprocessor(md_instance) |
| 22 postprocessors["amp_substitute"] = AndSubstitutePostprocessor() |
| 23 postprocessors["unescape"] = UnescapePostprocessor() |
| 24 return postprocessors |
| 25 |
| 26 |
| 27 class Postprocessor(util.Processor): |
| 28 """ |
| 29 Postprocessors are run after the ElementTree it converted back into text. |
| 30 |
| 31 Each Postprocessor implements a "run" method that takes a pointer to a |
| 32 text string, modifies it as necessary and returns a text string. |
| 33 |
| 34 Postprocessors must extend markdown.Postprocessor. |
| 35 |
| 36 """ |
| 37 |
| 38 def run(self, text): |
| 39 """ |
| 40 Subclasses of Postprocessor should implement a `run` method, which |
| 41 takes the html document as a single text string and returns a |
| 42 (possibly modified) string. |
| 43 |
| 44 """ |
| 45 pass # pragma: no cover |
| 46 |
| 47 |
| 48 class RawHtmlPostprocessor(Postprocessor): |
| 49 """ Restore raw html to the document. """ |
| 50 |
| 51 def run(self, text): |
| 52 """ Iterate over html stash and restore "safe" html. """ |
| 53 for i in range(self.markdown.htmlStash.html_counter): |
| 54 html, safe = self.markdown.htmlStash.rawHtmlBlocks[i] |
| 55 if self.markdown.safeMode and not safe: |
| 56 if str(self.markdown.safeMode).lower() == 'escape': |
| 57 html = self.escape(html) |
| 58 elif str(self.markdown.safeMode).lower() == 'remove': |
| 59 html = '' |
| 60 else: |
| 61 html = self.markdown.html_replacement_text |
| 62 if (self.isblocklevel(html) and |
| 63 (safe or not self.markdown.safeMode)): |
| 64 text = text.replace( |
| 65 "<p>%s</p>" % |
| 66 (self.markdown.htmlStash.get_placeholder(i)), |
| 67 html + "\n" |
| 68 ) |
| 69 text = text.replace( |
| 70 self.markdown.htmlStash.get_placeholder(i), html |
| 71 ) |
| 72 return text |
| 73 |
| 74 def escape(self, html): |
| 75 """ Basic html escaping """ |
| 76 html = html.replace('&', '&') |
| 77 html = html.replace('<', '<') |
| 78 html = html.replace('>', '>') |
| 79 return html.replace('"', '"') |
| 80 |
| 81 def isblocklevel(self, html): |
| 82 m = re.match(r'^\<\/?([^ >]+)', html) |
| 83 if m: |
| 84 if m.group(1)[0] in ('!', '?', '@', '%'): |
| 85 # Comment, php etc... |
| 86 return True |
| 87 return util.isBlockLevel(m.group(1)) |
| 88 return False |
| 89 |
| 90 |
| 91 class AndSubstitutePostprocessor(Postprocessor): |
| 92 """ Restore valid entities """ |
| 93 |
| 94 def run(self, text): |
| 95 text = text.replace(util.AMP_SUBSTITUTE, "&") |
| 96 return text |
| 97 |
| 98 |
| 99 class UnescapePostprocessor(Postprocessor): |
| 100 """ Restore escaped chars """ |
| 101 |
| 102 RE = re.compile('%s(\d+)%s' % (util.STX, util.ETX)) |
| 103 |
| 104 def unescape(self, m): |
| 105 return util.int2str(int(m.group(1))) |
| 106 |
| 107 def run(self, text): |
| 108 return self.RE.sub(self.unescape, text) |
OLD | NEW |