From f19a63759bdedb4dfab421291222da93a04d2a2e Mon Sep 17 00:00:00 2001 From: Brian Granger Date: Mon, 6 Feb 2012 15:02:02 -0800 Subject: [PATCH 01/12] First version of cluster web service. This exposes ipcluster's over the web. The current implementation uses IPClusterLauncher to run ipcluster in a separate process. Here is the URL scheme we are using: GET /clusters => list available clusters GET /cluster/profile => list info for cluster with profile POST /cluster/profile/start => start a cluster POST /cluster/profile/stop => stop a cluster --- .../frontend/html/notebook/clustermanager.py | 90 +++++++++++++++++++ IPython/frontend/html/notebook/handlers.py | 36 +++++++- IPython/frontend/html/notebook/notebookapp.py | 20 ++++- 3 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 IPython/frontend/html/notebook/clustermanager.py diff --git a/IPython/frontend/html/notebook/clustermanager.py b/IPython/frontend/html/notebook/clustermanager.py new file mode 100644 index 000000000..4fc8626d8 --- /dev/null +++ b/IPython/frontend/html/notebook/clustermanager.py @@ -0,0 +1,90 @@ +"""Manage IPython.parallel clusters in the notebook. + +Authors: + +* Brian Granger +""" + +#----------------------------------------------------------------------------- +# 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. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +import datetime +import os +import uuid +import glob + +from tornado import web +from zmq.eventloop import ioloop + +from IPython.config.configurable import LoggingConfigurable +from IPython.utils.traitlets import Unicode, List, Dict, Bool +from IPython.parallel.apps.launcher import IPClusterLauncher +from IPython.core.profileapp import list_profiles_in, list_bundled_profiles +from IPython.utils.path import get_ipython_dir, get_ipython_package_dir + +#----------------------------------------------------------------------------- +# Classes +#----------------------------------------------------------------------------- + +class ClusterManager(LoggingConfigurable): + + profiles = Dict() + + + def list_profile_names(self): + """List all profiles in the ipython_dir and cwd. + """ + profiles = list_profiles_in(get_ipython_dir()) + profiles += list_profiles_in(os.getcwdu()) + return profiles + + + def list_profiles(self): + profiles = self.list_profile_names() + result = [self.profile_info(p) for p in profiles] + return result + + + def profile_info(self, profile): + if profile not in self.list_profile_names(): + raise web.HTTPError(404, u'profile not found') + result = dict(profile=profile) + data = self.profiles.get(profile) + if data is None: + result['status'] = 'stopped' + else: + result['status'] = 'running' + result['n'] = data['n'] + return result + + def start_cluster(self, profile, n=4): + """Start a cluster for a given profile.""" + if profile not in self.list_profile_names(): + raise web.HTTPError(404, u'profile not found') + if profile in self.profiles: + raise web.HTTPError(409, u'cluster already running') + launcher = IPClusterLauncher(ipcluster_profile=profile, ipcluster_n=n) + launcher.start() + self.profiles[profile] = { + 'launcher': launcher, + 'n': n + } + + def stop_cluster(self, profile): + """Stop a cluster for a given profile.""" + if profile not in self.profiles: + raise web.HTTPError(409, u'cluster not running') + launcher = self.profiles.pop(profile)['launcher'] + launcher.stop() + + def stop_all_clusters(self): + for p in self.profiles.values(): + p['launcher'].stop() diff --git a/IPython/frontend/html/notebook/handlers.py b/IPython/frontend/html/notebook/handlers.py index faba77de4..ba1e5a26f 100644 --- a/IPython/frontend/html/notebook/handlers.py +++ b/IPython/frontend/html/notebook/handlers.py @@ -587,7 +587,6 @@ class NotebookRootHandler(AuthenticatedHandler): @authenticate_unless_readonly def get(self): - nbm = self.application.notebook_manager files = nbm.list_notebooks() self.finish(jsonapi.dumps(files)) @@ -661,6 +660,41 @@ class NotebookCopyHandler(AuthenticatedHandler): mathjax_url=self.application.ipython_app.mathjax_url, ) + +#----------------------------------------------------------------------------- +# Cluster handlers +#----------------------------------------------------------------------------- + + +class MainClusterHandler(AuthenticatedHandler): + + @web.authenticated + def get(self): + cm = self.application.cluster_manager + self.finish(jsonapi.dumps(cm.list_profiles())) + + +class ClusterProfileHandler(AuthenticatedHandler): + + @web.authenticated + def get(self, profile): + cm = self.application.cluster_manager + self.finish(jsonapi.dumps(cm.profile_info(profile))) + + +class ClusterActionHandler(AuthenticatedHandler): + + @web.authenticated + def post(self, profile, action): + cm = self.application.cluster_manager + if action == 'start': + n = int(self.get_argument('n', default=4)) + cm.start_cluster(profile, n) + if action == 'stop': + cm.stop_cluster(profile) + self.finish() + + #----------------------------------------------------------------------------- # RST web service handlers #----------------------------------------------------------------------------- diff --git a/IPython/frontend/html/notebook/notebookapp.py b/IPython/frontend/html/notebook/notebookapp.py index 09b91dec2..0c5be714f 100644 --- a/IPython/frontend/html/notebook/notebookapp.py +++ b/IPython/frontend/html/notebook/notebookapp.py @@ -49,9 +49,11 @@ from .handlers import (LoginHandler, LogoutHandler, ProjectDashboardHandler, NewHandler, NamedNotebookHandler, MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler, ShellHandler, NotebookRootHandler, NotebookHandler, NotebookCopyHandler, - RSTHandler, AuthenticatedFileHandler, PrintNotebookHandler + RSTHandler, AuthenticatedFileHandler, PrintNotebookHandler, + MainClusterHandler, ClusterProfileHandler, ClusterActionHandler ) from .notebookmanager import NotebookManager +from .clustermanager import ClusterManager from IPython.config.application import catch_config_error, boolean_flag from IPython.core.application import BaseIPythonApplication @@ -74,6 +76,9 @@ from IPython.utils import py3compat _kernel_id_regex = r"(?P\w+-\w+-\w+-\w+-\w+)" _kernel_action_regex = r"(?Prestart|interrupt)" _notebook_id_regex = r"(?P\w+-\w+-\w+-\w+-\w+)" +_profile_regex = r"(?P[a-zA-Z0-9]+)" +_cluster_action_regex = r"(?Pstart|stop)" + LOCALHOST = '127.0.0.1' @@ -101,7 +106,8 @@ def url_path_join(a,b): class NotebookWebApplication(web.Application): - def __init__(self, ipython_app, kernel_manager, notebook_manager, log, + def __init__(self, ipython_app, kernel_manager, notebook_manager, + cluster_manager, log, base_project_url, settings_overrides): handlers = [ (r"/", ProjectDashboardHandler), @@ -120,6 +126,9 @@ class NotebookWebApplication(web.Application): (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler), (r"/rstservice/render", RSTHandler), (r"/files/(.*)", AuthenticatedFileHandler, {'path' : notebook_manager.notebook_dir}), + (r"/clusters", MainClusterHandler), + (r"/clusters/%s/%s" % (_profile_regex, _cluster_action_regex), ClusterActionHandler), + (r"/clusters/%s" % _profile_regex, ClusterProfileHandler), ] settings = dict( template_path=os.path.join(os.path.dirname(__file__), "templates"), @@ -151,10 +160,11 @@ class NotebookWebApplication(web.Application): super(NotebookWebApplication, self).__init__(new_handlers, **settings) self.kernel_manager = kernel_manager - self.log = log self.notebook_manager = notebook_manager + self.cluster_manager = cluster_manager self.ipython_app = ipython_app self.read_only = self.ipython_app.read_only + self.log = log #----------------------------------------------------------------------------- @@ -395,6 +405,7 @@ class NotebookApp(BaseIPythonApplication): ) self.notebook_manager = NotebookManager(config=self.config, log=self.log) self.notebook_manager.list_notebooks() + self.cluster_manager = ClusterManager(config=self.config, log=self.log) def init_logging(self): super(NotebookApp, self).init_logging() @@ -406,7 +417,8 @@ class NotebookApp(BaseIPythonApplication): def init_webapp(self): """initialize tornado webapp and httpserver""" self.web_app = NotebookWebApplication( - self, self.kernel_manager, self.notebook_manager, self.log, + self, self.kernel_manager, self.notebook_manager, + self.cluster_manager, self.log, self.base_project_url, self.webapp_settings ) if self.certfile: From 6dc7b078b95484fe8c1d93986d0ac755491e305f Mon Sep 17 00:00:00 2001 From: Brian Granger Date: Tue, 7 Feb 2012 16:05:54 -0800 Subject: [PATCH 02/12] Refactoring templates and top level js/css organization. --- IPython/frontend/html/notebook/handlers.py | 2 + .../html/notebook/static/css/login.css | 6 +++ .../html/notebook/static/css/logout.css | 7 +++ .../html/notebook/static/css/notebook.css | 8 ++++ .../static/css/{base.css => page.css} | 20 +++++---- .../notebook/static/css/projectdashboard.css | 37 ++-------------- .../html/notebook/static/js/loginmain.js | 16 ++----- .../html/notebook/static/js/loginwidget.js | 2 + .../html/notebook/static/js/logoutmain.js | 20 +++++++++ .../html/notebook/static/js/notebooklist.js | 1 - .../html/notebook/static/js/notebookmain.js | 1 - .../frontend/html/notebook/static/js/page.js | 44 +++++++++++++++++++ .../html/notebook/static/js/pagemain.js | 19 ++++++++ .../static/js/projectdashboardmain.js | 18 ++------ .../html/notebook/templates/login.html | 42 ++++++++++++------ .../html/notebook/templates/logout.html | 42 +++++++++++------- .../templates/{layout.html => page.html} | 42 +++--------------- .../notebook/templates/projectdashboard.html | 20 +++++---- 18 files changed, 206 insertions(+), 141 deletions(-) create mode 100644 IPython/frontend/html/notebook/static/css/login.css create mode 100644 IPython/frontend/html/notebook/static/css/logout.css rename IPython/frontend/html/notebook/static/css/{base.css => page.css} (86%) create mode 100644 IPython/frontend/html/notebook/static/js/logoutmain.js create mode 100644 IPython/frontend/html/notebook/static/js/page.js create mode 100644 IPython/frontend/html/notebook/static/js/pagemain.js rename IPython/frontend/html/notebook/templates/{layout.html => page.html} (58%) diff --git a/IPython/frontend/html/notebook/handlers.py b/IPython/frontend/html/notebook/handlers.py index ba1e5a26f..eb9e9cdba 100644 --- a/IPython/frontend/html/notebook/handlers.py +++ b/IPython/frontend/html/notebook/handlers.py @@ -211,6 +211,7 @@ class LoginHandler(AuthenticatedHandler): read_only=self.read_only, logged_in=self.logged_in, login_available=self.login_available, + base_project_url=self.application.ipython_app.base_project_url, message=message ) @@ -246,6 +247,7 @@ class LogoutHandler(AuthenticatedHandler): read_only=self.read_only, logged_in=self.logged_in, login_available=self.login_available, + base_project_url=self.application.ipython_app.base_project_url, message=message) diff --git a/IPython/frontend/html/notebook/static/css/login.css b/IPython/frontend/html/notebook/static/css/login.css new file mode 100644 index 000000000..41eb7900a --- /dev/null +++ b/IPython/frontend/html/notebook/static/css/login.css @@ -0,0 +1,6 @@ + +#main_app { + height: 100px; + width: 350px; + margin: 50px auto; +} diff --git a/IPython/frontend/html/notebook/static/css/logout.css b/IPython/frontend/html/notebook/static/css/logout.css new file mode 100644 index 000000000..7767494f8 --- /dev/null +++ b/IPython/frontend/html/notebook/static/css/logout.css @@ -0,0 +1,7 @@ + +#main_app { + height: 100px; + width: 200px; + margin: 50px auto; +} + diff --git a/IPython/frontend/html/notebook/static/css/notebook.css b/IPython/frontend/html/notebook/static/css/notebook.css index 6fa3ab9bb..dabd75528 100644 --- a/IPython/frontend/html/notebook/static/css/notebook.css +++ b/IPython/frontend/html/notebook/static/css/notebook.css @@ -78,6 +78,14 @@ span#notebook_name { font-size: 85%; } + +div#main_app { + /* Initially hidden to prevent FLOUC */ + display: none; + width: 100%; + position: relative; +} + span#quick_help_area { position: static; padding: 5px 0px; diff --git a/IPython/frontend/html/notebook/static/css/base.css b/IPython/frontend/html/notebook/static/css/page.css similarity index 86% rename from IPython/frontend/html/notebook/static/css/base.css rename to IPython/frontend/html/notebook/static/css/page.css index 5088bfb77..e6e7e778c 100644 --- a/IPython/frontend/html/notebook/static/css/base.css +++ b/IPython/frontend/html/notebook/static/css/page.css @@ -14,7 +14,7 @@ body { right: 0px; top: 0px; bottom: 0px; - overflow: hidden; + overflow: visible; } @@ -41,11 +41,9 @@ span#ipython_notebook h1 img { color: black; } -div#main_app { - /* Initially hidden to prevent FLOUC */ +#site { + width: 100% display: none; - width: 100%; - position: relative; } /* We set the fonts by hand here to override the values in the theme */ @@ -63,11 +61,17 @@ div#main_app { font-size: 77%; } +input.ui-button { + padding: 0.3em 0.9em; +} + span#login_widget { float: right; } -/* generic class for hidden objects */ -.hidden { - display: none; +.border-box-sizing { + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; } + diff --git a/IPython/frontend/html/notebook/static/css/projectdashboard.css b/IPython/frontend/html/notebook/static/css/projectdashboard.css index 0ca74842f..1217970e1 100644 --- a/IPython/frontend/html/notebook/static/css/projectdashboard.css +++ b/IPython/frontend/html/notebook/static/css/projectdashboard.css @@ -5,46 +5,17 @@ * Author: IPython Development Team */ - -body { - background-color: white; - /* This makes sure that the body covers the entire window and needs to - be in a different element than the display: box in wrapper below */ - position: absolute; - left: 0px; - right: 0px; - top: 0px; - bottom: 0px; - overflow: auto; -} - -#left_panel { +#main_app { + width: 920px; + margin: auto; } -#drop_zone { - height: 200px; - width: 200px -} - -#content_panel { - width: 600px; -} - -#content_toolbar { +#notebooks_toolbar { padding: 5px; height: 25px; line-height: 25px; } -#header_border { - width: 100%; - height: 2px; -} - -#app_hbox { - width: 100%; -} - #drag_info { float: left; } diff --git a/IPython/frontend/html/notebook/static/js/loginmain.js b/IPython/frontend/html/notebook/static/js/loginmain.js index 684d3e00c..503f1eaa2 100644 --- a/IPython/frontend/html/notebook/static/js/loginmain.js +++ b/IPython/frontend/html/notebook/static/js/loginmain.js @@ -12,19 +12,11 @@ $(document).ready(function () { - $('div#header').addClass('border-box-sizing'); - $('div#header_border').addClass('border-box-sizing ui-widget ui-widget-content'); - + IPython.page = new IPython.Page(); + $('input#login_submit').button(); $('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'); + IPython.page.show(); + $('input#password_input').focus(); }); diff --git a/IPython/frontend/html/notebook/static/js/loginwidget.js b/IPython/frontend/html/notebook/static/js/loginwidget.js index 763118e8d..288772a94 100644 --- a/IPython/frontend/html/notebook/static/js/loginwidget.js +++ b/IPython/frontend/html/notebook/static/js/loginwidget.js @@ -24,6 +24,8 @@ var IPython = (function (IPython) { this.element.find('button#logout').button(); this.element.find('button#login').button(); }; + + LoginWidget.prototype.bind_events = function () { var that = this; this.element.find("button#logout").click(function () { diff --git a/IPython/frontend/html/notebook/static/js/logoutmain.js b/IPython/frontend/html/notebook/static/js/logoutmain.js new file mode 100644 index 000000000..8bbddb4af --- /dev/null +++ b/IPython/frontend/html/notebook/static/js/logoutmain.js @@ -0,0 +1,20 @@ +//---------------------------------------------------------------------------- +// 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 () { + + IPython.page = new IPython.Page(); + $('div#main_app').addClass('border-box-sizing ui-widget'); + IPython.page.show(); + +}); + diff --git a/IPython/frontend/html/notebook/static/js/notebooklist.js b/IPython/frontend/html/notebook/static/js/notebooklist.js index 50dd96a61..1a79e045a 100644 --- a/IPython/frontend/html/notebook/static/js/notebooklist.js +++ b/IPython/frontend/html/notebook/static/js/notebooklist.js @@ -21,7 +21,6 @@ var IPython = (function (IPython) { }; NotebookList.prototype.style = function () { - this.element.addClass('ui-widget ui-widget-content'); $('div#project_name').addClass('ui-widget ui-widget-header'); }; diff --git a/IPython/frontend/html/notebook/static/js/notebookmain.js b/IPython/frontend/html/notebook/static/js/notebookmain.js index 34cd61c33..f048e938b 100644 --- a/IPython/frontend/html/notebook/static/js/notebookmain.js +++ b/IPython/frontend/html/notebook/static/js/notebookmain.js @@ -99,7 +99,6 @@ $(document).ready(function () { // hide various elements from read-only view $('div#pager').remove(); $('div#pager_splitter').remove(); - $('span#login_widget').removeClass('hidden'); // set the notebook name field as not modifiable $('#notebook_name').attr('disabled','disabled') diff --git a/IPython/frontend/html/notebook/static/js/page.js b/IPython/frontend/html/notebook/static/js/page.js new file mode 100644 index 000000000..7eaca8372 --- /dev/null +++ b/IPython/frontend/html/notebook/static/js/page.js @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------------- +// 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. +//---------------------------------------------------------------------------- + +//============================================================================ +// Global header/site setup. +//============================================================================ + +var IPython = (function (IPython) { + + var Page = function () { + this.style(); + this.bind_events(); + }; + + Page.prototype.style = function () { + $('div#header').addClass('border-box-sizing'). + addClass('ui-widget ui-widget-content'). + css('border-top-style','none'). + css('border-left-style','none'). + css('border-right-style','none'); + $('div#site').addClass('border-box-sizing') + }; + + + Page.prototype.bind_events = function () { + }; + + + Page.prototype.show = function () { + // The header and site divs start out hidden to prevent FLOUC. + // Main scripts should call this method after styling everything. + $('div#header').css('display','block'); + $('div#site').css('display','block'); + }; + + IPython.Page = Page; + + return IPython; + +}(IPython)); diff --git a/IPython/frontend/html/notebook/static/js/pagemain.js b/IPython/frontend/html/notebook/static/js/pagemain.js new file mode 100644 index 000000000..35c2670fc --- /dev/null +++ b/IPython/frontend/html/notebook/static/js/pagemain.js @@ -0,0 +1,19 @@ +//---------------------------------------------------------------------------- +// 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 () { + + IPython.page = new IPython.Page(); + IPython.page.show(); + +}); + diff --git a/IPython/frontend/html/notebook/static/js/projectdashboardmain.js b/IPython/frontend/html/notebook/static/js/projectdashboardmain.js index 516b406ba..41337c38a 100644 --- a/IPython/frontend/html/notebook/static/js/projectdashboardmain.js +++ b/IPython/frontend/html/notebook/static/js/projectdashboardmain.js @@ -12,31 +12,21 @@ $(document).ready(function () { - $('div#header').addClass('border-box-sizing'); - $('div#header_border').addClass('border-box-sizing ui-widget ui-widget-content'); + IPython.page = new IPython.Page(); $('div#main_app').addClass('border-box-sizing ui-widget'); - $('div#app_hbox').addClass('hbox'); - - $('div#content_toolbar').addClass('ui-widget ui-helper-clearfix'); - + $('div#notebooks_toolbar').addClass('ui-widget ui-helper-clearfix'); $('#new_notebook').button().click(function (e) { window.open($('body').data('baseProjectUrl')+'new'); }); - $('div#left_panel').addClass('box-flex'); - $('div#right_panel').addClass('box-flex'); - - IPython.read_only = $('meta[name=read_only]').attr("content") == 'True'; + IPython.read_only = $('body').data('readOnly') === 'True'; IPython.notebook_list = new IPython.NotebookList('div#notebook_list'); IPython.login_widget = new IPython.LoginWidget('span#login_widget'); IPython.notebook_list.load_list(); - // 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'); - + IPython.page.show(); }); diff --git a/IPython/frontend/html/notebook/templates/login.html b/IPython/frontend/html/notebook/templates/login.html index 4c5b2c069..b99dc0866 100644 --- a/IPython/frontend/html/notebook/templates/login.html +++ b/IPython/frontend/html/notebook/templates/login.html @@ -1,26 +1,42 @@ -{% extends layout.html %} +{% extends page.html %} -{% block content_panel %} +{% block stylesheet %} - {% if login_available %} + + +{% end %} + + +{% block login_widget %} +{% end %} + + +{% block site %} +
+ + {% if login_available %}
- Password: - + Password: +
+ {% end %} + {% if message %} + {% for key in message %} +
+ {{message[key]}} +
+ {% end %} {% end %} -{% end %} +
-{% block login_widget %} {% end %} + {% block script %} - + + + {% end %} diff --git a/IPython/frontend/html/notebook/templates/logout.html b/IPython/frontend/html/notebook/templates/logout.html index 8087508af..e31f0ac1c 100644 --- a/IPython/frontend/html/notebook/templates/logout.html +++ b/IPython/frontend/html/notebook/templates/logout.html @@ -1,28 +1,40 @@ -{% extends layout.html %} +{% extends page.html %} -{% block content_panel %} -
    - {% if read_only or not login_available %} +{% block stylesheet %} - Proceed to the list of notebooks. + - {% else %} +{% end %} + + +{% block login_widget %} +{% end %} + +{% block site %} - Proceed to the login page. +
    + {% if message %} + {% for key in message %} +
    + {{message[key]}} +
    + {% end %} {% end %} -
