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 |