diff --git a/IPython/core/profileapp.py b/IPython/core/profileapp.py index 2ae9812..cbe53a3 100644 --- a/IPython/core/profileapp.py +++ b/IPython/core/profileapp.py @@ -194,15 +194,15 @@ class ProfileCreate(BaseIPythonApplication): else: apps.append(IPythonQtConsoleApp) try: - from IPython.frontend.html.notebook.notebookapp import IPythonNotebookApp + from IPython.frontend.html.notebook.notebookapp import NotebookApp except ImportError: pass except Exception: - self.log.debug('Unexpected error when importing IPythonNotebookApp', + self.log.debug('Unexpected error when importing NotebookApp', exc_info=True ) else: - apps.append(IPythonNotebookApp) + apps.append(NotebookApp) if self.parallel: from IPython.parallel.apps.ipcontrollerapp import IPControllerApp from IPython.parallel.apps.ipengineapp import IPEngineApp diff --git a/IPython/frontend/html/notebook/handlers.py b/IPython/frontend/html/notebook/handlers.py index 1245374..1ce17b5 100644 --- a/IPython/frontend/html/notebook/handlers.py +++ b/IPython/frontend/html/notebook/handlers.py @@ -18,6 +18,7 @@ Authors: import logging import Cookie +import uuid from tornado import web from tornado import websocket @@ -40,51 +41,74 @@ except ImportError: class AuthenticatedHandler(web.RequestHandler): """A RequestHandler with an authenticated user.""" + def get_current_user(self): - user_id = self.get_secure_cookie("user") + user_id = self.get_secure_cookie("username") + # For now the user_id should not return empty, but it could eventually if user_id == '': user_id = 'anonymous' if user_id is None: # prevent extra Invalid cookie sig warnings: - self.clear_cookie('user') + self.clear_cookie('username') if not self.application.password: user_id = 'anonymous' return user_id -class NBBrowserHandler(AuthenticatedHandler): +class ProjectDashboardHandler(AuthenticatedHandler): + @web.authenticated def get(self): nbm = self.application.notebook_manager project = nbm.notebook_dir - self.render('nbbrowser.html', project=project) + self.render( + 'projectdashboard.html', project=project, + base_project_url=u'/', base_kernel_url=u'/' + ) + class LoginHandler(AuthenticatedHandler): + def get(self): - user_id = self.get_secure_cookie("user") or '' - self.render('login.html', user_id=user_id) + self.render('login.html', next='/') def post(self): - pwd = self.get_argument("password", default=u'') + pwd = self.get_argument('password', default=u'') if self.application.password and pwd == self.application.password: - self.set_secure_cookie("user", self.get_argument("name", default=u'')) - url = self.get_argument("next", default="/") + self.set_secure_cookie('username', str(uuid.uuid4())) + url = self.get_argument('next', default='/') self.redirect(url) + class NewHandler(AuthenticatedHandler): + @web.authenticated def get(self): - notebook_id = self.application.notebook_manager.new_notebook() - self.render('notebook.html', notebook_id=notebook_id) + nbm = self.application.notebook_manager + project = nbm.notebook_dir + notebook_id = nbm.new_notebook() + self.render( + 'notebook.html', project=project, + notebook_id=notebook_id, + base_project_url=u'/', base_kernel_url=u'/', + kill_kernel=False + ) class NamedNotebookHandler(AuthenticatedHandler): + @web.authenticated def get(self, notebook_id): nbm = self.application.notebook_manager + project = nbm.notebook_dir if not nbm.notebook_exists(notebook_id): raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id) - self.render('notebook.html', notebook_id=notebook_id) + self.render( + 'notebook.html', project=project, + notebook_id=notebook_id, + base_project_url=u'/', base_kernel_url=u'/', + kill_kernel=False + ) #----------------------------------------------------------------------------- @@ -166,11 +190,13 @@ class ZMQStreamHandler(websocket.WebSocketHandler): try: msg = self._reserialize_reply(msg_list) except: - self.application.kernel_manager.log.critical("Malformed message: %r" % msg_list) + self.application.log.critical("Malformed message: %r" % msg_list) else: self.write_message(msg) + class AuthenticatedZMQStreamHandler(ZMQStreamHandler): + def open(self, kernel_id): self.kernel_id = kernel_id.decode('ascii') try: @@ -184,7 +210,7 @@ class AuthenticatedZMQStreamHandler(ZMQStreamHandler): self.on_message = self.on_first_message def get_current_user(self): - user_id = self.get_secure_cookie("user") + user_id = self.get_secure_cookie("username") if user_id == '' or (user_id is None and not self.application.password): user_id = 'anonymous' return user_id @@ -196,7 +222,7 @@ class AuthenticatedZMQStreamHandler(ZMQStreamHandler): # Cookie can't constructor doesn't accept unicode strings for some reason msg = msg.encode('utf8', 'replace') try: - self._cookies = Cookie.SimpleCookie(msg) + self.request._cookies = Cookie.SimpleCookie(msg) except: logging.warn("couldn't parse cookie string: %s",msg, exc_info=True) diff --git a/IPython/frontend/html/notebook/notebookapp.py b/IPython/frontend/html/notebook/notebookapp.py index 2228962..55f601f 100644 --- a/IPython/frontend/html/notebook/notebookapp.py +++ b/IPython/frontend/html/notebook/notebookapp.py @@ -37,7 +37,7 @@ from tornado import web from .kernelmanager import MappingKernelManager from .handlers import (LoginHandler, - NBBrowserHandler, NewHandler, NamedNotebookHandler, + ProjectDashboardHandler, NewHandler, NamedNotebookHandler, MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler, ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler ) @@ -80,7 +80,7 @@ class NotebookWebApplication(web.Application): def __init__(self, ipython_app, kernel_manager, notebook_manager, log): handlers = [ - (r"/", NBBrowserHandler), + (r"/", ProjectDashboardHandler), (r"/login", LoginHandler), (r"/new", NewHandler), (r"/%s" % _notebook_id_regex, NamedNotebookHandler), @@ -125,11 +125,11 @@ notebook_flags = ['no-browser'] aliases = dict(ipkernel_aliases) aliases.update({ - 'ip': 'IPythonNotebookApp.ip', - 'port': 'IPythonNotebookApp.port', - 'keyfile': 'IPythonNotebookApp.keyfile', - 'certfile': 'IPythonNotebookApp.certfile', - 'ws-hostname': 'IPythonNotebookApp.ws_hostname', + 'ip': 'NotebookApp.ip', + 'port': 'NotebookApp.port', + 'keyfile': 'NotebookApp.keyfile', + 'certfile': 'NotebookApp.certfile', + 'ws-hostname': 'NotebookApp.ws_hostname', 'notebook-dir': 'NotebookManager.notebook_dir', }) @@ -141,10 +141,10 @@ notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile', u'ws-hostname', u'notebook-dir'] #----------------------------------------------------------------------------- -# IPythonNotebookApp +# NotebookApp #----------------------------------------------------------------------------- -class IPythonNotebookApp(BaseIPythonApplication): +class NotebookApp(BaseIPythonApplication): name = 'ipython-notebook' default_config_file_name='ipython_notebook_config.py' @@ -213,7 +213,7 @@ class IPythonNotebookApp(BaseIPythonApplication): return prefix + self.ws_hostname + u':' + unicode(self.port) def parse_command_line(self, argv=None): - super(IPythonNotebookApp, self).parse_command_line(argv) + super(NotebookApp, self).parse_command_line(argv) if argv is None: argv = sys.argv[1:] @@ -254,14 +254,14 @@ class IPythonNotebookApp(BaseIPythonApplication): self.notebook_manager.list_notebooks() def init_logging(self): - super(IPythonNotebookApp, self).init_logging() + super(NotebookApp, self).init_logging() # This prevents double log messages because tornado use a root logger that # self.log is a child of. The logging module dipatches log messages to a log # and all of its ancenstors until propagate is set to False. self.log.propagate = False def initialize(self, argv=None): - super(IPythonNotebookApp, self).initialize(argv) + super(NotebookApp, self).initialize(argv) self.init_configurables() self.web_app = NotebookWebApplication( self, self.kernel_manager, self.notebook_manager, self.log @@ -309,7 +309,7 @@ class IPythonNotebookApp(BaseIPythonApplication): #----------------------------------------------------------------------------- def launch_new_instance(): - app = IPythonNotebookApp() + app = NotebookApp() app.initialize() app.start() diff --git a/IPython/frontend/html/notebook/static/css/notebook.css b/IPython/frontend/html/notebook/static/css/notebook.css index e56090f..1938e4c 100644 --- a/IPython/frontend/html/notebook/static/css/notebook.css +++ b/IPython/frontend/html/notebook/static/css/notebook.css @@ -37,9 +37,8 @@ input#notebook_name { } span#kernel_status { - position: absolute; - padding: 8px 5px 5px 5px; - right: 10px; + float: right; + padding: 0px 5px; font-weight: bold; } @@ -65,10 +64,14 @@ div#left_panel { position: absolute; } -h3.section_header { +div.section_header { padding: 5px; } +div.section_header h3 { + display: inline; +} + div.section_content { padding: 5px; } diff --git a/IPython/frontend/html/notebook/static/css/nbbrowser.css b/IPython/frontend/html/notebook/static/css/projectdashboard.css similarity index 100% rename from IPython/frontend/html/notebook/static/css/nbbrowser.css rename to IPython/frontend/html/notebook/static/css/projectdashboard.css diff --git a/IPython/frontend/html/notebook/static/js/kernel.js b/IPython/frontend/html/notebook/static/js/kernel.js index f3797e2..35980b5 100644 --- a/IPython/frontend/html/notebook/static/js/kernel.js +++ b/IPython/frontend/html/notebook/static/js/kernel.js @@ -15,12 +15,10 @@ var IPython = (function (IPython) { var Kernel = function () { this.kernel_id = null; - this.base_url = "/kernels"; - this.kernel_url = null; this.shell_channel = null; this.iopub_channel = null; + this.base_url = $('body').data('baseKernelUrl') + "kernels"; this.running = false; - this.username = "username"; this.session_id = utils.uuid(); @@ -52,7 +50,8 @@ var IPython = (function (IPython) { var that = this; if (!this.running) { var qs = $.param({notebook:notebook_id}); - $.post(this.base_url + '?' + qs, + var url = this.base_url + '?' + qs + $.post(url, function (kernel_id) { that._handle_start_kernel(kernel_id, callback); }, @@ -97,7 +96,6 @@ var IPython = (function (IPython) { this.iopub_channel = new this.WebSocket(ws_url + "/iopub"); send_cookie = function(){ this.send(document.cookie); - console.log(this); } this.shell_channel.onopen = send_cookie; this.iopub_channel.onopen = send_cookie; diff --git a/IPython/frontend/html/notebook/static/js/loginmain.js b/IPython/frontend/html/notebook/static/js/loginmain.js new file mode 100644 index 0000000..684d3e0 --- /dev/null +++ b/IPython/frontend/html/notebook/static/js/loginmain.js @@ -0,0 +1,30 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2008-2011 The IPython Development Team +// +// Distributed under the terms of the BSD License. The full license is in +// the file COPYING, distributed as part of this software. +//---------------------------------------------------------------------------- + +//============================================================================ +// On document ready +//============================================================================ + + +$(document).ready(function () { + + $('div#header').addClass('border-box-sizing'); + $('div#header_border').addClass('border-box-sizing ui-widget ui-widget-content'); + + $('div#main_app').addClass('border-box-sizing ui-widget'); + $('div#app_hbox').addClass('hbox'); + + $('div#left_panel').addClass('box-flex'); + $('div#right_panel').addClass('box-flex'); + $('input#signin').button(); + + // These have display: none in the css file and are made visible here to prevent FLOUC. + $('div#header').css('display','block'); + $('div#main_app').css('display','block'); + +}); + diff --git a/IPython/frontend/html/notebook/static/js/notebook.js b/IPython/frontend/html/notebook/static/js/notebook.js index 0cc2e20..e8c0f84 100644 --- a/IPython/frontend/html/notebook/static/js/notebook.js +++ b/IPython/frontend/html/notebook/static/js/notebook.js @@ -931,7 +931,8 @@ var IPython = (function (IPython) { error : $.proxy(this.notebook_save_failed,this) }; IPython.save_widget.status_saving(); - $.ajax("/notebooks/" + notebook_id, settings); + var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id + $.ajax(url, settings); }; }; @@ -939,7 +940,7 @@ var IPython = (function (IPython) { Notebook.prototype.notebook_saved = function (data, status, xhr) { this.dirty = false; IPython.save_widget.notebook_saved(); - setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500); + IPython.save_widget.status_save(); } @@ -947,7 +948,7 @@ var IPython = (function (IPython) { // Notify the user and reset the save button // TODO: Handle different types of errors (timeout etc.) alert('An unexpected error occured while saving the notebook.'); - setTimeout($.proxy(IPython.save_widget.reset_status,IPython.save_widget),500); + IPython.save_widget.reset_status(); } @@ -968,7 +969,8 @@ var IPython = (function (IPython) { } }; IPython.save_widget.status_loading(); - $.ajax("/notebooks/" + notebook_id, settings); + var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id + $.ajax(url, settings); } @@ -989,8 +991,10 @@ var IPython = (function (IPython) { }, 50); }; + IPython.Notebook = Notebook; + return IPython; }(IPython)); diff --git a/IPython/frontend/html/notebook/static/js/notebooklist.js b/IPython/frontend/html/notebook/static/js/notebooklist.js index 7fac3b7..5a3bf86 100644 --- a/IPython/frontend/html/notebook/static/js/notebooklist.js +++ b/IPython/frontend/html/notebook/static/js/notebooklist.js @@ -67,7 +67,8 @@ var IPython = (function (IPython) { dataType : "json", success : $.proxy(this.list_loaded, this) }; - $.ajax("/notebooks", settings); + var url = $('body').data('baseProjectUrl') + 'notebooks' + $.ajax(url, settings); }; @@ -105,7 +106,7 @@ var IPython = (function (IPython) { var new_item_name = $('').addClass('item_name'); new_item_name.append( $(''). - attr('href','/'+notebook_id). + attr('href', $('body').data('baseProjectURL')+notebook_id). attr('target','_blank'). text(nbname) ); @@ -170,7 +171,8 @@ var IPython = (function (IPython) { parent_item.remove(); } }; - $.ajax("/notebooks/" + notebook_id, settings); + var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id + $.ajax(url, settings); $(this).dialog('close'); }, "Cancel": function () { @@ -217,7 +219,8 @@ var IPython = (function (IPython) { }; var qs = $.param({name:nbname, format:nbformat}); - $.ajax('/notebooks?' + qs, settings); + var url = $('body').data('baseProjectUrl') + 'notebooks?' + qs + $.ajax(url, settings); }); var cancel_button = $('').button(). click(function (e) { diff --git a/IPython/frontend/html/notebook/static/js/notebook_main.js b/IPython/frontend/html/notebook/static/js/notebookmain.js similarity index 100% rename from IPython/frontend/html/notebook/static/js/notebook_main.js rename to IPython/frontend/html/notebook/static/js/notebookmain.js diff --git a/IPython/frontend/html/notebook/static/js/panelsection.js b/IPython/frontend/html/notebook/static/js/panelsection.js index ea84567..324febf 100644 --- a/IPython/frontend/html/notebook/static/js/panelsection.js +++ b/IPython/frontend/html/notebook/static/js/panelsection.js @@ -19,7 +19,7 @@ var IPython = (function (IPython) { this.selector = selector; if (this.selector !== undefined) { this.element = $(selector); - this.header = this.element.find('h3.section_header'); + this.header = this.element.find('div.section_header'); this.content = this.element.find('div.section_content'); this.style(); this.bind_events(); @@ -29,7 +29,7 @@ var IPython = (function (IPython) { PanelSection.prototype.style = function () { - this.header.addClass('ui-widget ui-state-default'); + this.header.addClass('ui-widget ui-state-default ui-helper-clearfix'); this.header.attr('title', "Click to Show/Hide Section"); this.content.addClass('ui-widget section_content'); }; @@ -106,15 +106,15 @@ var IPython = (function (IPython) { PanelSection.prototype.bind_events.apply(this); var that = this; this.content.find('#new_notebook').click(function () { - window.open('/new'); + window.open($('body').data('baseProjectUrl')+'new'); }); this.content.find('#open_notebook').click(function () { - window.open('/'); + window.open($('body').data('baseProjectUrl')); }); this.content.find('#download_notebook').click(function () { var format = that.content.find('#download_format').val(); var notebook_id = IPython.save_widget.get_notebook_id(); - var url = '/notebooks/' + notebook_id + '?format=' + format; + var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id + '?format=' + format; window.open(url,'_newtab'); }); }; diff --git a/IPython/frontend/html/notebook/static/js/nbbrowser_main.js b/IPython/frontend/html/notebook/static/js/projectdashboardmain.js similarity index 96% rename from IPython/frontend/html/notebook/static/js/nbbrowser_main.js rename to IPython/frontend/html/notebook/static/js/projectdashboardmain.js index c5b4587..9ae6256 100644 --- a/IPython/frontend/html/notebook/static/js/nbbrowser_main.js +++ b/IPython/frontend/html/notebook/static/js/projectdashboardmain.js @@ -21,7 +21,7 @@ $(document).ready(function () { $('div#content_toolbar').addClass('ui-widget ui-helper-clearfix'); $('#new_notebook').button().click(function (e) { - window.open('/new'); + window.open($('body').data('baseProjectUrl')+'new'); }); $('div#left_panel').addClass('box-flex'); diff --git a/IPython/frontend/html/notebook/static/js/savewidget.js b/IPython/frontend/html/notebook/static/js/savewidget.js index 18a16cd..2c7f631 100644 --- a/IPython/frontend/html/notebook/static/js/savewidget.js +++ b/IPython/frontend/html/notebook/static/js/savewidget.js @@ -82,12 +82,12 @@ var IPython = (function (IPython) { SaveWidget.prototype.set_document_title = function () { nbname = this.get_notebook_name(); - document.title = 'IPy: ' + nbname; + document.title = nbname; }; SaveWidget.prototype.get_notebook_id = function () { - return this.element.find('span#notebook_id').text() + return $('body').data('notebookId'); }; diff --git a/IPython/frontend/html/notebook/templates/focus.html b/IPython/frontend/html/notebook/templates/focus.html deleted file mode 100644 index 51df6ca..0000000 --- a/IPython/frontend/html/notebook/templates/focus.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - Event ordering - - - - - - -
- This is the outer div. - -
- This is the inner div. -
- This is the innerinner div -
-
- -
- - - - - - - - - - - diff --git a/IPython/frontend/html/notebook/templates/login.html b/IPython/frontend/html/notebook/templates/login.html index 855db58..86f160a 100644 --- a/IPython/frontend/html/notebook/templates/login.html +++ b/IPython/frontend/html/notebook/templates/login.html @@ -7,24 +7,13 @@ IPython Notebook - - - - + - +
-
- Name: + Password: - +
@@ -56,8 +44,7 @@ function add_next_to_action(){ - - + diff --git a/IPython/frontend/html/notebook/templates/notebook.html b/IPython/frontend/html/notebook/templates/notebook.html index 6f16348..f96e79b 100644 --- a/IPython/frontend/html/notebook/templates/notebook.html +++ b/IPython/frontend/html/notebook/templates/notebook.html @@ -6,10 +6,6 @@ IPython Notebook - - - - + @@ -47,19 +44,20 @@ - +
-

Notebook

+
+

Notebook

+
@@ -121,7 +121,9 @@
-

Cell

+
+

Cell

+
@@ -175,7 +177,10 @@
-

Kernel

+
+

Kernel

+ Idle +
@@ -186,7 +191,11 @@
- + {% if kill_kernel %} + + {% else %} + + {% end %} Kill kernel upon exit:
@@ -194,7 +203,9 @@
-

Help

+
+

Cell

+
@@ -272,8 +283,7 @@ - - + diff --git a/IPython/frontend/html/notebook/templates/nbbrowser.html b/IPython/frontend/html/notebook/templates/projectdashboard.html similarity index 87% rename from IPython/frontend/html/notebook/templates/nbbrowser.html rename to IPython/frontend/html/notebook/templates/projectdashboard.html index f95afa1..7f24bf5 100644 --- a/IPython/frontend/html/notebook/templates/nbbrowser.html +++ b/IPython/frontend/html/notebook/templates/projectdashboard.html @@ -7,17 +7,15 @@ IPython Notebook - - - - + - +