+ {% if read_only or not login_available %} + Proceed to the dashboard. + {% else %} + Proceed to the login page. + {% end %} -{% end %} -{% block login_widget %} +
+ {% end %} {% block script %} - + + + {% end %} diff --git a/IPython/frontend/html/notebook/templates/layout.html b/IPython/frontend/html/notebook/templates/page.html similarity index 58% rename from IPython/frontend/html/notebook/templates/layout.html rename to IPython/frontend/html/notebook/templates/page.html index 700a7062c..2701985b7 100644 --- a/IPython/frontend/html/notebook/templates/layout.html +++ b/IPython/frontend/html/notebook/templates/page.html @@ -8,8 +8,8 @@ - - + + {% block stylesheet %} {% end %} @@ -21,7 +21,7 @@ -
- -
- -
- -
- {% block left_panel %} - {% end %} -
- -
- {% if message %} - - {% for key in message %} -
- {{message[key]}} -
- {% end %} - {% end %} - - {% block content_panel %} - {% end %} -
-
- {% block right_panel %} - {% end %} -
- -
- +
+{% block site %} +{% end %}
- + {% block script %} diff --git a/IPython/frontend/html/notebook/templates/projectdashboard.html b/IPython/frontend/html/notebook/templates/projectdashboard.html index 9a64a0c60..b5cb84840 100644 --- a/IPython/frontend/html/notebook/templates/projectdashboard.html +++ b/IPython/frontend/html/notebook/templates/projectdashboard.html @@ -1,27 +1,26 @@ -{% extends layout.html %} +{% extends page.html %} -{% block title %} -IPython Dashboard -{% end %} +{% block title %}IPython Dashboard{% end %} {% block stylesheet %} {% end %} -{% block meta %} - -{% end %} {% block params %} data-project={{project}} data-base-project-url={{base_project_url}} data-base-kernel-url={{base_kernel_url}} +data-read-only={{read_only}} {% end %} -{% block content_panel %} +{% block site %} + +
+ {% if logged_in or not read_only %} -
+
Drag files onto the list to import notebooks. @@ -35,6 +34,9 @@ data-base-kernel-url={{base_kernel_url}}

