##// END OF EJS Templates
Adding base_project_url and base_kernel_url as HTML data attribs....
Brian E. Granger -
Show More
@@ -1,424 +1,427 b''
1 """Tornado handlers for the notebook.
1 """Tornado handlers for the notebook.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import logging
19 import logging
20 import Cookie
20 import Cookie
21
21
22 from tornado import web
22 from tornado import web
23 from tornado import websocket
23 from tornado import websocket
24
24
25 from zmq.eventloop import ioloop
25 from zmq.eventloop import ioloop
26 from zmq.utils import jsonapi
26 from zmq.utils import jsonapi
27
27
28 from IPython.zmq.session import Session
28 from IPython.zmq.session import Session
29
29
30 try:
30 try:
31 from docutils.core import publish_string
31 from docutils.core import publish_string
32 except ImportError:
32 except ImportError:
33 publish_string = None
33 publish_string = None
34
34
35
35
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Top-level handlers
38 # Top-level handlers
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40
40
41 class AuthenticatedHandler(web.RequestHandler):
41 class AuthenticatedHandler(web.RequestHandler):
42 """A RequestHandler with an authenticated user."""
42 """A RequestHandler with an authenticated user."""
43 def get_current_user(self):
43 def get_current_user(self):
44 user_id = self.get_secure_cookie("user")
44 user_id = self.get_secure_cookie("user")
45 if user_id == '':
45 if user_id == '':
46 user_id = 'anonymous'
46 user_id = 'anonymous'
47 if user_id is None:
47 if user_id is None:
48 # prevent extra Invalid cookie sig warnings:
48 # prevent extra Invalid cookie sig warnings:
49 self.clear_cookie('user')
49 self.clear_cookie('user')
50 if not self.application.password:
50 if not self.application.password:
51 user_id = 'anonymous'
51 user_id = 'anonymous'
52 return user_id
52 return user_id
53
53
54
54
55 class NBBrowserHandler(AuthenticatedHandler):
55 class NBBrowserHandler(AuthenticatedHandler):
56 @web.authenticated
56 @web.authenticated
57 def get(self):
57 def get(self):
58 nbm = self.application.notebook_manager
58 nbm = self.application.notebook_manager
59 project = nbm.notebook_dir
59 project = nbm.notebook_dir
60 self.render('nbbrowser.html', project=project)
60 self.render('nbbrowser.html', project=project,
61 base_project_url=u'/', base_kernel_url=u'/')
61
62
62 class LoginHandler(AuthenticatedHandler):
63 class LoginHandler(AuthenticatedHandler):
63 def get(self):
64 def get(self):
64 user_id = self.get_secure_cookie("user") or ''
65 user_id = self.get_secure_cookie("user") or ''
65 self.render('login.html', user_id=user_id)
66 self.render('login.html', user_id=user_id)
66
67
67 def post(self):
68 def post(self):
68 pwd = self.get_argument("password", default=u'')
69 pwd = self.get_argument("password", default=u'')
69 if self.application.password and pwd == self.application.password:
70 if self.application.password and pwd == self.application.password:
70 self.set_secure_cookie("user", self.get_argument("name", default=u''))
71 self.set_secure_cookie("user", self.get_argument("name", default=u''))
71 url = self.get_argument("next", default="/")
72 url = self.get_argument("next", default="/")
72 self.redirect(url)
73 self.redirect(url)
73
74
74 class NewHandler(AuthenticatedHandler):
75 class NewHandler(AuthenticatedHandler):
75 @web.authenticated
76 @web.authenticated
76 def get(self):
77 def get(self):
77 notebook_id = self.application.notebook_manager.new_notebook()
78 notebook_id = self.application.notebook_manager.new_notebook()
78 self.render('notebook.html', notebook_id=notebook_id)
79 self.render('notebook.html', notebook_id=notebook_id,
80 base_project_url=u'/', base_kernel_url=u'/')
79
81
80
82
81 class NamedNotebookHandler(AuthenticatedHandler):
83 class NamedNotebookHandler(AuthenticatedHandler):
82 @web.authenticated
84 @web.authenticated
83 def get(self, notebook_id):
85 def get(self, notebook_id):
84 nbm = self.application.notebook_manager
86 nbm = self.application.notebook_manager
85 if not nbm.notebook_exists(notebook_id):
87 if not nbm.notebook_exists(notebook_id):
86 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
88 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
87 self.render('notebook.html', notebook_id=notebook_id)
89 self.render('notebook.html', notebook_id=notebook_id,
90 base_project_url=u'/', base_kernel_url=u'/')
88
91
89
92
90 #-----------------------------------------------------------------------------
93 #-----------------------------------------------------------------------------
91 # Kernel handlers
94 # Kernel handlers
92 #-----------------------------------------------------------------------------
95 #-----------------------------------------------------------------------------
93
96
94
97
95 class MainKernelHandler(AuthenticatedHandler):
98 class MainKernelHandler(AuthenticatedHandler):
96
99
97 @web.authenticated
100 @web.authenticated
98 def get(self):
101 def get(self):
99 km = self.application.kernel_manager
102 km = self.application.kernel_manager
100 self.finish(jsonapi.dumps(km.kernel_ids))
103 self.finish(jsonapi.dumps(km.kernel_ids))
101
104
102 @web.authenticated
105 @web.authenticated
103 def post(self):
106 def post(self):
104 km = self.application.kernel_manager
107 km = self.application.kernel_manager
105 notebook_id = self.get_argument('notebook', default=None)
108 notebook_id = self.get_argument('notebook', default=None)
106 kernel_id = km.start_kernel(notebook_id)
109 kernel_id = km.start_kernel(notebook_id)
107 ws_url = self.application.ipython_app.get_ws_url()
110 ws_url = self.application.ipython_app.get_ws_url()
108 data = {'ws_url':ws_url,'kernel_id':kernel_id}
111 data = {'ws_url':ws_url,'kernel_id':kernel_id}
109 self.set_header('Location', '/'+kernel_id)
112 self.set_header('Location', '/'+kernel_id)
110 self.finish(jsonapi.dumps(data))
113 self.finish(jsonapi.dumps(data))
111
114
112
115
113 class KernelHandler(AuthenticatedHandler):
116 class KernelHandler(AuthenticatedHandler):
114
117
115 SUPPORTED_METHODS = ('DELETE')
118 SUPPORTED_METHODS = ('DELETE')
116
119
117 @web.authenticated
120 @web.authenticated
118 def delete(self, kernel_id):
121 def delete(self, kernel_id):
119 km = self.application.kernel_manager
122 km = self.application.kernel_manager
120 km.kill_kernel(kernel_id)
123 km.kill_kernel(kernel_id)
121 self.set_status(204)
124 self.set_status(204)
122 self.finish()
125 self.finish()
123
126
124
127
125 class KernelActionHandler(AuthenticatedHandler):
128 class KernelActionHandler(AuthenticatedHandler):
126
129
127 @web.authenticated
130 @web.authenticated
128 def post(self, kernel_id, action):
131 def post(self, kernel_id, action):
129 km = self.application.kernel_manager
132 km = self.application.kernel_manager
130 if action == 'interrupt':
133 if action == 'interrupt':
131 km.interrupt_kernel(kernel_id)
134 km.interrupt_kernel(kernel_id)
132 self.set_status(204)
135 self.set_status(204)
133 if action == 'restart':
136 if action == 'restart':
134 new_kernel_id = km.restart_kernel(kernel_id)
137 new_kernel_id = km.restart_kernel(kernel_id)
135 ws_url = self.application.ipython_app.get_ws_url()
138 ws_url = self.application.ipython_app.get_ws_url()
136 data = {'ws_url':ws_url,'kernel_id':new_kernel_id}
139 data = {'ws_url':ws_url,'kernel_id':new_kernel_id}
137 self.set_header('Location', '/'+new_kernel_id)
140 self.set_header('Location', '/'+new_kernel_id)
138 self.write(jsonapi.dumps(data))
141 self.write(jsonapi.dumps(data))
139 self.finish()
142 self.finish()
140
143
141
144
142 class ZMQStreamHandler(websocket.WebSocketHandler):
145 class ZMQStreamHandler(websocket.WebSocketHandler):
143
146
144 def _reserialize_reply(self, msg_list):
147 def _reserialize_reply(self, msg_list):
145 """Reserialize a reply message using JSON.
148 """Reserialize a reply message using JSON.
146
149
147 This takes the msg list from the ZMQ socket, unserializes it using
150 This takes the msg list from the ZMQ socket, unserializes it using
148 self.session and then serializes the result using JSON. This method
151 self.session and then serializes the result using JSON. This method
149 should be used by self._on_zmq_reply to build messages that can
152 should be used by self._on_zmq_reply to build messages that can
150 be sent back to the browser.
153 be sent back to the browser.
151 """
154 """
152 idents, msg_list = self.session.feed_identities(msg_list)
155 idents, msg_list = self.session.feed_identities(msg_list)
153 msg = self.session.unserialize(msg_list)
156 msg = self.session.unserialize(msg_list)
154 try:
157 try:
155 msg['header'].pop('date')
158 msg['header'].pop('date')
156 except KeyError:
159 except KeyError:
157 pass
160 pass
158 try:
161 try:
159 msg['parent_header'].pop('date')
162 msg['parent_header'].pop('date')
160 except KeyError:
163 except KeyError:
161 pass
164 pass
162 msg.pop('buffers')
165 msg.pop('buffers')
163 return jsonapi.dumps(msg)
166 return jsonapi.dumps(msg)
164
167
165 def _on_zmq_reply(self, msg_list):
168 def _on_zmq_reply(self, msg_list):
166 try:
169 try:
167 msg = self._reserialize_reply(msg_list)
170 msg = self._reserialize_reply(msg_list)
168 except:
171 except:
169 self.application.kernel_manager.log.critical("Malformed message: %r" % msg_list)
172 self.application.kernel_manager.log.critical("Malformed message: %r" % msg_list)
170 else:
173 else:
171 self.write_message(msg)
174 self.write_message(msg)
172
175
173 class AuthenticatedZMQStreamHandler(ZMQStreamHandler):
176 class AuthenticatedZMQStreamHandler(ZMQStreamHandler):
174 def open(self, kernel_id):
177 def open(self, kernel_id):
175 self.kernel_id = kernel_id.decode('ascii')
178 self.kernel_id = kernel_id.decode('ascii')
176 try:
179 try:
177 cfg = self.application.ipython_app.config
180 cfg = self.application.ipython_app.config
178 except AttributeError:
181 except AttributeError:
179 # protect from the case where this is run from something other than
182 # protect from the case where this is run from something other than
180 # the notebook app:
183 # the notebook app:
181 cfg = None
184 cfg = None
182 self.session = Session(config=cfg)
185 self.session = Session(config=cfg)
183 self.save_on_message = self.on_message
186 self.save_on_message = self.on_message
184 self.on_message = self.on_first_message
187 self.on_message = self.on_first_message
185
188
186 def get_current_user(self):
189 def get_current_user(self):
187 user_id = self.get_secure_cookie("user")
190 user_id = self.get_secure_cookie("user")
188 if user_id == '' or (user_id is None and not self.application.password):
191 if user_id == '' or (user_id is None and not self.application.password):
189 user_id = 'anonymous'
192 user_id = 'anonymous'
190 return user_id
193 return user_id
191
194
192 def _inject_cookie_message(self, msg):
195 def _inject_cookie_message(self, msg):
193 """Inject the first message, which is the document cookie,
196 """Inject the first message, which is the document cookie,
194 for authentication."""
197 for authentication."""
195 if isinstance(msg, unicode):
198 if isinstance(msg, unicode):
196 # Cookie can't constructor doesn't accept unicode strings for some reason
199 # Cookie can't constructor doesn't accept unicode strings for some reason
197 msg = msg.encode('utf8', 'replace')
200 msg = msg.encode('utf8', 'replace')
198 try:
201 try:
199 self._cookies = Cookie.SimpleCookie(msg)
202 self._cookies = Cookie.SimpleCookie(msg)
200 except:
203 except:
201 logging.warn("couldn't parse cookie string: %s",msg, exc_info=True)
204 logging.warn("couldn't parse cookie string: %s",msg, exc_info=True)
202
205
203 def on_first_message(self, msg):
206 def on_first_message(self, msg):
204 self._inject_cookie_message(msg)
207 self._inject_cookie_message(msg)
205 if self.get_current_user() is None:
208 if self.get_current_user() is None:
206 logging.warn("Couldn't authenticate WebSocket connection")
209 logging.warn("Couldn't authenticate WebSocket connection")
207 raise web.HTTPError(403)
210 raise web.HTTPError(403)
208 self.on_message = self.save_on_message
211 self.on_message = self.save_on_message
209
212
210
213
211 class IOPubHandler(AuthenticatedZMQStreamHandler):
214 class IOPubHandler(AuthenticatedZMQStreamHandler):
212
215
213 def initialize(self, *args, **kwargs):
216 def initialize(self, *args, **kwargs):
214 self._kernel_alive = True
217 self._kernel_alive = True
215 self._beating = False
218 self._beating = False
216 self.iopub_stream = None
219 self.iopub_stream = None
217 self.hb_stream = None
220 self.hb_stream = None
218
221
219 def on_first_message(self, msg):
222 def on_first_message(self, msg):
220 try:
223 try:
221 super(IOPubHandler, self).on_first_message(msg)
224 super(IOPubHandler, self).on_first_message(msg)
222 except web.HTTPError:
225 except web.HTTPError:
223 self.close()
226 self.close()
224 return
227 return
225 km = self.application.kernel_manager
228 km = self.application.kernel_manager
226 self.time_to_dead = km.time_to_dead
229 self.time_to_dead = km.time_to_dead
227 kernel_id = self.kernel_id
230 kernel_id = self.kernel_id
228 try:
231 try:
229 self.iopub_stream = km.create_iopub_stream(kernel_id)
232 self.iopub_stream = km.create_iopub_stream(kernel_id)
230 self.hb_stream = km.create_hb_stream(kernel_id)
233 self.hb_stream = km.create_hb_stream(kernel_id)
231 except web.HTTPError:
234 except web.HTTPError:
232 # WebSockets don't response to traditional error codes so we
235 # WebSockets don't response to traditional error codes so we
233 # close the connection.
236 # close the connection.
234 if not self.stream.closed():
237 if not self.stream.closed():
235 self.stream.close()
238 self.stream.close()
236 self.close()
239 self.close()
237 else:
240 else:
238 self.iopub_stream.on_recv(self._on_zmq_reply)
241 self.iopub_stream.on_recv(self._on_zmq_reply)
239 self.start_hb(self.kernel_died)
242 self.start_hb(self.kernel_died)
240
243
241 def on_message(self, msg):
244 def on_message(self, msg):
242 pass
245 pass
243
246
244 def on_close(self):
247 def on_close(self):
245 # This method can be called twice, once by self.kernel_died and once
248 # This method can be called twice, once by self.kernel_died and once
246 # from the WebSocket close event. If the WebSocket connection is
249 # from the WebSocket close event. If the WebSocket connection is
247 # closed before the ZMQ streams are setup, they could be None.
250 # closed before the ZMQ streams are setup, they could be None.
248 self.stop_hb()
251 self.stop_hb()
249 if self.iopub_stream is not None and not self.iopub_stream.closed():
252 if self.iopub_stream is not None and not self.iopub_stream.closed():
250 self.iopub_stream.on_recv(None)
253 self.iopub_stream.on_recv(None)
251 self.iopub_stream.close()
254 self.iopub_stream.close()
252 if self.hb_stream is not None and not self.hb_stream.closed():
255 if self.hb_stream is not None and not self.hb_stream.closed():
253 self.hb_stream.close()
256 self.hb_stream.close()
254
257
255 def start_hb(self, callback):
258 def start_hb(self, callback):
256 """Start the heartbeating and call the callback if the kernel dies."""
259 """Start the heartbeating and call the callback if the kernel dies."""
257 if not self._beating:
260 if not self._beating:
258 self._kernel_alive = True
261 self._kernel_alive = True
259
262
260 def ping_or_dead():
263 def ping_or_dead():
261 if self._kernel_alive:
264 if self._kernel_alive:
262 self._kernel_alive = False
265 self._kernel_alive = False
263 self.hb_stream.send(b'ping')
266 self.hb_stream.send(b'ping')
264 else:
267 else:
265 try:
268 try:
266 callback()
269 callback()
267 except:
270 except:
268 pass
271 pass
269 finally:
272 finally:
270 self._hb_periodic_callback.stop()
273 self._hb_periodic_callback.stop()
271
274
272 def beat_received(msg):
275 def beat_received(msg):
273 self._kernel_alive = True
276 self._kernel_alive = True
274
277
275 self.hb_stream.on_recv(beat_received)
278 self.hb_stream.on_recv(beat_received)
276 self._hb_periodic_callback = ioloop.PeriodicCallback(ping_or_dead, self.time_to_dead*1000)
279 self._hb_periodic_callback = ioloop.PeriodicCallback(ping_or_dead, self.time_to_dead*1000)
277 self._hb_periodic_callback.start()
280 self._hb_periodic_callback.start()
278 self._beating= True
281 self._beating= True
279
282
280 def stop_hb(self):
283 def stop_hb(self):
281 """Stop the heartbeating and cancel all related callbacks."""
284 """Stop the heartbeating and cancel all related callbacks."""
282 if self._beating:
285 if self._beating:
283 self._hb_periodic_callback.stop()
286 self._hb_periodic_callback.stop()
284 if not self.hb_stream.closed():
287 if not self.hb_stream.closed():
285 self.hb_stream.on_recv(None)
288 self.hb_stream.on_recv(None)
286
289
287 def kernel_died(self):
290 def kernel_died(self):
288 self.application.kernel_manager.delete_mapping_for_kernel(self.kernel_id)
291 self.application.kernel_manager.delete_mapping_for_kernel(self.kernel_id)
289 self.write_message(
292 self.write_message(
290 {'header': {'msg_type': 'status'},
293 {'header': {'msg_type': 'status'},
291 'parent_header': {},
294 'parent_header': {},
292 'content': {'execution_state':'dead'}
295 'content': {'execution_state':'dead'}
293 }
296 }
294 )
297 )
295 self.on_close()
298 self.on_close()
296
299
297
300
298 class ShellHandler(AuthenticatedZMQStreamHandler):
301 class ShellHandler(AuthenticatedZMQStreamHandler):
299
302
300 def initialize(self, *args, **kwargs):
303 def initialize(self, *args, **kwargs):
301 self.shell_stream = None
304 self.shell_stream = None
302
305
303 def on_first_message(self, msg):
306 def on_first_message(self, msg):
304 try:
307 try:
305 super(ShellHandler, self).on_first_message(msg)
308 super(ShellHandler, self).on_first_message(msg)
306 except web.HTTPError:
309 except web.HTTPError:
307 self.close()
310 self.close()
308 return
311 return
309 km = self.application.kernel_manager
312 km = self.application.kernel_manager
310 self.max_msg_size = km.max_msg_size
313 self.max_msg_size = km.max_msg_size
311 kernel_id = self.kernel_id
314 kernel_id = self.kernel_id
312 try:
315 try:
313 self.shell_stream = km.create_shell_stream(kernel_id)
316 self.shell_stream = km.create_shell_stream(kernel_id)
314 except web.HTTPError:
317 except web.HTTPError:
315 # WebSockets don't response to traditional error codes so we
318 # WebSockets don't response to traditional error codes so we
316 # close the connection.
319 # close the connection.
317 if not self.stream.closed():
320 if not self.stream.closed():
318 self.stream.close()
321 self.stream.close()
319 self.close()
322 self.close()
320 else:
323 else:
321 self.shell_stream.on_recv(self._on_zmq_reply)
324 self.shell_stream.on_recv(self._on_zmq_reply)
322
325
323 def on_message(self, msg):
326 def on_message(self, msg):
324 if len(msg) < self.max_msg_size:
327 if len(msg) < self.max_msg_size:
325 msg = jsonapi.loads(msg)
328 msg = jsonapi.loads(msg)
326 self.session.send(self.shell_stream, msg)
329 self.session.send(self.shell_stream, msg)
327
330
328 def on_close(self):
331 def on_close(self):
329 # Make sure the stream exists and is not already closed.
332 # Make sure the stream exists and is not already closed.
330 if self.shell_stream is not None and not self.shell_stream.closed():
333 if self.shell_stream is not None and not self.shell_stream.closed():
331 self.shell_stream.close()
334 self.shell_stream.close()
332
335
333
336
334 #-----------------------------------------------------------------------------
337 #-----------------------------------------------------------------------------
335 # Notebook web service handlers
338 # Notebook web service handlers
336 #-----------------------------------------------------------------------------
339 #-----------------------------------------------------------------------------
337
340
338 class NotebookRootHandler(AuthenticatedHandler):
341 class NotebookRootHandler(AuthenticatedHandler):
339
342
340 @web.authenticated
343 @web.authenticated
341 def get(self):
344 def get(self):
342 nbm = self.application.notebook_manager
345 nbm = self.application.notebook_manager
343 files = nbm.list_notebooks()
346 files = nbm.list_notebooks()
344 self.finish(jsonapi.dumps(files))
347 self.finish(jsonapi.dumps(files))
345
348
346 @web.authenticated
349 @web.authenticated
347 def post(self):
350 def post(self):
348 nbm = self.application.notebook_manager
351 nbm = self.application.notebook_manager
349 body = self.request.body.strip()
352 body = self.request.body.strip()
350 format = self.get_argument('format', default='json')
353 format = self.get_argument('format', default='json')
351 name = self.get_argument('name', default=None)
354 name = self.get_argument('name', default=None)
352 if body:
355 if body:
353 notebook_id = nbm.save_new_notebook(body, name=name, format=format)
356 notebook_id = nbm.save_new_notebook(body, name=name, format=format)
354 else:
357 else:
355 notebook_id = nbm.new_notebook()
358 notebook_id = nbm.new_notebook()
356 self.set_header('Location', '/'+notebook_id)
359 self.set_header('Location', '/'+notebook_id)
357 self.finish(jsonapi.dumps(notebook_id))
360 self.finish(jsonapi.dumps(notebook_id))
358
361
359
362
360 class NotebookHandler(AuthenticatedHandler):
363 class NotebookHandler(AuthenticatedHandler):
361
364
362 SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
365 SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
363
366
364 @web.authenticated
367 @web.authenticated
365 def get(self, notebook_id):
368 def get(self, notebook_id):
366 nbm = self.application.notebook_manager
369 nbm = self.application.notebook_manager
367 format = self.get_argument('format', default='json')
370 format = self.get_argument('format', default='json')
368 last_mod, name, data = nbm.get_notebook(notebook_id, format)
371 last_mod, name, data = nbm.get_notebook(notebook_id, format)
369 if format == u'json':
372 if format == u'json':
370 self.set_header('Content-Type', 'application/json')
373 self.set_header('Content-Type', 'application/json')
371 self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name)
374 self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name)
372 elif format == u'py':
375 elif format == u'py':
373 self.set_header('Content-Type', 'application/x-python')
376 self.set_header('Content-Type', 'application/x-python')
374 self.set_header('Content-Disposition','attachment; filename="%s.py"' % name)
377 self.set_header('Content-Disposition','attachment; filename="%s.py"' % name)
375 self.set_header('Last-Modified', last_mod)
378 self.set_header('Last-Modified', last_mod)
376 self.finish(data)
379 self.finish(data)
377
380
378 @web.authenticated
381 @web.authenticated
379 def put(self, notebook_id):
382 def put(self, notebook_id):
380 nbm = self.application.notebook_manager
383 nbm = self.application.notebook_manager
381 format = self.get_argument('format', default='json')
384 format = self.get_argument('format', default='json')
382 name = self.get_argument('name', default=None)
385 name = self.get_argument('name', default=None)
383 nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
386 nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
384 self.set_status(204)
387 self.set_status(204)
385 self.finish()
388 self.finish()
386
389
387 @web.authenticated
390 @web.authenticated
388 def delete(self, notebook_id):
391 def delete(self, notebook_id):
389 nbm = self.application.notebook_manager
392 nbm = self.application.notebook_manager
390 nbm.delete_notebook(notebook_id)
393 nbm.delete_notebook(notebook_id)
391 self.set_status(204)
394 self.set_status(204)
392 self.finish()
395 self.finish()
393
396
394 #-----------------------------------------------------------------------------
397 #-----------------------------------------------------------------------------
395 # RST web service handlers
398 # RST web service handlers
396 #-----------------------------------------------------------------------------
399 #-----------------------------------------------------------------------------
397
400
398
401
399 class RSTHandler(AuthenticatedHandler):
402 class RSTHandler(AuthenticatedHandler):
400
403
401 @web.authenticated
404 @web.authenticated
402 def post(self):
405 def post(self):
403 if publish_string is None:
406 if publish_string is None:
404 raise web.HTTPError(503, u'docutils not available')
407 raise web.HTTPError(503, u'docutils not available')
405 body = self.request.body.strip()
408 body = self.request.body.strip()
406 source = body
409 source = body
407 # template_path=os.path.join(os.path.dirname(__file__), u'templates', u'rst_template.html')
410 # template_path=os.path.join(os.path.dirname(__file__), u'templates', u'rst_template.html')
408 defaults = {'file_insertion_enabled': 0,
411 defaults = {'file_insertion_enabled': 0,
409 'raw_enabled': 0,
412 'raw_enabled': 0,
410 '_disable_config': 1,
413 '_disable_config': 1,
411 'stylesheet_path': 0
414 'stylesheet_path': 0
412 # 'template': template_path
415 # 'template': template_path
413 }
416 }
414 try:
417 try:
415 html = publish_string(source, writer_name='html',
418 html = publish_string(source, writer_name='html',
416 settings_overrides=defaults
419 settings_overrides=defaults
417 )
420 )
418 except:
421 except:
419 raise web.HTTPError(400, u'Invalid RST')
422 raise web.HTTPError(400, u'Invalid RST')
420 print html
423 print html
421 self.set_header('Content-Type', 'text/html')
424 self.set_header('Content-Type', 'text/html')
422 self.finish(html)
425 self.finish(html)
423
426
424
427
@@ -1,157 +1,157 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // SaveWidget
9 // SaveWidget
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13
13
14 var utils = IPython.utils;
14 var utils = IPython.utils;
15
15
16 var SaveWidget = function (selector) {
16 var SaveWidget = function (selector) {
17 this.selector = selector;
17 this.selector = selector;
18 this.notebook_name_blacklist_re = /[\/\\]/
18 this.notebook_name_blacklist_re = /[\/\\]/
19 this.last_saved_name = '';
19 this.last_saved_name = '';
20 if (this.selector !== undefined) {
20 if (this.selector !== undefined) {
21 this.element = $(selector);
21 this.element = $(selector);
22 this.style();
22 this.style();
23 this.bind_events();
23 this.bind_events();
24 }
24 }
25 };
25 };
26
26
27
27
28 SaveWidget.prototype.style = function () {
28 SaveWidget.prototype.style = function () {
29 this.element.find('input#notebook_name').addClass('ui-widget ui-widget-content');
29 this.element.find('input#notebook_name').addClass('ui-widget ui-widget-content');
30 this.element.find('input#notebook_name').attr('tabindex','1');
30 this.element.find('input#notebook_name').attr('tabindex','1');
31 this.element.find('button#save_notebook').button();
31 this.element.find('button#save_notebook').button();
32 this.element.find('button#save_notebook').attr('title', 'Save the Notebook');
32 this.element.find('button#save_notebook').attr('title', 'Save the Notebook');
33 var left_panel_width = $('div#left_panel').outerWidth();
33 var left_panel_width = $('div#left_panel').outerWidth();
34 var left_panel_splitter_width = $('div#left_panel_splitter').outerWidth();
34 var left_panel_splitter_width = $('div#left_panel_splitter').outerWidth();
35 $('span#save_widget').css({marginLeft:left_panel_width+left_panel_splitter_width});
35 $('span#save_widget').css({marginLeft:left_panel_width+left_panel_splitter_width});
36
36
37 };
37 };
38
38
39
39
40 SaveWidget.prototype.bind_events = function () {
40 SaveWidget.prototype.bind_events = function () {
41 var that = this;
41 var that = this;
42 this.element.find('button#save_notebook').click(function () {
42 this.element.find('button#save_notebook').click(function () {
43 that.save_notebook();
43 that.save_notebook();
44 });
44 });
45 this.element.find('input#notebook_name').keyup(function () {
45 this.element.find('input#notebook_name').keyup(function () {
46 that.is_renaming();
46 that.is_renaming();
47 });
47 });
48 };
48 };
49
49
50
50
51 SaveWidget.prototype.save_notebook = function () {
51 SaveWidget.prototype.save_notebook = function () {
52 IPython.notebook.save_notebook();
52 IPython.notebook.save_notebook();
53 };
53 };
54
54
55
55
56 SaveWidget.prototype.notebook_saved = function () {
56 SaveWidget.prototype.notebook_saved = function () {
57 this.set_document_title();
57 this.set_document_title();
58 this.last_saved_name = this.get_notebook_name();
58 this.last_saved_name = this.get_notebook_name();
59 };
59 };
60
60
61
61
62 SaveWidget.prototype.is_renaming = function () {
62 SaveWidget.prototype.is_renaming = function () {
63 if (this.get_notebook_name() !== this.last_saved_name) {
63 if (this.get_notebook_name() !== this.last_saved_name) {
64 this.status_rename();
64 this.status_rename();
65 } else {
65 } else {
66 this.status_save();
66 this.status_save();
67 };
67 };
68 };
68 };
69
69
70
70
71 SaveWidget.prototype.get_notebook_name = function () {
71 SaveWidget.prototype.get_notebook_name = function () {
72 return this.element.find('input#notebook_name').attr('value');
72 return this.element.find('input#notebook_name').attr('value');
73 }
73 }
74
74
75
75
76 SaveWidget.prototype.set_notebook_name = function (nbname) {
76 SaveWidget.prototype.set_notebook_name = function (nbname) {
77 this.element.find('input#notebook_name').attr('value',nbname);
77 this.element.find('input#notebook_name').attr('value',nbname);
78 this.set_document_title();
78 this.set_document_title();
79 this.last_saved_name = nbname;
79 this.last_saved_name = nbname;
80 }
80 }
81
81
82
82
83 SaveWidget.prototype.set_document_title = function () {
83 SaveWidget.prototype.set_document_title = function () {
84 nbname = this.get_notebook_name();
84 nbname = this.get_notebook_name();
85 document.title = 'IPy: ' + nbname;
85 document.title = 'IPy: ' + nbname;
86 };
86 };
87
87
88
88
89 SaveWidget.prototype.get_notebook_id = function () {
89 SaveWidget.prototype.get_notebook_id = function () {
90 return this.element.find('span#notebook_id').text()
90 return $('body').data('notebookId');
91 };
91 };
92
92
93
93
94 SaveWidget.prototype.update_url = function () {
94 SaveWidget.prototype.update_url = function () {
95 var notebook_id = this.get_notebook_id();
95 var notebook_id = this.get_notebook_id();
96 if (notebook_id !== '') {
96 if (notebook_id !== '') {
97 window.history.replaceState({}, '', notebook_id);
97 window.history.replaceState({}, '', notebook_id);
98 };
98 };
99 };
99 };
100
100
101
101
102 SaveWidget.prototype.test_notebook_name = function () {
102 SaveWidget.prototype.test_notebook_name = function () {
103 var nbname = this.get_notebook_name();
103 var nbname = this.get_notebook_name();
104 if (this.notebook_name_blacklist_re.test(nbname) == false) {
104 if (this.notebook_name_blacklist_re.test(nbname) == false) {
105 return true;
105 return true;
106 } else {
106 } else {
107 var bad_name = $('<div/>');
107 var bad_name = $('<div/>');
108 bad_name.html(
108 bad_name.html(
109 "The notebook name you entered (" +
109 "The notebook name you entered (" +
110 nbname +
110 nbname +
111 ") is not valid. Notebook names can contain any characters except / and \\."
111 ") is not valid. Notebook names can contain any characters except / and \\."
112 );
112 );
113 bad_name.dialog({title: 'Invalid name', modal: true});
113 bad_name.dialog({title: 'Invalid name', modal: true});
114 return false;
114 return false;
115 };
115 };
116 };
116 };
117
117
118
118
119 SaveWidget.prototype.reset_status = function () {
119 SaveWidget.prototype.reset_status = function () {
120 this.is_renaming();
120 this.is_renaming();
121 };
121 };
122
122
123
123
124 SaveWidget.prototype.status_save = function () {
124 SaveWidget.prototype.status_save = function () {
125 this.element.find('button#save_notebook').button('option', 'label', '<u>S</u>ave');
125 this.element.find('button#save_notebook').button('option', 'label', '<u>S</u>ave');
126 this.element.find('button#save_notebook').button('enable');
126 this.element.find('button#save_notebook').button('enable');
127 IPython.print_widget.enable();
127 IPython.print_widget.enable();
128 };
128 };
129
129
130
130
131 SaveWidget.prototype.status_saving = function () {
131 SaveWidget.prototype.status_saving = function () {
132 this.element.find('button#save_notebook').button('option', 'label', 'Saving');
132 this.element.find('button#save_notebook').button('option', 'label', 'Saving');
133 this.element.find('button#save_notebook').button('disable');
133 this.element.find('button#save_notebook').button('disable');
134 IPython.print_widget.disable();
134 IPython.print_widget.disable();
135 };
135 };
136
136
137
137
138 SaveWidget.prototype.status_loading = function () {
138 SaveWidget.prototype.status_loading = function () {
139 this.element.find('button#save_notebook').button('option', 'label', 'Loading');
139 this.element.find('button#save_notebook').button('option', 'label', 'Loading');
140 this.element.find('button#save_notebook').button('disable');
140 this.element.find('button#save_notebook').button('disable');
141 IPython.print_widget.disable();
141 IPython.print_widget.disable();
142 };
142 };
143
143
144
144
145 SaveWidget.prototype.status_rename = function () {
145 SaveWidget.prototype.status_rename = function () {
146 this.element.find('button#save_notebook').button('option', 'label', 'Rename');
146 this.element.find('button#save_notebook').button('option', 'label', 'Rename');
147 this.element.find('button#save_notebook').button('enable');
147 this.element.find('button#save_notebook').button('enable');
148 IPython.print_widget.enable();
148 IPython.print_widget.enable();
149 };
149 };
150
150
151
151
152 IPython.SaveWidget = SaveWidget;
152 IPython.SaveWidget = SaveWidget;
153
153
154 return IPython;
154 return IPython;
155
155
156 }(IPython));
156 }(IPython));
157
157
@@ -1,65 +1,65 b''
1 <!DOCTYPE HTML>
1 <!DOCTYPE HTML>
2 <html>
2 <html>
3
3
4 <head>
4 <head>
5 <meta charset="utf-8">
5 <meta charset="utf-8">
6
6
7 <title>IPython Notebook</title>
7 <title>IPython Notebook</title>
8
8
9 <link rel="stylesheet" href="static/jquery/css/themes/aristo/jquery-wijmo.css" type="text/css" />
9 <link rel="stylesheet" href="static/jquery/css/themes/aristo/jquery-wijmo.css" type="text/css" />
10 <!-- <link rel="stylesheet" href="static/jquery/css/themes/rocket/jquery-wijmo.css" type="text/css" /> -->
10 <!-- <link rel="stylesheet" href="static/jquery/css/themes/rocket/jquery-wijmo.css" type="text/css" /> -->
11 <!-- <link rel="stylesheet" href="static/jquery/css/themes/smoothness/jquery-ui-1.8.14.custom.css" type="text/css" />-->
11 <!-- <link rel="stylesheet" href="static/jquery/css/themes/smoothness/jquery-ui-1.8.14.custom.css" type="text/css" />-->
12
12
13 <link rel="stylesheet" href="static/css/boilerplate.css" type="text/css" />
13 <link rel="stylesheet" href="static/css/boilerplate.css" type="text/css" />
14 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
14 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
15 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
15 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
16 <link rel="stylesheet" href="static/css/nbbrowser.css" type="text/css" />
16 <link rel="stylesheet" href="static/css/nbbrowser.css" type="text/css" />
17
17
18 </head>
18 </head>
19
19
20 <body>
20 <body data-base-project-url={{base_project_url}} data-base-kernel-url={{base_kernel_url}}>
21
21
22 <div id="header">
22 <div id="header">
23 <span id="ipython_notebook"><h1>IPython Notebook</h1></span>
23 <span id="ipython_notebook"><h1>IPython Notebook</h1></span>
24 </div>
24 </div>
25
25
26 <div id="header_border"></div>
26 <div id="header_border"></div>
27
27
28 <div id="main_app">
28 <div id="main_app">
29
29
30 <div id="app_hbox">
30 <div id="app_hbox">
31
31
32 <div id="left_panel">
32 <div id="left_panel">
33 </div>
33 </div>
34
34
35 <div id="content_panel">
35 <div id="content_panel">
36 <div id="content_toolbar">
36 <div id="content_toolbar">
37 <span id="drag_info">Drag files onto the list to import notebooks.</span>
37 <span id="drag_info">Drag files onto the list to import notebooks.</span>
38 <span id="notebooks_buttons">
38 <span id="notebooks_buttons">
39 <button id="new_notebook">New Notebook</button>
39 <button id="new_notebook">New Notebook</button>
40 </span>
40 </span>
41 </div>
41 </div>
42 <div id="notebook_list">
42 <div id="notebook_list">
43 <div id="project_name"><h2>{{project}}</h2></div>
43 <div id="project_name"><h2>{{project}}</h2></div>
44 </div>
44 </div>
45
45
46 </div>
46 </div>
47
47
48 <div id="right_panel">
48 <div id="right_panel">
49 </div>
49 </div>
50
50
51 </div>
51 </div>
52
52
53 </div>
53 </div>
54
54
55 <script src="static/jquery/js/jquery-1.6.2.min.js" type="text/javascript" charset="utf-8"></script>
55 <script src="static/jquery/js/jquery-1.6.2.min.js" type="text/javascript" charset="utf-8"></script>
56 <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script>
56 <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script>
57 <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script>
57 <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script>
58 <script src="static/js/notebooklist.js" type="text/javascript" charset="utf-8"></script>
58 <script src="static/js/notebooklist.js" type="text/javascript" charset="utf-8"></script>
59 <script src="static/js/nbbrowser_main.js" type="text/javascript" charset="utf-8"></script>
59 <script src="static/js/nbbrowser_main.js" type="text/javascript" charset="utf-8"></script>
60
60
61 </body>
61 </body>
62
62
63 </html>
63 </html>
64
64
65
65
@@ -1,280 +1,280 b''
1 <!DOCTYPE HTML>
1 <!DOCTYPE HTML>
2 <html>
2 <html>
3
3
4 <head>
4 <head>
5 <meta charset="utf-8">
5 <meta charset="utf-8">
6
6
7 <title>IPython Notebook</title>
7 <title>IPython Notebook</title>
8
8
9 <link rel="stylesheet" href="static/jquery/css/themes/aristo/jquery-wijmo.css" type="text/css" />
9 <link rel="stylesheet" href="static/jquery/css/themes/aristo/jquery-wijmo.css" type="text/css" />
10 <!-- <link rel="stylesheet" href="static/jquery/css/themes/rocket/jquery-wijmo.css" type="text/css" /> -->
10 <!-- <link rel="stylesheet" href="static/jquery/css/themes/rocket/jquery-wijmo.css" type="text/css" /> -->
11 <!-- <link rel="stylesheet" href="static/jquery/css/themes/smoothness/jquery-ui-1.8.14.custom.css" type="text/css" />-->
11 <!-- <link rel="stylesheet" href="static/jquery/css/themes/smoothness/jquery-ui-1.8.14.custom.css" type="text/css" />-->
12
12
13 <!-- <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" charset="utf-8"></script> -->
13 <!-- <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" charset="utf-8"></script> -->
14 <script type='text/javascript' src='static/mathjax/MathJax.js?config=TeX-AMS_HTML' charset='utf-8'></script>
14 <script type='text/javascript' src='static/mathjax/MathJax.js?config=TeX-AMS_HTML' charset='utf-8'></script>
15 <script type="text/javascript">
15 <script type="text/javascript">
16 function CheckMathJax(){
16 function CheckMathJax(){
17 var div=document.getElementById("MathJaxFetchingWarning")
17 var div=document.getElementById("MathJaxFetchingWarning")
18 if(window.MathJax){
18 if(window.MathJax){
19 document.body.removeChild(div)
19 document.body.removeChild(div)
20 }
20 }
21 else{
21 else{
22 div.style.display = "block";
22 div.style.display = "block";
23 }
23 }
24 }
24 }
25 if (typeof MathJax == 'undefined') {
25 if (typeof MathJax == 'undefined') {
26 console.log("No local MathJax, loading from CDN");
26 console.log("No local MathJax, loading from CDN");
27 document.write(unescape("%3Cscript type='text/javascript' src='http://cdn.mathjax.org/mathjax/latest/MathJax.js%3Fconfig=TeX-AMS_HTML' charset='utf-8'%3E%3C/script%3E"));
27 document.write(unescape("%3Cscript type='text/javascript' src='http://cdn.mathjax.org/mathjax/latest/MathJax.js%3Fconfig=TeX-AMS_HTML' charset='utf-8'%3E%3C/script%3E"));
28 }else{
28 }else{
29 console.log("Using local MathJax");
29 console.log("Using local MathJax");
30 }
30 }
31 </script>
31 </script>
32
32
33 <link rel="stylesheet" href="static/codemirror/lib/codemirror.css">
33 <link rel="stylesheet" href="static/codemirror/lib/codemirror.css">
34 <link rel="stylesheet" href="static/codemirror/mode/markdown/markdown.css">
34 <link rel="stylesheet" href="static/codemirror/mode/markdown/markdown.css">
35 <link rel="stylesheet" href="static/codemirror/mode/rst/rst.css">
35 <link rel="stylesheet" href="static/codemirror/mode/rst/rst.css">
36 <link rel="stylesheet" href="static/codemirror/theme/ipython.css">
36 <link rel="stylesheet" href="static/codemirror/theme/ipython.css">
37 <link rel="stylesheet" href="static/codemirror/theme/default.css">
37 <link rel="stylesheet" href="static/codemirror/theme/default.css">
38
38
39 <link rel="stylesheet" href="static/prettify/prettify.css"/>
39 <link rel="stylesheet" href="static/prettify/prettify.css"/>
40
40
41 <link rel="stylesheet" href="static/css/boilerplate.css" type="text/css" />
41 <link rel="stylesheet" href="static/css/boilerplate.css" type="text/css" />
42 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
42 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
43 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
43 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
44 <link rel="stylesheet" href="static/css/notebook.css" type="text/css" />
44 <link rel="stylesheet" href="static/css/notebook.css" type="text/css" />
45 <link rel="stylesheet" href="static/css/renderedhtml.css" type="text/css" />
45 <link rel="stylesheet" href="static/css/renderedhtml.css" type="text/css" />
46
46
47
47
48 </head>
48 </head>
49
49
50 <body onload='CheckMathJax();'>
50 <body data-base-project-url={{base_project_url}} data-base-kernel-url={{base_kernel_url}}
51 data-notebook-id={{notebook_id}} onload='CheckMathJax();'>
51
52
52 <div id="header">
53 <div id="header">
53 <span id="ipython_notebook"><h1>IPython Notebook</h1></span>
54 <span id="ipython_notebook"><h1>IPython Notebook</h1></span>
54 <span id="save_widget">
55 <span id="save_widget">
55 <input type="text" id="notebook_name" size="20"></textarea>
56 <input type="text" id="notebook_name" size="20"></textarea>
56 <span id="notebook_id" style="display:none">{{notebook_id}}</span>
57 <button id="save_notebook"><u>S</u>ave</button>
57 <button id="save_notebook"><u>S</u>ave</button>
58 </span>
58 </span>
59 <span id="quick_help_area">
59 <span id="quick_help_area">
60 <button id="quick_help">Quick<u>H</u>elp</button>
60 <button id="quick_help">Quick<u>H</u>elp</button>
61 </span>
61 </span>
62 <span id="kernel_status">Idle</span>
62 <span id="kernel_status">Idle</span>
63 </div>
63 </div>
64
64
65 <div id="MathJaxFetchingWarning"
65 <div id="MathJaxFetchingWarning"
66 style="width:80%; margin:auto;padding-top:20%;text-align: justify; display:none">
66 style="width:80%; margin:auto;padding-top:20%;text-align: justify; display:none">
67 <p style="font-size:26px;">There was an issue trying to fetch MathJax.js
67 <p style="font-size:26px;">There was an issue trying to fetch MathJax.js
68 from the internet.</p>
68 from the internet.</p>
69
69
70 <p style="padding:0.2em"> With a working internet connection, you can run
70 <p style="padding:0.2em"> With a working internet connection, you can run
71 the following at a Python or IPython prompt, which will install a local
71 the following at a Python or IPython prompt, which will install a local
72 copy of MathJax:</p>
72 copy of MathJax:</p>
73
73
74 <pre style="background-color:lightblue;border:thin silver solid;padding:0.4em">
74 <pre style="background-color:lightblue;border:thin silver solid;padding:0.4em">
75 from IPython.external import mathjax; mathjax.install_mathjax()
75 from IPython.external import mathjax; mathjax.install_mathjax()
76 </pre>
76 </pre>
77 This will try to install MathJax into the directory where you installed
77 This will try to install MathJax into the directory where you installed
78 IPython. If you installed IPython to a location that requires
78 IPython. If you installed IPython to a location that requires
79 administrative privileges to write, you will need to make this call as
79 administrative privileges to write, you will need to make this call as
80 an administrator. On OSX/Linux/Unix, this can be done at the
80 an administrator. On OSX/Linux/Unix, this can be done at the
81 command-line via:
81 command-line via:
82 <pre style="background-color:lightblue;border:thin silver solid;padding:0.4em">
82 <pre style="background-color:lightblue;border:thin silver solid;padding:0.4em">
83 sudo python -c "from IPython.external import mathjax; mathjax.install_mathjax()"
83 sudo python -c "from IPython.external import mathjax; mathjax.install_mathjax()"
84 </pre>
84 </pre>
85 </p>
85 </p>
86 </div>
86 </div>
87
87
88 <div id="main_app">
88 <div id="main_app">
89
89
90 <div id="left_panel">
90 <div id="left_panel">
91
91
92 <div id="notebook_section">
92 <div id="notebook_section">
93 <h3 class="section_header">Notebook</h3>
93 <h3 class="section_header">Notebook</h3>
94 <div class="section_content">
94 <div class="section_content">
95 <div class="section_row">
95 <div class="section_row">
96 <span id="new_open" class="section_row_buttons">
96 <span id="new_open" class="section_row_buttons">
97 <button id="new_notebook">New</button>
97 <button id="new_notebook">New</button>
98 <button id="open_notebook">Open</button>
98 <button id="open_notebook">Open</button>
99 </span>
99 </span>
100 <span class="section_row_header">Actions</span>
100 <span class="section_row_header">Actions</span>
101 </div>
101 </div>
102 <div class="section_row">
102 <div class="section_row">
103 <span>
103 <span>
104 <select id="download_format">
104 <select id="download_format">
105 <option value="json">ipynb</option>
105 <option value="json">ipynb</option>
106 <option value="py">py</option>
106 <option value="py">py</option>
107 </select>
107 </select>
108 </span>
108 </span>
109 <span class="section_row_buttons">
109 <span class="section_row_buttons">
110 <button id="download_notebook">Download</button>
110 <button id="download_notebook">Download</button>
111 </span>
111 </span>
112 </div>
112 </div>
113 <div class="section_row">
113 <div class="section_row">
114 <span class="section_row_buttons">
114 <span class="section_row_buttons">
115 <span id="print_widget">
115 <span id="print_widget">
116 <button id="print_notebook">Print</button>
116 <button id="print_notebook">Print</button>
117 </span>
117 </span>
118 </span>
118 </span>
119 </div>
119 </div>
120 </div>
120 </div>
121 </div>
121 </div>
122
122
123 <div id="cell_section">
123 <div id="cell_section">
124 <h3 class="section_header">Cell</h3>
124 <h3 class="section_header">Cell</h3>
125 <div class="section_content">
125 <div class="section_content">
126 <div class="section_row">
126 <div class="section_row">
127 <span class="section_row_buttons">
127 <span class="section_row_buttons">
128 <button id="delete_cell"><u>D</u>elete</button>
128 <button id="delete_cell"><u>D</u>elete</button>
129 </span>
129 </span>
130 <span class="section_row_header">Actions</span>
130 <span class="section_row_header">Actions</span>
131 </div>
131 </div>
132 <div class="section_row">
132 <div class="section_row">
133 <span id="cell_type" class="section_row_buttons">
133 <span id="cell_type" class="section_row_buttons">
134 <button id="to_code"><u>C</u>ode</button>
134 <button id="to_code"><u>C</u>ode</button>
135 <!-- <button id="to_html">HTML</button>-->
135 <!-- <button id="to_html">HTML</button>-->
136 <button id="to_markdown"><u>M</u>arkdown</button>
136 <button id="to_markdown"><u>M</u>arkdown</button>
137 </span>
137 </span>
138 <span class="button_label">Format</span>
138 <span class="button_label">Format</span>
139 </div>
139 </div>
140 <div class="section_row">
140 <div class="section_row">
141 <span id="cell_output" class="section_row_buttons">
141 <span id="cell_output" class="section_row_buttons">
142 <button id="toggle_output"><u>T</u>oggle</button>
142 <button id="toggle_output"><u>T</u>oggle</button>
143 <button id="clear_all_output">ClearAll</button>
143 <button id="clear_all_output">ClearAll</button>
144 </span>
144 </span>
145 <span class="button_label">Output</span>
145 <span class="button_label">Output</span>
146 </div>
146 </div>
147 <div class="section_row">
147 <div class="section_row">
148 <span id="insert" class="section_row_buttons">
148 <span id="insert" class="section_row_buttons">
149 <button id="insert_cell_above"><u>A</u>bove</button>
149 <button id="insert_cell_above"><u>A</u>bove</button>
150 <button id="insert_cell_below"><u>B</u>elow</button>
150 <button id="insert_cell_below"><u>B</u>elow</button>
151 </span>
151 </span>
152 <span class="button_label">Insert</span>
152 <span class="button_label">Insert</span>
153 </div>
153 </div>
154 <div class="section_row">
154 <div class="section_row">
155 <span id="move" class="section_row_buttons">
155 <span id="move" class="section_row_buttons">
156 <button id="move_cell_up">Up</button>
156 <button id="move_cell_up">Up</button>
157 <button id="move_cell_down">Down</button>
157 <button id="move_cell_down">Down</button>
158 </span>
158 </span>
159 <span class="button_label">Move</span>
159 <span class="button_label">Move</span>
160 </div>
160 </div>
161 <div class="section_row">
161 <div class="section_row">
162 <span id="run_cells" class="section_row_buttons">
162 <span id="run_cells" class="section_row_buttons">
163 <button id="run_selected_cell">Selected</button>
163 <button id="run_selected_cell">Selected</button>
164 <button id="run_all_cells">All</button>
164 <button id="run_all_cells">All</button>
165 </span>
165 </span>
166 <span class="button_label">Run</span>
166 <span class="button_label">Run</span>
167 </div>
167 </div>
168 <div class="section_row">
168 <div class="section_row">
169 <span id="autoindent_span">
169 <span id="autoindent_span">
170 <input type="checkbox" id="autoindent" checked="true"></input>
170 <input type="checkbox" id="autoindent" checked="true"></input>
171 </span>
171 </span>
172 <span class="checkbox_label" id="autoindent_label">Autoindent:</span>
172 <span class="checkbox_label" id="autoindent_label">Autoindent:</span>
173 </div>
173 </div>
174 </div>
174 </div>
175 </div>
175 </div>
176
176
177 <div id="kernel_section">
177 <div id="kernel_section">
178 <h3 class="section_header">Kernel</h3>
178 <h3 class="section_header">Kernel</h3>
179 <div class="section_content">
179 <div class="section_content">
180 <div class="section_row">
180 <div class="section_row">
181 <span id="int_restart" class="section_row_buttons">
181 <span id="int_restart" class="section_row_buttons">
182 <button id="int_kernel"><u>I</u>nterrupt</button>
182 <button id="int_kernel"><u>I</u>nterrupt</button>
183 <button id="restart_kernel">Restart</button>
183 <button id="restart_kernel">Restart</button>
184 </span>
184 </span>
185 <span class="section_row_header">Actions</span>
185 <span class="section_row_header">Actions</span>
186 </div>
186 </div>
187 <div class="section_row">
187 <div class="section_row">
188 <span id="kernel_persist">
188 <span id="kernel_persist">
189 <input type="checkbox" id="kill_kernel"></input>
189 <input type="checkbox" id="kill_kernel"></input>
190 </span>
190 </span>
191 <span class="checkbox_label" id="kill_kernel_label">Kill kernel upon exit:</span>
191 <span class="checkbox_label" id="kill_kernel_label">Kill kernel upon exit:</span>
192 </div>
192 </div>
193 </div>
193 </div>
194 </div>
194 </div>
195
195
196 <div id="help_section">
196 <div id="help_section">
197 <h3 class="section_header">Help</h3>
197 <h3 class="section_header">Help</h3>
198 <div class="section_content">
198 <div class="section_content">
199 <div class="section_row">
199 <div class="section_row">
200 <span id="help_buttons0" class="section_row_buttons">
200 <span id="help_buttons0" class="section_row_buttons">
201 <a id="python_help" href="http://docs.python.org" target="_blank">Python</a>
201 <a id="python_help" href="http://docs.python.org" target="_blank">Python</a>
202 <a id="ipython_help" href="http://ipython.org/documentation.html" target="_blank">IPython</a>
202 <a id="ipython_help" href="http://ipython.org/documentation.html" target="_blank">IPython</a>
203 </span>
203 </span>
204 <span class="section_row_header">Links</span>
204 <span class="section_row_header">Links</span>
205 </div>
205 </div>
206 <div class="section_row">
206 <div class="section_row">
207 <span id="help_buttons1" class="section_row_buttons">
207 <span id="help_buttons1" class="section_row_buttons">
208 <a id="numpy_help" href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a>
208 <a id="numpy_help" href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a>
209 <a id="scipy_help" href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a>
209 <a id="scipy_help" href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a>
210 </span>
210 </span>
211 </div>
211 </div>
212 <div class="section_row">
212 <div class="section_row">
213 <span id="help_buttons2" class="section_row_buttons">
213 <span id="help_buttons2" class="section_row_buttons">
214 <a id="matplotlib_help" href="http://matplotlib.sourceforge.net/" target="_blank">MPL</a>
214 <a id="matplotlib_help" href="http://matplotlib.sourceforge.net/" target="_blank">MPL</a>
215 <a id="sympy_help" href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a>
215 <a id="sympy_help" href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a>
216 </span>
216 </span>
217 </div>
217 </div>
218 <div class="section_row">
218 <div class="section_row">
219 <span class="help_string">run selected cell</span>
219 <span class="help_string">run selected cell</span>
220 <span class="help_string_label">Shift-Enter :</span>
220 <span class="help_string_label">Shift-Enter :</span>
221 </div>
221 </div>
222 <div class="section_row">
222 <div class="section_row">
223 <span class="help_string">run selected cell in-place</span>
223 <span class="help_string">run selected cell in-place</span>
224 <span class="help_string_label">Ctrl-Enter :</span>
224 <span class="help_string_label">Ctrl-Enter :</span>
225 </div>
225 </div>
226 <div class="section_row">
226 <div class="section_row">
227 <span class="help_string">show keyboard shortcuts</span>
227 <span class="help_string">show keyboard shortcuts</span>
228 <span class="help_string_label">Ctrl-m h :</span>
228 <span class="help_string_label">Ctrl-m h :</span>
229 </div>
229 </div>
230 </div>
230 </div>
231 </div>
231 </div>
232
232
233 </div>
233 </div>
234 <div id="left_panel_splitter"></div>
234 <div id="left_panel_splitter"></div>
235 <div id="notebook_panel">
235 <div id="notebook_panel">
236 <div id="notebook"></div>
236 <div id="notebook"></div>
237 <div id="pager_splitter"></div>
237 <div id="pager_splitter"></div>
238 <div id="pager"></div>
238 <div id="pager"></div>
239 </div>
239 </div>
240
240
241 </div>
241 </div>
242
242
243 <script src="static/jquery/js/jquery-1.6.2.min.js" type="text/javascript" charset="utf-8"></script>
243 <script src="static/jquery/js/jquery-1.6.2.min.js" type="text/javascript" charset="utf-8"></script>
244 <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script>
244 <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script>
245 <script src="static/jquery/js/jquery.autogrow.js" type="text/javascript" charset="utf-8"></script>
245 <script src="static/jquery/js/jquery.autogrow.js" type="text/javascript" charset="utf-8"></script>
246
246
247 <script src="static/codemirror/lib/codemirror.js" charset="utf-8"></script>
247 <script src="static/codemirror/lib/codemirror.js" charset="utf-8"></script>
248 <script src="static/codemirror/mode/python/python.js" charset="utf-8"></script>
248 <script src="static/codemirror/mode/python/python.js" charset="utf-8"></script>
249 <script src="static/codemirror/mode/htmlmixed/htmlmixed.js" charset="utf-8"></script>
249 <script src="static/codemirror/mode/htmlmixed/htmlmixed.js" charset="utf-8"></script>
250 <script src="static/codemirror/mode/xml/xml.js" charset="utf-8"></script>
250 <script src="static/codemirror/mode/xml/xml.js" charset="utf-8"></script>
251 <script src="static/codemirror/mode/javascript/javascript.js" charset="utf-8"></script>
251 <script src="static/codemirror/mode/javascript/javascript.js" charset="utf-8"></script>
252 <script src="static/codemirror/mode/css/css.js" charset="utf-8"></script>
252 <script src="static/codemirror/mode/css/css.js" charset="utf-8"></script>
253 <script src="static/codemirror/mode/rst/rst.js" charset="utf-8"></script>
253 <script src="static/codemirror/mode/rst/rst.js" charset="utf-8"></script>
254 <script src="static/codemirror/mode/markdown/markdown.js" charset="utf-8"></script>
254 <script src="static/codemirror/mode/markdown/markdown.js" charset="utf-8"></script>
255
255
256 <script src="static/pagedown/Markdown.Converter.js" charset="utf-8"></script>
256 <script src="static/pagedown/Markdown.Converter.js" charset="utf-8"></script>
257
257
258 <script src="static/prettify/prettify.js" charset="utf-8"></script>
258 <script src="static/prettify/prettify.js" charset="utf-8"></script>
259
259
260 <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script>
260 <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script>
261 <script src="static/js/utils.js" type="text/javascript" charset="utf-8"></script>
261 <script src="static/js/utils.js" type="text/javascript" charset="utf-8"></script>
262 <script src="static/js/cell.js" type="text/javascript" charset="utf-8"></script>
262 <script src="static/js/cell.js" type="text/javascript" charset="utf-8"></script>
263 <script src="static/js/codecell.js" type="text/javascript" charset="utf-8"></script>
263 <script src="static/js/codecell.js" type="text/javascript" charset="utf-8"></script>
264 <script src="static/js/textcell.js" type="text/javascript" charset="utf-8"></script>
264 <script src="static/js/textcell.js" type="text/javascript" charset="utf-8"></script>
265 <script src="static/js/kernel.js" type="text/javascript" charset="utf-8"></script>
265 <script src="static/js/kernel.js" type="text/javascript" charset="utf-8"></script>
266 <script src="static/js/kernelstatus.js" type="text/javascript" charset="utf-8"></script>
266 <script src="static/js/kernelstatus.js" type="text/javascript" charset="utf-8"></script>
267 <script src="static/js/layout.js" type="text/javascript" charset="utf-8"></script>
267 <script src="static/js/layout.js" type="text/javascript" charset="utf-8"></script>
268 <script src="static/js/savewidget.js" type="text/javascript" charset="utf-8"></script>
268 <script src="static/js/savewidget.js" type="text/javascript" charset="utf-8"></script>
269 <script src="static/js/quickhelp.js" type="text/javascript" charset="utf-8"></script>
269 <script src="static/js/quickhelp.js" type="text/javascript" charset="utf-8"></script>
270 <script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script>
270 <script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script>
271 <script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script>
271 <script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script>
272 <script src="static/js/printwidget.js" type="text/javascript" charset="utf-8"></script>
272 <script src="static/js/printwidget.js" type="text/javascript" charset="utf-8"></script>
273 <script src="static/js/leftpanel.js" type="text/javascript" charset="utf-8"></script>
273 <script src="static/js/leftpanel.js" type="text/javascript" charset="utf-8"></script>
274 <script src="static/js/notebook.js" type="text/javascript" charset="utf-8"></script>
274 <script src="static/js/notebook.js" type="text/javascript" charset="utf-8"></script>
275 <script src="static/js/notebook_main.js" type="text/javascript" charset="utf-8"></script>
275 <script src="static/js/notebook_main.js" type="text/javascript" charset="utf-8"></script>
276
276
277
277
278 </body>
278 </body>
279
279
280 </html>
280 </html>
General Comments 0
You need to be logged in to leave comments. Login now