##// END OF EJS Templates
Merge pull request #5043 from minrk/base-url-unicode...
Brian E. Granger -
r15245:aa3ba1f8 merge
parent child Browse files
Show More
@@ -32,13 +32,13 b' class LoginHandler(IPythonHandler):'
32
32
33 def _render(self, message=None):
33 def _render(self, message=None):
34 self.write(self.render_template('login.html',
34 self.write(self.render_template('login.html',
35 next=url_escape(self.get_argument('next', default=self.base_project_url)),
35 next=url_escape(self.get_argument('next', default=self.base_url)),
36 message=message,
36 message=message,
37 ))
37 ))
38
38
39 def get(self):
39 def get(self):
40 if self.current_user:
40 if self.current_user:
41 self.redirect(self.get_argument('next', default=self.base_project_url))
41 self.redirect(self.get_argument('next', default=self.base_url))
42 else:
42 else:
43 self._render()
43 self._render()
44
44
@@ -51,7 +51,7 b' class LoginHandler(IPythonHandler):'
51 self._render(message={'error': 'Invalid password'})
51 self._render(message={'error': 'Invalid password'})
52 return
52 return
53
53
54 self.redirect(self.get_argument('next', default=self.base_project_url))
54 self.redirect(self.get_argument('next', default=self.base_url))
55
55
56
56
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
@@ -133,8 +133,8 b' class IPythonHandler(AuthenticatedHandler):'
133 return self.settings.get('mathjax_url', '')
133 return self.settings.get('mathjax_url', '')
134
134
135 @property
135 @property
136 def base_project_url(self):
136 def base_url(self):
137 return self.settings.get('base_project_url', '/')
137 return self.settings.get('base_url', '/')
138
138
139 @property
139 @property
140 def base_kernel_url(self):
140 def base_kernel_url(self):
@@ -180,7 +180,7 b' class IPythonHandler(AuthenticatedHandler):'
180 @property
180 @property
181 def template_namespace(self):
181 def template_namespace(self):
182 return dict(
182 return dict(
183 base_project_url=self.base_project_url,
183 base_url=self.base_url,
184 base_kernel_url=self.base_kernel_url,
184 base_kernel_url=self.base_kernel_url,
185 logged_in=self.logged_in,
185 logged_in=self.logged_in,
186 login_available=self.login_available,
186 login_available=self.login_available,
@@ -58,7 +58,7 b' class NotebookRedirectHandler(IPythonHandler):'
58 nbm = self.notebook_manager
58 nbm = self.notebook_manager
59 if nbm.path_exists(path):
59 if nbm.path_exists(path):
60 # it's a *directory*, redirect to /tree
60 # it's a *directory*, redirect to /tree
61 url = url_path_join(self.base_project_url, 'tree', path)
61 url = url_path_join(self.base_url, 'tree', path)
62 else:
62 else:
63 # otherwise, redirect to /files
63 # otherwise, redirect to /files
64 if '/files/' in path:
64 if '/files/' in path:
@@ -73,7 +73,7 b' class NotebookRedirectHandler(IPythonHandler):'
73 if not os.path.exists(files_path):
73 if not os.path.exists(files_path):
74 path = path.replace('/files/', '/', 1)
74 path = path.replace('/files/', '/', 1)
75
75
76 url = url_path_join(self.base_project_url, 'files', path)
76 url = url_path_join(self.base_url, 'files', path)
77 url = url_escape(url)
77 url = url_escape(url)
78 self.log.debug("Redirecting %s to %s", self.request.path, url)
78 self.log.debug("Redirecting %s to %s", self.request.path, url)
79 self.redirect(url)
79 self.redirect(url)
@@ -133,42 +133,42 b' def load_handlers(name):'
133 class NotebookWebApplication(web.Application):
133 class NotebookWebApplication(web.Application):
134
134
135 def __init__(self, ipython_app, kernel_manager, notebook_manager,
135 def __init__(self, ipython_app, kernel_manager, notebook_manager,
136 cluster_manager, session_manager, log, base_project_url,
136 cluster_manager, session_manager, log, base_url,
137 settings_overrides):
137 settings_overrides):
138
138
139 settings = self.init_settings(
139 settings = self.init_settings(
140 ipython_app, kernel_manager, notebook_manager, cluster_manager,
140 ipython_app, kernel_manager, notebook_manager, cluster_manager,
141 session_manager, log, base_project_url, settings_overrides)
141 session_manager, log, base_url, settings_overrides)
142 handlers = self.init_handlers(settings)
142 handlers = self.init_handlers(settings)
143
143
144 super(NotebookWebApplication, self).__init__(handlers, **settings)
144 super(NotebookWebApplication, self).__init__(handlers, **settings)
145
145
146 def init_settings(self, ipython_app, kernel_manager, notebook_manager,
146 def init_settings(self, ipython_app, kernel_manager, notebook_manager,
147 cluster_manager, session_manager, log, base_project_url,
147 cluster_manager, session_manager, log, base_url,
148 settings_overrides):
148 settings_overrides):
149 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
149 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
150 # base_project_url will always be unicode, which will in turn
150 # base_url will always be unicode, which will in turn
151 # make the patterns unicode, and ultimately result in unicode
151 # make the patterns unicode, and ultimately result in unicode
152 # keys in kwargs to handler._execute(**kwargs) in tornado.
152 # keys in kwargs to handler._execute(**kwargs) in tornado.
153 # This enforces that base_project_url be ascii in that situation.
153 # This enforces that base_url be ascii in that situation.
154 #
154 #
155 # Note that the URLs these patterns check against are escaped,
155 # Note that the URLs these patterns check against are escaped,
156 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
156 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
157 base_project_url = py3compat.unicode_to_str(base_project_url, 'ascii')
157 base_url = py3compat.unicode_to_str(base_url, 'ascii')
158 template_path = settings_overrides.get("template_path", os.path.join(os.path.dirname(__file__), "templates"))
158 template_path = settings_overrides.get("template_path", os.path.join(os.path.dirname(__file__), "templates"))
159 settings = dict(
159 settings = dict(
160 # basics
160 # basics
161 log_function=log_request,
161 log_function=log_request,
162 base_project_url=base_project_url,
162 base_url=base_url,
163 base_kernel_url=ipython_app.base_kernel_url,
163 base_kernel_url=ipython_app.base_kernel_url,
164 template_path=template_path,
164 template_path=template_path,
165 static_path=ipython_app.static_file_path,
165 static_path=ipython_app.static_file_path,
166 static_handler_class = FileFindHandler,
166 static_handler_class = FileFindHandler,
167 static_url_prefix = url_path_join(base_project_url,'/static/'),
167 static_url_prefix = url_path_join(base_url,'/static/'),
168
168
169 # authentication
169 # authentication
170 cookie_secret=ipython_app.cookie_secret,
170 cookie_secret=ipython_app.cookie_secret,
171 login_url=url_path_join(base_project_url,'/login'),
171 login_url=url_path_join(base_url,'/login'),
172 password=ipython_app.password,
172 password=ipython_app.password,
173
173
174 # managers
174 # managers
@@ -206,10 +206,10 b' class NotebookWebApplication(web.Application):'
206 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : settings['notebook_manager'].notebook_dir}),
206 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : settings['notebook_manager'].notebook_dir}),
207 (r"/nbextensions/(.*)", FileFindHandler, {'path' : settings['nbextensions_path']}),
207 (r"/nbextensions/(.*)", FileFindHandler, {'path' : settings['nbextensions_path']}),
208 ])
208 ])
209 # prepend base_project_url onto the patterns that we match
209 # prepend base_url onto the patterns that we match
210 new_handlers = []
210 new_handlers = []
211 for handler in handlers:
211 for handler in handlers:
212 pattern = url_path_join(settings['base_project_url'], handler[0])
212 pattern = url_path_join(settings['base_url'], handler[0])
213 new_handler = tuple([pattern] + list(handler[1:]))
213 new_handler = tuple([pattern] + list(handler[1:]))
214 new_handlers.append(new_handler)
214 new_handlers.append(new_handler)
215 # add 404 on the end, which will catch everything that falls through
215 # add 404 on the end, which will catch everything that falls through
@@ -414,17 +414,22 b' class NotebookApp(BaseIPythonApplication):'
414 if not new:
414 if not new:
415 self.mathjax_url = u''
415 self.mathjax_url = u''
416
416
417 base_project_url = Unicode('/', config=True,
417 base_url = Unicode('/', config=True,
418 help='''The base URL for the notebook server.
418 help='''The base URL for the notebook server.
419
419
420 Leading and trailing slashes can be omitted,
420 Leading and trailing slashes can be omitted,
421 and will automatically be added.
421 and will automatically be added.
422 ''')
422 ''')
423 def _base_project_url_changed(self, name, old, new):
423 def _base_url_changed(self, name, old, new):
424 if not new.startswith('/'):
424 if not new.startswith('/'):
425 self.base_project_url = '/'+new
425 self.base_url = '/'+new
426 elif not new.endswith('/'):
426 elif not new.endswith('/'):
427 self.base_project_url = new+'/'
427 self.base_url = new+'/'
428
429 base_project_url = Unicode('/', config=True, help="""DEPRECATED use base_url""")
430 def _base_project_url_changed(self, name, old, new):
431 self.log.warn("base_project_url is deprecated, use base_url")
432 self.base_url = new
428
433
429 base_kernel_url = Unicode('/', config=True,
434 base_kernel_url = Unicode('/', config=True,
430 help='''The base URL for the kernel server
435 help='''The base URL for the kernel server
@@ -473,12 +478,12 b' class NotebookApp(BaseIPythonApplication):'
473 if not self.enable_mathjax:
478 if not self.enable_mathjax:
474 return u''
479 return u''
475 static_url_prefix = self.webapp_settings.get("static_url_prefix",
480 static_url_prefix = self.webapp_settings.get("static_url_prefix",
476 url_path_join(self.base_project_url, "static")
481 url_path_join(self.base_url, "static")
477 )
482 )
478
483
479 # try local mathjax, either in nbextensions/mathjax or static/mathjax
484 # try local mathjax, either in nbextensions/mathjax or static/mathjax
480 for (url_prefix, search_path) in [
485 for (url_prefix, search_path) in [
481 (url_path_join(self.base_project_url, "nbextensions"), self.nbextensions_path),
486 (url_path_join(self.base_url, "nbextensions"), self.nbextensions_path),
482 (static_url_prefix, self.static_file_path),
487 (static_url_prefix, self.static_file_path),
483 ]:
488 ]:
484 self.log.debug("searching for local mathjax in %s", search_path)
489 self.log.debug("searching for local mathjax in %s", search_path)
@@ -586,7 +591,7 b' class NotebookApp(BaseIPythonApplication):'
586 self.web_app = NotebookWebApplication(
591 self.web_app = NotebookWebApplication(
587 self, self.kernel_manager, self.notebook_manager,
592 self, self.kernel_manager, self.notebook_manager,
588 self.cluster_manager, self.session_manager,
593 self.cluster_manager, self.session_manager,
589 self.log, self.base_project_url, self.webapp_settings
594 self.log, self.base_url, self.webapp_settings
590 )
595 )
591 if self.certfile:
596 if self.certfile:
592 ssl_options = dict(certfile=self.certfile)
597 ssl_options = dict(certfile=self.certfile)
@@ -639,7 +644,7 b' class NotebookApp(BaseIPythonApplication):'
639
644
640 def _url(self, ip):
645 def _url(self, ip):
641 proto = 'https' if self.certfile else 'http'
646 proto = 'https' if self.certfile else 'http'
642 return "%s://%s:%i%s" % (proto, ip, self.port, self.base_project_url)
647 return "%s://%s:%i%s" % (proto, ip, self.port, self.base_url)
643
648
644 def init_signal(self):
649 def init_signal(self):
645 if not sys.platform.startswith('win'):
650 if not sys.platform.startswith('win'):
@@ -745,7 +750,7 b' class NotebookApp(BaseIPythonApplication):'
745 'hostname': self.ip if self.ip else 'localhost',
750 'hostname': self.ip if self.ip else 'localhost',
746 'port': self.port,
751 'port': self.port,
747 'secure': bool(self.certfile),
752 'secure': bool(self.certfile),
748 'base_project_url': self.base_project_url,
753 'base_url': self.base_url,
749 'notebook_dir': os.path.abspath(self.notebook_manager.notebook_dir),
754 'notebook_dir': os.path.abspath(self.notebook_manager.notebook_dir),
750 }
755 }
751
756
@@ -47,7 +47,7 b' class NotebookHandler(IPythonHandler):'
47 The URL path of the notebook.
47 The URL path of the notebook.
48 """
48 """
49 return url_escape(url_path_join(
49 return url_escape(url_path_join(
50 self.base_project_url, 'api', 'notebooks', path, name
50 self.base_url, 'api', 'notebooks', path, name
51 ))
51 ))
52
52
53 def _finish_model(self, model, location=True):
53 def _finish_model(self, model, location=True):
@@ -242,7 +242,7 b' class NotebookCheckpointsHandler(IPythonHandler):'
242 nbm = self.notebook_manager
242 nbm = self.notebook_manager
243 checkpoint = nbm.create_checkpoint(name, path)
243 checkpoint = nbm.create_checkpoint(name, path)
244 data = json.dumps(checkpoint, default=date_default)
244 data = json.dumps(checkpoint, default=date_default)
245 location = url_path_join(self.base_project_url, 'api/notebooks',
245 location = url_path_join(self.base_url, 'api/notebooks',
246 path, name, 'checkpoints', checkpoint['id'])
246 path, name, 'checkpoints', checkpoint['id'])
247 self.set_header('Location', url_escape(location))
247 self.set_header('Location', url_escape(location))
248 self.set_status(201)
248 self.set_status(201)
@@ -10,10 +10,11 b''
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13
14
14 var LoginWidget = function (selector, options) {
15 var LoginWidget = function (selector, options) {
15 var options = options || {};
16 options = options || {};
16 this.base_url = options.baseProjectUrl || $('body').data('baseProjectUrl') ;
17 this.base_url = options.base_url || IPython.utils.get_body_data("baseUrl");
17 this.selector = selector;
18 this.selector = selector;
18 if (this.selector !== undefined) {
19 if (this.selector !== undefined) {
19 this.element = $(selector);
20 this.element = $(selector);
@@ -30,10 +31,16 b' var IPython = (function (IPython) {'
30 LoginWidget.prototype.bind_events = function () {
31 LoginWidget.prototype.bind_events = function () {
31 var that = this;
32 var that = this;
32 this.element.find("button#logout").click(function () {
33 this.element.find("button#logout").click(function () {
33 window.location = that.base_url+"logout";
34 window.location = IPythin.utils.url_join_encode(
35 that.base_url,
36 "logout"
37 );
34 });
38 });
35 this.element.find("button#login").click(function () {
39 this.element.find("button#login").click(function () {
36 window.location = that.base_url+"login";
40 window.location = IPythin.utils.url_join_encode(
41 that.base_url,
42 "login"
43 );
37 });
44 });
38 };
45 };
39
46
@@ -417,15 +417,29 b' IPython.utils = (function (IPython) {'
417 url = url + arguments[i];
417 url = url + arguments[i];
418 }
418 }
419 }
419 }
420 url = url.replace(/\/\/+/, '/');
420 return url;
421 return url;
421 };
422 };
422
423
424 var parse_url = function (url) {
425 // an `a` element with an href allows attr-access to the parsed segments of a URL
426 // a = parse_url("http://localhost:8888/path/name#hash")
427 // a.protocol = "http:"
428 // a.host = "localhost:8888"
429 // a.hostname = "localhost"
430 // a.port = 8888
431 // a.pathname = "/path/name"
432 // a.hash = "#hash"
433 var a = document.createElement("a");
434 a.href = url;
435 return a;
436 };
423
437
424 var encode_uri_components = function (uri) {
438 var encode_uri_components = function (uri) {
425 // encode just the components of a multi-segment uri,
439 // encode just the components of a multi-segment uri,
426 // leaving '/' separators
440 // leaving '/' separators
427 return uri.split('/').map(encodeURIComponent).join('/');
441 return uri.split('/').map(encodeURIComponent).join('/');
428 }
442 };
429
443
430 var url_join_encode = function () {
444 var url_join_encode = function () {
431 // join a sequence of url components with '/',
445 // join a sequence of url components with '/',
@@ -443,7 +457,15 b' IPython.utils = (function (IPython) {'
443 } else {
457 } else {
444 return [filename, ''];
458 return [filename, ''];
445 }
459 }
446 }
460 };
461
462
463 var get_body_data = function(key) {
464 // get a url-encoded item from body.data and decode it
465 // we should never have any encoded URLs anywhere else in code
466 // until we are building an actual request
467 return decodeURIComponent($('body').data(key));
468 };
447
469
448
470
449 // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
471 // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
@@ -508,6 +530,8 b' IPython.utils = (function (IPython) {'
508 fixCarriageReturn : fixCarriageReturn,
530 fixCarriageReturn : fixCarriageReturn,
509 autoLinkUrls : autoLinkUrls,
531 autoLinkUrls : autoLinkUrls,
510 points_to_pixels : points_to_pixels,
532 points_to_pixels : points_to_pixels,
533 get_body_data : get_body_data,
534 parse_url : parse_url,
511 url_path_join : url_path_join,
535 url_path_join : url_path_join,
512 url_join_encode : url_join_encode,
536 url_join_encode : url_join_encode,
513 encode_uri_components : encode_uri_components,
537 encode_uri_components : encode_uri_components,
@@ -8,7 +8,6 b''
8 //============================================================================
8 //============================================================================
9 // On document ready
9 // On document ready
10 //============================================================================
10 //============================================================================
11 "use strict";
12
11
13 // for the time beeing, we have to pass marked as a parameter here,
12 // for the time beeing, we have to pass marked as a parameter here,
14 // as injecting require.js make marked not to put itself in the globals,
13 // as injecting require.js make marked not to put itself in the globals,
@@ -18,28 +17,28 b" require(['components/marked/lib/marked',"
18 'notebook/js/widgets/init'],
17 'notebook/js/widgets/init'],
19
18
20 function (marked) {
19 function (marked) {
20 "use strict";
21
21
22 window.marked = marked
22 window.marked = marked;
23
23
24 // monkey patch CM to be able to syntax highlight cell magics
24 // monkey patch CM to be able to syntax highlight cell magics
25 // bug reported upstream,
25 // bug reported upstream,
26 // see https://github.com/marijnh/CodeMirror2/issues/670
26 // see https://github.com/marijnh/CodeMirror2/issues/670
27 if(CodeMirror.getMode(1,'text/plain').indent == undefined ){
27 if(CodeMirror.getMode(1,'text/plain').indent === undefined ){
28 console.log('patching CM for undefined indent');
28 console.log('patching CM for undefined indent');
29 CodeMirror.modes.null = function() {
29 CodeMirror.modes.null = function() {
30 return {token: function(stream) {stream.skipToEnd();},indent : function(){return 0}}
30 return {token: function(stream) {stream.skipToEnd();},indent : function(){return 0;}};
31 }
31 };
32 }
32 }
33
33
34 CodeMirror.patchedGetMode = function(config, mode){
34 CodeMirror.patchedGetMode = function(config, mode){
35 var cmmode = CodeMirror.getMode(config, mode);
35 var cmmode = CodeMirror.getMode(config, mode);
36 if(cmmode.indent == null)
36 if(cmmode.indent === null) {
37 {
38 console.log('patch mode "' , mode, '" on the fly');
37 console.log('patch mode "' , mode, '" on the fly');
39 cmmode.indent = function(){return 0};
38 cmmode.indent = function(){return 0;};
40 }
39 }
41 return cmmode;
40 return cmmode;
42 }
41 };
43 // end monkey patching CodeMirror
42 // end monkey patching CodeMirror
44
43
45 IPython.mathjaxutils.init();
44 IPython.mathjaxutils.init();
@@ -47,35 +46,32 b' function (marked) {'
47 $('#ipython-main-app').addClass('border-box-sizing');
46 $('#ipython-main-app').addClass('border-box-sizing');
48 $('div#notebook_panel').addClass('border-box-sizing');
47 $('div#notebook_panel').addClass('border-box-sizing');
49
48
50 var baseProjectUrl = $('body').data('baseProjectUrl');
49 var opts = {
51 var notebookPath = $('body').data('notebookPath');
50 base_url : IPython.utils.get_body_data("baseUrl"),
52 var notebookName = $('body').data('notebookName');
51 base_kernel_url : IPython.utils.get_body_data("baseKernelUrl"),
53 notebookName = decodeURIComponent(notebookName);
52 notebook_path : IPython.utils.get_body_data("notebookPath"),
54 notebookPath = decodeURIComponent(notebookPath);
53 notebook_name : IPython.utils.get_body_data('notebookName')
55 console.log(notebookName);
54 };
56 if (notebookPath == 'None'){
57 notebookPath = "";
58 }
59
55
60 IPython.page = new IPython.Page();
56 IPython.page = new IPython.Page();
61 IPython.layout_manager = new IPython.LayoutManager();
57 IPython.layout_manager = new IPython.LayoutManager();
62 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
58 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
63 IPython.quick_help = new IPython.QuickHelp();
59 IPython.quick_help = new IPython.QuickHelp();
64 IPython.login_widget = new IPython.LoginWidget('span#login_widget',{baseProjectUrl:baseProjectUrl});
60 IPython.login_widget = new IPython.LoginWidget('span#login_widget', opts);
65 IPython.notebook = new IPython.Notebook('div#notebook',{baseProjectUrl:baseProjectUrl, notebookPath:notebookPath, notebookName:notebookName});
61 IPython.notebook = new IPython.Notebook('div#notebook', opts);
66 IPython.keyboard_manager = new IPython.KeyboardManager();
62 IPython.keyboard_manager = new IPython.KeyboardManager();
67 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
63 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
68 IPython.menubar = new IPython.MenuBar('#menubar',{baseProjectUrl:baseProjectUrl, notebookPath: notebookPath})
64 IPython.menubar = new IPython.MenuBar('#menubar', opts);
69 IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container')
65 IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container');
70 IPython.tooltip = new IPython.Tooltip()
66 IPython.tooltip = new IPython.Tooltip();
71 IPython.notification_area = new IPython.NotificationArea('#notification_area')
67 IPython.notification_area = new IPython.NotificationArea('#notification_area');
72 IPython.notification_area.init_notification_widgets();
68 IPython.notification_area.init_notification_widgets();
73
69
74 IPython.layout_manager.do_resize();
70 IPython.layout_manager.do_resize();
75
71
76 $('body').append('<div id="fonttest"><pre><span id="test1">x</span>'+
72 $('body').append('<div id="fonttest"><pre><span id="test1">x</span>'+
77 '<span id="test2" style="font-weight: bold;">x</span>'+
73 '<span id="test2" style="font-weight: bold;">x</span>'+
78 '<span id="test3" style="font-style: italic;">x</span></pre></div>')
74 '<span id="test3" style="font-style: italic;">x</span></pre></div>');
79 var nh = $('#test1').innerHeight();
75 var nh = $('#test1').innerHeight();
80 var bh = $('#test2').innerHeight();
76 var bh = $('#test2').innerHeight();
81 var ih = $('#test3').innerHeight();
77 var ih = $('#test3').innerHeight();
@@ -101,7 +97,7 b' function (marked) {'
101
97
102 $([IPython.events]).on('notebook_loaded.Notebook', first_load);
98 $([IPython.events]).on('notebook_loaded.Notebook', first_load);
103 $([IPython.events]).trigger('app_initialized.NotebookApp');
99 $([IPython.events]).trigger('app_initialized.NotebookApp');
104 IPython.notebook.load_notebook(notebookName, notebookPath);
100 IPython.notebook.load_notebook(opts.notebook_name, opts.notebook_path);
105
101
106 if (marked) {
102 if (marked) {
107 marked.setOptions({
103 marked.setOptions({
@@ -121,8 +117,6 b' function (marked) {'
121 }
117 }
122 return highlighted.value;
118 return highlighted.value;
123 }
119 }
124 })
120 });
125 }
121 }
126 }
122 });
127
128 );
@@ -30,16 +30,14 b' var IPython = (function (IPython) {'
30 *
30 *
31 * @param selector {string} selector for the menubar element in DOM
31 * @param selector {string} selector for the menubar element in DOM
32 * @param {object} [options]
32 * @param {object} [options]
33 * @param [options.baseProjectUrl] {String} String to use for the
33 * @param [options.base_url] {String} String to use for the
34 * Base Project url, default would be to inspect
34 * base project url. Default is to inspect
35 * $('body').data('baseProjectUrl');
35 * $('body').data('baseUrl');
36 * does not support change for now is set through this option
36 * does not support change for now is set through this option
37 */
37 */
38 var MenuBar = function (selector, options) {
38 var MenuBar = function (selector, options) {
39 options = options || {};
39 options = options || {};
40 if (options.baseProjectUrl !== undefined) {
40 this.base_url = options.base_url || IPython.utils.get_body_data("baseUrl");
41 this._baseProjectUrl = options.baseProjectUrl;
42 }
43 this.selector = selector;
41 this.selector = selector;
44 if (this.selector !== undefined) {
42 if (this.selector !== undefined) {
45 this.element = $(selector);
43 this.element = $(selector);
@@ -48,16 +46,6 b' var IPython = (function (IPython) {'
48 }
46 }
49 };
47 };
50
48
51 MenuBar.prototype.baseProjectUrl = function(){
52 return this._baseProjectUrl || $('body').data('baseProjectUrl');
53 };
54
55 MenuBar.prototype.notebookPath = function() {
56 var path = $('body').data('notebookPath');
57 path = decodeURIComponent(path);
58 return path;
59 };
60
61 MenuBar.prototype.style = function () {
49 MenuBar.prototype.style = function () {
62 this.element.addClass('border-box-sizing');
50 this.element.addClass('border-box-sizing');
63 this.element.find("li").click(function (event, ui) {
51 this.element.find("li").click(function (event, ui) {
@@ -71,20 +59,21 b' var IPython = (function (IPython) {'
71
59
72 MenuBar.prototype._nbconvert = function (format, download) {
60 MenuBar.prototype._nbconvert = function (format, download) {
73 download = download || false;
61 download = download || false;
74 var notebook_name = IPython.notebook.get_notebook_name();
62 var notebook_path = IPython.notebook.notebook_path;
63 var notebook_name = IPython.notebook.notebook_name;
75 if (IPython.notebook.dirty) {
64 if (IPython.notebook.dirty) {
76 IPython.notebook.save_notebook({async : false});
65 IPython.notebook.save_notebook({async : false});
77 }
66 }
78 var url = utils.url_path_join(
67 var url = utils.url_join_encode(
79 this.baseProjectUrl(),
68 this.base_url,
80 'nbconvert',
69 'nbconvert',
81 format,
70 format,
82 this.notebookPath(),
71 notebook_path,
83 notebook_name + '.ipynb'
72 notebook_name
84 ) + "?download=" + download.toString();
73 ) + "?download=" + download.toString();
85
74
86 window.open(url);
75 window.open(url);
87 }
76 };
88
77
89 MenuBar.prototype.bind_events = function () {
78 MenuBar.prototype.bind_events = function () {
90 // File
79 // File
@@ -94,9 +83,9 b' var IPython = (function (IPython) {'
94 });
83 });
95 this.element.find('#open_notebook').click(function () {
84 this.element.find('#open_notebook').click(function () {
96 window.open(utils.url_join_encode(
85 window.open(utils.url_join_encode(
97 that.baseProjectUrl(),
86 IPython.notebook.base_url,
98 'tree',
87 'tree',
99 that.notebookPath()
88 IPython.notebook.notebook_path
100 ));
89 ));
101 });
90 });
102 this.element.find('#copy_notebook').click(function () {
91 this.element.find('#copy_notebook').click(function () {
@@ -104,16 +93,18 b' var IPython = (function (IPython) {'
104 return false;
93 return false;
105 });
94 });
106 this.element.find('#download_ipynb').click(function () {
95 this.element.find('#download_ipynb').click(function () {
107 var notebook_name = IPython.notebook.get_notebook_name();
96 var base_url = IPython.notebook.base_url;
97 var notebook_path = IPython.notebook.notebook_path;
98 var notebook_name = IPython.notebook.notebook_name;
108 if (IPython.notebook.dirty) {
99 if (IPython.notebook.dirty) {
109 IPython.notebook.save_notebook({async : false});
100 IPython.notebook.save_notebook({async : false});
110 }
101 }
111
102
112 var url = utils.url_join_encode(
103 var url = utils.url_join_encode(
113 that.baseProjectUrl(),
104 base_url,
114 'files',
105 'files',
115 that.notebookPath(),
106 notebook_path,
116 notebook_name + '.ipynb'
107 notebook_name
117 );
108 );
118 window.location.assign(url);
109 window.location.assign(url);
119 });
110 });
@@ -23,10 +23,10 b' var IPython = (function (IPython) {'
23 * @param {Object} [options] A config object
23 * @param {Object} [options] A config object
24 */
24 */
25 var Notebook = function (selector, options) {
25 var Notebook = function (selector, options) {
26 var options = options || {};
26 this.options = options = options || {};
27 this._baseProjectUrl = options.baseProjectUrl;
27 this.base_url = options.base_url;
28 this.notebook_path = options.notebookPath;
28 this.notebook_path = options.notebook_path;
29 this.notebook_name = options.notebookName;
29 this.notebook_name = options.notebook_name;
30 this.element = $(selector);
30 this.element = $(selector);
31 this.element.scroll();
31 this.element.scroll();
32 this.element.data("notebook", this);
32 this.element.data("notebook", this);
@@ -53,8 +53,8 b' var IPython = (function (IPython) {'
53 // single worksheet for now
53 // single worksheet for now
54 this.worksheet_metadata = {};
54 this.worksheet_metadata = {};
55 this.notebook_name_blacklist_re = /[\/\\:]/;
55 this.notebook_name_blacklist_re = /[\/\\:]/;
56 this.nbformat = 3 // Increment this when changing the nbformat
56 this.nbformat = 3; // Increment this when changing the nbformat
57 this.nbformat_minor = 0 // Increment this when changing the nbformat
57 this.nbformat_minor = 0; // Increment this when changing the nbformat
58 this.style();
58 this.style();
59 this.create_elements();
59 this.create_elements();
60 this.bind_events();
60 this.bind_events();
@@ -70,24 +70,6 b' var IPython = (function (IPython) {'
70 };
70 };
71
71
72 /**
72 /**
73 * Get the root URL of the notebook server.
74 *
75 * @method baseProjectUrl
76 * @return {String} The base project URL
77 */
78 Notebook.prototype.baseProjectUrl = function() {
79 return this._baseProjectUrl || $('body').data('baseProjectUrl');
80 };
81
82 Notebook.prototype.notebookName = function() {
83 return $('body').data('notebookName');
84 };
85
86 Notebook.prototype.notebookPath = function() {
87 return $('body').data('notebookPath');
88 };
89
90 /**
91 * Create an HTML and CSS representation of the notebook.
73 * Create an HTML and CSS representation of the notebook.
92 *
74 *
93 * @method create_elements
75 * @method create_elements
@@ -163,7 +145,7 b' var IPython = (function (IPython) {'
163 };
145 };
164
146
165 this.element.bind('collapse_pager', function (event, extrap) {
147 this.element.bind('collapse_pager', function (event, extrap) {
166 var time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
148 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
167 collapse_time(time);
149 collapse_time(time);
168 });
150 });
169
151
@@ -176,7 +158,7 b' var IPython = (function (IPython) {'
176 };
158 };
177
159
178 this.element.bind('expand_pager', function (event, extrap) {
160 this.element.bind('expand_pager', function (event, extrap) {
179 var time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
161 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
180 expand_time(time);
162 expand_time(time);
181 });
163 });
182
164
@@ -205,7 +187,7 b' var IPython = (function (IPython) {'
205 } else {
187 } else {
206 return "Unsaved changes will be lost.";
188 return "Unsaved changes will be lost.";
207 }
189 }
208 };
190 }
209 // Null is the *only* return value that will make the browser not
191 // Null is the *only* return value that will make the browser not
210 // pop up the "don't leave" dialog.
192 // pop up the "don't leave" dialog.
211 return null;
193 return null;
@@ -237,7 +219,7 b' var IPython = (function (IPython) {'
237 */
219 */
238 Notebook.prototype.scroll_to_cell = function (cell_number, time) {
220 Notebook.prototype.scroll_to_cell = function (cell_number, time) {
239 var cells = this.get_cells();
221 var cells = this.get_cells();
240 var time = time || 0;
222 time = time || 0;
241 cell_number = Math.min(cells.length-1,cell_number);
223 cell_number = Math.min(cells.length-1,cell_number);
242 cell_number = Math.max(0 ,cell_number);
224 cell_number = Math.max(0 ,cell_number);
243 var scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ;
225 var scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ;
@@ -349,7 +331,7 b' var IPython = (function (IPython) {'
349 result = ce.data('cell');
331 result = ce.data('cell');
350 }
332 }
351 return result;
333 return result;
352 }
334 };
353
335
354 /**
336 /**
355 * Get the cell below a given cell.
337 * Get the cell below a given cell.
@@ -365,7 +347,7 b' var IPython = (function (IPython) {'
365 result = this.get_cell(index+1);
347 result = this.get_cell(index+1);
366 }
348 }
367 return result;
349 return result;
368 }
350 };
369
351
370 /**
352 /**
371 * Get the cell above a given cell.
353 * Get the cell above a given cell.
@@ -383,7 +365,7 b' var IPython = (function (IPython) {'
383 result = this.get_cell(index-1);
365 result = this.get_cell(index-1);
384 }
366 }
385 return result;
367 return result;
386 }
368 };
387
369
388 /**
370 /**
389 * Get the numeric index of a given cell.
371 * Get the numeric index of a given cell.
@@ -397,7 +379,7 b' var IPython = (function (IPython) {'
397 this.get_cell_elements().filter(function (index) {
379 this.get_cell_elements().filter(function (index) {
398 if ($(this).data("cell") === cell) {
380 if ($(this).data("cell") === cell) {
399 result = index;
381 result = index;
400 };
382 }
401 });
383 });
402 return result;
384 return result;
403 };
385 };
@@ -444,8 +426,8 b' var IPython = (function (IPython) {'
444 return true;
426 return true;
445 } else {
427 } else {
446 return false;
428 return false;
447 };
429 }
448 }
430 };
449
431
450 /**
432 /**
451 * Get the index of the currently selected cell.
433 * Get the index of the currently selected cell.
@@ -458,7 +440,7 b' var IPython = (function (IPython) {'
458 this.get_cell_elements().filter(function (index) {
440 this.get_cell_elements().filter(function (index) {
459 if ($(this).data("cell").selected === true) {
441 if ($(this).data("cell").selected === true) {
460 result = index;
442 result = index;
461 };
443 }
462 });
444 });
463 return result;
445 return result;
464 };
446 };
@@ -475,11 +457,11 b' var IPython = (function (IPython) {'
475 */
457 */
476 Notebook.prototype.select = function (index) {
458 Notebook.prototype.select = function (index) {
477 if (this.is_valid_cell_index(index)) {
459 if (this.is_valid_cell_index(index)) {
478 var sindex = this.get_selected_index()
460 var sindex = this.get_selected_index();
479 if (sindex !== null && index !== sindex) {
461 if (sindex !== null && index !== sindex) {
480 this.command_mode();
462 this.command_mode();
481 this.get_cell(sindex).unselect();
463 this.get_cell(sindex).unselect();
482 };
464 }
483 var cell = this.get_cell(index);
465 var cell = this.get_cell(index);
484 cell.select();
466 cell.select();
485 if (cell.cell_type === 'heading') {
467 if (cell.cell_type === 'heading') {
@@ -490,8 +472,8 b' var IPython = (function (IPython) {'
490 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
472 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
491 {'cell_type':cell.cell_type}
473 {'cell_type':cell.cell_type}
492 );
474 );
493 };
475 }
494 };
476 }
495 return this;
477 return this;
496 };
478 };
497
479
@@ -527,7 +509,7 b' var IPython = (function (IPython) {'
527 this.get_cell_elements().filter(function (index) {
509 this.get_cell_elements().filter(function (index) {
528 if ($(this).data("cell").mode === 'edit') {
510 if ($(this).data("cell").mode === 'edit') {
529 result = index;
511 result = index;
530 };
512 }
531 });
513 });
532 return result;
514 return result;
533 };
515 };
@@ -539,10 +521,10 b' var IPython = (function (IPython) {'
539 var cell = this.get_cell(index);
521 var cell = this.get_cell(index);
540 if (cell) {
522 if (cell) {
541 cell.command_mode();
523 cell.command_mode();
542 };
524 }
543 this.mode = 'command';
525 this.mode = 'command';
544 IPython.keyboard_manager.command_mode();
526 IPython.keyboard_manager.command_mode();
545 };
527 }
546 };
528 };
547
529
548 Notebook.prototype.edit_mode = function () {
530 Notebook.prototype.edit_mode = function () {
@@ -555,7 +537,7 b' var IPython = (function (IPython) {'
555 this.mode = 'edit';
537 this.mode = 'edit';
556 IPython.keyboard_manager.edit_mode();
538 IPython.keyboard_manager.edit_mode();
557 cell.edit_mode();
539 cell.edit_mode();
558 };
540 }
559 };
541 };
560
542
561 Notebook.prototype.focus_cell = function () {
543 Notebook.prototype.focus_cell = function () {
@@ -584,9 +566,9 b' var IPython = (function (IPython) {'
584 this.select(i-1);
566 this.select(i-1);
585 var cell = this.get_selected_cell();
567 var cell = this.get_selected_cell();
586 cell.focus_cell();
568 cell.focus_cell();
587 };
569 }
588 this.set_dirty(true);
570 this.set_dirty(true);
589 };
571 }
590 return this;
572 return this;
591 };
573 };
592
574
@@ -609,8 +591,8 b' var IPython = (function (IPython) {'
609 this.select(i+1);
591 this.select(i+1);
610 var cell = this.get_selected_cell();
592 var cell = this.get_selected_cell();
611 cell.focus_cell();
593 cell.focus_cell();
612 };
594 }
613 };
595 }
614 this.set_dirty();
596 this.set_dirty();
615 return this;
597 return this;
616 };
598 };
@@ -650,10 +632,10 b' var IPython = (function (IPython) {'
650 this.select(i);
632 this.select(i);
651 this.undelete_index = i;
633 this.undelete_index = i;
652 this.undelete_below = false;
634 this.undelete_below = false;
653 };
635 }
654 $([IPython.events]).trigger('delete.Cell', {'cell': cell, 'index': i});
636 $([IPython.events]).trigger('delete.Cell', {'cell': cell, 'index': i});
655 this.set_dirty(true);
637 this.set_dirty(true);
656 };
638 }
657 return this;
639 return this;
658 };
640 };
659
641
@@ -691,7 +673,7 b' var IPython = (function (IPython) {'
691 this.undelete_index = null;
673 this.undelete_index = null;
692 }
674 }
693 $('#undelete_cell').addClass('disabled');
675 $('#undelete_cell').addClass('disabled');
694 }
676 };
695
677
696 /**
678 /**
697 * Insert a cell so that after insertion the cell is at given index.
679 * Insert a cell so that after insertion the cell is at given index.
@@ -709,8 +691,8 b' var IPython = (function (IPython) {'
709 Notebook.prototype.insert_cell_at_index = function(type, index){
691 Notebook.prototype.insert_cell_at_index = function(type, index){
710
692
711 var ncells = this.ncells();
693 var ncells = this.ncells();
712 var index = Math.min(index,ncells);
694 index = Math.min(index,ncells);
713 index = Math.max(index,0);
695 index = Math.max(index,0);
714 var cell = null;
696 var cell = null;
715
697
716 if (ncells === 0 || this.is_valid_cell_index(index) || index === ncells) {
698 if (ncells === 0 || this.is_valid_cell_index(index) || index === ncells) {
@@ -850,8 +832,8 b' var IPython = (function (IPython) {'
850 source_element.remove();
832 source_element.remove();
851 this.select(i);
833 this.select(i);
852 this.set_dirty(true);
834 this.set_dirty(true);
853 };
835 }
854 };
836 }
855 };
837 };
856
838
857 /**
839 /**
@@ -870,7 +852,7 b' var IPython = (function (IPython) {'
870 var text = source_cell.get_text();
852 var text = source_cell.get_text();
871 if (text === source_cell.placeholder) {
853 if (text === source_cell.placeholder) {
872 text = '';
854 text = '';
873 };
855 }
874 // We must show the editor before setting its contents
856 // We must show the editor before setting its contents
875 target_cell.unrender();
857 target_cell.unrender();
876 target_cell.set_text(text);
858 target_cell.set_text(text);
@@ -883,8 +865,8 b' var IPython = (function (IPython) {'
883 target_cell.render();
865 target_cell.render();
884 }
866 }
885 this.set_dirty(true);
867 this.set_dirty(true);
886 };
868 }
887 };
869 }
888 };
870 };
889
871
890 /**
872 /**
@@ -904,7 +886,7 b' var IPython = (function (IPython) {'
904 var text = source_cell.get_text();
886 var text = source_cell.get_text();
905 if (text === source_cell.placeholder) {
887 if (text === source_cell.placeholder) {
906 text = '';
888 text = '';
907 };
889 }
908 // We must show the editor before setting its contents
890 // We must show the editor before setting its contents
909 target_cell.unrender();
891 target_cell.unrender();
910 target_cell.set_text(text);
892 target_cell.set_text(text);
@@ -914,8 +896,8 b' var IPython = (function (IPython) {'
914 source_element.remove();
896 source_element.remove();
915 this.select(i);
897 this.select(i);
916 this.set_dirty(true);
898 this.set_dirty(true);
917 };
899 }
918 };
900 }
919 };
901 };
920
902
921 /**
903 /**
@@ -939,7 +921,7 b' var IPython = (function (IPython) {'
939 var text = source_cell.get_text();
921 var text = source_cell.get_text();
940 if (text === source_cell.placeholder) {
922 if (text === source_cell.placeholder) {
941 text = '';
923 text = '';
942 };
924 }
943 // We must show the editor before setting its contents
925 // We must show the editor before setting its contents
944 target_cell.set_level(level);
926 target_cell.set_level(level);
945 target_cell.unrender();
927 target_cell.unrender();
@@ -952,12 +934,12 b' var IPython = (function (IPython) {'
952 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
934 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
953 target_cell.render();
935 target_cell.render();
954 }
936 }
955 };
937 }
956 this.set_dirty(true);
938 this.set_dirty(true);
957 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
939 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
958 {'cell_type':'heading',level:level}
940 {'cell_type':'heading',level:level}
959 );
941 );
960 };
942 }
961 };
943 };
962
944
963
945
@@ -978,7 +960,7 b' var IPython = (function (IPython) {'
978 $('#paste_cell_below').removeClass('disabled')
960 $('#paste_cell_below').removeClass('disabled')
979 .on('click', function () {that.paste_cell_below();});
961 .on('click', function () {that.paste_cell_below();});
980 this.paste_enabled = true;
962 this.paste_enabled = true;
981 };
963 }
982 };
964 };
983
965
984 /**
966 /**
@@ -992,7 +974,7 b' var IPython = (function (IPython) {'
992 $('#paste_cell_above').addClass('disabled').off('click');
974 $('#paste_cell_above').addClass('disabled').off('click');
993 $('#paste_cell_below').addClass('disabled').off('click');
975 $('#paste_cell_below').addClass('disabled').off('click');
994 this.paste_enabled = false;
976 this.paste_enabled = false;
995 };
977 }
996 };
978 };
997
979
998 /**
980 /**
@@ -1003,7 +985,7 b' var IPython = (function (IPython) {'
1003 Notebook.prototype.cut_cell = function () {
985 Notebook.prototype.cut_cell = function () {
1004 this.copy_cell();
986 this.copy_cell();
1005 this.delete_cell();
987 this.delete_cell();
1006 }
988 };
1007
989
1008 /**
990 /**
1009 * Copy a cell.
991 * Copy a cell.
@@ -1029,7 +1011,7 b' var IPython = (function (IPython) {'
1029 var old_cell = this.get_next_cell(new_cell);
1011 var old_cell = this.get_next_cell(new_cell);
1030 this.delete_cell(this.find_cell_index(old_cell));
1012 this.delete_cell(this.find_cell_index(old_cell));
1031 this.select(this.find_cell_index(new_cell));
1013 this.select(this.find_cell_index(new_cell));
1032 };
1014 }
1033 };
1015 };
1034
1016
1035 /**
1017 /**
@@ -1043,7 +1025,7 b' var IPython = (function (IPython) {'
1043 var new_cell = this.insert_cell_above(cell_data.cell_type);
1025 var new_cell = this.insert_cell_above(cell_data.cell_type);
1044 new_cell.fromJSON(cell_data);
1026 new_cell.fromJSON(cell_data);
1045 new_cell.focus_cell();
1027 new_cell.focus_cell();
1046 };
1028 }
1047 };
1029 };
1048
1030
1049 /**
1031 /**
@@ -1057,7 +1039,7 b' var IPython = (function (IPython) {'
1057 var new_cell = this.insert_cell_below(cell_data.cell_type);
1039 var new_cell = this.insert_cell_below(cell_data.cell_type);
1058 new_cell.fromJSON(cell_data);
1040 new_cell.fromJSON(cell_data);
1059 new_cell.focus_cell();
1041 new_cell.focus_cell();
1060 };
1042 }
1061 };
1043 };
1062
1044
1063 // Split/merge
1045 // Split/merge
@@ -1088,7 +1070,7 b' var IPython = (function (IPython) {'
1088 new_cell.unrender();
1070 new_cell.unrender();
1089 new_cell.set_text(texta);
1071 new_cell.set_text(texta);
1090 }
1072 }
1091 };
1073 }
1092 };
1074 };
1093
1075
1094 /**
1076 /**
@@ -1122,10 +1104,10 b' var IPython = (function (IPython) {'
1122 // that of the original selected cell;
1104 // that of the original selected cell;
1123 cell.render();
1105 cell.render();
1124 }
1106 }
1125 };
1107 }
1126 this.delete_cell(index-1);
1108 this.delete_cell(index-1);
1127 this.select(this.find_cell_index(cell));
1109 this.select(this.find_cell_index(cell));
1128 };
1110 }
1129 };
1111 };
1130
1112
1131 /**
1113 /**
@@ -1159,10 +1141,10 b' var IPython = (function (IPython) {'
1159 // that of the original selected cell;
1141 // that of the original selected cell;
1160 cell.render();
1142 cell.render();
1161 }
1143 }
1162 };
1144 }
1163 this.delete_cell(index+1);
1145 this.delete_cell(index+1);
1164 this.select(this.find_cell_index(cell));
1146 this.select(this.find_cell_index(cell));
1165 };
1147 }
1166 };
1148 };
1167
1149
1168
1150
@@ -1365,7 +1347,7 b' var IPython = (function (IPython) {'
1365 * @method start_session
1347 * @method start_session
1366 */
1348 */
1367 Notebook.prototype.start_session = function () {
1349 Notebook.prototype.start_session = function () {
1368 this.session = new IPython.Session(this.notebook_name, this.notebook_path, this);
1350 this.session = new IPython.Session(this, this.options);
1369 this.session.start($.proxy(this._session_started, this));
1351 this.session.start($.proxy(this._session_started, this));
1370 };
1352 };
1371
1353
@@ -1382,8 +1364,8 b' var IPython = (function (IPython) {'
1382 var cell = this.get_cell(i);
1364 var cell = this.get_cell(i);
1383 if (cell instanceof IPython.CodeCell) {
1365 if (cell instanceof IPython.CodeCell) {
1384 cell.set_kernel(this.session.kernel);
1366 cell.set_kernel(this.session.kernel);
1385 };
1367 }
1386 };
1368 }
1387 };
1369 };
1388
1370
1389 /**
1371 /**
@@ -1424,7 +1406,7 b' var IPython = (function (IPython) {'
1424 this.command_mode();
1406 this.command_mode();
1425 cell.focus_cell();
1407 cell.focus_cell();
1426 this.set_dirty(true);
1408 this.set_dirty(true);
1427 }
1409 };
1428
1410
1429 /**
1411 /**
1430 * Execute or render cell outputs and insert a new cell below.
1412 * Execute or render cell outputs and insert a new cell below.
@@ -1520,7 +1502,7 b' var IPython = (function (IPython) {'
1520 for (var i=start; i<end; i++) {
1502 for (var i=start; i<end; i++) {
1521 this.select(i);
1503 this.select(i);
1522 this.execute_cell();
1504 this.execute_cell();
1523 };
1505 }
1524 };
1506 };
1525
1507
1526 // Persistance and loading
1508 // Persistance and loading
@@ -1529,7 +1511,7 b' var IPython = (function (IPython) {'
1529 * Getter method for this notebook's name.
1511 * Getter method for this notebook's name.
1530 *
1512 *
1531 * @method get_notebook_name
1513 * @method get_notebook_name
1532 * @return {String} This notebook's name
1514 * @return {String} This notebook's name (excluding file extension)
1533 */
1515 */
1534 Notebook.prototype.get_notebook_name = function () {
1516 Notebook.prototype.get_notebook_name = function () {
1535 var nbname = this.notebook_name.substring(0,this.notebook_name.length-6);
1517 var nbname = this.notebook_name.substring(0,this.notebook_name.length-6);
@@ -1555,11 +1537,11 b' var IPython = (function (IPython) {'
1555 */
1537 */
1556 Notebook.prototype.test_notebook_name = function (nbname) {
1538 Notebook.prototype.test_notebook_name = function (nbname) {
1557 nbname = nbname || '';
1539 nbname = nbname || '';
1558 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1540 if (nbname.length>0 && !this.notebook_name_blacklist_re.test(nbname)) {
1559 return true;
1541 return true;
1560 } else {
1542 } else {
1561 return false;
1543 return false;
1562 };
1544 }
1563 };
1545 };
1564
1546
1565 /**
1547 /**
@@ -1577,7 +1559,7 b' var IPython = (function (IPython) {'
1577 for (i=0; i<ncells; i++) {
1559 for (i=0; i<ncells; i++) {
1578 // Always delete cell 0 as they get renumbered as they are deleted.
1560 // Always delete cell 0 as they get renumbered as they are deleted.
1579 this.delete_cell(0);
1561 this.delete_cell(0);
1580 };
1562 }
1581 // Save the metadata and name.
1563 // Save the metadata and name.
1582 this.metadata = content.metadata;
1564 this.metadata = content.metadata;
1583 this.notebook_name = data.name;
1565 this.notebook_name = data.name;
@@ -1601,8 +1583,8 b' var IPython = (function (IPython) {'
1601
1583
1602 new_cell = this.insert_cell_at_index(cell_data.cell_type, i);
1584 new_cell = this.insert_cell_at_index(cell_data.cell_type, i);
1603 new_cell.fromJSON(cell_data);
1585 new_cell.fromJSON(cell_data);
1604 };
1586 }
1605 };
1587 }
1606 if (content.worksheets.length > 1) {
1588 if (content.worksheets.length > 1) {
1607 IPython.dialog.modal({
1589 IPython.dialog.modal({
1608 title : "Multiple worksheets",
1590 title : "Multiple worksheets",
@@ -1630,7 +1612,7 b' var IPython = (function (IPython) {'
1630 var cell_array = new Array(ncells);
1612 var cell_array = new Array(ncells);
1631 for (var i=0; i<ncells; i++) {
1613 for (var i=0; i<ncells; i++) {
1632 cell_array[i] = cells[i].toJSON();
1614 cell_array[i] = cells[i].toJSON();
1633 };
1615 }
1634 var data = {
1616 var data = {
1635 // Only handle 1 worksheet for now.
1617 // Only handle 1 worksheet for now.
1636 worksheets : [{
1618 worksheets : [{
@@ -1666,7 +1648,7 b' var IPython = (function (IPython) {'
1666 } else {
1648 } else {
1667 this.autosave_timer = null;
1649 this.autosave_timer = null;
1668 $([IPython.events]).trigger("autosave_disabled.Notebook");
1650 $([IPython.events]).trigger("autosave_disabled.Notebook");
1669 };
1651 }
1670 };
1652 };
1671
1653
1672 /**
1654 /**
@@ -1701,7 +1683,7 b' var IPython = (function (IPython) {'
1701 }
1683 }
1702 $([IPython.events]).trigger('notebook_saving.Notebook');
1684 $([IPython.events]).trigger('notebook_saving.Notebook');
1703 var url = utils.url_join_encode(
1685 var url = utils.url_join_encode(
1704 this._baseProjectUrl,
1686 this.base_url,
1705 'api/notebooks',
1687 'api/notebooks',
1706 this.notebook_path,
1688 this.notebook_path,
1707 this.notebook_name
1689 this.notebook_name
@@ -1725,7 +1707,7 b' var IPython = (function (IPython) {'
1725 if (this._checkpoint_after_save) {
1707 if (this._checkpoint_after_save) {
1726 this.create_checkpoint();
1708 this.create_checkpoint();
1727 this._checkpoint_after_save = false;
1709 this._checkpoint_after_save = false;
1728 };
1710 }
1729 };
1711 };
1730
1712
1731 /**
1713 /**
@@ -1762,7 +1744,7 b' var IPython = (function (IPython) {'
1762
1744
1763 Notebook.prototype.new_notebook = function(){
1745 Notebook.prototype.new_notebook = function(){
1764 var path = this.notebook_path;
1746 var path = this.notebook_path;
1765 var base_project_url = this._baseProjectUrl;
1747 var base_url = this.base_url;
1766 var settings = {
1748 var settings = {
1767 processData : false,
1749 processData : false,
1768 cache : false,
1750 cache : false,
@@ -1773,7 +1755,7 b' var IPython = (function (IPython) {'
1773 var notebook_name = data.name;
1755 var notebook_name = data.name;
1774 window.open(
1756 window.open(
1775 utils.url_join_encode(
1757 utils.url_join_encode(
1776 base_project_url,
1758 base_url,
1777 'notebooks',
1759 'notebooks',
1778 path,
1760 path,
1779 notebook_name
1761 notebook_name
@@ -1783,7 +1765,7 b' var IPython = (function (IPython) {'
1783 }
1765 }
1784 };
1766 };
1785 var url = utils.url_join_encode(
1767 var url = utils.url_join_encode(
1786 base_project_url,
1768 base_url,
1787 'api/notebooks',
1769 'api/notebooks',
1788 path
1770 path
1789 );
1771 );
@@ -1793,7 +1775,7 b' var IPython = (function (IPython) {'
1793
1775
1794 Notebook.prototype.copy_notebook = function(){
1776 Notebook.prototype.copy_notebook = function(){
1795 var path = this.notebook_path;
1777 var path = this.notebook_path;
1796 var base_project_url = this._baseProjectUrl;
1778 var base_url = this.base_url;
1797 var settings = {
1779 var settings = {
1798 processData : false,
1780 processData : false,
1799 cache : false,
1781 cache : false,
@@ -1803,7 +1785,7 b' var IPython = (function (IPython) {'
1803 async : false,
1785 async : false,
1804 success : function (data, status, xhr) {
1786 success : function (data, status, xhr) {
1805 window.open(utils.url_join_encode(
1787 window.open(utils.url_join_encode(
1806 base_project_url,
1788 base_url,
1807 'notebooks',
1789 'notebooks',
1808 data.path,
1790 data.path,
1809 data.name
1791 data.name
@@ -1811,7 +1793,7 b' var IPython = (function (IPython) {'
1811 }
1793 }
1812 };
1794 };
1813 var url = utils.url_join_encode(
1795 var url = utils.url_join_encode(
1814 base_project_url,
1796 base_url,
1815 'api/notebooks',
1797 'api/notebooks',
1816 path
1798 path
1817 );
1799 );
@@ -1820,7 +1802,10 b' var IPython = (function (IPython) {'
1820
1802
1821 Notebook.prototype.rename = function (nbname) {
1803 Notebook.prototype.rename = function (nbname) {
1822 var that = this;
1804 var that = this;
1823 var data = {name: nbname + '.ipynb'};
1805 if (!nbname.match(/\.ipynb$/)) {
1806 nbname = nbname + ".ipynb";
1807 }
1808 var data = {name: nbname};
1824 var settings = {
1809 var settings = {
1825 processData : false,
1810 processData : false,
1826 cache : false,
1811 cache : false,
@@ -1833,7 +1818,7 b' var IPython = (function (IPython) {'
1833 };
1818 };
1834 $([IPython.events]).trigger('rename_notebook.Notebook', data);
1819 $([IPython.events]).trigger('rename_notebook.Notebook', data);
1835 var url = utils.url_join_encode(
1820 var url = utils.url_join_encode(
1836 this._baseProjectUrl,
1821 this.base_url,
1837 'api/notebooks',
1822 'api/notebooks',
1838 this.notebook_path,
1823 this.notebook_path,
1839 this.notebook_name
1824 this.notebook_name
@@ -1850,7 +1835,7 b' var IPython = (function (IPython) {'
1850 dataType: "json",
1835 dataType: "json",
1851 };
1836 };
1852 var url = utils.url_join_encode(
1837 var url = utils.url_join_encode(
1853 this._baseProjectUrl,
1838 this.base_url,
1854 'api/notebooks',
1839 'api/notebooks',
1855 this.notebook_path,
1840 this.notebook_path,
1856 this.notebook_name
1841 this.notebook_name
@@ -1860,19 +1845,18 b' var IPython = (function (IPython) {'
1860
1845
1861
1846
1862 Notebook.prototype.rename_success = function (json, status, xhr) {
1847 Notebook.prototype.rename_success = function (json, status, xhr) {
1863 this.notebook_name = json.name;
1848 var name = this.notebook_name = json.name;
1864 var name = this.notebook_name;
1865 var path = json.path;
1849 var path = json.path;
1866 this.session.rename_notebook(name, path);
1850 this.session.rename_notebook(name, path);
1867 $([IPython.events]).trigger('notebook_renamed.Notebook', json);
1851 $([IPython.events]).trigger('notebook_renamed.Notebook', json);
1868 }
1852 };
1869
1853
1870 Notebook.prototype.rename_error = function (xhr, status, error) {
1854 Notebook.prototype.rename_error = function (xhr, status, error) {
1871 var that = this;
1855 var that = this;
1872 var dialog = $('<div/>').append(
1856 var dialog = $('<div/>').append(
1873 $("<p/>").addClass("rename-message")
1857 $("<p/>").addClass("rename-message")
1874 .text('This notebook name already exists.')
1858 .text('This notebook name already exists.')
1875 )
1859 );
1876 $([IPython.events]).trigger('notebook_rename_failed.Notebook', [xhr, status, error]);
1860 $([IPython.events]).trigger('notebook_rename_failed.Notebook', [xhr, status, error]);
1877 IPython.dialog.modal({
1861 IPython.dialog.modal({
1878 title: "Notebook Rename Error!",
1862 title: "Notebook Rename Error!",
@@ -1896,7 +1880,7 b' var IPython = (function (IPython) {'
1896 that.find('input[type="text"]').focus();
1880 that.find('input[type="text"]').focus();
1897 }
1881 }
1898 });
1882 });
1899 }
1883 };
1900
1884
1901 /**
1885 /**
1902 * Request a notebook's data from the server.
1886 * Request a notebook's data from the server.
@@ -1919,7 +1903,7 b' var IPython = (function (IPython) {'
1919 };
1903 };
1920 $([IPython.events]).trigger('notebook_loading.Notebook');
1904 $([IPython.events]).trigger('notebook_loading.Notebook');
1921 var url = utils.url_join_encode(
1905 var url = utils.url_join_encode(
1922 this._baseProjectUrl,
1906 this.base_url,
1923 'api/notebooks',
1907 'api/notebooks',
1924 this.notebook_path,
1908 this.notebook_path,
1925 this.notebook_name
1909 this.notebook_name
@@ -1946,7 +1930,7 b' var IPython = (function (IPython) {'
1946 } else {
1930 } else {
1947 this.select(0);
1931 this.select(0);
1948 this.command_mode();
1932 this.command_mode();
1949 };
1933 }
1950 this.set_dirty(false);
1934 this.set_dirty(false);
1951 this.scroll_to_top();
1935 this.scroll_to_top();
1952 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1936 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
@@ -1971,7 +1955,7 b' var IPython = (function (IPython) {'
1971 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
1955 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
1972 var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
1956 var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
1973 this_vs + ". You can still work with this notebook, but some features " +
1957 this_vs + ". You can still work with this notebook, but some features " +
1974 "introduced in later notebook versions may not be available."
1958 "introduced in later notebook versions may not be available.";
1975
1959
1976 IPython.dialog.modal({
1960 IPython.dialog.modal({
1977 title : "Newer Notebook",
1961 title : "Newer Notebook",
@@ -1987,7 +1971,7 b' var IPython = (function (IPython) {'
1987
1971
1988 // Create the session after the notebook is completely loaded to prevent
1972 // Create the session after the notebook is completely loaded to prevent
1989 // code execution upon loading, which is a security risk.
1973 // code execution upon loading, which is a security risk.
1990 if (this.session == null) {
1974 if (this.session === null) {
1991 this.start_session();
1975 this.start_session();
1992 }
1976 }
1993 // load our checkpoint list
1977 // load our checkpoint list
@@ -2012,10 +1996,11 b' var IPython = (function (IPython) {'
2012 */
1996 */
2013 Notebook.prototype.load_notebook_error = function (xhr, status, error) {
1997 Notebook.prototype.load_notebook_error = function (xhr, status, error) {
2014 $([IPython.events]).trigger('notebook_load_failed.Notebook', [xhr, status, error]);
1998 $([IPython.events]).trigger('notebook_load_failed.Notebook', [xhr, status, error]);
1999 var msg;
2015 if (xhr.status === 400) {
2000 if (xhr.status === 400) {
2016 var msg = error;
2001 msg = error;
2017 } else if (xhr.status === 500) {
2002 } else if (xhr.status === 500) {
2018 var msg = "An unknown error occurred while loading this notebook. " +
2003 msg = "An unknown error occurred while loading this notebook. " +
2019 "This version can load notebook formats " +
2004 "This version can load notebook formats " +
2020 "v" + this.nbformat + " or earlier.";
2005 "v" + this.nbformat + " or earlier.";
2021 }
2006 }
@@ -2026,7 +2011,7 b' var IPython = (function (IPython) {'
2026 "OK": {}
2011 "OK": {}
2027 }
2012 }
2028 });
2013 });
2029 }
2014 };
2030
2015
2031 /********************* checkpoint-related *********************/
2016 /********************* checkpoint-related *********************/
2032
2017
@@ -2069,7 +2054,7 b' var IPython = (function (IPython) {'
2069 */
2054 */
2070 Notebook.prototype.list_checkpoints = function () {
2055 Notebook.prototype.list_checkpoints = function () {
2071 var url = utils.url_join_encode(
2056 var url = utils.url_join_encode(
2072 this._baseProjectUrl,
2057 this.base_url,
2073 'api/notebooks',
2058 'api/notebooks',
2074 this.notebook_path,
2059 this.notebook_path,
2075 this.notebook_name,
2060 this.notebook_name,
@@ -2091,7 +2076,7 b' var IPython = (function (IPython) {'
2091 * @param {jqXHR} xhr jQuery Ajax object
2076 * @param {jqXHR} xhr jQuery Ajax object
2092 */
2077 */
2093 Notebook.prototype.list_checkpoints_success = function (data, status, xhr) {
2078 Notebook.prototype.list_checkpoints_success = function (data, status, xhr) {
2094 var data = $.parseJSON(data);
2079 data = $.parseJSON(data);
2095 this.checkpoints = data;
2080 this.checkpoints = data;
2096 if (data.length) {
2081 if (data.length) {
2097 this.last_checkpoint = data[data.length - 1];
2082 this.last_checkpoint = data[data.length - 1];
@@ -2120,9 +2105,9 b' var IPython = (function (IPython) {'
2120 */
2105 */
2121 Notebook.prototype.create_checkpoint = function () {
2106 Notebook.prototype.create_checkpoint = function () {
2122 var url = utils.url_join_encode(
2107 var url = utils.url_join_encode(
2123 this._baseProjectUrl,
2108 this.base_url,
2124 'api/notebooks',
2109 'api/notebooks',
2125 this.notebookPath(),
2110 this.notebook_path,
2126 this.notebook_name,
2111 this.notebook_name,
2127 'checkpoints'
2112 'checkpoints'
2128 );
2113 );
@@ -2142,7 +2127,7 b' var IPython = (function (IPython) {'
2142 * @param {jqXHR} xhr jQuery Ajax object
2127 * @param {jqXHR} xhr jQuery Ajax object
2143 */
2128 */
2144 Notebook.prototype.create_checkpoint_success = function (data, status, xhr) {
2129 Notebook.prototype.create_checkpoint_success = function (data, status, xhr) {
2145 var data = $.parseJSON(data);
2130 data = $.parseJSON(data);
2146 this.add_checkpoint(data);
2131 this.add_checkpoint(data);
2147 $([IPython.events]).trigger('checkpoint_created.Notebook', data);
2132 $([IPython.events]).trigger('checkpoint_created.Notebook', data);
2148 };
2133 };
@@ -2161,7 +2146,7 b' var IPython = (function (IPython) {'
2161
2146
2162 Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) {
2147 Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) {
2163 var that = this;
2148 var that = this;
2164 var checkpoint = checkpoint || this.last_checkpoint;
2149 checkpoint = checkpoint || this.last_checkpoint;
2165 if ( ! checkpoint ) {
2150 if ( ! checkpoint ) {
2166 console.log("restore dialog, but no checkpoint to restore to!");
2151 console.log("restore dialog, but no checkpoint to restore to!");
2167 return;
2152 return;
@@ -2196,7 +2181,7 b' var IPython = (function (IPython) {'
2196 Cancel : {}
2181 Cancel : {}
2197 }
2182 }
2198 });
2183 });
2199 }
2184 };
2200
2185
2201 /**
2186 /**
2202 * Restore the notebook to a checkpoint state.
2187 * Restore the notebook to a checkpoint state.
@@ -2207,9 +2192,9 b' var IPython = (function (IPython) {'
2207 Notebook.prototype.restore_checkpoint = function (checkpoint) {
2192 Notebook.prototype.restore_checkpoint = function (checkpoint) {
2208 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2193 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2209 var url = utils.url_join_encode(
2194 var url = utils.url_join_encode(
2210 this._baseProjectUrl,
2195 this.base_url,
2211 'api/notebooks',
2196 'api/notebooks',
2212 this.notebookPath(),
2197 this.notebook_path,
2213 this.notebook_name,
2198 this.notebook_name,
2214 'checkpoints',
2199 'checkpoints',
2215 checkpoint
2200 checkpoint
@@ -2255,9 +2240,9 b' var IPython = (function (IPython) {'
2255 Notebook.prototype.delete_checkpoint = function (checkpoint) {
2240 Notebook.prototype.delete_checkpoint = function (checkpoint) {
2256 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2241 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2257 var url = utils.url_join_encode(
2242 var url = utils.url_join_encode(
2258 this._baseProjectUrl,
2243 this.base_url,
2259 'api/notebooks',
2244 'api/notebooks',
2260 this.notebookPath(),
2245 this.notebook_path,
2261 this.notebook_name,
2246 this.notebook_name,
2262 'checkpoints',
2247 'checkpoints',
2263 checkpoint
2248 checkpoint
@@ -127,7 +127,7 b' var IPython = (function (IPython) {'
127
127
128 SaveWidget.prototype.update_address_bar = function(){
128 SaveWidget.prototype.update_address_bar = function(){
129 var nbname = IPython.notebook.notebook_name;
129 var nbname = IPython.notebook.notebook_name;
130 var path = IPython.notebook.notebookPath();
130 var path = IPython.notebook.notebook_path;
131 var state = {path : utils.url_join_encode(path, nbname)};
131 var state = {path : utils.url_join_encode(path, nbname)};
132 window.history.replaceState(state, "", utils.url_join_encode(
132 window.history.replaceState(state, "", utils.url_join_encode(
133 "/notebooks",
133 "/notebooks",
@@ -25,12 +25,12 b' var IPython = (function (IPython) {'
25 * A Kernel Class to communicate with the Python kernel
25 * A Kernel Class to communicate with the Python kernel
26 * @Class Kernel
26 * @Class Kernel
27 */
27 */
28 var Kernel = function (base_url) {
28 var Kernel = function (kernel_service_url) {
29 this.kernel_id = null;
29 this.kernel_id = null;
30 this.shell_channel = null;
30 this.shell_channel = null;
31 this.iopub_channel = null;
31 this.iopub_channel = null;
32 this.stdin_channel = null;
32 this.stdin_channel = null;
33 this.base_url = base_url;
33 this.kernel_service_url = kernel_service_url;
34 this.running = false;
34 this.running = false;
35 this.username = "username";
35 this.username = "username";
36 this.session_id = utils.uuid();
36 this.session_id = utils.uuid();
@@ -94,8 +94,7 b' var IPython = (function (IPython) {'
94 params = params || {};
94 params = params || {};
95 if (!this.running) {
95 if (!this.running) {
96 var qs = $.param(params);
96 var qs = $.param(params);
97 var url = this.base_url + '?' + qs;
97 $.post(utils.url_join_encode(this.kernel_service_url) + '?' + qs,
98 $.post(url,
99 $.proxy(this._kernel_started, this),
98 $.proxy(this._kernel_started, this),
100 'json'
99 'json'
101 );
100 );
@@ -114,8 +113,7 b' var IPython = (function (IPython) {'
114 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
113 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
115 if (this.running) {
114 if (this.running) {
116 this.stop_channels();
115 this.stop_channels();
117 var url = utils.url_join_encode(this.kernel_url, "restart");
116 $.post(utils.url_join_encode(this.kernel_url, "restart"),
118 $.post(url,
119 $.proxy(this._kernel_started, this),
117 $.proxy(this._kernel_started, this),
120 'json'
118 'json'
121 );
119 );
@@ -133,8 +131,10 b' var IPython = (function (IPython) {'
133 var prot = location.protocol.replace('http', 'ws') + "//";
131 var prot = location.protocol.replace('http', 'ws') + "//";
134 ws_url = prot + location.host + ws_url;
132 ws_url = prot + location.host + ws_url;
135 }
133 }
136 this.ws_url = ws_url;
134 var parsed = utils.parse_url(ws_url);
137 this.kernel_url = utils.url_join_encode(this.base_url, this.kernel_id);
135 this.ws_host = parsed.protocol + "//" + parsed.host;
136 this.kernel_url = utils.url_path_join(this.kernel_service_url, this.kernel_id);
137 this.ws_url = utils.url_path_join(parsed.pathname, this.kernel_url);
138 this.start_channels();
138 this.start_channels();
139 };
139 };
140
140
@@ -155,12 +155,18 b' var IPython = (function (IPython) {'
155 Kernel.prototype.start_channels = function () {
155 Kernel.prototype.start_channels = function () {
156 var that = this;
156 var that = this;
157 this.stop_channels();
157 this.stop_channels();
158 var ws_url = this.ws_url + this.kernel_url;
158 console.log("Starting WebSockets:", this.ws_host + this.ws_url);
159 console.log("Starting WebSockets:", ws_url);
159 this.shell_channel = new this.WebSocket(
160 this.shell_channel = new this.WebSocket(ws_url + "/shell");
160 this.ws_host + utils.url_join_encode(this.ws_url, "shell")
161 this.stdin_channel = new this.WebSocket(ws_url + "/stdin");
161 );
162 this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
162 this.stdin_channel = new this.WebSocket(
163 this.ws_host + utils.url_join_encode(this.ws_url, "stdin")
164 );
165 this.iopub_channel = new this.WebSocket(
166 this.ws_host + utils.url_join_encode(this.ws_url, "iopub")
167 );
163
168
169 var ws_host_url = this.ws_host + this.ws_url;
164 var already_called_onclose = false; // only alert once
170 var already_called_onclose = false; // only alert once
165 var ws_closed_early = function(evt){
171 var ws_closed_early = function(evt){
166 if (already_called_onclose){
172 if (already_called_onclose){
@@ -168,7 +174,7 b' var IPython = (function (IPython) {'
168 }
174 }
169 already_called_onclose = true;
175 already_called_onclose = true;
170 if ( ! evt.wasClean ){
176 if ( ! evt.wasClean ){
171 that._websocket_closed(ws_url, true);
177 that._websocket_closed(ws_host_url, true);
172 }
178 }
173 };
179 };
174 var ws_closed_late = function(evt){
180 var ws_closed_late = function(evt){
@@ -177,7 +183,7 b' var IPython = (function (IPython) {'
177 }
183 }
178 already_called_onclose = true;
184 already_called_onclose = true;
179 if ( ! evt.wasClean ){
185 if ( ! evt.wasClean ){
180 that._websocket_closed(ws_url, false);
186 that._websocket_closed(ws_host_url, false);
181 }
187 }
182 };
188 };
183 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
189 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
@@ -387,7 +393,7 b' var IPython = (function (IPython) {'
387 Kernel.prototype.interrupt = function () {
393 Kernel.prototype.interrupt = function () {
388 if (this.running) {
394 if (this.running) {
389 $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
395 $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
390 $.post(this.kernel_url + "/interrupt");
396 $.post(utils.url_join_encode(this.kernel_url, "interrupt"));
391 }
397 }
392 };
398 };
393
399
@@ -399,7 +405,7 b' var IPython = (function (IPython) {'
399 cache : false,
405 cache : false,
400 type : "DELETE"
406 type : "DELETE"
401 };
407 };
402 $.ajax(this.kernel_url, settings);
408 $.ajax(utils.url_join_encode(this.kernel_url), settings);
403 }
409 }
404 };
410 };
405
411
@@ -14,13 +14,14 b' var IPython = (function (IPython) {'
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16
16
17 var Session = function(notebook_name, notebook_path, notebook){
17 var Session = function(notebook, options){
18 this.kernel = null;
18 this.kernel = null;
19 this.id = null;
19 this.id = null;
20 this.name = notebook_name;
21 this.path = notebook_path;
22 this.notebook = notebook;
20 this.notebook = notebook;
23 this._baseProjectUrl = notebook.baseProjectUrl();
21 this.name = notebook.notebook_name;
22 this.path = notebook.notebook_path;
23 this.base_url = notebook.base_url;
24 this.base_kernel_url = options.base_kernel_url || utils.get_body_data("baseKernelUrl");
24 };
25 };
25
26
26 Session.prototype.start = function(callback) {
27 Session.prototype.start = function(callback) {
@@ -44,7 +45,7 b' var IPython = (function (IPython) {'
44 }
45 }
45 },
46 },
46 };
47 };
47 var url = utils.url_join_encode(this._baseProjectUrl, 'api/sessions');
48 var url = utils.url_join_encode(this.base_url, 'api/sessions');
48 $.ajax(url, settings);
49 $.ajax(url, settings);
49 };
50 };
50
51
@@ -64,7 +65,7 b' var IPython = (function (IPython) {'
64 data: JSON.stringify(model),
65 data: JSON.stringify(model),
65 dataType : "json",
66 dataType : "json",
66 };
67 };
67 var url = utils.url_join_encode(this._baseProjectUrl, 'api/sessions', this.id);
68 var url = utils.url_join_encode(this.base_url, 'api/sessions', this.id);
68 $.ajax(url, settings);
69 $.ajax(url, settings);
69 };
70 };
70
71
@@ -76,7 +77,7 b' var IPython = (function (IPython) {'
76 dataType : "json",
77 dataType : "json",
77 };
78 };
78 this.kernel.running = false;
79 this.kernel.running = false;
79 var url = utils.url_join_encode(this._baseProjectUrl, 'api/sessions', this.id);
80 var url = utils.url_join_encode(this.base_url, 'api/sessions', this.id);
80 $.ajax(url, settings);
81 $.ajax(url, settings);
81 };
82 };
82
83
@@ -88,8 +89,8 b' var IPython = (function (IPython) {'
88 */
89 */
89 Session.prototype._handle_start_success = function (data, status, xhr) {
90 Session.prototype._handle_start_success = function (data, status, xhr) {
90 this.id = data.id;
91 this.id = data.id;
91 var base_url = utils.url_path_join($('body').data('baseKernelUrl'), "api/kernels");
92 var kernel_service_url = utils.url_path_join(this.base_kernel_url, "api/kernels");
92 this.kernel = new IPython.Kernel(base_url);
93 this.kernel = new IPython.Kernel(kernel_service_url);
93 this.kernel._kernel_started(data.kernel);
94 this.kernel._kernel_started(data.kernel);
94 };
95 };
95
96
@@ -14,17 +14,17 b' var IPython = (function (IPython) {'
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16
16
17 var ClusterList = function (selector) {
17 var ClusterList = function (selector, options) {
18 this.selector = selector;
18 this.selector = selector;
19 if (this.selector !== undefined) {
19 if (this.selector !== undefined) {
20 this.element = $(selector);
20 this.element = $(selector);
21 this.style();
21 this.style();
22 this.bind_events();
22 this.bind_events();
23 }
23 }
24 };
24 options = options || {};
25
25 this.options = options;
26 ClusterList.prototype.baseProjectUrl = function(){
26 this.base_url = options.base_url || utils.get_body_data("baseUrl");
27 return this._baseProjectUrl || $('body').data('baseProjectUrl');
27 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
28 };
28 };
29
29
30 ClusterList.prototype.style = function () {
30 ClusterList.prototype.style = function () {
@@ -51,7 +51,7 b' var IPython = (function (IPython) {'
51 dataType : "json",
51 dataType : "json",
52 success : $.proxy(this.load_list_success, this)
52 success : $.proxy(this.load_list_success, this)
53 };
53 };
54 var url = utils.url_join_encode(this.baseProjectUrl(), 'clusters');
54 var url = utils.url_join_encode(this.base_url, 'clusters');
55 $.ajax(url, settings);
55 $.ajax(url, settings);
56 };
56 };
57
57
@@ -65,7 +65,7 b' var IPython = (function (IPython) {'
65 var len = data.length;
65 var len = data.length;
66 for (var i=0; i<len; i++) {
66 for (var i=0; i<len; i++) {
67 var element = $('<div/>');
67 var element = $('<div/>');
68 var item = new ClusterItem(element);
68 var item = new ClusterItem(element, this.options);
69 item.update_state(data[i]);
69 item.update_state(data[i]);
70 element.data('item', item);
70 element.data('item', item);
71 this.element.append(element);
71 this.element.append(element);
@@ -73,17 +73,14 b' var IPython = (function (IPython) {'
73 };
73 };
74
74
75
75
76 var ClusterItem = function (element) {
76 var ClusterItem = function (element, options) {
77 this.element = $(element);
77 this.element = $(element);
78 this.base_url = options.base_url || utils.get_body_data("baseUrl");
79 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
78 this.data = null;
80 this.data = null;
79 this.style();
81 this.style();
80 };
82 };
81
83
82 ClusterItem.prototype.baseProjectUrl = function(){
83 return this._baseProjectUrl || $('body').data('baseProjectUrl');
84 };
85
86
87 ClusterItem.prototype.style = function () {
84 ClusterItem.prototype.style = function () {
88 this.element.addClass('list_item').addClass("row-fluid");
85 this.element.addClass('list_item').addClass("row-fluid");
89 };
86 };
@@ -138,7 +135,7 b' var IPython = (function (IPython) {'
138 };
135 };
139 status_col.text('starting');
136 status_col.text('starting');
140 var url = utils.url_join_encode(
137 var url = utils.url_join_encode(
141 that.baseProjectUrl(),
138 that.base_url,
142 'clusters',
139 'clusters',
143 that.data.profile,
140 that.data.profile,
144 'start'
141 'start'
@@ -180,7 +177,7 b' var IPython = (function (IPython) {'
180 };
177 };
181 status_col.text('stopping');
178 status_col.text('stopping');
182 var url = utils.url_join_encode(
179 var url = utils.url_join_encode(
183 that.baseProjectUrl(),
180 that.base_url,
184 'clusters',
181 'clusters',
185 that.data.profile,
182 that.data.profile,
186 'stop'
183 'stop'
@@ -15,12 +15,16 b' $(document).ready(function () {'
15 IPython.page = new IPython.Page();
15 IPython.page = new IPython.Page();
16
16
17 $('#new_notebook').button().click(function (e) {
17 $('#new_notebook').button().click(function (e) {
18 IPython.notebook_list.new_notebook($('body').data('baseProjectUrl'))
18 IPython.notebook_list.new_notebook()
19 });
19 });
20
20
21 IPython.notebook_list = new IPython.NotebookList('#notebook_list');
21 var opts = {
22 IPython.cluster_list = new IPython.ClusterList('#cluster_list');
22 base_url : IPython.utils.get_body_data("baseUrl"),
23 IPython.login_widget = new IPython.LoginWidget('#login_widget');
23 notebook_path : IPython.utils.get_body_data("notebookPath"),
24 };
25 IPython.notebook_list = new IPython.NotebookList('#notebook_list', opts);
26 IPython.cluster_list = new IPython.ClusterList('#cluster_list', opts);
27 IPython.login_widget = new IPython.LoginWidget('#login_widget', opts);
24
28
25 var interval_id=0;
29 var interval_id=0;
26 // auto refresh every xx secondes, no need to be fast,
30 // auto refresh every xx secondes, no need to be fast,
@@ -14,7 +14,7 b' var IPython = (function (IPython) {'
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16
16
17 var NotebookList = function (selector) {
17 var NotebookList = function (selector, options) {
18 this.selector = selector;
18 this.selector = selector;
19 if (this.selector !== undefined) {
19 if (this.selector !== undefined) {
20 this.element = $(selector);
20 this.element = $(selector);
@@ -23,16 +23,10 b' var IPython = (function (IPython) {'
23 }
23 }
24 this.notebooks_list = [];
24 this.notebooks_list = [];
25 this.sessions = {};
25 this.sessions = {};
26 this.base_url = options.base_url || utils.get_body_data("baseUrl");
27 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
26 };
28 };
27
29
28 NotebookList.prototype.baseProjectUrl = function () {
29 return $('body').data('baseProjectUrl');
30 };
31
32 NotebookList.prototype.notebookPath = function() {
33 return $('body').data('notebookPath');
34 };
35
36 NotebookList.prototype.style = function () {
30 NotebookList.prototype.style = function () {
37 $('#notebook_toolbar').addClass('list_toolbar');
31 $('#notebook_toolbar').addClass('list_toolbar');
38 $('#drag_info').addClass('toolbar_info');
32 $('#drag_info').addClass('toolbar_info');
@@ -112,7 +106,7 b' var IPython = (function (IPython) {'
112 dataType : "json",
106 dataType : "json",
113 success : $.proxy(that.sessions_loaded, this)
107 success : $.proxy(that.sessions_loaded, this)
114 };
108 };
115 var url = this.baseProjectUrl() + 'api/sessions';
109 var url = utils.url_join_encode(this.base_url, 'api/sessions');
116 $.ajax(url,settings);
110 $.ajax(url,settings);
117 };
111 };
118
112
@@ -152,10 +146,10 b' var IPython = (function (IPython) {'
152 };
146 };
153
147
154 var url = utils.url_join_encode(
148 var url = utils.url_join_encode(
155 this.baseProjectUrl(),
149 this.base_url,
156 'api',
150 'api',
157 'notebooks',
151 'notebooks',
158 this.notebookPath()
152 this.notebook_path
159 );
153 );
160 $.ajax(url, settings);
154 $.ajax(url, settings);
161 };
155 };
@@ -175,7 +169,7 b' var IPython = (function (IPython) {'
175 span12.empty();
169 span12.empty();
176 span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
170 span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
177 }
171 }
178 var path = this.notebookPath();
172 var path = this.notebook_path;
179 var offset = 0;
173 var offset = 0;
180 if (path !== '') {
174 if (path !== '') {
181 item = this.new_notebook_item(0);
175 item = this.new_notebook_item(0);
@@ -233,7 +227,7 b' var IPython = (function (IPython) {'
233 item.find("a.item_link")
227 item.find("a.item_link")
234 .attr('href',
228 .attr('href',
235 utils.url_join_encode(
229 utils.url_join_encode(
236 this.baseProjectUrl(),
230 this.base_url,
237 "tree",
231 "tree",
238 path,
232 path,
239 name
233 name
@@ -250,7 +244,7 b' var IPython = (function (IPython) {'
250 item.find("a.item_link")
244 item.find("a.item_link")
251 .attr('href',
245 .attr('href',
252 utils.url_join_encode(
246 utils.url_join_encode(
253 this.baseProjectUrl(),
247 this.base_url,
254 "notebooks",
248 "notebooks",
255 path,
249 path,
256 nbname
250 nbname
@@ -291,7 +285,7 b' var IPython = (function (IPython) {'
291 }
285 }
292 };
286 };
293 var url = utils.url_join_encode(
287 var url = utils.url_join_encode(
294 that.baseProjectUrl(),
288 that.base_url,
295 'api/sessions',
289 'api/sessions',
296 session
290 session
297 );
291 );
@@ -331,9 +325,9 b' var IPython = (function (IPython) {'
331 }
325 }
332 };
326 };
333 var url = utils.url_join_encode(
327 var url = utils.url_join_encode(
334 notebooklist.baseProjectUrl(),
328 notebooklist.base_url,
335 'api/notebooks',
329 'api/notebooks',
336 notebooklist.notebookPath(),
330 notebooklist.notebook_path,
337 nbname
331 nbname
338 );
332 );
339 $.ajax(url, settings);
333 $.ajax(url, settings);
@@ -357,7 +351,7 b' var IPython = (function (IPython) {'
357 if (nbname.slice(nbname.length-6, nbname.length) != ".ipynb") {
351 if (nbname.slice(nbname.length-6, nbname.length) != ".ipynb") {
358 nbname = nbname + ".ipynb";
352 nbname = nbname + ".ipynb";
359 }
353 }
360 var path = that.notebookPath();
354 var path = that.notebook_path;
361 var nbdata = item.data('nbdata');
355 var nbdata = item.data('nbdata');
362 var content_type = 'application/json';
356 var content_type = 'application/json';
363 var model = {
357 var model = {
@@ -380,9 +374,9 b' var IPython = (function (IPython) {'
380 };
374 };
381
375
382 var url = utils.url_join_encode(
376 var url = utils.url_join_encode(
383 that.baseProjectUrl(),
377 that.base_url,
384 'api/notebooks',
378 'api/notebooks',
385 that.notebookPath(),
379 that.notebook_path,
386 nbname
380 nbname
387 );
381 );
388 $.ajax(url, settings);
382 $.ajax(url, settings);
@@ -402,8 +396,8 b' var IPython = (function (IPython) {'
402
396
403
397
404 NotebookList.prototype.new_notebook = function(){
398 NotebookList.prototype.new_notebook = function(){
405 var path = this.notebookPath();
399 var path = this.notebook_path;
406 var base_project_url = this.baseProjectUrl();
400 var base_url = this.base_url;
407 var settings = {
401 var settings = {
408 processData : false,
402 processData : false,
409 cache : false,
403 cache : false,
@@ -414,7 +408,7 b' var IPython = (function (IPython) {'
414 var notebook_name = data.name;
408 var notebook_name = data.name;
415 window.open(
409 window.open(
416 utils.url_join_encode(
410 utils.url_join_encode(
417 base_project_url,
411 base_url,
418 'notebooks',
412 'notebooks',
419 path,
413 path,
420 notebook_name),
414 notebook_name),
@@ -423,7 +417,7 b' var IPython = (function (IPython) {'
423 }
417 }
424 };
418 };
425 var url = utils.url_join_encode(
419 var url = utils.url_join_encode(
426 base_project_url,
420 base_url,
427 'api/notebooks',
421 'api/notebooks',
428 path
422 path
429 );
423 );
@@ -20,7 +20,7 b''
20 <div class="container">
20 <div class="container">
21 <div class="center-nav">
21 <div class="center-nav">
22 <p class="navbar-text nav">Password:</p>
22 <p class="navbar-text nav">Password:</p>
23 <form action="{{base_project_url}}login?next={{next}}" method="post" class="navbar-form pull-left">
23 <form action="{{base_url}}login?next={{next}}" method="post" class="navbar-form pull-left">
24 <input type="password" name="password" id="password_input">
24 <input type="password" name="password" id="password_input">
25 <button type="submit" id="login_submit">Log in</button>
25 <button type="submit" id="login_submit">Log in</button>
26 </form>
26 </form>
@@ -21,9 +21,9 b''
21 {% endif %}
21 {% endif %}
22
22
23 {% if not login_available %}
23 {% if not login_available %}
24 Proceed to the <a href="{{base_project_url}}">dashboard</a>.
24 Proceed to the <a href="{{base_url}}">dashboard</a>.
25 {% else %}
25 {% else %}
26 Proceed to the <a href="{{base_project_url}}login">login page</a>.
26 Proceed to the <a href="{{base_url}}login">login page</a>.
27 {% endif %}
27 {% endif %}
28
28
29
29
@@ -22,7 +22,7 b' window.mathjax_url = "{{mathjax_url}}";'
22 {% block params %}
22 {% block params %}
23
23
24 data-project="{{project}}"
24 data-project="{{project}}"
25 data-base-project-url="{{base_project_url}}"
25 data-base-url="{{base_url}}"
26 data-base-kernel-url="{{base_kernel_url}}"
26 data-base-kernel-url="{{base_kernel_url}}"
27 data-notebook-name="{{notebook_name}}"
27 data-notebook-name="{{notebook_name}}"
28 data-notebook-path="{{notebook_path}}"
28 data-notebook-path="{{notebook_path}}"
@@ -21,7 +21,7 b''
21 require.config({
21 require.config({
22 baseUrl: '{{static_url("")}}',
22 baseUrl: '{{static_url("")}}',
23 paths: {
23 paths: {
24 nbextensions : '{{ base_project_url }}nbextensions',
24 nbextensions : '{{ base_url }}nbextensions',
25 underscore : '{{static_url("components/underscore/underscore-min")}}',
25 underscore : '{{static_url("components/underscore/underscore-min")}}',
26 backbone : '{{static_url("components/backbone/backbone-min")}}',
26 backbone : '{{static_url("components/backbone/backbone-min")}}',
27 },
27 },
@@ -54,7 +54,7 b''
54 <div id="header" class="navbar navbar-static-top">
54 <div id="header" class="navbar navbar-static-top">
55 <div class="navbar-inner navbar-nobg">
55 <div class="navbar-inner navbar-nobg">
56 <div class="container">
56 <div class="container">
57 <div id="ipython_notebook" class="nav brand pull-left"><a href="{{base_project_url}}tree/{{notebook_path}}" alt='dashboard'><img src='{{static_url("base/images/ipynblogo.png") }}' alt='IPython Notebook'/></a></div>
57 <div id="ipython_notebook" class="nav brand pull-left"><a href="{{base_url}}tree/{{notebook_path}}" alt='dashboard'><img src='{{static_url("base/images/ipynblogo.png") }}' alt='IPython Notebook'/></a></div>
58
58
59 {% block login_widget %}
59 {% block login_widget %}
60
60
@@ -11,7 +11,7 b''
11 {% block params %}
11 {% block params %}
12
12
13 data-project="{{project}}"
13 data-project="{{project}}"
14 data-base-project-url="{{base_project_url}}"
14 data-base-url="{{base_url}}"
15 data-notebook-path="{{notebook_path}}"
15 data-notebook-path="{{notebook_path}}"
16 data-base-kernel-url="{{base_kernel_url}}"
16 data-base-kernel-url="{{base_kernel_url}}"
17
17
@@ -18,9 +18,12 b' casper.test_items = function (baseUrl) {'
18 if (!item.label.match('.ipynb$')) {
18 if (!item.label.match('.ipynb$')) {
19 var followed_url = baseUrl+item.link;
19 var followed_url = baseUrl+item.link;
20 if (!followed_url.match('/\.\.$')) {
20 if (!followed_url.match('/\.\.$')) {
21 casper.thenOpen(baseUrl+item.link, function () {
21 casper.thenOpen(followed_url, function () {
22 casper.wait_for_dashboard();
22 casper.wait_for_dashboard();
23 this.test.assertEquals(this.getCurrentUrl(), followed_url, 'Testing dashboard link: '+followed_url);
23 // getCurrentUrl is with host, and url-decoded,
24 // but item.link is without host, and url-encoded
25 var expected = baseUrl + decodeURIComponent(item.link);
26 this.test.assertEquals(this.getCurrentUrl(), expected, 'Testing dashboard link: ' + expected);
24 casper.test_items(baseUrl);
27 casper.test_items(baseUrl);
25 this.back();
28 this.back();
26 });
29 });
@@ -31,7 +34,7 b' casper.test_items = function (baseUrl) {'
31 }
34 }
32
35
33 casper.dashboard_test(function () {
36 casper.dashboard_test(function () {
34 baseUrl = this.get_notebook_server()
37 baseUrl = this.get_notebook_server();
35 casper.test_items(baseUrl);
38 casper.test_items(baseUrl);
36 })
39 })
37
40
@@ -30,12 +30,12 b' class TreeHandler(IPythonHandler):'
30 """Render the tree view, listing notebooks, clusters, etc."""
30 """Render the tree view, listing notebooks, clusters, etc."""
31
31
32 def generate_breadcrumbs(self, path):
32 def generate_breadcrumbs(self, path):
33 breadcrumbs = [(url_escape(url_path_join(self.base_project_url, 'tree')), '')]
33 breadcrumbs = [(url_escape(url_path_join(self.base_url, 'tree')), '')]
34 comps = path.split('/')
34 comps = path.split('/')
35 ncomps = len(comps)
35 ncomps = len(comps)
36 for i in range(ncomps):
36 for i in range(ncomps):
37 if comps[i]:
37 if comps[i]:
38 link = url_escape(url_path_join(self.base_project_url, 'tree', *comps[0:i+1]))
38 link = url_escape(url_path_join(self.base_url, 'tree', *comps[0:i+1]))
39 breadcrumbs.append((link, comps[i]))
39 breadcrumbs.append((link, comps[i]))
40 return breadcrumbs
40 return breadcrumbs
41
41
@@ -57,7 +57,7 b' class TreeHandler(IPythonHandler):'
57 if name is not None:
57 if name is not None:
58 # is a notebook, redirect to notebook handler
58 # is a notebook, redirect to notebook handler
59 url = url_escape(url_path_join(
59 url = url_escape(url_path_join(
60 self.base_project_url, 'notebooks', path, name
60 self.base_url, 'notebooks', path, name
61 ))
61 ))
62 self.log.debug("Redirecting %s to %s", self.request.path, url)
62 self.log.debug("Redirecting %s to %s", self.request.path, url)
63 self.redirect(url)
63 self.redirect(url)
@@ -81,7 +81,7 b' class TreeRedirectHandler(IPythonHandler):'
81 @web.authenticated
81 @web.authenticated
82 def get(self, path=''):
82 def get(self, path=''):
83 url = url_escape(url_path_join(
83 url = url_escape(url_path_join(
84 self.base_project_url, 'tree', path.strip('/')
84 self.base_url, 'tree', path.strip('/')
85 ))
85 ))
86 self.log.debug("Redirecting %s to %s", self.request.path, url)
86 self.log.debug("Redirecting %s to %s", self.request.path, url)
87 self.redirect(url)
87 self.redirect(url)
@@ -181,8 +181,8 b' class JSController(TestController):'
181 self.ipydir = TemporaryDirectory()
181 self.ipydir = TemporaryDirectory()
182 self.nbdir = TemporaryDirectory()
182 self.nbdir = TemporaryDirectory()
183 print("Running notebook tests in directory: %r" % self.nbdir.name)
183 print("Running notebook tests in directory: %r" % self.nbdir.name)
184 os.makedirs(os.path.join(self.nbdir.name, os.path.join('subdir1', 'subdir1a')))
184 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'subir1', u'sub ∂ir 1a')))
185 os.makedirs(os.path.join(self.nbdir.name, os.path.join('subdir2', 'subdir2a')))
185 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'subir2', u'sub ∂ir 1b')))
186 self.dirs.append(self.ipydir)
186 self.dirs.append(self.ipydir)
187 self.dirs.append(self.nbdir)
187 self.dirs.append(self.nbdir)
188
188
General Comments 0
You need to be logged in to leave comments. Login now