{{project}}

+ +
+ {% end %} {% block script %} From 3631fae1539e349d15e4127f1e4f9b1988719eb8 Mon Sep 17 00:00:00 2001 From: Brian Granger Date: Tue, 7 Feb 2012 21:40:33 -0800 Subject: [PATCH 03/12] Major refactoring of notebook. * Created new base page html/css/js. * Everything inherits from the page template. * Universal header border. * Notebook list borders are set to 1px all around. * No border around notebook area. * Border cleanup of toolbar/menubar. * Lots of code reorg to get ready for further refactoring. --- .../html/notebook/static/css/notebook.css | 17 --- .../html/notebook/static/css/page.css | 2 +- .../html/notebook/static/js/menubar.js | 1 + .../html/notebook/static/js/notebooklist.js | 1 + .../html/notebook/static/js/notebookmain.js | 79 ++---------- .../frontend/html/notebook/static/js/page.js | 15 +++ .../html/notebook/static/js/toolbar.js | 6 +- .../html/notebook/templates/notebook.html | 115 ++++++++---------- .../notebook/templates/projectdashboard.html | 3 + 9 files changed, 86 insertions(+), 153 deletions(-) diff --git a/IPython/frontend/html/notebook/static/css/notebook.css b/IPython/frontend/html/notebook/static/css/notebook.css index dabd75528..88f9259d4 100644 --- a/IPython/frontend/html/notebook/static/css/notebook.css +++ b/IPython/frontend/html/notebook/static/css/notebook.css @@ -6,14 +6,6 @@ body { - background-color: white; - /* This makes sure that the body covers the entire window and needs to - be in a different element than the display: box in wrapper below */ - position: absolute; - left: 0px; - right: 0px; - top: 0px; - bottom: 0px; overflow: hidden; } @@ -31,11 +23,6 @@ span#notebook_name { font-size: 146.5%; } -#menubar { - /* Initially hidden to prevent FLOUC */ - display: none; -} - .ui-menubar-item .ui-button .ui-button-text { padding: 0.4em 1.0em; font-size: 100%; @@ -69,8 +56,6 @@ span#notebook_name { } #toolbar { - /* Initially hidden to prevent FLOUC */ - display: none; padding: 3px 15px; } @@ -80,8 +65,6 @@ span#notebook_name { div#main_app { - /* Initially hidden to prevent FLOUC */ - display: none; width: 100%; position: relative; } diff --git a/IPython/frontend/html/notebook/static/css/page.css b/IPython/frontend/html/notebook/static/css/page.css index e6e7e778c..ff2b16cc3 100644 --- a/IPython/frontend/html/notebook/static/css/page.css +++ b/IPython/frontend/html/notebook/static/css/page.css @@ -42,7 +42,7 @@ span#ipython_notebook h1 img { } #site { - width: 100% + width: 100%; display: none; } diff --git a/IPython/frontend/html/notebook/static/js/menubar.js b/IPython/frontend/html/notebook/static/js/menubar.js index eef2e448d..a3d3ec035 100644 --- a/IPython/frontend/html/notebook/static/js/menubar.js +++ b/IPython/frontend/html/notebook/static/js/menubar.js @@ -22,6 +22,7 @@ var IPython = (function (IPython) { MenuBar.prototype.style = function () { + this.element.addClass('border-box-sizing'); $('ul#menus').menubar({ select : function (event, ui) { // The selected cell loses focus when the menu is entered, so we diff --git a/IPython/frontend/html/notebook/static/js/notebooklist.js b/IPython/frontend/html/notebook/static/js/notebooklist.js index 1a79e045a..21f9bba91 100644 --- a/IPython/frontend/html/notebook/static/js/notebooklist.js +++ b/IPython/frontend/html/notebook/static/js/notebooklist.js @@ -93,6 +93,7 @@ var IPython = (function (IPython) { NotebookList.prototype.new_notebook_item = function (index) { var item = $('
'); item.addClass('notebook_item ui-widget ui-widget-content ui-helper-clearfix'); + item.css('border-top-style','none'); var item_name = $('').addClass('item_name'); item.append(item_name); diff --git a/IPython/frontend/html/notebook/static/js/notebookmain.js b/IPython/frontend/html/notebook/static/js/notebookmain.js index f048e938b..6a613efdf 100644 --- a/IPython/frontend/html/notebook/static/js/notebookmain.js +++ b/IPython/frontend/html/notebook/static/js/notebookmain.js @@ -11,75 +11,17 @@ $(document).ready(function () { - if (window.MathJax){ - // MathJax loaded - MathJax.Hub.Config({ - tex2jax: { - inlineMath: [ ['$','$'], ["\\(","\\)"] ], - displayMath: [ ['$$','$$'], ["\\[","\\]"] ] - }, - displayAlign: 'left', // Change this to 'center' to center equations. - "HTML-CSS": { - styles: {'.MathJax_Display': {"margin": 0}} - } - }); - }else if (window.mathjax_url != ""){ - // Don't have MathJax, but should. Show dialog. - var dialog = $('
') - .append( - $("

").addClass('dialog').html( - "Math/LaTeX rendering will be disabled." - ) - ).append( - $("

").addClass('dialog').html( - "If you have administrative access to the notebook server and" + - " a working internet connection, you can install a local copy" + - " of MathJax for offline use with the following command on the server" + - " at a Python or IPython prompt:" - ) - ).append( - $("
").addClass('dialog').html(
-                    ">>> from IPython.external import mathjax; mathjax.install_mathjax()"
-                )
-            ).append(
-                $("

").addClass('dialog').html( - "This will try to install MathJax into the IPython source directory." - ) - ).append( - $("

").addClass('dialog').html( - "If IPython is installed to a location that requires" + - " administrative privileges to write, you will need to make this call as" + - " an administrator, via 'sudo'." - ) - ).append( - $("

").addClass('dialog').html( - "When you start the notebook server, you can instruct it to disable MathJax support altogether:" - ) - ).append( - $("
").addClass('dialog').html(
-                    "$ ipython notebook --no-mathjax"
-                )
-            ).append(
-                $("

").addClass('dialog').html( - "which will prevent this dialog from appearing." - ) - ).dialog({ - title: "Failed to retrieve MathJax from '" + window.mathjax_url + "'", - width: "70%", - modal: true, - }) - }else{ - // No MathJax, but none expected. No dialog. - } - - IPython.markdown_converter = new Markdown.Converter(); - IPython.read_only = $('meta[name=read_only]').attr("content") == 'True'; + IPython.init_mathjax(); - $('div#header').addClass('border-box-sizing'); - $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content'); + IPython.read_only = $('body').data('readOnly') === 'True'; + $('div#main_app').addClass('border-box-sizing ui-widget'); $('div#notebook_panel').addClass('border-box-sizing ui-widget'); + // The header's bottom border is provided by the menu bar so we remove it. + $('div#header').css('border-bottom-style','none'); + IPython.page = new IPython.Page(); + IPython.markdown_converter = new Markdown.Converter(); IPython.layout_manager = new IPython.LayoutManager(); IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter'); IPython.quick_help = new IPython.QuickHelp('span#quick_help_area'); @@ -92,9 +34,6 @@ $(document).ready(function () { IPython.layout_manager.do_resize(); - // These have display: none in the css file and are made visible here to prevent FLOUC. - $('div#header').css('display','block'); - if(IPython.read_only){ // hide various elements from read-only view $('div#pager').remove(); @@ -104,9 +43,7 @@ $(document).ready(function () { $('#notebook_name').attr('disabled','disabled') } - $('div#menubar').css('display','block'); - $('div#toolbar').css('display','block'); - $('div#main_app').css('display','block'); + IPython.page.show(); IPython.layout_manager.do_resize(); $([IPython.events]).on('notebook_loaded.Notebook', function () { diff --git a/IPython/frontend/html/notebook/static/js/page.js b/IPython/frontend/html/notebook/static/js/page.js index 7eaca8372..6a58a7182 100644 --- a/IPython/frontend/html/notebook/static/js/page.js +++ b/IPython/frontend/html/notebook/static/js/page.js @@ -31,12 +31,27 @@ var IPython = (function (IPython) { Page.prototype.show = function () { + // The header and site divs start out hidden to prevent FLOUC. + // Main scripts should call this method after styling everything. + this.show_header(); + this.show_site(); + }; + + + Page.prototype.show_header = function () { // The header and site divs start out hidden to prevent FLOUC. // Main scripts should call this method after styling everything. $('div#header').css('display','block'); + }; + + + Page.prototype.show_site = function () { + // The header and site divs start out hidden to prevent FLOUC. + // Main scripts should call this method after styling everything. $('div#site').css('display','block'); }; + IPython.Page = Page; return IPython; diff --git a/IPython/frontend/html/notebook/static/js/toolbar.js b/IPython/frontend/html/notebook/static/js/toolbar.js index 78820c37d..564ed0a57 100644 --- a/IPython/frontend/html/notebook/static/js/toolbar.js +++ b/IPython/frontend/html/notebook/static/js/toolbar.js @@ -22,7 +22,11 @@ var IPython = (function (IPython) { ToolBar.prototype.style = function () { - this.element.addClass('border-box-sizing'); + this.element.addClass('border-box-sizing'). + addClass('ui-widget ui-widget-content'). + css('border-top-style','none'). + css('border-left-style','none'). + css('border-right-style','none'); this.element.find('#cell_type').addClass('ui-widget ui-widget-content'); this.element.find('#save_b').button({ icons : {primary: 'ui-icon-disk'}, diff --git a/IPython/frontend/html/notebook/templates/notebook.html b/IPython/frontend/html/notebook/templates/notebook.html index 7b0b08764..97f384d4e 100644 --- a/IPython/frontend/html/notebook/templates/notebook.html +++ b/IPython/frontend/html/notebook/templates/notebook.html @@ -1,60 +1,49 @@ - - - - - - - IPython Notebook - - {% if mathjax_url %} - - {% end %} - - - - - - - - - - - - - - - {% comment In the notebook, the read-only flag is used to determine %} - {% comment whether to hide the side panels and switch off input %} - - - - - - - +{% block stylesheet %} + +{% if mathjax_url %} + +{% end %} + + + + + + + + + + +{% end %} + + +{% block params %} + +data-project={{project}} +data-base-project-url={{base_project_url}} +data-base-kernel-url={{base_kernel_url}} +data-read-only={{read_only and not logged_in}} +data-notebook-id={{notebook_id}} + +{% end %} + + +{% block header %} + + + + + + +{% end %} + + +{% block site %}