##// END OF EJS Templates
Updated reveal CDN and use the new data-fragment-index attribute to get composite fragments (several cells inside the same fragment).
damianavila -
Show More
@@ -1,112 +1,112 b''
1 1 """PostProcessor for serving reveal.js HTML slideshows."""
2 2 from __future__ import print_function
3 3 #-----------------------------------------------------------------------------
4 4 #Copyright (c) 2013, the IPython Development Team.
5 5 #
6 6 #Distributed under the terms of the Modified BSD License.
7 7 #
8 8 #The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import os
16 16 import webbrowser
17 17
18 18 from tornado import web, ioloop, httpserver
19 19 from tornado.httpclient import AsyncHTTPClient
20 20
21 21 from IPython.utils.traitlets import Bool, Unicode, Int
22 22
23 23 from .base import PostProcessorBase
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Classes
27 27 #-----------------------------------------------------------------------------
28 28
29 29 class ProxyHandler(web.RequestHandler):
30 30 """handler the proxies requests from a local prefix to a CDN"""
31 31 @web.asynchronous
32 32 def get(self, prefix, url):
33 33 """proxy a request to a CDN"""
34 34 proxy_url = "/".join([self.settings['cdn'], url])
35 35 client = self.settings['client']
36 36 client.fetch(proxy_url, callback=self.finish_get)
37 37
38 38 def finish_get(self, response):
39 39 """finish the request"""
40 40 # copy potentially relevant headers
41 41 for header in ["Content-Type", "Cache-Control", "Date", "Last-Modified", "Expires"]:
42 42 if header in response.headers:
43 43 self.set_header(header, response.headers[header])
44 44 self.finish(response.body)
45 45
46 46 class ServePostProcessor(PostProcessorBase):
47 47 """Post processor designed to serve files
48 48
49 49 Proxies reveal.js requests to a CDN if no local reveal.js is present
50 50 """
51 51
52 52
53 53 open_in_browser = Bool(True, config=True,
54 54 help="""Should the browser be opened automatically?"""
55 55 )
56 reveal_cdn = Unicode("https://cdn.jsdelivr.net/reveal.js/2.5.0", config=True,
56 reveal_cdn = Unicode("https://cdn.jsdelivr.net/reveal.js/2.6.2", config=True,
57 57 help="""URL for reveal.js CDN."""
58 58 )
59 59 reveal_prefix = Unicode("reveal.js", config=True, help="URL prefix for reveal.js")
60 60 ip = Unicode("127.0.0.1", config=True, help="The IP address to listen on.")
61 61 port = Int(8000, config=True, help="port for the server to listen on.")
62 62
63 63 def postprocess(self, input):
64 64 """Serve the build directory with a webserver."""
65 65 dirname, filename = os.path.split(input)
66 66 handlers = [
67 67 (r"/(.+)", web.StaticFileHandler, {'path' : dirname}),
68 68 (r"/", web.RedirectHandler, {"url": "/%s" % filename})
69 69 ]
70 70
71 71 if ('://' in self.reveal_prefix or self.reveal_prefix.startswith("//")):
72 72 # reveal specifically from CDN, nothing to do
73 73 pass
74 74 elif os.path.isdir(os.path.join(dirname, self.reveal_prefix)):
75 75 # reveal prefix exists
76 76 self.log.info("Serving local %s", self.reveal_prefix)
77 77 else:
78 78 self.log.info("Redirecting %s requests to %s", self.reveal_prefix, self.reveal_cdn)
79 79 handlers.insert(0, (r"/(%s)/(.*)" % self.reveal_prefix, ProxyHandler))
80 80
81 81 app = web.Application(handlers,
82 82 cdn=self.reveal_cdn,
83 83 client=AsyncHTTPClient(),
84 84 )
85 85 # hook up tornado logging to our logger
86 86 try:
87 87 from tornado import log
88 88 log.app_log = self.log
89 89 except ImportError:
90 90 # old tornado (<= 3), ignore
91 91 pass
92 92
93 93 http_server = httpserver.HTTPServer(app)
94 94 http_server.listen(self.port, address=self.ip)
95 95 url = "http://%s:%i/%s" % (self.ip, self.port, filename)
96 96 print("Serving your slides at %s" % url)
97 97 print("Use Control-C to stop this server")
98 98 if self.open_in_browser:
99 99 webbrowser.open(url, new=2)
100 100 try:
101 101 ioloop.IOLoop.instance().start()
102 102 except KeyboardInterrupt:
103 103 print("\nInterrupted")
104 104
105 105 def main(path):
106 106 """allow running this module to serve the slides"""
107 107 server = ServePostProcessor()
108 108 server(path)
109 109
110 110 if __name__ == '__main__':
111 111 import sys
112 112 main(sys.argv[1])
@@ -1,72 +1,75 b''
1 1 """Module that pre-processes the notebook for export via Reveal.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2013, the IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 from .base import Preprocessor
16 16 from IPython.utils.traitlets import Unicode
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Classes and functions
20 20 #-----------------------------------------------------------------------------
21 21
22 22 class RevealHelpPreprocessor(Preprocessor):
23 23
24 24 url_prefix = Unicode('reveal.js', config=True,
25 25 help="""The URL prefix for reveal.js.
26 26 This can be a a relative URL for a local copy of reveal.js,
27 27 or point to a CDN.
28 28
29 29 For speaker notes to work, a local reveal.js prefix must be used.
30 30 """
31 31 )
32 32
33 33 def preprocess(self, nb, resources):
34 34 """
35 35 Called once to 'preprocess' contents of the notebook.
36 36
37 37 Parameters
38 38 ----------
39 39 nb : NotebookNode
40 40 Notebook being converted
41 41 resources : dictionary
42 42 Additional resources used in the conversion process. Allows
43 43 preprocessors to pass variables into the Jinja engine.
44 44 """
45 45
46 46 for worksheet in nb.worksheets:
47 47 for index, cell in enumerate(worksheet.cells):
48 48
49 49 #Make sure the cell has slideshow metadata.
50 50 cell.metadata.slide_type = cell.get('metadata', {}).get('slideshow', {}).get('slide_type', '-')
51 51
52 52 #Get the slide type. If type is start of subslide or slide,
53 53 #end the last subslide/slide.
54 54 if cell.metadata.slide_type in ['slide']:
55 55 worksheet.cells[index - 1].metadata.slide_helper = 'slide_end'
56 56 if cell.metadata.slide_type in ['subslide']:
57 57 worksheet.cells[index - 1].metadata.slide_helper = 'subslide_end'
58 58 #Prevent the rendering of "do nothing" cells before fragments
59 #Group fragments passing frag_number to the data-fragment-index
59 60 if cell.metadata.slide_type in ['fragment']:
61 worksheet.cells[index].metadata.frag_number = index
60 62 i = 1
61 63 while i < len(worksheet.cells) - index:
62 64 worksheet.cells[index + i].metadata.frag_helper = 'fragment_end'
65 worksheet.cells[index + i].metadata.frag_number = index
63 66 i += 1
64 67 #Restart the slide_helper when the cell status is changed
65 68 #to "do nothing".
66 69 if cell.metadata.slide_type in ['-']:
67 70 worksheet.cells[index - 1].metadata.slide_helper = '-'
68 71
69 72 if not isinstance(resources['reveal'], dict):
70 73 resources['reveal'] = {}
71 74 resources['reveal']['url_prefix'] = self.url_prefix
72 75 return nb, resources
@@ -1,203 +1,203 b''
1 1 {%- extends 'basic.tpl' -%}
2 2 {% from 'mathjax.tpl' import mathjax %}
3 3
4 4 {%- block any_cell scoped -%}
5 5 {%- if cell.metadata.slide_type in ['slide'] -%}
6 6 <section>
7 7 <section>
8 8 {{ super() }}
9 9 {%- elif cell.metadata.slide_type in ['subslide'] -%}
10 10 <section>
11 11 {{ super() }}
12 12 {%- elif cell.metadata.slide_type in ['-'] -%}
13 13 {%- if cell.metadata.frag_helper in ['fragment_end'] -%}
14 <div class="fragment">
14 <div class="fragment" data-fragment-index="{{ cell.metadata.frag_number }}">
15 15 {{ super() }}
16 16 </div>
17 17 {%- else -%}
18 18 {{ super() }}
19 19 {%- endif -%}
20 20 {%- elif cell.metadata.slide_type in ['skip'] -%}
21 21 <div style=display:none>
22 22 {{ super() }}
23 23 </div>
24 24 {%- elif cell.metadata.slide_type in ['notes'] -%}
25 25 <aside class="notes">
26 26 {{ super() }}
27 27 </aside>
28 28 {%- elif cell.metadata.slide_type in ['fragment'] -%}
29 <div class="fragment">
29 <div class="fragment" data-fragment-index="{{ cell.metadata.frag_number }}">
30 30 {{ super() }}
31 31 </div>
32 32 {%- endif -%}
33 33 {%- if cell.metadata.slide_helper in ['subslide_end'] -%}
34 34 </section>
35 35 {%- elif cell.metadata.slide_helper in ['slide_end'] -%}
36 36 </section>
37 37 </section>
38 38 {%- endif -%}
39 39 {%- endblock any_cell -%}
40 40
41 41 {% block header %}
42 42 <!DOCTYPE html>
43 43 <html>
44 44 <head>
45 45
46 46 <meta charset="utf-8" />
47 47 <meta http-equiv="X-UA-Compatible" content="chrome=1" />
48 48
49 49 <meta name="apple-mobile-web-app-capable" content="yes" />
50 50 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
51 51
52 52 <title>{{resources['metadata']['name']}} slides</title>
53 53
54 54 <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script>
55 55 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
56 56
57 57 <!-- General and theme style sheets -->
58 58 <link rel="stylesheet" href="{{resources.reveal.url_prefix}}/css/reveal.css">
59 59 <link rel="stylesheet" href="{{resources.reveal.url_prefix}}/css/theme/simple.css" id="theme">
60 60
61 61 <!-- For syntax highlighting -->
62 62 <link rel="stylesheet" href="{{resources.reveal.url_prefix}}/lib/css/zenburn.css">
63 63
64 64 <!-- If the query includes 'print-pdf', include the PDF print sheet -->
65 65 <script>
66 66 if( window.location.search.match( /print-pdf/gi ) ) {
67 67 var link = document.createElement( 'link' );
68 68 link.rel = 'stylesheet';
69 69 link.type = 'text/css';
70 70 link.href = '{{resources.reveal.url_prefix}}/css/print/pdf.css';
71 71 document.getElementsByTagName( 'head' )[0].appendChild( link );
72 72 }
73 73
74 74 </script>
75 75
76 76 <!--[if lt IE 9]>
77 77 <script src="{{resources.reveal.url_prefix}}/lib/js/html5shiv.js"></script>
78 78 <![endif]-->
79 79
80 80 <!-- Get Font-awesome from cdn -->
81 81 <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css">
82 82
83 83 {% for css in resources.inlining.css -%}
84 84 <style type="text/css">
85 85 {{ css }}
86 86 </style>
87 87 {% endfor %}
88 88
89 89 <style type="text/css">
90 90 /* Overrides of notebook CSS for static HTML export */
91 91 html {
92 92 overflow-y: auto;
93 93 }
94 94 .reveal {
95 95 font-size: 160%;
96 96 }
97 97 .reveal pre {
98 98 width: inherit;
99 99 padding: 0.4em;
100 100 margin: 0px;
101 101 font-family: monospace, sans-serif;
102 102 font-size: 80%;
103 103 box-shadow: 0px 0px 0px rgba(0, 0, 0, 0);
104 104 }
105 105 .reveal section img {
106 106 border: 0px solid black;
107 107 box-shadow: 0 0 10px rgba(0, 0, 0, 0);
108 108 }
109 109 .reveal i {
110 110 font-style: normal;
111 111 font-family: FontAwesome;
112 112 font-size: 2em;
113 113 }
114 114 .reveal .slides {
115 115 text-align: left;
116 116 }
117 117 .reveal.fade {
118 118 opacity: 1;
119 119 }
120 120 .reveal .progress {
121 121 position: static;
122 122 }
123 123 div.input_area {
124 124 padding: 0.06em;
125 125 }
126 126 div.code_cell {
127 127 background-color: transparent;
128 128 }
129 129 div.prompt {
130 130 width: 11ex;
131 131 padding: 0.4em;
132 132 margin: 0px;
133 133 font-family: monospace, sans-serif;
134 134 font-size: 80%;
135 135 text-align: right;
136 136 }
137 137 div.output_area pre {
138 138 font-family: monospace, sans-serif;
139 139 font-size: 80%;
140 140 }
141 141 div.output_prompt {
142 142 /* 5px right shift to account for margin in parent container */
143 143 margin: 5px 5px 0 0;
144 144 }
145 145 .rendered_html p {
146 146 text-align: inherit;
147 147 }
148 148 </style>
149 149
150 150 <!-- Custom stylesheet, it must be in the same directory as the html file -->
151 151 <link rel="stylesheet" href="custom.css">
152 152
153 153 </head>
154 154 {% endblock header%}
155 155
156 156
157 157 {% block body %}
158 158 <body>
159 159 <div class="reveal">
160 160 <div class="slides">
161 161 {{ super() }}
162 162 </div>
163 163 </div>
164 164
165 165 <script src="{{resources.reveal.url_prefix}}/lib/js/head.min.js"></script>
166 166
167 167 <script src="{{resources.reveal.url_prefix}}/js/reveal.js"></script>
168 168
169 169 <script>
170 170
171 171 // Full list of configuration options available here: https://github.com/hakimel/reveal.js#configuration
172 172 Reveal.initialize({
173 173 controls: true,
174 174 progress: true,
175 175 history: true,
176 176
177 177 theme: Reveal.getQueryHash().theme, // available themes are in /css/theme
178 178 transition: Reveal.getQueryHash().transition || 'linear', // default/cube/page/concave/zoom/linear/none
179 179
180 180 // Optional libraries used to extend on reveal.js
181 181 dependencies: [
182 182 { src: "{{resources.reveal.url_prefix}}/lib/js/classList.js", condition: function() { return !document.body.classList; } },
183 183 { src: "{{resources.reveal.url_prefix}}/plugin/notes/notes.js", async: true, condition: function() { return !!document.body.classList; } }
184 184 ]
185 185 });
186 186 </script>
187 187
188 188 <!-- Loading mathjax macro -->
189 189 {{ mathjax() }}
190 190
191 191 <script>
192 192 Reveal.addEventListener( 'slidechanged', function( event ) {
193 193 window.scrollTo(0,0);
194 194 MathJax.Hub.Rerender(event.currentSlide);
195 195 });
196 196 </script>
197 197
198 198 </body>
199 199 {% endblock body %}
200 200
201 201 {% block footer %}
202 202 </html>
203 203 {% endblock footer %} No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now