"""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, '' % 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('
') n = self._get_prompt_number(cell) lines.append( '
In [%s]:
' % n ) lines.append('
') lines.append(highlight(cell.input) if self.highlight_source else cell.input) lines.append('
') # input_area 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]