File size: 4,577 Bytes
d1ceb73 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
from ..core import BaseRenderer
from ..util import escape as escape_text, striptags, safe_entity
class HTMLRenderer(BaseRenderer):
"""A renderer for converting Markdown to HTML."""
NAME = 'html'
HARMFUL_PROTOCOLS = (
'javascript:',
'vbscript:',
'file:',
'data:',
)
GOOD_DATA_PROTOCOLS = (
'data:image/gif;',
'data:image/png;',
'data:image/jpeg;',
'data:image/webp;',
)
def __init__(self, escape=True, allow_harmful_protocols=None):
super(HTMLRenderer, self).__init__()
self._allow_harmful_protocols = allow_harmful_protocols
self._escape = escape
def render_token(self, token, state):
# backward compitable with v2
func = self._get_method(token['type'])
attrs = token.get('attrs')
if 'raw' in token:
text = token['raw']
elif 'children' in token:
text = self.render_tokens(token['children'], state)
else:
if attrs:
return func(**attrs)
else:
return func()
if attrs:
return func(text, **attrs)
else:
return func(text)
def safe_url(self, url: str) -> str:
"""Ensure the given URL is safe. This method is used for rendering
links, images, and etc.
"""
if self._allow_harmful_protocols is True:
return url
_url = url.lower()
if self._allow_harmful_protocols and \
_url.startswith(tuple(self._allow_harmful_protocols)):
return url
if _url.startswith(self.HARMFUL_PROTOCOLS) and \
not _url.startswith(self.GOOD_DATA_PROTOCOLS):
return '#harmful-link'
return url
def text(self, text: str) -> str:
if self._escape:
return escape_text(text)
return safe_entity(text)
def emphasis(self, text: str) -> str:
return '<em>' + text + '</em>'
def strong(self, text: str) -> str:
return '<strong>' + text + '</strong>'
def link(self, text: str, url: str, title=None) -> str:
s = '<a href="' + self.safe_url(url) + '"'
if title:
s += ' title="' + safe_entity(title) + '"'
return s + '>' + text + '</a>'
def image(self, text: str, url: str, title=None) -> str:
src = self.safe_url(url)
alt = escape_text(striptags(text))
s = '<img src="' + src + '" alt="' + alt + '"'
if title:
s += ' title="' + safe_entity(title) + '"'
return s + ' />'
def codespan(self, text: str) -> str:
return '<code>' + text + '</code>'
def linebreak(self) -> str:
return '<br />\n'
def softbreak(self) -> str:
return '\n'
def inline_html(self, html: str) -> str:
if self._escape:
return escape_text(html)
return html
def paragraph(self, text: str) -> str:
return '<p>' + text + '</p>\n'
def heading(self, text: str, level: int, **attrs) -> str:
tag = 'h' + str(level)
html = '<' + tag
_id = attrs.get('id')
if _id:
html += ' id="' + _id + '"'
return html + '>' + text + '</' + tag + '>\n'
def blank_line(self) -> str:
return ''
def thematic_break(self) -> str:
return '<hr />\n'
def block_text(self, text: str) -> str:
return text
def block_code(self, code: str, info=None) -> str:
html = '<pre><code'
if info is not None:
info = safe_entity(info.strip())
if info:
lang = info.split(None, 1)[0]
html += ' class="language-' + lang + '"'
return html + '>' + escape_text(code) + '</code></pre>\n'
def block_quote(self, text: str) -> str:
return '<blockquote>\n' + text + '</blockquote>\n'
def block_html(self, html: str) -> str:
if self._escape:
return '<p>' + escape_text(html.strip()) + '</p>\n'
return html + '\n'
def block_error(self, text: str) -> str:
return '<div class="error"><pre>' + text + '</pre></div>\n'
def list(self, text: str, ordered: bool, **attrs) -> str:
if ordered:
html = '<ol'
start = attrs.get('start')
if start is not None:
html += ' start="' + str(start) + '"'
return html + '>\n' + text + '</ol>\n'
return '<ul>\n' + text + '</ul>\n'
def list_item(self, text: str) -> str:
return '<li>' + text + '</li>\n'
|