##// END OF EJS Templates
Changed name option from slider to reveal
damianavila -
Show More
@@ -1,79 +1,27
1 from __future__ import absolute_import
1 from converters.markdown import ConverterMarkdown
2
3 from converters.html import ConverterHTML
4 from converters.utils import text_cell
5 from converters.utils import highlight, coalesce_streams
6
7 from IPython.utils import path
8 from markdown import markdown
9
10 import os
11 import io
2 import io
12 import itertools
3 import os
13
4
5 class ConverterReveal(ConverterMarkdown):
6 """Convert a notebook to a html slideshow.
14
7
15 class ConverterReveal(ConverterHTML):
8 It generates a static html slideshow based in markdown and reveal.js.
16 """
9 """
17 Convert a ipython notebook to a html slideshow
18 based in reveal.js library.
19 """
20
21 @text_cell
22 def render_heading(self, cell):
23 marker = cell.level
24 return [self.meta2str(cell.metadata),
25 u'<h{1}>\n {0}\n</h{1}>'.format(cell.source, marker)]
26
10
27 def render_code(self, cell):
11 def __init__(self, infile, highlight_source=False, show_prompts=True,
28 if not cell.input:
12 inline_prompt=True):
29 return []
13 super(ConverterMarkdown, self).__init__(infile)
30 lines = []
14 self.highlight_source = highlight_source
31 meta_code = self.meta2str(cell.metadata)
15 self.show_prompts = show_prompts
32 lines.extend([meta_code])
16 self.inline_prompt = inline_prompt
33 lines.extend(['<div class="cell border-box-sizing code_cell vbox">'])
34 lines.append('<div class="input hbox">')
35 n = self._get_prompt_number(cell)
36 lines.append(
37 '<div class="prompt input_prompt">In&nbsp;[%s]:</div>' % n
38 )
39 lines.append('<div class="input_area box-flex1">')
40 lines.append(highlight(cell.input))
41 lines.append('</div>') # input_area
42 lines.append('</div>') # input
43 if cell.outputs:
44 lines.append('<div class="vbox output_wrapper">')
45 lines.append('<div class="output vbox">')
46 for output in coalesce_streams(cell.outputs):
47 conv_fn = self.dispatch(output.output_type)
48 lines.extend(conv_fn(output))
49 lines.append('</div>') # output
50 lines.append('</div>') # output_wrapper
51 lines.append('</div>') # cell
52 return lines
53
54 @text_cell
55 def render_markdown(self, cell):
56 return [self.meta2str(cell.metadata), markdown(cell.source)]
57
58 def render_raw(self, cell):
59 if self.raw_as_verbatim:
60 return [self.in_tag('pre', self.meta2str(cell.metadata)),
61 self.in_tag('pre', cell.source)]
62 else:
63 return [self.meta2str(cell.metadata), cell.source]
64
65 def meta2str(self, meta):
66 "transform metadata dict (containing slides delimiters) to string "
67 try:
68 meta_tuple = meta[u'slideshow'].items()
69 except KeyError as e: # if there is not slideshow metadata
70 meta_tuple = [(u'slide_type', u'untouched')]
71 meta_list = [[x + ' = ' + unicode(y)] for x, y in meta_tuple]
72 return u'\n'.join(list(itertools.chain(*meta_list)))
73
17
74 def convert(self, cell_separator='\n'):
18 def convert(self, cell_separator='\n'):
75 """
19 """
76 Specific method to converts notebook to a string representation.
20 Generic method to converts notebook to a string representation.
21
22 This is accomplished by dispatching on the cell_type, so subclasses of
23 Convereter class do not need to re-implement this method, but just
24 need implementation for the methods that will be dispatched.
77
25
78 Parameters
26 Parameters
79 ----------
27 ----------
@@ -84,105 +32,17 class ConverterReveal(ConverterHTML):
84 -------
32 -------
85 out : string
33 out : string
86 """
34 """
87
88 lines = []
35 lines = []
89 lines.extend(self.optional_header())
36 lines.extend(self.optional_header())
90 begin = ['<div class="reveal"><div class="slides">']
37 top = '<section data-markdown><script type="text/template">'
91 lines.extend(begin)
38 bottom = '</script></section>'
92 slides_list = self.build_slides()
93 lines.extend(slides_list)
94 end = ['</div></div>']
95 lines.extend(end)
96 lines.extend(self.optional_footer())
97 return u'\n'.join(lines)
98
99 def clean_text(self, cell_separator='\n'):
100 "clean and reorganize the text list to be slided"
101 text = self.main_body(cell_separator)
39 text = self.main_body(cell_separator)
102 self.delim = [u'slide_type = untouched',
103 u'slide_type = -',
104 u'slide_type = slide',
105 u'slide_type = subslide',
106 u'slide_type = fragment',
107 u'slide_type = notes',
108 u'slide_type = skip'] # keep this one the last
109 text_cell_render = \
110 u'<div class="text_cell_render border-box-sizing rendered_html">'
111 for i, j in enumerate(text):
112 if j in self.delim and text[i - 1] == text_cell_render:
113 if j == self.delim[0]:
114 text[i - 1] = self.delim[0]
115 elif j == self.delim[1]:
116 text[i - 1] = self.delim[1]
117 elif j == self.delim[2]:
118 text[i - 1] = self.delim[2]
119 elif j == self.delim[3]:
120 text[i - 1] = self.delim[3]
121 elif j == self.delim[4]:
122 text[i - 1] = self.delim[4]
123 elif j == self.delim[5]:
124 text[i - 1] = self.delim[5]
125 else:
126 text[i - 1] = self.delim[6]
127 text[i] = text_cell_render
128 return text
129
130 def build_slides(self):
131 "build the slides structure from text list and delimiters"
132 text = self.clean_text()
133 left = '<section>'
134 right = '</section>'
135 notes_start = '<aside class="notes">'
136 notes_end = '</aside>'
137 #encapsulation of skipped cells
138 for i, j in enumerate(text):
139 if j == u'slide_type = skip':
140 text.pop(i)
141 text[i] = text[i][:4] + \
142 ' style=display:none' + text[i][4:]
143 #encapsulation of notes cells
144 for i, j in enumerate(text):
40 for i,j in enumerate(text):
145 if j == u'slide_type = notes':
41 if j == u'---':
146 text.pop(i)
42 text[i] = bottom + top
147 temp_list = []
43 lines.extend(text)
148 while not text[i] in self.delim[:6]:
44 lines.extend(self.optional_footer())
149 temp_list.append(text.pop(i))
45 return u'\n'.join(lines)
150 else:
151 temp_list.insert(0, notes_start)
152 temp_list.append(notes_end)
153 text[i:i] = temp_list
154 # elimination of none names
155 for i, j in enumerate(text):
156 if j in [u'slide_type = untouched', u'slide_type = -']:
157 text.pop(i)
158 #generation of slides as a list of list
159 slides = [list(x[1]) for x in itertools.groupby(text,
160 lambda x: x == u'slide_type = slide') if not x[0]]
161 for slide in slides:
162 slide.insert(0, left)
163 slide.append(right)
164 # encapsulation of each fragment
165 for i, j in enumerate(slide):
166 if j == u'slide_type = fragment':
167 slide.pop(i)
168 slide[i] = slide[i][:4] + \
169 ' class="fragment"' + slide[i][4:]
170 # encapsulation of each nested slide
171 if u'slide_type = subslide' in slide:
172 slide.insert(0, left)
173 slide.append(right)
174 for i, j in enumerate(slide):
175 if j == u'slide_type = subslide':
176 slide[i] = right + left
177 return list(itertools.chain(*slides))
178
179 def render(self):
180 "read, convert, and save self.infile"
181 if not hasattr(self, 'nb'):
182 self.read()
183 self.output = self.convert()
184 assert(type(self.output) == unicode)
185 return self.save()
186
46
187 def save(self, outfile=None, encoding=None):
47 def save(self, outfile=None, encoding=None):
188 "read and parse notebook into self.nb"
48 "read and parse notebook into self.nb"
@@ -194,55 +54,81 class ConverterReveal(ConverterHTML):
194 f.write(self.output)
54 f.write(self.output)
195 return os.path.abspath(outfile)
55 return os.path.abspath(outfile)
196
56
197 def header_body(self):
198 "return the body of the header as a list of strings"
199 from pygments.formatters import HtmlFormatter
200 header = []
201 static = os.path.join(path.get_ipython_package_dir(),
202 'frontend', 'html', 'notebook', 'static',)
203 here = os.path.split(os.path.realpath(__file__))[0]
204 css = os.path.join(static, 'css')
205 for sheet in [
206 # do we need jquery and prettify?
207 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
208 # 'jquery-ui.min.css'),
209 # os.path.join(static, 'prettify', 'prettify.css'),
210 os.path.join(css, 'boilerplate.css'),
211 os.path.join(css, 'style.min.css'),
212 # our overrides:
213 os.path.join(here, '..', 'css', 'reveal_html.css'),
214 ]:
215 header.extend(self._stylesheet(sheet))
216 # pygments css
217 pygments_css = HtmlFormatter().get_style_defs('.highlight')
218 header.extend(['<meta charset="UTF-8">'])
219 header.extend(self.in_tag('style', pygments_css,
220 dict(type='"text/css"')))
221 return header
222
223 def template_read(self, templ):
224 "read the reveal_template.html"
225 here = os.path.split(os.path.realpath(__file__))[0]
226 reveal_template = os.path.join(here, '..', 'templates',
227 templ)
228 with io.open(reveal_template, 'r', encoding='utf-8') as f:
229 template = f.readlines()
230 template = [s.strip() for s in template]
231 return template
232
233 def template_split(self):
234 "split the reveal_template.html in header and footer lists"
235 temp = self.template_read('reveal_base.html')
236 splitted_temp = [list(x[1]) for x in itertools.groupby(temp,
237 lambda x: x == u'%slides%') if not x[0]]
238 return splitted_temp
239
240 def optional_header(self):
57 def optional_header(self):
241 optional_header_body = self.template_split()
58 optional_header_body = [\
242 return ['<!DOCTYPE html>', '<html>', '<head>'] + \
59 '''
243 optional_header_body[0] + self.header_body() + \
60 <!DOCTYPE html>
244 ['</head>', '<body>']
61 <html>
62 <head>
63 <meta charset="utf-8" />
64 <meta http-equiv="X-UA-Compatible" content="chrome=1">
65
66 <meta name="apple-mobile-web-app-capable" content="yes" />
67 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
68
69 <link rel="stylesheet" href="reveal/css/reveal.css">
70 <link rel="stylesheet" href="reveal/css/theme/default.css" id="theme">
71
72 <!-- For syntax highlighting -->
73 <link rel="stylesheet" href="reveal/lib/css/zenburn.css">
74
75 <!-- If the query includes 'print-pdf', use the PDF print sheet -->
76 <script>
77 document.write( '<link rel="stylesheet" href="reveal/css/print/' + ( window.location.search.match( /print-pdf/gi ) ? 'pdf' : 'paper' ) + '.css" type="text/css" media="print">' );
78 </script>
79
80 <!--[if lt IE 9]>
81 <script src="reveal/lib/js/html5shiv.js"></script>
82 <![endif]-->
83
84 </head>
85 <body><div class="reveal"><div class="slides">
86 <section data-markdown><script type="text/template">
87 ''']
88 return optional_header_body
245
89
246 def optional_footer(self):
90 def optional_footer(self):
247 optional_footer_body = self.template_split()
91 optional_footer_body = [\
248 return optional_footer_body[1] + ['</body>', '</html>'] No newline at end of file
92 '''
93 </script></section>
94 </div></div>
95
96 <script src="reveal/lib/js/head.min.js"></script>
97
98 <script src="reveal/js/reveal.min.js"></script>
99
100 <script>
101
102 // Full list of configuration options available here: https://github.com/hakimel/reveal.js#configuration
103 Reveal.initialize({
104 controls: true,
105 progress: true,
106 history: true,
107
108 theme: Reveal.getQueryHash().theme, // available themes are in /css/theme
109 transition: Reveal.getQueryHash().transition || 'page', // default/cube/page/concave/zoom/linear/none
110
111 // Optional libraries used to extend on reveal.js
112 dependencies: [
113 { src: 'reveal/lib/js/classList.js', condition: function() { return !document.body.classList; } },
114 { src: 'reveal/plugin/markdown/showdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
115 { src: 'reveal/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
116 { src: 'reveal/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
117 { src: 'reveal/plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
118 { src: 'reveal/plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } },
119 { src: 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS_HTML', async: true },
120 { src: 'js/initmathjax.js', async: true}
121 ]
122 });
123 </script>
124
125 <script>
126 Reveal.addEventListener( 'slidechanged', function( event ) {
127 MathJax.Hub.Rerender();
128 });
129 </script>
130
131 </body>
132 </html>
133 ''']
134 return optional_footer_body
@@ -15,13 +15,6 from __future__ import print_function
15 # From IPython
15 # From IPython
16 from IPython.external import argparse
16 from IPython.external import argparse
17
17
18 # All the stuff needed for the configurable things
19 from IPython.config.application import Application, catch_config_error
20 from IPython.config.configurable import Configurable, SingletonConfigurable
21 from IPython.config.loader import Config, ConfigFileNotFound
22 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, CaselessStrEnum
23
24
25 # local
18 # local
26 from converters.html import ConverterHTML
19 from converters.html import ConverterHTML
27 from converters.markdown import ConverterMarkdown
20 from converters.markdown import ConverterMarkdown
@@ -30,7 +23,6 from converters.rst import ConverterRST
30 from converters.latex import ConverterLaTeX
23 from converters.latex import ConverterLaTeX
31 from converters.python import ConverterPy
24 from converters.python import ConverterPy
32 from converters.reveal import ConverterReveal
25 from converters.reveal import ConverterReveal
33 from converters.base import Converter
34
26
35
27
36 # When adding a new format, make sure to add it to the `converters`
28 # When adding a new format, make sure to add it to the `converters`
@@ -54,17 +46,18 default_format = 'rst'
54 known_formats = ', '.join([key + " (default)" if key == default_format else key
46 known_formats = ', '.join([key + " (default)" if key == default_format else key
55 for key in converters])
47 for key in converters])
56
48
57 class NbconvertApp(Application):
58
49
59
50
60 fmt = CaselessStrEnum(converters.keys(),
51 def main(infile, format='rst', preamble=None, exclude=None):
61 default_value='rst',
52 """Convert a notebook to html in one step"""
62 config=True,
53 try:
63 help="Supported conversion format")
54 ConverterClass = converters[format]
55 except KeyError:
56 raise SystemExit("Unknown format '%s', " % format +
57 "known formats are: " + known_formats)
64
58
65 exclude = List( [],
59 converter = ConverterClass(infile)
66 config=True,
60 converter.render()
67 help = 'list of cells to exclude while converting')
68
61
69 aliases = {
62 aliases = {
70 'format':'NbconvertApp.fmt',
63 'format':'NbconvertApp.fmt',
@@ -113,13 +106,21 please consider using the new version.
113 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
114
107
115 if __name__ == '__main__':
108 if __name__ == '__main__':
109 parser = argparse.ArgumentParser(description=__doc__,
110 formatter_class=argparse.RawTextHelpFormatter)
116 # TODO: consider passing file like object around, rather than filenames
111 # TODO: consider passing file like object around, rather than filenames
117 # would allow us to process stdin, or even http streams
112 # would allow us to process stdin, or even http streams
118 #parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
113 #parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
119 # default=sys.stdin)
114 # default=sys.stdin)
120
115
121 #parser.add_argument('-e', '--exclude', default='',
116 #Require a filename as a positional argument
122 # help='Comma-separated list of cells to exclude')
117 parser.add_argument('infile', nargs=1)
123 #exclude_cells = [s.strip() for s in args.exclude.split(',')]
118 parser.add_argument('-f', '--format', default='rst',
119 help='Output format. Supported formats: \n' +
120 known_formats)
121 parser.add_argument('-p', '--preamble',
122 help='Path to a user-specified preamble file')
123 parser.add_argument('-e', '--exclude', default='',
124 help='Comma-separated list of cells to exclude')
124
125
125 main()
126 main()
General Comments 0
You need to be logged in to leave comments. Login now