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
import util
12
import odict
13
14
def build_postprocessors(md_instance, **kwargs):
15
    """ Build the default postprocessors for Markdown. """
16
    postprocessors = odict.OrderedDict()
17
    postprocessors["raw_html"] = RawHtmlPostprocessor(md_instance)
18
    postprocessors["amp_substitute"] = AndSubstitutePostprocessor()
19
    return postprocessors
20
21
22
class Postprocessor(util.Processor):
23
    """
24
    Postprocessors are run after the ElementTree it converted back into text.
25
26
    Each Postprocessor implements a "run" method that takes a pointer to a
27
    text string, modifies it as necessary and returns a text string.
28
29
    Postprocessors must extend markdown.Postprocessor.
30
31
    """
32
33
    def run(self, text):
34
        """
35
        Subclasses of Postprocessor should implement a `run` method, which
36
        takes the html document as a single text string and returns a
37
        (possibly modified) string.
38
39
        """
40
        pass
41
42
43
class RawHtmlPostprocessor(Postprocessor):
44
    """ Restore raw html to the document. """
45
46
    def run(self, text):
47
        """ Iterate over html stash and restore "safe" html. """
48
        for i in range(self.markdown.htmlStash.html_counter):
49
            html, safe  = self.markdown.htmlStash.rawHtmlBlocks[i]
50
            html = self.unescape(html)
51
            if self.markdown.safeMode and not safe:
52
                if str(self.markdown.safeMode).lower() == 'escape':
53
                    html = self.escape(html)
54
                elif str(self.markdown.safeMode).lower() == 'remove':
55
                    html = ''
56
                else:
57
                    html = self.markdown.html_replacement_text
58
            if safe or not self.markdown.safeMode:
59
                text = text.replace("<p>%s</p>" % 
60
                            (self.markdown.htmlStash.get_placeholder(i)),
61
                            html + "\n")
62
            text =  text.replace(self.markdown.htmlStash.get_placeholder(i), 
63
                                 html)
64
        return text
65
66
    def unescape(self, html):
67
        """ Unescape any markdown escaped text within inline html. """
68
        for k, v in self.markdown.treeprocessors['inline'].stashed_nodes.items():
69
            ph = util.INLINE_PLACEHOLDER % k
70
            html = html.replace(ph, '\%s' % v)
71
        return html
72
73
    def escape(self, html):
74
        """ Basic html escaping """
75
        html = html.replace('&', '&amp;')
76
        html = html.replace('<', '&lt;')
77
        html = html.replace('>', '&gt;')
78
        return html.replace('"', '&quot;')
79
80
81
class AndSubstitutePostprocessor(Postprocessor):
82
    """ Restore valid entities """
83
    def __init__(self):
84
        pass
85
86
    def run(self, text):
87
        text =  text.replace(util.AMP_SUBSTITUTE, "&")
88
        return text