From 1699c903560119c9b913b327983884ce4ab43166 2011-08-05 05:57:01 From: Brian E. Granger Date: 2011-08-05 05:57:01 Subject: [PATCH] Implemented basic notebook browser and fixed numerous bugs. --- diff --git a/IPython/frontend/html/notebook/handlers.py b/IPython/frontend/html/notebook/handlers.py index 7984ef3..630c3bd 100644 --- a/IPython/frontend/html/notebook/handlers.py +++ b/IPython/frontend/html/notebook/handlers.py @@ -17,7 +17,14 @@ from tornado import websocket #----------------------------------------------------------------------------- -class MainHandler(web.RequestHandler): +class NBBrowserHandler(web.RequestHandler): + def get(self): + nbm = self.application.notebook_manager + project = nbm.notebook_dir + self.render('nbbrowser.html', project=project) + + +class NewHandler(web.RequestHandler): def get(self): notebook_id = self.application.notebook_manager.new_notebook() self.render('notebook.html', notebook_id=notebook_id) diff --git a/IPython/frontend/html/notebook/notebookapp.py b/IPython/frontend/html/notebook/notebookapp.py index f21a002..a8314bb 100644 --- a/IPython/frontend/html/notebook/notebookapp.py +++ b/IPython/frontend/html/notebook/notebookapp.py @@ -30,7 +30,7 @@ from tornado import web from .kernelmanager import KernelManager from .sessionmanager import SessionManager from .handlers import ( - MainHandler, NamedNotebookHandler, + NBBrowserHandler, NewHandler, NamedNotebookHandler, KernelHandler, KernelActionHandler, ZMQStreamHandler, NotebookRootHandler, NotebookHandler ) @@ -67,7 +67,8 @@ class NotebookWebApplication(web.Application): def __init__(self, kernel_manager, log, kernel_argv, config): handlers = [ - (r"/", MainHandler), + (r"/", NBBrowserHandler), + (r"/new", NewHandler), (r"/%s" % _notebook_id_regex, NamedNotebookHandler), (r"/kernels", KernelHandler), (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler), diff --git a/IPython/frontend/html/notebook/notebookmanager.py b/IPython/frontend/html/notebook/notebookmanager.py index f0b434f..c9cca58 100644 --- a/IPython/frontend/html/notebook/notebookmanager.py +++ b/IPython/frontend/html/notebook/notebookmanager.py @@ -44,8 +44,9 @@ class NotebookManager(Configurable): dict(notebook_id=notebook,name=name) """ names = os.listdir(self.notebook_dir) - names = [name.strip(self.filename_ext)\ + names = [name.split(u'.')[0] \ for name in names if name.endswith(self.filename_ext)] + print names data = [] for name in names: if name not in self.rev_mapping: @@ -53,6 +54,7 @@ class NotebookManager(Configurable): else: notebook_id = self.rev_mapping[name] data.append(dict(notebook_id=notebook_id,name=name)) + data = sorted(data, key=lambda item: item['name']) return data def new_notebook_id(self, name): @@ -112,11 +114,13 @@ class NotebookManager(Configurable): with open(path,'r') as f: s = f.read() try: - # v2 and later have xml in the .ipynb files + # v2 and later have xml in the .ipynb files. nb = current.reads(s, 'xml') except: - # v1 had json in the .ipynb files + # v1 had json in the .ipynb files. nb = current.reads(s, 'json') + # v1 notebooks don't have a name field, so use the filename. + nb.name = os.path.split(path)[-1].split(u'.')[0] except: raise web.HTTPError(404) return last_modified, nb diff --git a/IPython/frontend/html/notebook/static/css/base.css b/IPython/frontend/html/notebook/static/css/base.css new file mode 100644 index 0000000..1b9e1d0 --- /dev/null +++ b/IPython/frontend/html/notebook/static/css/base.css @@ -0,0 +1,56 @@ + +/** + * Primary styles + * + * 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: hidden; +} + + +div#header { + /* Initially hidden to prevent FLOUC */ + display: none; + position: relative; + height: 45px; + padding: 5px; + margin: 0px; + width: 100%; +} + +span#ipython_notebook { + position: absolute; + padding: 2px; +} + +span#ipython_notebook h1 { + font-family: Verdana, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif; + font-size: 197%; + display: inline; + color: black; +} + +div#main_app { + /* Initially hidden to prevent FLOUC */ + display: none; + width: 100%; + position: relative; +} + +.ui-button .ui-button-text { + padding: 0.2em 0.8em; + font-size: 77%; +} + + diff --git a/IPython/frontend/html/notebook/static/css/boilerplate.css b/IPython/frontend/html/notebook/static/css/boilerplate.css new file mode 100644 index 0000000..9fa1ee5 --- /dev/null +++ b/IPython/frontend/html/notebook/static/css/boilerplate.css @@ -0,0 +1,73 @@ +/** + * HTML5 ✰ Boilerplate + * + * style.css contains a reset, font normalization and some base styles. + * + * Credit is left where credit is due. + * Much inspiration was taken from these projects: + * - yui.yahooapis.com/2.8.1/build/base/base.css + * - camendesign.com/design/ + * - praegnanz.de/weblog/htmlcssjs-kickstart + */ + + +/** + * html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline) + * v1.6.1 2010-09-17 | Authors: Eric Meyer & Richard Clark + * html5doctor.com/html-5-reset-stylesheet/ + */ + +html, body, div, span, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, +small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, figcaption, figure, +footer, header, hgroup, menu, nav, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +blockquote, q { quotes: none; } + +blockquote:before, blockquote:after, +q:before, q:after { content: ""; content: none; } + +ins { background-color: #ff9; color: #000; text-decoration: none; } + +mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; } + +del { text-decoration: line-through; } + +abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; } + +table { border-collapse: collapse; border-spacing: 0; } + +hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; } + +input, select { vertical-align: middle; } + + +/** + * Font normalization inspired by YUI Library's fonts.css: developer.yahoo.com/yui/ + */ + +body { font:13px/1.231 sans-serif; *font-size:small; } /* Hack retained to preserve specificity */ +select, input, textarea, button { font:99% sans-serif; } + +/* Normalize monospace sizing: + en.wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome */ +pre, code, kbd, samp { font-family: monospace, sans-serif; } + + diff --git a/IPython/frontend/html/notebook/static/css/layout.css b/IPython/frontend/html/notebook/static/css/layout.css index f67b362..e80cca1 100644 --- a/IPython/frontend/html/notebook/static/css/layout.css +++ b/IPython/frontend/html/notebook/static/css/layout.css @@ -100,4 +100,4 @@ -webkit-box-pack: center; -moz-box-pack: center; box-pack: center; -} \ No newline at end of file +} diff --git a/IPython/frontend/html/notebook/static/css/nbbrowser.css b/IPython/frontend/html/notebook/static/css/nbbrowser.css new file mode 100644 index 0000000..45c821f --- /dev/null +++ b/IPython/frontend/html/notebook/static/css/nbbrowser.css @@ -0,0 +1,64 @@ + +/** + * Primary styles + * + * 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; +} + +#content_panel { + width: 600px; +} + +#content_toolbar { + padding: 10px 5px; +} + +#header_border { + width: 100%; + height: 2px; +} + +#app_hbox { + width: 100%; +} + +#notebooks_buttons { + float: right; +} + +#project_name { + height: 25px; + line-height: 25px; + padding: 3px; +} + +.notebook_item { + height: 25px; + line-height: 25px; + padding: 3px; +} + +.notebook_item a { + text-decoration: none; +} + +.item_buttons { + float: right; +} + +.highlight_text { + color: blue; +} diff --git a/IPython/frontend/html/notebook/static/css/notebook.css b/IPython/frontend/html/notebook/static/css/notebook.css index d1f0b50..cbf831f 100644 --- a/IPython/frontend/html/notebook/static/css/notebook.css +++ b/IPython/frontend/html/notebook/static/css/notebook.css @@ -1,75 +1,3 @@ -/** - * HTML5 ✰ Boilerplate - * - * style.css contains a reset, font normalization and some base styles. - * - * Credit is left where credit is due. - * Much inspiration was taken from these projects: - * - yui.yahooapis.com/2.8.1/build/base/base.css - * - camendesign.com/design/ - * - praegnanz.de/weblog/htmlcssjs-kickstart - */ - - -/** - * html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline) - * v1.6.1 2010-09-17 | Authors: Eric Meyer & Richard Clark - * html5doctor.com/html-5-reset-stylesheet/ - */ - -html, body, div, span, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, -small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, figcaption, figure, -footer, header, hgroup, menu, nav, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} - -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} - -blockquote, q { quotes: none; } - -blockquote:before, blockquote:after, -q:before, q:after { content: ""; content: none; } - -ins { background-color: #ff9; color: #000; text-decoration: none; } - -mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; } - -del { text-decoration: line-through; } - -abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; } - -table { border-collapse: collapse; border-spacing: 0; } - -hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; } - -input, select { vertical-align: middle; } - - -/** - * Font normalization inspired by YUI Library's fonts.css: developer.yahoo.com/yui/ - */ - -body { font:13px/1.231 sans-serif; *font-size:small; } /* Hack retained to preserve specificity */ -select, input, textarea, button { font:99% sans-serif; } - -/* Normalize monospace sizing: - en.wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome */ -pre, code, kbd, samp { font-family: monospace, sans-serif; } - /** * Primary styles @@ -90,28 +18,6 @@ body { overflow: hidden; } - -div#header { - /* Initially hidden to prevent FLOUC */ - display: none; - position: relative; - height: 45px; - padding: 5px; - margin: 0px; - width: 100%; -} - -span#ipython_notebook { - position: absolute; - padding: 2px; -} - -span#ipython_notebook h1 { - font-family: Verdana, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif; - font-size: 197%; - display: inline; -} - span#save_widget { position: absolute; left: 0px; @@ -144,13 +50,6 @@ span#kernel_status { color: black; } -div#notebook_app { - /* Initially hidden to prevent FLOUC */ - display: none; - width: 100%; - position: relative; -} - div#left_panel { overflow-y: auto; top: 0px; @@ -200,12 +99,6 @@ span.button_label { margin-bottom: 0px; } - -.ui-button .ui-button-text { - padding: 0.2em 0.8em; - font-size: 77%; -} - #download_format { float: right; font-size: 85%; diff --git a/IPython/frontend/html/notebook/static/js/layout.js b/IPython/frontend/html/notebook/static/js/layout.js index 2c344d7..7973cd5 100644 --- a/IPython/frontend/html/notebook/static/js/layout.js +++ b/IPython/frontend/html/notebook/static/js/layout.js @@ -22,7 +22,7 @@ var IPython = (function (IPython) { var header_height = $('div#header').outerHeight(true); var app_height = h - header_height - 2; // content height - $('div#notebook_app').height(app_height + 2); // content+padding+border height + $('div#main_app').height(app_height + 2); // content+padding+border height $('div#left_panel').height(app_height); diff --git a/IPython/frontend/html/notebook/static/js/nbbrowser_main.js b/IPython/frontend/html/notebook/static/js/nbbrowser_main.js new file mode 100644 index 0000000..c82a720 --- /dev/null +++ b/IPython/frontend/html/notebook/static/js/nbbrowser_main.js @@ -0,0 +1,30 @@ + +//============================================================================ +// 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 center'); + + $('div#content_toolbar').addClass('ui-widget ui-helper-clearfix'); + + $('#new_notebook').click(function (e) { + window.open('/new'); + }); + + IPython.notebook_list = new IPython.NotebookList('div#notebook_list'); + 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'); + + +}); + diff --git a/IPython/frontend/html/notebook/static/js/notebook.js b/IPython/frontend/html/notebook/static/js/notebook.js index 68cc7a5..792e51b 100644 --- a/IPython/frontend/html/notebook/static/js/notebook.js +++ b/IPython/frontend/html/notebook/static/js/notebook.js @@ -61,14 +61,14 @@ var IPython = (function (IPython) { }); this.element.bind('collapse_pager', function () { - var app_height = $('div#notebook_app').height(); // content height + var app_height = $('div#main_app').height(); // content height var splitter_height = $('div#pager_splitter').outerHeight(true); var new_height = app_height - splitter_height; that.element.animate({height : new_height + 'px'}, 'fast'); }); this.element.bind('expand_pager', function () { - var app_height = $('div#notebook_app').height(); // content height + var app_height = $('div#main_app').height(); // content height var splitter_height = $('div#pager_splitter').outerHeight(true); var pager_height = $('div#pager').outerHeight(true); var new_height = app_height - pager_height - splitter_height; @@ -94,6 +94,12 @@ var IPython = (function (IPython) { this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0); }; + + Notebook.prototype.scroll_to_top = function () { + this.element.animate({scrollTop:0}, 0); + }; + + // Cell indexing, retrieval, etc. @@ -296,12 +302,10 @@ var IPython = (function (IPython) { // TODO: Bounds check for i var i = this.index_or_selected(index); var cell = new IPython.CodeCell(this); - // cell.set_input_prompt(this.next_prompt_number); cell.set_input_prompt(); - this.next_prompt_number = this.next_prompt_number + 1; this.insert_cell_before(cell, i); this.select(this.find_cell_index(cell)); - return this; + return cell; } @@ -309,12 +313,10 @@ var IPython = (function (IPython) { // TODO: Bounds check for i var i = this.index_or_selected(index); var cell = new IPython.CodeCell(this); - // cell.set_input_prompt(this.next_prompt_number); cell.set_input_prompt(); - this.next_prompt_number = this.next_prompt_number + 1; this.insert_cell_after(cell, i); this.select(this.find_cell_index(cell)); - return this; + return cell; } @@ -325,7 +327,7 @@ var IPython = (function (IPython) { cell.config_mathjax(); this.insert_cell_before(cell, i); this.select(this.find_cell_index(cell)); - return this; + return cell; } @@ -336,7 +338,7 @@ var IPython = (function (IPython) { cell.config_mathjax(); this.insert_cell_after(cell, i); this.select(this.find_cell_index(cell)); - return this; + return cell; } @@ -517,14 +519,15 @@ var IPython = (function (IPython) { var new_cells = worksheet.cells; ncells = new_cells.length; var cell_data = null; + var new_cell = null; for (var i=0; i').addClass('notebook_item ui-widget ui-widget-content ui-helper-clearfix'); + var nbname = $('').addClass('item_name').append( + $('').attr('href','/'+data[i].notebook_id). + attr('target','_blank'). + text(data[i].name) + ); + var buttons = $('').addClass('item_buttons').append( + $('').button() + ) + div.append(nbname).append(buttons); + this.element.append(div); + } + }; + + + IPython.NotebookList = NotebookList; + + return IPython; + +}(IPython)); + diff --git a/IPython/frontend/html/notebook/static/js/panelsection.js b/IPython/frontend/html/notebook/static/js/panelsection.js index 82a76c3..71b62ea 100644 --- a/IPython/frontend/html/notebook/static/js/panelsection.js +++ b/IPython/frontend/html/notebook/static/js/panelsection.js @@ -93,11 +93,10 @@ var IPython = (function (IPython) { PanelSection.prototype.bind_events.apply(this); var that = this; this.content.find('#new_notebook').click(function () { - console.log('click!') - window.open('/'); + window.open('/new'); }); this.content.find('#open_notebook').click(function () { - alert('Not Implemented'); + window.open('/'); }); this.content.find('#download_notebook').click(function () { var format = that.content.find('#download_format').val(); diff --git a/IPython/frontend/html/notebook/templates/nbbrowser.html b/IPython/frontend/html/notebook/templates/nbbrowser.html index 3ff4ff7..b3b3aaa 100644 --- a/IPython/frontend/html/notebook/templates/nbbrowser.html +++ b/IPython/frontend/html/notebook/templates/nbbrowser.html @@ -1,30 +1,64 @@ + - + + IPython Notebook - IPython Notebook Browser - - - - - - + + + + + + + + + +
+ +
+ +
+ + + +
+
+ + + +
+
+

{{project}}

+
- +
- - - - + + + +
+ +
+ + + + + + - \ No newline at end of file + + + + diff --git a/IPython/frontend/html/notebook/templates/notebook.html b/IPython/frontend/html/notebook/templates/notebook.html index 024a7fa..599437a 100644 --- a/IPython/frontend/html/notebook/templates/notebook.html +++ b/IPython/frontend/html/notebook/templates/notebook.html @@ -22,7 +22,9 @@ + + @@ -39,7 +41,7 @@ Idle -
+