| # markdown is released under the BSD license |
| # Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later) |
| # Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) |
| # Copyright 2004 Manfred Stienstra (the original version) |
| # |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are met: |
| # |
| # * Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # * Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # * Neither the name of the <organization> nor the |
| # names of its contributors may be used to endorse or promote products |
| # derived from this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY |
| # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| # DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT |
| # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| # POSSIBILITY OF SUCH DAMAGE. |
| |
| |
| """ |
| POST-PROCESSORS |
| ============================================================================= |
| |
| Markdown also allows post-processors, which are similar to preprocessors in |
| that they need to implement a "run" method. However, they are run after core |
| processing. |
| |
| """ |
| |
| from __future__ import absolute_import |
| from __future__ import unicode_literals |
| from . import util |
| from . import odict |
| import re |
| |
| |
| def build_postprocessors(md_instance, **kwargs): |
| """ Build the default postprocessors for Markdown. """ |
| postprocessors = odict.OrderedDict() |
| postprocessors["raw_html"] = RawHtmlPostprocessor(md_instance) |
| postprocessors["amp_substitute"] = AndSubstitutePostprocessor() |
| postprocessors["unescape"] = UnescapePostprocessor() |
| return postprocessors |
| |
| |
| class Postprocessor(util.Processor): |
| """ |
| Postprocessors are run after the ElementTree it converted back into text. |
| |
| Each Postprocessor implements a "run" method that takes a pointer to a |
| text string, modifies it as necessary and returns a text string. |
| |
| Postprocessors must extend markdown.Postprocessor. |
| |
| """ |
| |
| def run(self, text): |
| """ |
| Subclasses of Postprocessor should implement a `run` method, which |
| takes the html document as a single text string and returns a |
| (possibly modified) string. |
| |
| """ |
| pass |
| |
| |
| class RawHtmlPostprocessor(Postprocessor): |
| """ Restore raw html to the document. """ |
| |
| def run(self, text): |
| """ Iterate over html stash and restore "safe" html. """ |
| for i in range(self.markdown.htmlStash.html_counter): |
| html, safe = self.markdown.htmlStash.rawHtmlBlocks[i] |
| if self.markdown.safeMode and not safe: |
| if str(self.markdown.safeMode).lower() == 'escape': |
| html = self.escape(html) |
| elif str(self.markdown.safeMode).lower() == 'remove': |
| html = '' |
| else: |
| html = self.markdown.html_replacement_text |
| if self.isblocklevel(html) and (safe or not self.markdown.safeMode): |
| text = text.replace("<p>%s</p>" % |
| (self.markdown.htmlStash.get_placeholder(i)), |
| html + "\n") |
| text = text.replace(self.markdown.htmlStash.get_placeholder(i), |
| html) |
| return text |
| |
| def escape(self, html): |
| """ Basic html escaping """ |
| html = html.replace('&', '&') |
| html = html.replace('<', '<') |
| html = html.replace('>', '>') |
| return html.replace('"', '"') |
| |
| def isblocklevel(self, html): |
| m = re.match(r'^\<\/?([^ >]+)', html) |
| if m: |
| if m.group(1)[0] in ('!', '?', '@', '%'): |
| # Comment, php etc... |
| return True |
| return util.isBlockLevel(m.group(1)) |
| return False |
| |
| |
| class AndSubstitutePostprocessor(Postprocessor): |
| """ Restore valid entities """ |
| |
| def run(self, text): |
| text = text.replace(util.AMP_SUBSTITUTE, "&") |
| return text |
| |
| |
| class UnescapePostprocessor(Postprocessor): |
| """ Restore escaped chars """ |
| |
| RE = re.compile('%s(\d+)%s' % (util.STX, util.ETX)) |
| |
| def unescape(self, m): |
| return util.int2str(int(m.group(1))) |
| |
| def run(self, text): |
| return self.RE.sub(self.unescape, text) |