"""Implements conversion to ordinary HTML output.
This file implements a class that handles rendering IPython notebooks as
HTML, suitable for posting to the web.
Converters for more specific HTML generation needs (suitable for posting to
a particular web service) can usefully subclass `ConverterHTML` and override
certain methods. For output tuned to the Blogger blogging platform, see the
`ConverterBloggerHTML` class.
"""
#-----------------------------------------------------------------------------
# Copyright (c) 2012, the IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
from __future__ import absolute_import
# Stdlib imports
import io
import os
# Third-party imports
from markdown import markdown
# IPython imports
from IPython.utils import path
# Our own imports
from .base import Converter
from .utils import text_cell, output_container
from .utils import highlight, coalesce_streams, ansi2html
#-----------------------------------------------------------------------------
# Class declarations
#-----------------------------------------------------------------------------
class ConverterHTML(Converter):
#-------------------------------------------------------------------------
# Class-level attributes determining the behaviour of the class but
# probably not varying from instance to instance.
#-------------------------------------------------------------------------
extension = 'html'
blank_symbol = ' '
def in_tag(self, tag, src, attrs=None):
"""Return a list of elements bracketed by the given tag"""
attr_s = '' if attrs is None else \
' '.join("%s=%s" % (attr, value)
for attr, value in attrs.iteritems())
return ['<%s %s>' % (tag, attr_s), src, '%s>' % tag]
def _ansi_colored(self, text):
return ['
%s
' % ansi2html(text)]
def _stylesheet(self, fname):
with io.open(fname, encoding='utf-8') as f:
s = f.read()
return self.in_tag('style', s, dict(type='"text/css"'))
def _out_prompt(self, output):
if output.output_type == 'pyout':
content = 'Out[%s]:' % self._get_prompt_number(output)
else:
content = ''
return ['%s
' % content]
def header_body(self):
"""Return the body of the header as a list of strings."""
from pygments.formatters import HtmlFormatter
header = []
static = os.path.join(path.get_ipython_package_dir(),
'frontend', 'html', 'notebook', 'static',
)
here = os.path.split(os.path.realpath(__file__))[0]
css = os.path.join(static, 'css')
for sheet in [
# do we need jquery and prettify?
# os.path.join(static, 'jquery', 'css', 'themes', 'base',
# 'jquery-ui.min.css'),
# os.path.join(static, 'prettify', 'prettify.css'),
os.path.join(css, 'boilerplate.css'),
os.path.join(css, 'style.min.css'),
# our overrides:
os.path.join(here, '..', 'css', 'static_html.css'),
]:
header.extend(self._stylesheet(sheet))
# pygments css
pygments_css = HtmlFormatter().get_style_defs('.highlight')
header.extend([''])
header.extend(self.in_tag('style', pygments_css,
dict(type='"text/css"')))
# TODO: this should be allowed to use local mathjax:
header.extend(self.in_tag('script', '', {'type': '"text/javascript"',
'src': '"https://c328740.ssl.cf1.rackcdn.com/mathjax/'
'latest/MathJax.js?config=TeX-AMS_HTML"',
}))
with io.open(os.path.join(here, '..', 'js', 'initmathjax.js'),
encoding='utf-8') as f:
header.extend(self.in_tag('script', f.read(),
{'type': '"text/javascript"'}))
return header
def optional_header(self):
return ['', ''] + self.header_body() + \
['', '']
def optional_footer(self):
return ['', '']
@text_cell
def render_heading(self, cell):
marker = cell.level
return [u'\n {0}\n'.format(cell.source, marker)]
def render_code(self, cell):
if not cell.input:
return []
lines = ['']
lines.append('
') # input
if cell.outputs:
lines.append('
')
lines.append('
')
for output in coalesce_streams(cell.outputs):
conv_fn = self.dispatch(output.output_type)
lines.extend(conv_fn(output))
lines.append('
') # output
lines.append('
') # output_wrapper
lines.append('
') # cell
return lines
@text_cell
def render_markdown(self, cell):
return [markdown(cell.source)]
def render_raw(self, cell):
if self.raw_as_verbatim:
return self.in_tag('pre', cell.source)
else:
return [cell.source]
@output_container
def render_pyout(self, output):
for fmt in ['html', 'latex', 'png', 'jpeg', 'svg', 'text']:
if fmt in output:
conv_fn = self.dispatch_display_format(fmt)
return conv_fn(output)
return []
render_display_data = render_pyout
@output_container
def render_stream(self, output):
return self._ansi_colored(output.text)
@output_container
def render_pyerr(self, output):
# Note: a traceback is a *list* of frames.
# lines = []
# stb =
return self._ansi_colored('\n'.join(output.traceback))
def _img_lines(self, img_file):
return ['' % img_file, '']
def _unknown_lines(self, data):
return ['Warning:: Unknown cell
'] + self.in_tag('pre', data)
def render_display_format_png(self, output):
return ['' % output.png]
def render_display_format_svg(self, output):
return [output.svg]
def render_display_format_jpeg(self, output):
return ['' % output.jpeg]
def render_display_format_text(self, output):
return self._ansi_colored(output.text)
def render_display_format_html(self, output):
return [output.html]
def render_display_format_latex(self, output):
return [output.latex]
def render_display_format_json(self, output):
# html ignores json
return []
def render_display_format_javascript(self, output):
return [output.javascript]