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 '' + text + ''
def strong(self, text: str) -> str:
return '' + text + ''
def link(self, text: str, url: str, title=None) -> str:
s = '' + text + ''
def image(self, text: str, url: str, title=None) -> str:
src = self.safe_url(url)
alt = escape_text(striptags(text))
s = ''
def codespan(self, text: str) -> str:
return '' + text + '
'
def linebreak(self) -> str:
return '
\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 '
' + text + '
\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 '' + escape_text(code) + '
\n'
def block_quote(self, text: str) -> str:
return '\n' + text + '\n' def block_html(self, html: str) -> str: if self._escape: return '
' + escape_text(html) + '
\n' return html + '\n' def block_error(self, text: str) -> str: return '' + text + '