##// END OF EJS Templates
use new css with old nbconvert html
Matthias BUSSONNIER -
Show More
@@ -1,218 +1,216 b''
1 """Implements conversion to ordinary HTML output.
1 """Implements conversion to ordinary HTML output.
2
2
3 This file implements a class that handles rendering IPython notebooks as
3 This file implements a class that handles rendering IPython notebooks as
4 HTML, suitable for posting to the web.
4 HTML, suitable for posting to the web.
5
5
6 Converters for more specific HTML generation needs (suitable for posting to
6 Converters for more specific HTML generation needs (suitable for posting to
7 a particular web service) can usefully subclass `ConverterHTML` and override
7 a particular web service) can usefully subclass `ConverterHTML` and override
8 certain methods. For output tuned to the Blogger blogging platform, see the
8 certain methods. For output tuned to the Blogger blogging platform, see the
9 `ConverterBloggerHTML` class.
9 `ConverterBloggerHTML` class.
10 """
10 """
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (c) 2012, the IPython Development Team.
12 # Copyright (c) 2012, the IPython Development Team.
13 #
13 #
14 # Distributed under the terms of the Modified BSD License.
14 # Distributed under the terms of the Modified BSD License.
15 #
15 #
16 # The full license is in the file COPYING.txt, distributed with this software.
16 # The full license is in the file COPYING.txt, distributed with this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from __future__ import absolute_import
19 from __future__ import absolute_import
20
20
21 # Stdlib imports
21 # Stdlib imports
22 import io
22 import io
23 import os
23 import os
24
24
25 # Third-party imports
25 # Third-party imports
26 from markdown import markdown
26 from markdown import markdown
27
27
28 # IPython imports
28 # IPython imports
29 from IPython.utils import path
29 from IPython.utils import path
30
30
31 # Our own imports
31 # Our own imports
32 from .base import Converter
32 from .base import Converter
33 from .utils import text_cell, output_container
33 from .utils import text_cell, output_container
34 from .utils import highlight, coalesce_streams, ansi2html
34 from .utils import highlight, coalesce_streams, ansi2html
35
35
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Class declarations
38 # Class declarations
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40
40
41 class ConverterHTML(Converter):
41 class ConverterHTML(Converter):
42 #-------------------------------------------------------------------------
42 #-------------------------------------------------------------------------
43 # Class-level attributes determining the behaviour of the class but
43 # Class-level attributes determining the behaviour of the class but
44 # probably not varying from instance to instance.
44 # probably not varying from instance to instance.
45 #-------------------------------------------------------------------------
45 #-------------------------------------------------------------------------
46 extension = 'html'
46 extension = 'html'
47 blank_symbol = ' '
47 blank_symbol = ' '
48
48
49 def in_tag(self, tag, src, attrs=None):
49 def in_tag(self, tag, src, attrs=None):
50 """Return a list of elements bracketed by the given tag"""
50 """Return a list of elements bracketed by the given tag"""
51 attr_s = '' if attrs is None else \
51 attr_s = '' if attrs is None else \
52 ' '.join("%s=%s" % (attr, value)
52 ' '.join("%s=%s" % (attr, value)
53 for attr, value in attrs.iteritems())
53 for attr, value in attrs.iteritems())
54 return ['<%s %s>' % (tag, attr_s), src, '</%s>' % tag]
54 return ['<%s %s>' % (tag, attr_s), src, '</%s>' % tag]
55
55
56 def _ansi_colored(self, text):
56 def _ansi_colored(self, text):
57 return ['<pre>%s</pre>' % ansi2html(text)]
57 return ['<pre>%s</pre>' % ansi2html(text)]
58
58
59 def _stylesheet(self, fname):
59 def _stylesheet(self, fname):
60 with io.open(fname, encoding='utf-8') as f:
60 with io.open(fname, encoding='utf-8') as f:
61 s = f.read()
61 s = f.read()
62 return self.in_tag('style', s, dict(type='"text/css"'))
62 return self.in_tag('style', s, dict(type='"text/css"'))
63
63
64 def _out_prompt(self, output):
64 def _out_prompt(self, output):
65 if output.output_type == 'pyout':
65 if output.output_type == 'pyout':
66 content = 'Out[%s]:' % self._get_prompt_number(output)
66 content = 'Out[%s]:' % self._get_prompt_number(output)
67 else:
67 else:
68 content = ''
68 content = ''
69 return ['<div class="prompt output_prompt">%s</div>' % content]
69 return ['<div class="prompt output_prompt">%s</div>' % content]
70
70
71 def header_body(self):
71 def header_body(self):
72 """Return the body of the header as a list of strings."""
72 """Return the body of the header as a list of strings."""
73
73
74 from pygments.formatters import HtmlFormatter
74 from pygments.formatters import HtmlFormatter
75
75
76 header = []
76 header = []
77 static = os.path.join(path.get_ipython_package_dir(),
77 static = os.path.join(path.get_ipython_package_dir(),
78 'frontend', 'html', 'notebook', 'static',
78 'frontend', 'html', 'notebook', 'static',
79 )
79 )
80 here = os.path.split(os.path.realpath(__file__))[0]
80 here = os.path.split(os.path.realpath(__file__))[0]
81 css = os.path.join(static, 'css')
81 css = os.path.join(static, 'css')
82 for sheet in [
82 for sheet in [
83 # do we need jquery and prettify?
83 # do we need jquery and prettify?
84 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
84 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
85 # 'jquery-ui.min.css'),
85 # 'jquery-ui.min.css'),
86 # os.path.join(static, 'prettify', 'prettify.css'),
86 # os.path.join(static, 'prettify', 'prettify.css'),
87 os.path.join(css, 'boilerplate.css'),
87 os.path.join(css, 'boilerplate.css'),
88 os.path.join(css, 'fbm.css'),
88 os.path.join(css, 'style.min.css'),
89 os.path.join(css, 'notebook.css'),
90 os.path.join(css, 'renderedhtml.css'),
91 # our overrides:
89 # our overrides:
92 os.path.join(here, '..', 'css', 'static_html.css'),
90 os.path.join(here, '..', 'css', 'static_html.css'),
93 ]:
91 ]:
94 header.extend(self._stylesheet(sheet))
92 header.extend(self._stylesheet(sheet))
95
93
96 # pygments css
94 # pygments css
97 pygments_css = HtmlFormatter().get_style_defs('.highlight')
95 pygments_css = HtmlFormatter().get_style_defs('.highlight')
98 header.extend(['<meta charset="UTF-8">'])
96 header.extend(['<meta charset="UTF-8">'])
99 header.extend(self.in_tag('style', pygments_css,
97 header.extend(self.in_tag('style', pygments_css,
100 dict(type='"text/css"')))
98 dict(type='"text/css"')))
101
99
102 # TODO: this should be allowed to use local mathjax:
100 # TODO: this should be allowed to use local mathjax:
103 header.extend(self.in_tag('script', '', {'type': '"text/javascript"',
101 header.extend(self.in_tag('script', '', {'type': '"text/javascript"',
104 'src': '"https://c328740.ssl.cf1.rackcdn.com/mathjax/'
102 'src': '"https://c328740.ssl.cf1.rackcdn.com/mathjax/'
105 'latest/MathJax.js?config=TeX-AMS_HTML"',
103 'latest/MathJax.js?config=TeX-AMS_HTML"',
106 }))
104 }))
107 with io.open(os.path.join(here, '..', 'js', 'initmathjax.js'),
105 with io.open(os.path.join(here, '..', 'js', 'initmathjax.js'),
108 encoding='utf-8') as f:
106 encoding='utf-8') as f:
109 header.extend(self.in_tag('script', f.read(),
107 header.extend(self.in_tag('script', f.read(),
110 {'type': '"text/javascript"'}))
108 {'type': '"text/javascript"'}))
111 return header
109 return header
112
110
113 def optional_header(self):
111 def optional_header(self):
114 return ['<html>', '<head>'] + self.header_body() + \
112 return ['<html>', '<head>'] + self.header_body() + \
115 ['</head>', '<body>']
113 ['</head>', '<body>']
116
114
117 def optional_footer(self):
115 def optional_footer(self):
118 return ['</body>', '</html>']
116 return ['</body>', '</html>']
119
117
120 @text_cell
118 @text_cell
121 def render_heading(self, cell):
119 def render_heading(self, cell):
122 marker = cell.level
120 marker = cell.level
123 return [u'<h{1}>\n {0}\n</h{1}>'.format(cell.source, marker)]
121 return [u'<h{1}>\n {0}\n</h{1}>'.format(cell.source, marker)]
124
122
125 def render_code(self, cell):
123 def render_code(self, cell):
126 if not cell.input:
124 if not cell.input:
127 return []
125 return []
128
126
129 lines = ['<div class="cell border-box-sizing code_cell vbox">']
127 lines = ['<div class="cell border-box-sizing code_cell vbox">']
130
128
131 lines.append('<div class="input hbox">')
129 lines.append('<div class="input hbox">')
132 n = self._get_prompt_number(cell)
130 n = self._get_prompt_number(cell)
133 lines.append(
131 lines.append(
134 '<div class="prompt input_prompt">In&nbsp;[%s]:</div>' % n
132 '<div class="prompt input_prompt">In&nbsp;[%s]:</div>' % n
135 )
133 )
136 lines.append('<div class="input_area box-flex1">')
134 lines.append('<div class="input_area box-flex1">')
137 lines.append(highlight(cell.input) if self.highlight_source
135 lines.append(highlight(cell.input) if self.highlight_source
138 else cell.input)
136 else cell.input)
139 lines.append('</div>') # input_area
137 lines.append('</div>') # input_area
140 lines.append('</div>') # input
138 lines.append('</div>') # input
141
139
142 if cell.outputs:
140 if cell.outputs:
143 lines.append('<div class="vbox output_wrapper">')
141 lines.append('<div class="vbox output_wrapper">')
144 lines.append('<div class="output vbox">')
142 lines.append('<div class="output vbox">')
145
143
146 for output in coalesce_streams(cell.outputs):
144 for output in coalesce_streams(cell.outputs):
147 conv_fn = self.dispatch(output.output_type)
145 conv_fn = self.dispatch(output.output_type)
148 lines.extend(conv_fn(output))
146 lines.extend(conv_fn(output))
149
147
150 lines.append('</div>') # output
148 lines.append('</div>') # output
151 lines.append('</div>') # output_wrapper
149 lines.append('</div>') # output_wrapper
152
150
153 lines.append('</div>') # cell
151 lines.append('</div>') # cell
154
152
155 return lines
153 return lines
156
154
157 @text_cell
155 @text_cell
158 def render_markdown(self, cell):
156 def render_markdown(self, cell):
159 return [markdown(cell.source)]
157 return [markdown(cell.source)]
160
158
161 def render_raw(self, cell):
159 def render_raw(self, cell):
162 if self.raw_as_verbatim:
160 if self.raw_as_verbatim:
163 return self.in_tag('pre', cell.source)
161 return self.in_tag('pre', cell.source)
164 else:
162 else:
165 return [cell.source]
163 return [cell.source]
166
164
167 @output_container
165 @output_container
168 def render_pyout(self, output):
166 def render_pyout(self, output):
169 for fmt in ['html', 'latex', 'png', 'jpeg', 'svg', 'text']:
167 for fmt in ['html', 'latex', 'png', 'jpeg', 'svg', 'text']:
170 if fmt in output:
168 if fmt in output:
171 conv_fn = self.dispatch_display_format(fmt)
169 conv_fn = self.dispatch_display_format(fmt)
172 return conv_fn(output)
170 return conv_fn(output)
173 return []
171 return []
174
172
175 render_display_data = render_pyout
173 render_display_data = render_pyout
176
174
177 @output_container
175 @output_container
178 def render_stream(self, output):
176 def render_stream(self, output):
179 return self._ansi_colored(output.text)
177 return self._ansi_colored(output.text)
180
178
181 @output_container
179 @output_container
182 def render_pyerr(self, output):
180 def render_pyerr(self, output):
183 # Note: a traceback is a *list* of frames.
181 # Note: a traceback is a *list* of frames.
184 # lines = []
182 # lines = []
185
183
186 # stb =
184 # stb =
187 return self._ansi_colored('\n'.join(output.traceback))
185 return self._ansi_colored('\n'.join(output.traceback))
188
186
189 def _img_lines(self, img_file):
187 def _img_lines(self, img_file):
190 return ['<img src="%s">' % img_file, '</img>']
188 return ['<img src="%s">' % img_file, '</img>']
191
189
192 def _unknown_lines(self, data):
190 def _unknown_lines(self, data):
193 return ['<h2>Warning:: Unknown cell</h2>'] + self.in_tag('pre', data)
191 return ['<h2>Warning:: Unknown cell</h2>'] + self.in_tag('pre', data)
194
192
195 def render_display_format_png(self, output):
193 def render_display_format_png(self, output):
196 return ['<img src="data:image/png;base64,%s"></img>' % output.png]
194 return ['<img src="data:image/png;base64,%s"></img>' % output.png]
197
195
198 def render_display_format_svg(self, output):
196 def render_display_format_svg(self, output):
199 return [output.svg]
197 return [output.svg]
200
198
201 def render_display_format_jpeg(self, output):
199 def render_display_format_jpeg(self, output):
202 return ['<img src="data:image/jpeg;base64,%s"></img>' % output.jpeg]
200 return ['<img src="data:image/jpeg;base64,%s"></img>' % output.jpeg]
203
201
204 def render_display_format_text(self, output):
202 def render_display_format_text(self, output):
205 return self._ansi_colored(output.text)
203 return self._ansi_colored(output.text)
206
204
207 def render_display_format_html(self, output):
205 def render_display_format_html(self, output):
208 return [output.html]
206 return [output.html]
209
207
210 def render_display_format_latex(self, output):
208 def render_display_format_latex(self, output):
211 return [output.latex]
209 return [output.latex]
212
210
213 def render_display_format_json(self, output):
211 def render_display_format_json(self, output):
214 # html ignores json
212 # html ignores json
215 return []
213 return []
216
214
217 def render_display_format_javascript(self, output):
215 def render_display_format_javascript(self, output):
218 return [output.javascript]
216 return [output.javascript]
General Comments 0
You need to be logged in to leave comments. Login now