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