##// END OF EJS Templates
Merge pull request #4048 from minrk/finish-notes...
Min RK -
r12517:829790a6 merge
parent child Browse files
Show More
@@ -4,11 +4,9 b' python:'
4 - 2.7
4 - 2.7
5 - 3.3
5 - 3.3
6 before_install:
6 before_install:
7 - pip install jinja2
8 - easy_install -q pyzmq
7 - easy_install -q pyzmq
8 - pip install jinja2 sphinx pygments tornado
9 - sudo apt-get install pandoc
9 - sudo apt-get install pandoc
10 - pip install pygments
11 - pip install sphinx
12 install:
10 install:
13 - python setup.py install -q
11 - python setup.py install -q
14 script:
12 script:
@@ -63,8 +63,7 b' nbconvert_aliases.update({'
63 'writer' : 'NbConvertApp.writer_class',
63 'writer' : 'NbConvertApp.writer_class',
64 'post': 'NbConvertApp.postprocessor_class',
64 'post': 'NbConvertApp.postprocessor_class',
65 'output': 'NbConvertApp.output_base',
65 'output': 'NbConvertApp.output_base',
66 'offline-slides': 'RevealHelpPreprocessor.url_prefix',
66 'reveal-prefix': 'RevealHelpPreprocessor.url_prefix',
67 'slide-notes': 'RevealHelpPreprocessor.speaker_notes'
68 })
67 })
69
68
70 nbconvert_flags = {}
69 nbconvert_flags = {}
@@ -1,3 +1,8 b''
1 from .base import PostProcessorBase
1 from .base import PostProcessorBase
2 from .pdf import PDFPostProcessor
2 from .pdf import PDFPostProcessor
3
4 # protect against unavailable tornado
5 try:
3 from .serve import ServePostProcessor
6 from .serve import ServePostProcessor
7 except ImportError:
8 pass
@@ -1,6 +1,4 b''
1 """
1 """PostProcessor for serving reveal.js HTML slideshows."""
2 Contains postprocessor for serving nbconvert output.
3 """
4 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
5 #Copyright (c) 2013, the IPython Development Team.
3 #Copyright (c) 2013, the IPython Development Team.
6 #
4 #
@@ -16,40 +14,94 b' Contains postprocessor for serving nbconvert output.'
16 import os
14 import os
17 import webbrowser
15 import webbrowser
18
16
19 from BaseHTTPServer import HTTPServer
17 from tornado import web, ioloop, httpserver
20 from SimpleHTTPServer import SimpleHTTPRequestHandler
18 from tornado.httpclient import AsyncHTTPClient
21
19
22 from IPython.utils.traitlets import Bool
20 from IPython.utils.traitlets import Bool, Unicode, Int
23
21
24 from .base import PostProcessorBase
22 from .base import PostProcessorBase
25
23
26 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
27 # Classes
25 # Classes
28 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
28 class ProxyHandler(web.RequestHandler):
29 """handler the proxies requests from a local prefix to a CDN"""
30 @web.asynchronous
31 def get(self, prefix, url):
32 """proxy a request to a CDN"""
33 proxy_url = "/".join([self.settings['cdn'], url])
34 client = self.settings['client']
35 client.fetch(proxy_url, callback=self.finish_get)
36
37 def finish_get(self, response):
38 """finish the request"""
39 # copy potentially relevant headers
40 for header in ["Content-Type", "Cache-Control", "Date", "Last-Modified", "Expires"]:
41 if header in response.headers:
42 self.set_header(header, response.headers[header])
43 self.finish(response.body)
44
29 class ServePostProcessor(PostProcessorBase):
45 class ServePostProcessor(PostProcessorBase):
30 """Post processor designed to serve files"""
46 """Post processor designed to serve files
47
48 Proxies reveal.js requests to a CDN if no local reveal.js is present
49 """
31
50
32
51
33 open_in_browser = Bool(True, config=True,
52 open_in_browser = Bool(True, config=True,
34 help="""Set to False to deactivate
53 help="""Should the browser be opened automatically?"""
35 the opening of the browser""")
54 )
55 reveal_cdn = Unicode("https://cdn.jsdelivr.net/reveal.js/2.4.0", config=True,
56 help="""URL for reveal.js CDN."""
57 )
58 reveal_prefix = Unicode("reveal.js", config=True, help="URL prefix for reveal.js")
59 ip = Unicode("127.0.0.1", config=True, help="The IP address to listen on.")
60 port = Int(8000, config=True, help="port for the server to listen on.")
36
61
37 def postprocess(self, input):
62 def postprocess(self, input):
38 """
63 """Serve the build directory with a webserver."""
39 Simple implementation to serve the build directory.
40 """
41
42 try:
43 dirname, filename = os.path.split(input)
64 dirname, filename = os.path.split(input)
44 if dirname:
65 handlers = [
45 os.chdir(dirname)
66 (r"/(.+)", web.StaticFileHandler, {'path' : dirname}),
46 httpd = HTTPServer(('127.0.0.1', 8000), SimpleHTTPRequestHandler)
67 (r"/", web.RedirectHandler, {"url": "/%s" % filename})
47 sa = httpd.socket.getsockname()
68 ]
48 url = "http://" + sa[0] + ":" + str(sa[1]) + "/" + filename
69
70 if ('://' in self.reveal_prefix or self.reveal_prefix.startswith("//")):
71 # reveal specifically from CDN, nothing to do
72 pass
73 elif os.path.isdir(os.path.join(dirname, self.reveal_prefix)):
74 # reveal prefix exists
75 self.log.info("Serving local %s", self.reveal_prefix)
76 else:
77 self.log.info("Redirecting %s requests to %s", self.reveal_prefix, self.reveal_cdn)
78 handlers.insert(0, (r"/(%s)/(.*)" % self.reveal_prefix, ProxyHandler))
79
80 app = web.Application(handlers,
81 cdn=self.reveal_cdn,
82 client=AsyncHTTPClient(),
83 )
84 # hook up tornado logging to our logger
85 from tornado import log
86 log.app_log = self.log
87
88 http_server = httpserver.HTTPServer(app)
89 http_server.listen(self.port, address=self.ip)
90 url = "http://%s:%i/%s" % (self.ip, self.port, filename)
91 print("Serving your slides at %s" % url)
92 print("Use Control-C to stop this server")
49 if self.open_in_browser:
93 if self.open_in_browser:
50 webbrowser.open(url, new=2)
94 webbrowser.open(url, new=2)
51 print("Serving your slides on " + url)
95 try:
52 print("Use Control-C to stop this server.")
96 ioloop.IOLoop.instance().start()
53 httpd.serve_forever()
54 except KeyboardInterrupt:
97 except KeyboardInterrupt:
55 print("The server is shut down.")
98 print("\nInterrupted")
99
100 def main(path):
101 """allow running this module to serve the slides"""
102 server = ServePostProcessor()
103 server(path)
104
105 if __name__ == '__main__':
106 import sys
107 main(sys.argv[1])
@@ -24,15 +24,14 b' from IPython.utils.traitlets import Unicode, Bool'
24
24
25 class RevealHelpPreprocessor(Preprocessor):
25 class RevealHelpPreprocessor(Preprocessor):
26
26
27 url_prefix = Unicode('//cdn.jsdelivr.net/reveal.js/2.4.0',
27 url_prefix = Unicode('reveal.js', config=True,
28 config=True,
28 help="""The URL prefix for reveal.js.
29 help="""If you want to use a local reveal.js library,
29 This can be a a relative URL for a local copy of reveal.js,
30 use 'url_prefix':'reveal.js' in your config object.""")
30 or point to a CDN.
31
31
32 speaker_notes = Bool(False,
32 For speaker notes to work, a local reveal.js prefix must be used.
33 config=True,
33 """
34 help="""If you want to use the speaker notes
34 )
35 set this to True.""")
36
35
37 def preprocess(self, nb, resources):
36 def preprocess(self, nb, resources):
38 """
37 """
@@ -65,30 +64,4 b' class RevealHelpPreprocessor(Preprocessor):'
65 if not isinstance(resources['reveal'], dict):
64 if not isinstance(resources['reveal'], dict):
66 resources['reveal'] = {}
65 resources['reveal'] = {}
67 resources['reveal']['url_prefix'] = self.url_prefix
66 resources['reveal']['url_prefix'] = self.url_prefix
68 resources['reveal']['notes_prefix'] = self.url_prefix
69
70 cdn = 'http://cdn.jsdelivr.net/reveal.js/2.4.0'
71 local = 'local'
72 html_path = 'plugin/notes/notes.html'
73 js_path = 'plugin/notes/notes.js'
74
75 html_infile = os.path.join(cdn, html_path)
76 js_infile = os.path.join(cdn, js_path)
77 html_outfile = os.path.join(local, html_path)
78 js_outfile = os.path.join(local, js_path)
79
80 if self.speaker_notes:
81 if 'outputs' not in resources:
82 resources['outputs'] = {}
83 resources['outputs'][html_outfile] = self.notes_helper(html_infile)
84 resources['outputs'][js_outfile] = self.notes_helper(js_infile)
85 resources['reveal']['notes_prefix'] = local
86
87 return nb, resources
67 return nb, resources
88
89 def notes_helper(self, infile):
90 """Helper function to get the content from an url."""
91
92 content = urllib2.urlopen(infile).read()
93
94 return content
@@ -135,7 +135,7 b" transition: Reveal.getQueryHash().transition || 'linear', // default/cube/page/c"
135 dependencies: [
135 dependencies: [
136 { src: "{{resources.reveal.url_prefix}}/lib/js/classList.js", condition: function() { return !document.body.classList; } },
136 { src: "{{resources.reveal.url_prefix}}/lib/js/classList.js", condition: function() { return !document.body.classList; } },
137 { src: "{{resources.reveal.url_prefix}}/plugin/highlight/highlight.js", async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
137 { src: "{{resources.reveal.url_prefix}}/plugin/highlight/highlight.js", async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
138 { src: "{{resources.reveal.notes_prefix}}/plugin/notes/notes.js", async: true, condition: function() { return !!document.body.classList; } }
138 { src: "{{resources.reveal.url_prefix}}/plugin/notes/notes.js", async: true, condition: function() { return !!document.body.classList; } }
139 // { src: 'http://s7.addthis.com/js/300/addthis_widget.js', async: true},
139 // { src: 'http://s7.addthis.com/js/300/addthis_widget.js', async: true},
140 ]
140 ]
141 });
141 });
@@ -293,6 +293,8 b' def make_exclude():'
293
293
294 if not have['tornado']:
294 if not have['tornado']:
295 exclusions.append(ipjoin('html'))
295 exclusions.append(ipjoin('html'))
296 exclusions.append(ipjoin('nbconvert', 'post_processors', 'serve'))
297 exclusions.append(ipjoin('nbconvert', 'post_processors', 'tests', 'test_serve'))
296
298
297 if not have['jinja2']:
299 if not have['jinja2']:
298 exclusions.append(ipjoin('html', 'notebookapp'))
300 exclusions.append(ipjoin('html', 'notebookapp'))
@@ -61,13 +61,8 b' The currently supported export formats are:'
61 * ``--to slides``
61 * ``--to slides``
62
62
63 This generates a Reveal.js HTML slideshow.
63 This generates a Reveal.js HTML slideshow.
64 It must be served by an HTTP server. The easiest way to get this is to add
64 It must be served by an HTTP server. The easiest way to do this is adding
65 ``--post serve`` on the command-line.
65 ``--post serve`` on the command-line.
66 If you want to use the speaker notes plugin, just add
67 ``--slide-notes=True`` on the command-line.
68 For low connectivity environments, you can use a local copy of the reveal.js library,
69 just add ``--offline-slides=reveal.js`` on the command-line, and do not forget to move
70 your downloaded ``reveal.js`` library to the same folder where your slides are located.
71
66
72 * ``--to markdown``
67 * ``--to markdown``
73
68
General Comments 0
You need to be logged in to leave comments. Login now