From d5a84bb8a49d4e3d1eb64acb5edf7cec488dc91a Mon Sep 17 00:00:00 2001 From: jhemmelg Date: Fri, 11 Jul 2014 17:44:10 -0500 Subject: [PATCH 01/54] Initial interface for javascript contentmanagers contentmanager.js is going to be a js proxy for the current filenbmanager.py. This will allow a contentmanager for Google Drive to be created. --- IPython/html/static/base/js/contentmanager.js | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 IPython/html/static/base/js/contentmanager.js diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js new file mode 100644 index 000000000..61762f586 --- /dev/null +++ b/IPython/html/static/base/js/contentmanager.js @@ -0,0 +1,42 @@ +// Copyright (c) IPython Development Team. +// Distributed under the terms of the Modified BSD License. + +define([ + 'base/js/namespace', + 'jquery', +], function(IPython, $) { + var ContentManager = function() { + // Constructor + // + // A contentmanager handles passing file operations + // to the back-end. This includes checkpointing + // with the normal file operations. + // + // Parameters: + // None + this.version = 0.1; + } + + ContentManager.prototype.new_notebook = function() { + } + + ContentManager.prototype.delete_notebook = function(name, path) { + } + + ContentManager.prototype.rename_notebook = function(new_name, new_path, old_name, old_path) { + } + + ContentManager.prototype.save_notebook = function(notebook, extra_settings) { + } + + ContentManager.prototype.save_checkpoint = function() { + } + + ContentManager.prototype.restore_checkpoint = function(id) { + } + + ContentManager.prototype.list_checkpoints = function() { + } + + return ContentManager; +}); From 112a74c566b44512e2aad215487e38905d31d7c4 Mon Sep 17 00:00:00 2001 From: jhemmelg Date: Sat, 12 Jul 2014 09:29:40 -0500 Subject: [PATCH 02/54] ContentManager function signatures updated --- IPython/html/services/contents/handlers.py | 3 + IPython/html/static/base/js/contentmanager.js | 147 +++++++++++++++++- 2 files changed, 142 insertions(+), 8 deletions(-) diff --git a/IPython/html/services/contents/handlers.py b/IPython/html/services/contents/handlers.py index a92d51bf9..aa02e18ae 100644 --- a/IPython/html/services/contents/handlers.py +++ b/IPython/html/services/contents/handlers.py @@ -205,6 +205,9 @@ class ContentsHandler(IPythonHandler): self._copy(copy_from, path, name) elif self.contents_manager.file_exists(name, path): self._save(model, path, name) + checkpoint = model.get('_checkpoint_after_save') + if checkpoint: + nbm.create_checkpoint(path, name) else: self._upload(model, path, name) else: diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 61762f586..73811e7b5 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -5,7 +5,7 @@ define([ 'base/js/namespace', 'jquery', ], function(IPython, $) { - var ContentManager = function() { + var ContentManager = function(notebook_path, base_url) { // Constructor // // A contentmanager handles passing file operations @@ -13,30 +13,161 @@ define([ // with the normal file operations. // // Parameters: - // None + // notebook_path + // base_url this.version = 0.1; + this.notebook_path = notebook_path; + this.base_url = base_url; } ContentManager.prototype.new_notebook = function() { + var path = this.notebook_path; + var base_url = this.base_url; + var settings = { + processData : false, + cache : false, + type : "POST", + dataType : "json", + async : false, + success : function (data, status, xhr){ + var notebook_name = data.name; + window.open( + utils.url_join_encode( + base_url, + 'notebooks', + path, + notebook_name + ), + '_blank' + ); + }, + error : utils.log_ajax_error, + }; + var url = utils.url_join_encode( + base_url, + 'api/notebooks', + path + ); + $.ajax(url,settings); } - ContentManager.prototype.delete_notebook = function(name, path) { + ContentManager.prototype.delete_notebook = function(notebook) { + var that = notebook; + var settings = { + processData : false, + cache : false, + type : "DELETE", + dataType: "json", + error : utils.log_ajax_error, + }; + var url = utils.url_join_encode( + that.base_url, + 'api/notebooks', + that.notebook_path, + that.notebook_name + ); + $.ajax(url, settings); } - ContentManager.prototype.rename_notebook = function(new_name, new_path, old_name, old_path) { + ContentManager.prototype.rename_notebook = function(notebook, nbname) { + var that = notebook; + if (!nbname.match(/\.ipynb$/)) { + nbname = nbname + ".ipynb"; + } + var data = {name: nbname}; + var settings = { + processData : false, + cache : false, + type : "PATCH", + data : JSON.stringify(data), + dataType: "json", + headers : {'Content-Type': 'application/json'}, + success : $.proxy(that.rename_success, this), + error : $.proxy(that.rename_error, this) + }; + this.events.trigger('rename_notebook.Notebook', data); + var url = utils.url_join_encode( + this.base_url, + 'api/notebooks', + this.notebook_path, + this.notebook_name + ); + $.ajax(url, settings); } ContentManager.prototype.save_notebook = function(notebook, extra_settings) { - } + // Create a JSON model to be sent to the server. + var model = {}; + model.name = notebook.notebook_name; + model.path = notebook.notebook_path; + model.content = notebook.toJSON(); + model.content.nbformat = notebook.nbformat; + model.content.nbformat_minor = notebook.nbformat_minor; + // time the ajax call for autosave tuning purposes. + var start = new Date().getTime(); + // We do the call with settings so we can set cache to false. + var settings = { + processData : false, + cache : false, + type : "PUT", + data : JSON.stringify(model), + headers : {'Content-Type': 'application/json'}, + success : $.proxy(notebook.save_notebook_success, this, start), + error : $.proxy(notebook.save_notebook_error, this) + }; + if (extra_settings) { + for (var key in extra_settings) { + settings[key] = extra_settings[key]; + } + } + notebook.events.trigger('notebook_saving.Notebook'); + var url = utils.url_join_encode( + notebook.base_url, + 'api/notebooks', + notebook.notebook_path, + notebook.notebook_name + ); + $.ajax(url, settings); + }; + } ContentManager.prototype.save_checkpoint = function() { + // This is not necessary - integrated into save } - ContentManager.prototype.restore_checkpoint = function(id) { + ContentManager.prototype.restore_checkpoint = function(notebook, id) { + that = notebook; + this.events.trigger('notebook_restoring.Notebook', checkpoint); + var url = utils.url_join_encode( + this.base_url, + 'api/notebooks', + this.notebook_path, + this.notebook_name, + 'checkpoints', + checkpoint + ); + $.post(url).done( + $.proxy(that.restore_checkpoint_success, that) + ).fail( + $.proxy(that.restore_checkpoint_error, that) + ); } - ContentManager.prototype.list_checkpoints = function() { + ContentManager.prototype.list_checkpoints = function(notebook) { + that = notebook; + var url = utils.url_join_encode( + that.base_url, + 'api/notebooks', + that.notebook_path, + that.notebook_name, + 'checkpoints' + ); + $.get(url).done( + $.proxy(that.list_checkpoints_success, that) + ).fail( + $.proxy(that.list_checkpoints_error, that) + ); } - return ContentManager; + return ContentManager; }); From 21a5b5a965e4984050b1b1a1716004a3311e680a Mon Sep 17 00:00:00 2001 From: KesterTong Date: Sun, 13 Jul 2014 15:54:07 -0500 Subject: [PATCH 03/54] Style and bug fixes --- IPython/html/static/base/js/contentmanager.js | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 73811e7b5..44cf23de3 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -4,7 +4,8 @@ define([ 'base/js/namespace', 'jquery', -], function(IPython, $) { + 'base/js/utils', +], function(IPython, $, utils) { var ContentManager = function(notebook_path, base_url) { // Constructor // @@ -18,7 +19,7 @@ define([ this.version = 0.1; this.notebook_path = notebook_path; this.base_url = base_url; - } + }; ContentManager.prototype.new_notebook = function() { var path = this.notebook_path; @@ -49,7 +50,7 @@ define([ path ); $.ajax(url,settings); - } + }; ContentManager.prototype.delete_notebook = function(notebook) { var that = notebook; @@ -67,7 +68,7 @@ define([ that.notebook_name ); $.ajax(url, settings); - } + }; ContentManager.prototype.rename_notebook = function(notebook, nbname) { var that = notebook; @@ -93,7 +94,7 @@ define([ this.notebook_name ); $.ajax(url, settings); - } + }; ContentManager.prototype.save_notebook = function(notebook, extra_settings) { // Create a JSON model to be sent to the server. @@ -129,11 +130,10 @@ define([ ); $.ajax(url, settings); }; - } ContentManager.prototype.save_checkpoint = function() { // This is not necessary - integrated into save - } + }; ContentManager.prototype.restore_checkpoint = function(notebook, id) { that = notebook; @@ -151,7 +151,7 @@ define([ ).fail( $.proxy(that.restore_checkpoint_error, that) ); - } + }; ContentManager.prototype.list_checkpoints = function(notebook) { that = notebook; @@ -167,7 +167,9 @@ define([ ).fail( $.proxy(that.list_checkpoints_error, that) ); - } + }; + + IPython.ContentManager = ContentManager; - return ContentManager; + return {'ContentManager': ContentManager}; }); From 99f2647edda91c5debfe34b3a8eadd4c906c0ca3 Mon Sep 17 00:00:00 2001 From: KesterTong Date: Sun, 13 Jul 2014 15:57:17 -0500 Subject: [PATCH 04/54] Use IPython style constructor --- IPython/html/static/base/js/contentmanager.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 44cf23de3..adf734885 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -6,7 +6,7 @@ define([ 'jquery', 'base/js/utils', ], function(IPython, $, utils) { - var ContentManager = function(notebook_path, base_url) { + var ContentManager = function(options) { // Constructor // // A contentmanager handles passing file operations @@ -14,13 +14,15 @@ define([ // with the normal file operations. // // Parameters: - // notebook_path - // base_url + // options: dictionary + // Dictionary of keyword arguments. + // notebook_path: string + // base_url: string this.version = 0.1; - this.notebook_path = notebook_path; - this.base_url = base_url; + this.notebook_path = options.notebook_path; + this.base_url = options.base_url; }; - + ContentManager.prototype.new_notebook = function() { var path = this.notebook_path; var base_url = this.base_url; From 5717a3eb10be85713e050cfddec21324d0beda88 Mon Sep 17 00:00:00 2001 From: KesterTong Date: Sun, 13 Jul 2014 15:59:36 -0500 Subject: [PATCH 05/54] Make ContentManager stateless Don't store notebook_path in ContentManager, because this sort of state (in addition to notebook_name) can change, and keeping track of this logic doesn't seem to be a part of the file management system. Instead, this logic can be left to the Notebook instance (and possible other places that manage it). This makes refactoring easier, and avoids having to replicate this logic in every implementation of ContentManager. --- IPython/html/static/base/js/contentmanager.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index adf734885..2972ef8a3 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -16,15 +16,21 @@ define([ // Parameters: // options: dictionary // Dictionary of keyword arguments. - // notebook_path: string + // events: $(Events) instance // base_url: string this.version = 0.1; - this.notebook_path = options.notebook_path; + this.events = options.events; this.base_url = options.base_url; }; - ContentManager.prototype.new_notebook = function() { - var path = this.notebook_path; + /** + * Creates a new notebook file at the specified path, and + * opens that notebook in a new window. + * + * @method scroll_to_cell + * @param {String} path The path to create the new notebook at + */ + ContentManager.prototype.new_notebook = function(path) { var base_url = this.base_url; var settings = { processData : false, From d17ca85f5b0fb58a4ed8feea9955b66bad2ce6ea Mon Sep 17 00:00:00 2001 From: KesterTong Date: Sun, 13 Jul 2014 16:03:12 -0500 Subject: [PATCH 06/54] Adds dialog on new_notebook failure This logic doesn't really belong in ContentManager. It would be better to trigger an event, which is handled somewhere else. But there's no obvious place to put this event, so creating the error dialog inside the new_notebook method is ok for now. --- IPython/html/static/base/js/contentmanager.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 2972ef8a3..0448aa163 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -5,7 +5,8 @@ define([ 'base/js/namespace', 'jquery', 'base/js/utils', -], function(IPython, $, utils) { + 'base/js/dialog', +], function(IPython, $, utils, dialog) { var ContentManager = function(options) { // Constructor // @@ -50,7 +51,20 @@ define([ '_blank' ); }, - error : utils.log_ajax_error, + error : function(xhr, status, error) { + utils.log_ajax_error(xhr, status, error); + var msg; + if (xhr.responseJSON && xhr.responseJSON.message) { + msg = xhr.responseJSON.message; + } else { + msg = xhr.statusText; + } + dialog.modal({ + title : 'Creating Notebook Failed', + body : "The error was: " + msg, + buttons : {'OK' : {'class' : 'btn-primary'}} + }); + } }; var url = utils.url_join_encode( base_url, From 993833d0188d6cb1e43c6bd660eb7d56fa3a140b Mon Sep 17 00:00:00 2001 From: KesterTong Date: Sun, 13 Jul 2014 16:12:42 -0500 Subject: [PATCH 07/54] Replace other methods with ContentManager.new_notebook Replaces Notebook.new_notebook and NotebookList.new_notebook with ContentManager.new_notebook --- IPython/html/static/notebook/js/main.js | 6 +++ IPython/html/static/notebook/js/menubar.js | 6 ++- IPython/html/static/notebook/js/notebook.js | 32 -------------- IPython/html/static/tree/js/main.js | 9 +++- IPython/html/static/tree/js/notebooklist.js | 48 +-------------------- 5 files changed, 19 insertions(+), 82 deletions(-) diff --git a/IPython/html/static/notebook/js/main.js b/IPython/html/static/notebook/js/main.js index 3cf2782e3..18853fe38 100644 --- a/IPython/html/static/notebook/js/main.js +++ b/IPython/html/static/notebook/js/main.js @@ -5,6 +5,7 @@ require([ 'base/js/namespace', 'jquery', 'notebook/js/notebook', + 'base/js/contentmanager', 'base/js/utils', 'base/js/page', 'notebook/js/layoutmanager', @@ -27,6 +28,7 @@ require([ IPython, $, notebook, + contentmanager, utils, page, layoutmanager, @@ -76,6 +78,9 @@ require([ save_widget: save_widget, config: user_config}, common_options)); + var content_manager = new contentmanager.ContentManager($.extend({ + events: events}, + common_options)); var login_widget = new loginwidget.LoginWidget('span#login_widget', common_options); var toolbar = new maintoolbar.MainToolBar('#maintoolbar-container', { notebook: notebook, @@ -86,6 +91,7 @@ require([ notebook: notebook}); var menubar = new menubar.MenuBar('#menubar', $.extend({ notebook: notebook, + content_manager: content_manager, layout_manager: layout_manager, events: events, save_widget: save_widget, diff --git a/IPython/html/static/notebook/js/menubar.js b/IPython/html/static/notebook/js/menubar.js index c7e359583..8ae3fd6d5 100644 --- a/IPython/html/static/notebook/js/menubar.js +++ b/IPython/html/static/notebook/js/menubar.js @@ -21,6 +21,7 @@ define([ // options: dictionary // Dictionary of keyword arguments. // notebook: Notebook instance + // content_manager: ContentManager instance // layout_manager: LayoutManager instance // events: $(Events) instance // save_widget: SaveWidget instance @@ -32,6 +33,7 @@ define([ this.base_url = options.base_url || utils.get_body_data("baseUrl"); this.selector = selector; this.notebook = options.notebook; + this.content_manager = options.content_manager; this.layout_manager = options.layout_manager; this.events = options.events; this.save_widget = options.save_widget; @@ -85,7 +87,9 @@ define([ // File var that = this; this.element.find('#new_notebook').click(function () { - that.notebook.new_notebook(); + // Create a new notebook in the same path as the current + // notebook's path. + that.content_manager.new_notebook(that.notebook.notebook_path); }); this.element.find('#open_notebook').click(function () { window.open(utils.url_join_encode( diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index bc75dfcea..1c3096693 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -2065,38 +2065,6 @@ define([ }); }; - Notebook.prototype.new_notebook = function(){ - var path = this.notebook_path; - var base_url = this.base_url; - var settings = { - processData : false, - cache : false, - type : "POST", - dataType : "json", - async : false, - success : function (data, status, xhr){ - var notebook_name = data.name; - window.open( - utils.url_join_encode( - base_url, - 'notebooks', - path, - notebook_name - ), - '_blank' - ); - }, - error : utils.log_ajax_error, - }; - var url = utils.url_join_encode( - base_url, - 'api/contents', - path - ); - $.ajax(url,settings); - }; - - Notebook.prototype.copy_notebook = function(){ var path = this.notebook_path; var base_url = this.base_url; diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index 1f1975828..9689d6a95 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -7,6 +7,7 @@ require([ 'base/js/events', 'base/js/page', 'base/js/utils', + 'base/js/contentmanager', 'tree/js/notebooklist', 'tree/js/clusterlist', 'tree/js/sessionlist', @@ -23,6 +24,7 @@ require([ events, page, utils, + contentmanager, notebooklist, clusterlist, sesssionlist, @@ -39,6 +41,9 @@ require([ session_list = new sesssionlist.SesssionList($.extend({ events: events}, common_options)); + content_manager = new contentmanager.ContentManager($.extend({ + events: events}, + common_options)); notebook_list = new notebooklist.NotebookList('#notebook_list', $.extend({ session_list: session_list}, common_options)); @@ -53,8 +58,8 @@ require([ login_widget = new loginwidget.LoginWidget('#login_widget', common_options); - $('#new_notebook').click(function (e) { - notebook_list.new_notebook(); + $('#new_notebook').button().click(function (e) { + content_manager.new_notebook(common_options.notebook_path); }); var interval_id=0; diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 7f526d788..51ae5ab42 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -487,53 +487,7 @@ define([ }; - NotebookList.prototype.new_notebook = function(){ - var path = this.notebook_path; - var base_url = this.base_url; - var settings = { - processData : false, - cache : false, - type : "POST", - dataType : "json", - async : false, - success : function (data, status, xhr) { - var notebook_name = data.name; - window.open( - utils.url_join_encode( - base_url, - 'notebooks', - path, - notebook_name), - '_blank' - ); - }, - error : $.proxy(this.new_notebook_failed, this), - }; - var url = utils.url_join_encode( - base_url, - 'api/contents', - path - ); - $.ajax(url, settings); - }; - - - NotebookList.prototype.new_notebook_failed = function (xhr, status, error) { - utils.log_ajax_error(xhr, status, error); - var msg; - if (xhr.responseJSON && xhr.responseJSON.message) { - msg = xhr.responseJSON.message; - } else { - msg = xhr.statusText; - } - dialog.modal({ - title : 'Creating Notebook Failed', - body : "The error was: " + msg, - buttons : {'OK' : {'class' : 'btn-primary'}} - }); - }; - - // Backwards compatability. + // Backwards compatability. IPython.NotebookList = NotebookList; return {'NotebookList': NotebookList}; From 728c6f005f0c59e69e689d34850d6273053f0dff Mon Sep 17 00:00:00 2001 From: Jeff Hemmelgarn Date: Fri, 18 Jul 2014 10:45:59 -0400 Subject: [PATCH 08/54] Move deleting a notebook to contentmanager.js Move code to handle deleting a notebook from notebooklist to contentmanager. --- IPython/html/static/base/js/contentmanager.js | 9 +++---- IPython/html/static/tree/js/main.js | 10 ++++++++ IPython/html/static/tree/js/notebooklist.js | 25 +++++-------------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 0448aa163..367c5e128 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -74,8 +74,7 @@ define([ $.ajax(url,settings); }; - ContentManager.prototype.delete_notebook = function(notebook) { - var that = notebook; + ContentManager.prototype.delete_notebook = function(name, path, base_url) { var settings = { processData : false, cache : false, @@ -84,10 +83,10 @@ define([ error : utils.log_ajax_error, }; var url = utils.url_join_encode( - that.base_url, + base_url, 'api/notebooks', - that.notebook_path, - that.notebook_name + path, + name ); $.ajax(url, settings); }; diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index 9689d6a95..3670fea36 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -45,6 +45,7 @@ require([ events: events}, common_options)); notebook_list = new notebooklist.NotebookList('#notebook_list', $.extend({ + content_manager: content_manager, session_list: session_list}, common_options)); cluster_list = new clusterlist.ClusterList('#cluster_list', common_options); @@ -124,4 +125,13 @@ require([ $("#tabs").find("a[href=" + window.location.hash + "]").click(); } + // For backwards compatability. + IPython.page = page; + IPython.content_manager = content_manager; + IPython.notebook_list = notebook_list; + IPython.cluster_list = cluster_list; + IPython.session_list = session_list; + IPython.kernel_list = kernel_list; + IPython.login_widget = login_widget; + IPython.events = events; }); diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 51ae5ab42..e1219dd66 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -34,6 +34,7 @@ define([ this.sessions = {}; this.base_url = options.base_url || utils.get_body_data("baseUrl"); this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath"); + this.content_manager = options.content_manager; if (this.session_list && this.session_list.events) { this.session_list.events.on('sessions_loaded.Dashboard', function(e, d) { that.sessions_loaded(d); }); @@ -329,8 +330,10 @@ define([ // We use the filename from the parent list_item element's // data because the outer scope's values change as we iterate through the loop. var parent_item = that.parents('div.list_item'); - var name = parent_item.data('name'); - var message = 'Are you sure you want to permanently delete the file: ' + name + '?'; + var nbname = parent_item.data('nbname'); + var path = parent_item.data('path'); + var base_url = utils.get_body_data("baseUrl"); + var message = 'Are you sure you want to permanently delete the notebook: ' + nbname + '?'; dialog.modal({ title : "Delete file", body : message, @@ -338,23 +341,7 @@ define([ Delete : { class: "btn-danger", click: function() { - var settings = { - processData : false, - cache : false, - type : "DELETE", - dataType : "json", - success : function (data, status, xhr) { - parent_item.remove(); - }, - error : utils.log_ajax_error, - }; - var url = utils.url_join_encode( - notebooklist.base_url, - 'api/contents', - notebooklist.notebook_path, - name - ); - $.ajax(url, settings); + notebooklist.content_manager.delete_notebook(nbname, path, base_url); } }, Cancel : {} From 7043aa1b9eae9fe78d40351557a6353864030735 Mon Sep 17 00:00:00 2001 From: Jeff Hemmelgarn Date: Sun, 20 Jul 2014 10:19:33 -0400 Subject: [PATCH 09/54] switch notebook.delete to use contentmanager Make notebook.delete call contentmanager.delete_notebook --- IPython/html/static/notebook/js/main.js | 8 +++++--- IPython/html/static/notebook/js/notebook.js | 17 ++--------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/IPython/html/static/notebook/js/main.js b/IPython/html/static/notebook/js/main.js index 18853fe38..8eb84eabe 100644 --- a/IPython/html/static/notebook/js/main.js +++ b/IPython/html/static/notebook/js/main.js @@ -72,15 +72,16 @@ require([ var save_widget = new savewidget.SaveWidget('span#save_widget', { events: events, keyboard_manager: keyboard_manager}); + var content_manager = new contentmanager.ContentManager($.extend({ + events: events}, + common_options)); var notebook = new notebook.Notebook('div#notebook', $.extend({ events: events, keyboard_manager: keyboard_manager, save_widget: save_widget, + content_manager: content_manager, config: user_config}, common_options)); - var content_manager = new contentmanager.ContentManager($.extend({ - events: events}, - common_options)); var login_widget = new loginwidget.LoginWidget('span#login_widget', common_options); var toolbar = new maintoolbar.MainToolBar('#maintoolbar-container', { notebook: notebook, @@ -137,6 +138,7 @@ require([ IPython.page = page; IPython.layout_manager = layout_manager; IPython.notebook = notebook; + IPython.content_manager = content_manager; IPython.pager = pager; IPython.quick_help = quick_help; IPython.login_widget = login_widget; diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 1c3096693..f094d9bd6 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -61,6 +61,7 @@ define([ this.notebook_name = options.notebook_name; this.events = options.events; this.keyboard_manager = options.keyboard_manager; + this.content_manager = options.content_manager; this.save_widget = options.save_widget; this.tooltip = new tooltip.Tooltip(this.events); this.ws_url = options.ws_url; @@ -2120,21 +2121,7 @@ define([ }; Notebook.prototype.delete = function () { - var that = this; - var settings = { - processData : false, - cache : false, - type : "DELETE", - dataType: "json", - error : utils.log_ajax_error, - }; - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - this.notebook_path, - this.notebook_name - ); - $.ajax(url, settings); + this.content_manager.delete_notebook(this.notebook_name, this.notebook_path, this.base_url); }; From 5b5e19408209ddc0998f9fcb5d0c73452bf954f3 Mon Sep 17 00:00:00 2001 From: Jeff Hemmelgarn Date: Sun, 20 Jul 2014 15:10:35 -0400 Subject: [PATCH 10/54] Move notebook.rename to contentmanager Make notebook.rename call contentmanager.rename --- IPython/html/static/base/js/contentmanager.js | 14 +++++------ IPython/html/static/notebook/js/notebook.js | 25 +------------------ 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 367c5e128..a784bebe2 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -103,16 +103,16 @@ define([ type : "PATCH", data : JSON.stringify(data), dataType: "json", - headers : {'Content-Type': 'application/json'}, - success : $.proxy(that.rename_success, this), - error : $.proxy(that.rename_error, this) + contentType: 'application/json', + success : $.proxy(that.rename_success, that), + error : $.proxy(that.rename_error, that) }; this.events.trigger('rename_notebook.Notebook', data); var url = utils.url_join_encode( - this.base_url, + that.base_url, 'api/notebooks', - this.notebook_path, - this.notebook_name + that.notebook_path, + that.notebook_name ); $.ajax(url, settings); }; @@ -133,7 +133,7 @@ define([ cache : false, type : "PUT", data : JSON.stringify(model), - headers : {'Content-Type': 'application/json'}, + contentType: 'application/json', success : $.proxy(notebook.save_notebook_success, this, start), error : $.proxy(notebook.save_notebook_error, this) }; diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index f094d9bd6..6044a4d4e 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -2095,36 +2095,13 @@ define([ }; Notebook.prototype.rename = function (nbname) { - var that = this; - if (!nbname.match(/\.ipynb$/)) { - nbname = nbname + ".ipynb"; - } - var data = {name: nbname}; - var settings = { - processData : false, - cache : false, - type : "PATCH", - data : JSON.stringify(data), - dataType: "json", - contentType: 'application/json', - success : $.proxy(that.rename_success, this), - error : $.proxy(that.rename_error, this) - }; - this.events.trigger('rename_notebook.Notebook', data); - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - this.notebook_path, - this.notebook_name - ); - $.ajax(url, settings); + this.content_manager.rename_notebook(this, nbname); }; Notebook.prototype.delete = function () { this.content_manager.delete_notebook(this.notebook_name, this.notebook_path, this.base_url); }; - Notebook.prototype.rename_success = function (json, status, xhr) { var name = this.notebook_name = json.name; var path = json.path; From 99323b1173356b5630d691dd3ea25b2d166e75a9 Mon Sep 17 00:00:00 2001 From: Jeff Hemmelgarn Date: Sun, 20 Jul 2014 15:35:40 -0400 Subject: [PATCH 11/54] Move saving to contentmanager Make notebook.save_notebook call contentmanager.save_notebook. --- IPython/html/static/base/js/contentmanager.js | 5 +-- IPython/html/static/notebook/js/notebook.js | 36 +------------------ 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index a784bebe2..49fc9a4d2 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -118,6 +118,7 @@ define([ }; ContentManager.prototype.save_notebook = function(notebook, extra_settings) { + var that = notebook; // Create a JSON model to be sent to the server. var model = {}; model.name = notebook.notebook_name; @@ -134,8 +135,8 @@ define([ type : "PUT", data : JSON.stringify(model), contentType: 'application/json', - success : $.proxy(notebook.save_notebook_success, this, start), - error : $.proxy(notebook.save_notebook_error, this) + success : $.proxy(notebook.save_notebook_success, that, start), + error : $.proxy(notebook.save_notebook_error, that) }; if (extra_settings) { for (var key in extra_settings) { diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 6044a4d4e..0f3fc3b2c 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -1904,41 +1904,7 @@ define([ * @method save_notebook */ Notebook.prototype.save_notebook = function (extra_settings) { - // Create a JSON model to be sent to the server. - var model = {}; - model.name = this.notebook_name; - model.path = this.notebook_path; - model.type = 'notebook'; - model.format = 'json'; - model.content = this.toJSON(); - model.content.nbformat = this.nbformat; - model.content.nbformat_minor = this.nbformat_minor; - // time the ajax call for autosave tuning purposes. - var start = new Date().getTime(); - // We do the call with settings so we can set cache to false. - var settings = { - processData : false, - cache : false, - type : "PUT", - data : JSON.stringify(model), - contentType: 'application/json', - dataType : "json", - success : $.proxy(this.save_notebook_success, this, start), - error : $.proxy(this.save_notebook_error, this) - }; - if (extra_settings) { - for (var key in extra_settings) { - settings[key] = extra_settings[key]; - } - } - this.events.trigger('notebook_saving.Notebook'); - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - this.notebook_path, - this.notebook_name - ); - $.ajax(url, settings); + this.content_manager.save_notebook(this, extra_settings); }; /** From 077ba397c1628ee3fca1d6b0a7de98f7db752cd0 Mon Sep 17 00:00:00 2001 From: KesterTong Date: Wed, 23 Jul 2014 16:10:26 -0400 Subject: [PATCH 12/54] Removes unnecessary parameter from ContentManager.delete_notebook --- IPython/html/static/base/js/contentmanager.js | 6 +++--- IPython/html/static/notebook/js/notebook.js | 2 +- IPython/html/static/tree/js/notebooklist.js | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 49fc9a4d2..a764e570a 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -74,16 +74,16 @@ define([ $.ajax(url,settings); }; - ContentManager.prototype.delete_notebook = function(name, path, base_url) { + ContentManager.prototype.delete_notebook = function(name, path) { var settings = { processData : false, cache : false, type : "DELETE", - dataType: "json", + dataType : "json", error : utils.log_ajax_error, }; var url = utils.url_join_encode( - base_url, + this.base_url, 'api/notebooks', path, name diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 0f3fc3b2c..3ae490dab 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -2065,7 +2065,7 @@ define([ }; Notebook.prototype.delete = function () { - this.content_manager.delete_notebook(this.notebook_name, this.notebook_path, this.base_url); + this.content_manager.delete_notebook(this.notebook_name, this.notebook_path); }; Notebook.prototype.rename_success = function (json, status, xhr) { diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index e1219dd66..83275fc3e 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -332,7 +332,6 @@ define([ var parent_item = that.parents('div.list_item'); var nbname = parent_item.data('nbname'); var path = parent_item.data('path'); - var base_url = utils.get_body_data("baseUrl"); var message = 'Are you sure you want to permanently delete the notebook: ' + nbname + '?'; dialog.modal({ title : "Delete file", @@ -341,7 +340,7 @@ define([ Delete : { class: "btn-danger", click: function() { - notebooklist.content_manager.delete_notebook(nbname, path, base_url); + notebooklist.content_manager.delete_notebook(nbname, path); } }, Cancel : {} From 0aada3ac5dc6c7cda5cd452d0761a0c8e8e9d5a3 Mon Sep 17 00:00:00 2001 From: KesterTong Date: Wed, 23 Jul 2014 16:56:12 -0400 Subject: [PATCH 13/54] Remove deleted notebook from notebook list Uses events to notify the NotebookList when the content manager deletes a notebook, and remove the deleted notebook in response to such an event. --- IPython/html/static/base/js/contentmanager.js | 9 ++++++++- IPython/html/static/tree/js/notebooklist.js | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index a764e570a..3c508f217 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -75,12 +75,19 @@ define([ }; ContentManager.prototype.delete_notebook = function(name, path) { + var that = this; var settings = { processData : false, cache : false, type : "DELETE", dataType : "json", - error : utils.log_ajax_error, + success : function (data, status, xhr) { + that.events.trigger('notebook_deleted.ContentManager', { + name: name, + path: path + }); + }, + error : utils.log_ajax_error }; var url = utils.url_join_encode( this.base_url, diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 83275fc3e..96b740bdd 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -39,6 +39,21 @@ define([ this.session_list.events.on('sessions_loaded.Dashboard', function(e, d) { that.sessions_loaded(d); }); } + + + if (this.content_manager && this.content_manager.events) { + this.content_manager.events.on('notebook_deleted.ContentManager', + function(e, d) { + // Remove the deleted notebook. + $( ":data(nbname)" ).each(function() { + var element = $( this ); + if (element.data( "nbname" ) == d.name && + element.data( "path" ) == d.path) { + element.remove(); + } + }); + }); + } }; NotebookList.prototype.style = function () { From 61a911fc0c3f6e539009a16daa819fc05a0367e1 Mon Sep 17 00:00:00 2001 From: KesterTong Date: Wed, 23 Jul 2014 16:57:58 -0400 Subject: [PATCH 14/54] Fix constructor comments Add content_manager as a dictionary key to the options param passed in to the NotebookList and Notebook constructors. --- IPython/html/static/notebook/js/notebook.js | 1 + IPython/html/static/tree/js/notebooklist.js | 1 + 2 files changed, 2 insertions(+) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 3ae490dab..8e070d4fb 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -50,6 +50,7 @@ define([ // Dictionary of keyword arguments. // events: $(Events) instance // keyboard_manager: KeyboardManager instance + // content_manager: ContentManager instance // save_widget: SaveWidget instance // config: dictionary // base_url : string diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 96b740bdd..31f292815 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -20,6 +20,7 @@ define([ // element_name: string // base_url: string // notebook_path: string + // content_manager: ContentManager instance var that = this; this.session_list = options.session_list; // allow code re-use by just changing element_name in kernellist.js From 9881d17bb1f53ab2d0fcb0bebb79ebf1b9d5c075 Mon Sep 17 00:00:00 2001 From: KesterTong Date: Wed, 23 Jul 2014 17:01:47 -0400 Subject: [PATCH 15/54] Remove unused event This event never seems to get used. --- IPython/html/static/base/js/contentmanager.js | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 3c508f217..eb2a6b2f9 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -114,7 +114,6 @@ define([ success : $.proxy(that.rename_success, that), error : $.proxy(that.rename_error, that) }; - this.events.trigger('rename_notebook.Notebook', data); var url = utils.url_join_encode( that.base_url, 'api/notebooks', From 75d7e69fc8b28457cfed86a9061376b066a86f82 Mon Sep 17 00:00:00 2001 From: KesterTong Date: Wed, 23 Jul 2014 17:09:54 -0400 Subject: [PATCH 16/54] Use $.proxy instead of that --- IPython/html/static/base/js/contentmanager.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index eb2a6b2f9..bb3b9e79b 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -75,18 +75,17 @@ define([ }; ContentManager.prototype.delete_notebook = function(name, path) { - var that = this; var settings = { processData : false, cache : false, type : "DELETE", dataType : "json", - success : function (data, status, xhr) { - that.events.trigger('notebook_deleted.ContentManager', { + success : $.proxy(this.events.trigger, this.events, + 'notebook_deleted.ContentManager', + { name: name, path: path - }); - }, + }), error : utils.log_ajax_error }; var url = utils.url_join_encode( From 04fc61285f544f59621d898bc2a4152d3969460e Mon Sep 17 00:00:00 2001 From: KesterTong Date: Wed, 23 Jul 2014 17:41:26 -0400 Subject: [PATCH 17/54] Use events for rename_notebook Triggers events on ContentManager.rename_notebook success and failure. Also moves some logic out of this method. --- IPython/html/static/base/js/contentmanager.js | 25 ++++++++------- IPython/html/static/notebook/js/notebook.js | 32 +++++++++++++------ 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index bb3b9e79b..fa1b3fe5f 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -97,12 +97,9 @@ define([ $.ajax(url, settings); }; - ContentManager.prototype.rename_notebook = function(notebook, nbname) { - var that = notebook; - if (!nbname.match(/\.ipynb$/)) { - nbname = nbname + ".ipynb"; - } - var data = {name: nbname}; + ContentManager.prototype.rename_notebook = function(path, name, new_name) { + var that = this; + var data = {name: new_name}; var settings = { processData : false, cache : false, @@ -110,14 +107,20 @@ define([ data : JSON.stringify(data), dataType: "json", contentType: 'application/json', - success : $.proxy(that.rename_success, that), - error : $.proxy(that.rename_error, that) + success : function (json, status, xhr) { + that.events.trigger('notebook_rename_success.ContentManager', + json); + }, + error : function (xhr, status, error) { + that.events.trigger('notebook_rename_error.ContentManager', + [xhr, status, error]); + } }; var url = utils.url_join_encode( - that.base_url, + this.base_url, 'api/notebooks', - that.notebook_path, - that.notebook_name + path, + name ); $.ajax(url, settings); }; diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 8e070d4fb..d718f5dfb 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -178,6 +178,19 @@ define([ Notebook.prototype.bind_events = function () { var that = this; + this.content_manager.events.on('notebook_rename_success.ContentManager', + function (event, data) { + var name = that.notebook_name = data.name; + var path = data.path; + that.session.rename_notebook(name, path); + that.events.trigger('notebook_renamed.Notebook', data); + }); + + this.content_manager.events.on('notebook_rename_error.ContentManager', + function (event, data) { + that.rename_error(data[0], data[1], data[2]); + }); + this.events.on('set_next_input.Notebook', function (event, data) { var index = that.find_cell_index(data.cell); var new_cell = that.insert_cell_below('code',index); @@ -2062,18 +2075,17 @@ define([ }; Notebook.prototype.rename = function (nbname) { - this.content_manager.rename_notebook(this, nbname); - }; + if (!nbname.match(/\.ipynb$/)) { + nbname = nbname + ".ipynb"; + } - Notebook.prototype.delete = function () { - this.content_manager.delete_notebook(this.notebook_name, this.notebook_path); + this.content_manager.rename_notebook(this.notebook_path, + this.notebook_name, nbname); }; - Notebook.prototype.rename_success = function (json, status, xhr) { - var name = this.notebook_name = json.name; - var path = json.path; - this.session.rename_notebook(name, path); - this.events.trigger('notebook_renamed.Notebook', json); + Notebook.prototype.delete = function () { + this.content_manager.delete_notebook(this.notebook_name, + this.notebook_path); }; Notebook.prototype.rename_error = function (xhr, status, error) { @@ -2092,7 +2104,7 @@ define([ "OK": { class: "btn-primary", click: function () { - this.save_widget.rename_notebook({notebook:that}); + that.save_widget.rename_notebook({notebook:that}); }} }, open : function (event, ui) { From dfcf14f26c49df1afbcf553f56461c48bd0559ec Mon Sep 17 00:00:00 2001 From: KesterTong Date: Wed, 23 Jul 2014 18:19:06 -0400 Subject: [PATCH 18/54] Uses events for ContentManager.save_notebook Modifies ContentManager.save_notebook() to use events, so that the Notebook instance can listen for success or failure events. Also moves some logic out of save_notebook() --- IPython/html/static/base/js/contentmanager.js | 30 +++++++++++-------- IPython/html/static/notebook/js/notebook.js | 27 ++++++++++++----- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index fa1b3fe5f..8211e4bad 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -125,15 +125,15 @@ define([ $.ajax(url, settings); }; - ContentManager.prototype.save_notebook = function(notebook, extra_settings) { + ContentManager.prototype.save_notebook = function(path, name, content, + extra_settings) { var that = notebook; // Create a JSON model to be sent to the server. - var model = {}; - model.name = notebook.notebook_name; - model.path = notebook.notebook_path; - model.content = notebook.toJSON(); - model.content.nbformat = notebook.nbformat; - model.content.nbformat_minor = notebook.nbformat_minor; + var model = { + name : name, + path : path, + content : content + }; // time the ajax call for autosave tuning purposes. var start = new Date().getTime(); // We do the call with settings so we can set cache to false. @@ -143,20 +143,24 @@ define([ type : "PUT", data : JSON.stringify(model), contentType: 'application/json', - success : $.proxy(notebook.save_notebook_success, that, start), - error : $.proxy(notebook.save_notebook_error, that) + success : $.proxy(this.events.trigger, this.events, + 'notebook_save_success.ContentManager', + $.extend(model, { start : start })), + error : function (xhr, status, error) { + that.events.trigger('notebook_save_error.ContentManager', + [xhr, status, error, model]); + } }; if (extra_settings) { for (var key in extra_settings) { settings[key] = extra_settings[key]; } } - notebook.events.trigger('notebook_saving.Notebook'); var url = utils.url_join_encode( - notebook.base_url, + this.base_url, 'api/notebooks', - notebook.notebook_path, - notebook.notebook_name + path, + name ); $.ajax(url, settings); }; diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index d718f5dfb..e616ab00d 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -191,6 +191,13 @@ define([ that.rename_error(data[0], data[1], data[2]); }); + this.content_manager.events.on('notebook_save_success.ContentManager', + $.proxy(this.save_notebook_success, this)); + + this.content_manager.events.on('notebook_save_error.ContentManager', + $.proxy(this.events.trigger, this.events, + 'notebook_save_failed.Notebook')); + this.events.on('set_next_input.Notebook', function (event, data) { var index = that.find_cell_index(data.cell); var new_cell = that.insert_cell_below('code',index); @@ -1918,19 +1925,25 @@ define([ * @method save_notebook */ Notebook.prototype.save_notebook = function (extra_settings) { - this.content_manager.save_notebook(this, extra_settings); + var content = $.extend(this.toJSON(), { + nbformat : this.nbformat, + nbformat_minor : this.nbformat_minor + }) + this.content_manager.save_notebook(this.notebook_path, + this.notebook_name, + content, + extra_settings); }; /** * Success callback for saving a notebook. * * @method save_notebook_success - * @param {Integer} start the time when the save request started - * @param {Object} data JSON representation of a notebook - * @param {String} status Description of response status - * @param {jqXHR} xhr jQuery Ajax object + * @param {Event} event The save notebook success event + * @param {Object} data dictionary of event data + * data.options start the time when the save request started */ - Notebook.prototype.save_notebook_success = function (start, data, status, xhr) { + Notebook.prototype.save_notebook_success = function (event, data) { this.set_dirty(false); if (data.message) { // save succeeded, but validation failed. @@ -1957,7 +1970,7 @@ define([ }); } this.events.trigger('notebook_saved.Notebook'); - this._update_autosave_interval(start); + this._update_autosave_interval(event.start); if (this._checkpoint_after_save) { this.create_checkpoint(); this._checkpoint_after_save = false; From e3ef5d3b70331901fd6af6bbb968aa4c56faee5c Mon Sep 17 00:00:00 2001 From: KesterTong Date: Fri, 25 Jul 2014 01:04:30 -0400 Subject: [PATCH 19/54] Moves list_notebooks to ContentManager --- IPython/html/static/base/js/contentmanager.js | 46 +++++++++++++++ IPython/html/static/tree/js/notebooklist.js | 59 ++++++++++--------- 2 files changed, 76 insertions(+), 29 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 8211e4bad..e993af201 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -24,6 +24,10 @@ define([ this.base_url = options.base_url; }; + /** + * Notebook Functions + */ + /** * Creates a new notebook file at the specified path, and * opens that notebook in a new window. @@ -165,6 +169,10 @@ define([ $.ajax(url, settings); }; + /** + * Checkpointing Functions + */ + ContentManager.prototype.save_checkpoint = function() { // This is not necessary - integrated into save }; @@ -203,6 +211,44 @@ define([ ); }; + /** + * File management functions + */ + + /** + * List notebooks and directories at a given path + * + * On success, load_callback is called with an array of dictionaries + * representing individual files or directories. Each dictionary has + * the keys: + * type: "notebook" or "directory" + * name: the name of the file or directory + * created: created date + * last_modified: last modified dat + * path: the path + * @method list_notebooks + * @param {String} path The path to list notebooks in + * @param {Function} load_callback called with list of notebooks on success + * @param {Function} error_callback called with ajax results on error + */ + ContentManager.prototype.list_contents = function(path, load_callback, + error_callback) { + var that = this; + var settings = { + processData : false, + cache : false, + type : "GET", + dataType : "json", + success : load_callback, + error : error_callback + }; + + var url = utils.url_join_encode(this.base_url, 'api', 'notebooks', + path); + $.ajax(url, settings); + } + + IPython.ContentManager = ContentManager; return {'ContentManager': ContentManager}; diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 31f292815..ea1a2c709 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -156,37 +156,26 @@ define([ }; NotebookList.prototype.load_list = function () { - var that = this; - var settings = { - processData : false, - cache : false, - type : "GET", - dataType : "json", - success : $.proxy(this.list_loaded, this), - error : $.proxy( function(xhr, status, error){ + this.content_manager.list_contents( + this.notebook_path, + $.proxy(this.draw_notebook_list, this), + $.proxy( function(xhr, status, error) { utils.log_ajax_error(xhr, status, error); - that.list_loaded([], null, null, {msg:"Error connecting to server."}); - },this) - }; - - var url = utils.url_join_encode( - this.base_url, - 'api', - 'contents', - this.notebook_path + that.draw_notebook_list([], "Error connecting to server."); + }, this) ); - $.ajax(url, settings); }; - - NotebookList.prototype.list_loaded = function (data, status, xhr, param) { - var message = 'Notebook list empty.'; - if (param !== undefined && param.msg) { - message = param.msg; - } + /** + * Draw the list of notebooks + * @method draw_notebook_list + * @param {Array} list An array of dictionaries representing files or + * direcotories. + * @param {String} error_msg An error message + */ + NotebookList.prototype.draw_notebook_list = function (list, error_msg) { + var message = error_msg || 'Notebook list empty.'; var item = null; - var model = null; - var list = data.content; var len = list.length; this.clear_list(); var n_uploads = this.element.children('.list_item').length; @@ -209,9 +198,21 @@ define([ offset += 1; } for (var i=0; i Date: Fri, 25 Jul 2014 23:25:59 -0400 Subject: [PATCH 20/54] Moves load_notebook to ContentManager and adds new_notebook to Google Drive version --- IPython/html/static/base/js/contentmanager.js | 34 +++++++++++++++++++ IPython/html/static/notebook/js/notebook.js | 23 +++---------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index e993af201..4404e446a 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -28,6 +28,40 @@ define([ * Notebook Functions */ + /** + * Load a notebook. + * + * Calls success_callback with notebook JSON object (as string), or + * error_callback with error. + * + * @method load_notebook + * @param {String} path + * @param {String} name + * @param {Function} success_callback + * @param {Function} error_callback + */ + ContentManager.prototype.load_notebook = function (path, name, success_callback, + error_callback) { + // We do the call with settings so we can set cache to false. + var settings = { + processData : false, + cache : false, + type : "GET", + dataType : "json", + success : success_callback, + error : error_callback, + }; + this.events.trigger('notebook_loading.Notebook'); + var url = utils.url_join_encode( + this.base_url, + 'api/notebooks', + path, + name + ); + $.ajax(url, settings); + }; + + /** * Creates a new notebook file at the specified path, and * opens that notebook in a new window. diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index e616ab00d..9b349d3f9 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -2140,26 +2140,13 @@ define([ * @param {String} notebook_name and path A notebook to load */ Notebook.prototype.load_notebook = function (notebook_name, notebook_path) { - var that = this; this.notebook_name = notebook_name; this.notebook_path = notebook_path; - // We do the call with settings so we can set cache to false. - var settings = { - processData : false, - cache : false, - type : "GET", - dataType : "json", - success : $.proxy(this.load_notebook_success,this), - error : $.proxy(this.load_notebook_error,this), - }; - this.events.trigger('notebook_loading.Notebook'); - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - this.notebook_path, - this.notebook_name - ); - $.ajax(url, settings); + this.content_manager.load_notebook( + notebook_path, + notebook_name, + $.proxy(this.load_notebook_success,this), + $.proxy(this.load_notebook_error,this)); }; /** From 3994d4d56a9c9430ec1c1a8699977dcf315588ef Mon Sep 17 00:00:00 2001 From: KesterTong Date: Sun, 27 Jul 2014 16:08:37 -0400 Subject: [PATCH 21/54] Adds configuration options to use Google Drive content manager Adds the key contentmanager_js_source to webapp_settings that allows for specifying the content manager JavaScript source file. Also adds a NotebookManager subclass, ClientSideNotebookManager, which does minimal logic. This class is used when the JavaScript content manager doesn't use the Python notebook manager, but rather implements that logic client side, as is the case for the Google Drive based content manager. A sample command line that uses the Google Drive content manager, and the ClientSideNotebookManager, is ipython notebook --NotebookApp.webapp_settings="{'contentmanager_js_source': 'base/js/drive_contentmanager'}" --NotebookApp.notebook_manager_class="IPython.html.services.notebooks.clientsidenbmanager.ClientSideNotebookManager" --- IPython/html/base/handlers.py | 10 +++++++++- IPython/html/static/notebook/js/main.js | 2 +- IPython/html/static/tree/js/main.js | 2 +- IPython/html/templates/page.html | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/IPython/html/base/handlers.py b/IPython/html/base/handlers.py index c64ebd7c5..b78a5eb64 100644 --- a/IPython/html/base/handlers.py +++ b/IPython/html/base/handlers.py @@ -136,6 +136,13 @@ class IPythonHandler(AuthenticatedHandler): @property def ws_url(self): return self.settings.get('websocket_url', '') + + @property + def contentmanager_js_source(self): + self.log.debug("Using contentmanager: %s", self.settings.get('contentmanager_js_source', + 'base/js/contentmanager')) + return self.settings.get('contentmanager_js_source', + 'base/js/contentmanager') #--------------------------------------------------------------- # Manager objects @@ -224,7 +231,8 @@ class IPythonHandler(AuthenticatedHandler): logged_in=self.logged_in, login_available=self.login_available, static_url=self.static_url, - sys_info=sys_info + sys_info=sys_info, + contentmanager_js_source=self.contentmanager_js_source, ) def get_json_body(self): diff --git a/IPython/html/static/notebook/js/main.js b/IPython/html/static/notebook/js/main.js index 8eb84eabe..4e5ca5ff2 100644 --- a/IPython/html/static/notebook/js/main.js +++ b/IPython/html/static/notebook/js/main.js @@ -5,7 +5,7 @@ require([ 'base/js/namespace', 'jquery', 'notebook/js/notebook', - 'base/js/contentmanager', + 'contentmanager', 'base/js/utils', 'base/js/page', 'notebook/js/layoutmanager', diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index 3670fea36..853eabfb9 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -7,7 +7,7 @@ require([ 'base/js/events', 'base/js/page', 'base/js/utils', - 'base/js/contentmanager', + 'contentmanager', 'tree/js/notebooklist', 'tree/js/clusterlist', 'tree/js/sessionlist', diff --git a/IPython/html/templates/page.html b/IPython/html/templates/page.html index b3c67b821..ffad39634 100644 --- a/IPython/html/templates/page.html +++ b/IPython/html/templates/page.html @@ -30,6 +30,7 @@ moment: "components/moment/moment", codemirror: 'components/codemirror', termjs: "components/term.js/src/term" + contentmanager: '{{ contentmanager_js_source }}', }, shim: { underscore: { From 09e0ff93d8262d7f5a481bd2419eb04316f266cc Mon Sep 17 00:00:00 2001 From: Jeff Hemmelgarn Date: Wed, 8 Oct 2014 08:23:37 -0400 Subject: [PATCH 22/54] Fix a few problems with cherry-picked commits api/notebooks => api/contents add type to JSON model fix a few things in notebooklist.js --- IPython/html/static/base/js/contentmanager.js | 21 +++++++------- IPython/html/static/tree/js/notebooklist.js | 28 ++++++------------- 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 4404e446a..716a5931c 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -54,7 +54,7 @@ define([ this.events.trigger('notebook_loading.Notebook'); var url = utils.url_join_encode( this.base_url, - 'api/notebooks', + 'api/contents', path, name ); @@ -82,7 +82,7 @@ define([ window.open( utils.url_join_encode( base_url, - 'notebooks', + 'contents', path, notebook_name ), @@ -106,7 +106,7 @@ define([ }; var url = utils.url_join_encode( base_url, - 'api/notebooks', + 'api/contents', path ); $.ajax(url,settings); @@ -128,7 +128,7 @@ define([ }; var url = utils.url_join_encode( this.base_url, - 'api/notebooks', + 'api/contents', path, name ); @@ -156,7 +156,7 @@ define([ }; var url = utils.url_join_encode( this.base_url, - 'api/notebooks', + 'api/contents', path, name ); @@ -165,11 +165,12 @@ define([ ContentManager.prototype.save_notebook = function(path, name, content, extra_settings) { - var that = notebook; + var that = content; // Create a JSON model to be sent to the server. var model = { name : name, path : path, + type : "notebook", content : content }; // time the ajax call for autosave tuning purposes. @@ -196,7 +197,7 @@ define([ } var url = utils.url_join_encode( this.base_url, - 'api/notebooks', + 'api/contents', path, name ); @@ -216,7 +217,7 @@ define([ this.events.trigger('notebook_restoring.Notebook', checkpoint); var url = utils.url_join_encode( this.base_url, - 'api/notebooks', + 'api/contents', this.notebook_path, this.notebook_name, 'checkpoints', @@ -233,7 +234,7 @@ define([ that = notebook; var url = utils.url_join_encode( that.base_url, - 'api/notebooks', + 'api/contents', that.notebook_path, that.notebook_name, 'checkpoints' @@ -277,7 +278,7 @@ define([ error : error_callback }; - var url = utils.url_join_encode(this.base_url, 'api', 'notebooks', + var url = utils.url_join_encode(this.base_url, 'api', 'contents', path); $.ajax(url, settings); } diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index ea1a2c709..3533b1b82 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -156,13 +156,14 @@ define([ }; NotebookList.prototype.load_list = function () { + var that = this this.content_manager.list_contents( - this.notebook_path, - $.proxy(this.draw_notebook_list, this), + that.notebook_path, + $.proxy(that.draw_notebook_list, that), $.proxy( function(xhr, status, error) { utils.log_ajax_error(xhr, status, error); that.draw_notebook_list([], "Error connecting to server."); - }, this) + }, that) ); }; @@ -176,7 +177,8 @@ define([ NotebookList.prototype.draw_notebook_list = function (list, error_msg) { var message = error_msg || 'Notebook list empty.'; var item = null; - var len = list.length; + var model = null; + var len = list.content.length; this.clear_list(); var n_uploads = this.element.children('.list_item').length; if (len === 0) { @@ -198,21 +200,9 @@ define([ offset += 1; } for (var i=0; i Date: Fri, 11 Jul 2014 17:44:10 -0500 Subject: [PATCH 23/54] Initial interface for javascript contentmanagers contentmanager.js is going to be a js proxy for the current filenbmanager.py. This will allow a contentmanager for Google Drive to be created. --- IPython/html/static/base/js/contentmanager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index 716a5931c..ec08325de 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -15,6 +15,7 @@ define([ // with the normal file operations. // // Parameters: +<<<<<<< HEAD // options: dictionary // Dictionary of keyword arguments. // events: $(Events) instance From 5109be2d28dd552b74b206d5afdd17848fb8fcb9 Mon Sep 17 00:00:00 2001 From: jhemmelg Date: Sat, 12 Jul 2014 09:29:40 -0500 Subject: [PATCH 24/54] ContentManager function signatures updated --- IPython/html/static/base/js/contentmanager.js | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contentmanager.js index ec08325de..716a5931c 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contentmanager.js @@ -15,7 +15,6 @@ define([ // with the normal file operations. // // Parameters: -<<<<<<< HEAD // options: dictionary // Dictionary of keyword arguments. // events: $(Events) instance From 53463898eb3c9c65a81417f22899a6088f38a4a5 Mon Sep 17 00:00:00 2001 From: Jeff Hemmelgarn Date: Sun, 19 Oct 2014 07:34:43 -0400 Subject: [PATCH 25/54] Move contentmanager to contents --- IPython/html/base/handlers.py | 12 +++---- .../js/{contentmanager.js => contents.js} | 36 +++++++++---------- IPython/html/static/notebook/js/main.js | 12 +++---- IPython/html/static/notebook/js/menubar.js | 6 ++-- IPython/html/static/notebook/js/notebook.js | 20 +++++------ IPython/html/static/tree/js/main.js | 12 +++---- IPython/html/static/tree/js/notebooklist.js | 12 +++---- IPython/html/templates/page.html | 2 +- 8 files changed, 56 insertions(+), 56 deletions(-) rename IPython/html/static/base/js/{contentmanager.js => contents.js} (88%) diff --git a/IPython/html/base/handlers.py b/IPython/html/base/handlers.py index b78a5eb64..fd8614e62 100644 --- a/IPython/html/base/handlers.py +++ b/IPython/html/base/handlers.py @@ -138,11 +138,11 @@ class IPythonHandler(AuthenticatedHandler): return self.settings.get('websocket_url', '') @property - def contentmanager_js_source(self): - self.log.debug("Using contentmanager: %s", self.settings.get('contentmanager_js_source', - 'base/js/contentmanager')) - return self.settings.get('contentmanager_js_source', - 'base/js/contentmanager') + def contents_js_source(self): + self.log.debug("Using contents: %s", self.settings.get('contents_js_source', + 'base/js/contents')) + return self.settings.get('contents_js_source', + 'base/js/contents') #--------------------------------------------------------------- # Manager objects @@ -232,7 +232,7 @@ class IPythonHandler(AuthenticatedHandler): login_available=self.login_available, static_url=self.static_url, sys_info=sys_info, - contentmanager_js_source=self.contentmanager_js_source, + contents_js_source=self.contents_js_source, ) def get_json_body(self): diff --git a/IPython/html/static/base/js/contentmanager.js b/IPython/html/static/base/js/contents.js similarity index 88% rename from IPython/html/static/base/js/contentmanager.js rename to IPython/html/static/base/js/contents.js index 716a5931c..e30a37a06 100644 --- a/IPython/html/static/base/js/contentmanager.js +++ b/IPython/html/static/base/js/contents.js @@ -7,10 +7,10 @@ define([ 'base/js/utils', 'base/js/dialog', ], function(IPython, $, utils, dialog) { - var ContentManager = function(options) { + var Contents = function(options) { // Constructor // - // A contentmanager handles passing file operations + // A contents handles passing file operations // to the back-end. This includes checkpointing // with the normal file operations. // @@ -40,7 +40,7 @@ define([ * @param {Function} success_callback * @param {Function} error_callback */ - ContentManager.prototype.load_notebook = function (path, name, success_callback, + Contents.prototype.load_notebook = function (path, name, success_callback, error_callback) { // We do the call with settings so we can set cache to false. var settings = { @@ -69,7 +69,7 @@ define([ * @method scroll_to_cell * @param {String} path The path to create the new notebook at */ - ContentManager.prototype.new_notebook = function(path) { + Contents.prototype.new_notebook = function(path) { var base_url = this.base_url; var settings = { processData : false, @@ -112,14 +112,14 @@ define([ $.ajax(url,settings); }; - ContentManager.prototype.delete_notebook = function(name, path) { + Contents.prototype.delete_notebook = function(name, path) { var settings = { processData : false, cache : false, type : "DELETE", dataType : "json", success : $.proxy(this.events.trigger, this.events, - 'notebook_deleted.ContentManager', + 'notebook_deleted.Contents', { name: name, path: path @@ -135,7 +135,7 @@ define([ $.ajax(url, settings); }; - ContentManager.prototype.rename_notebook = function(path, name, new_name) { + Contents.prototype.rename_notebook = function(path, name, new_name) { var that = this; var data = {name: new_name}; var settings = { @@ -146,11 +146,11 @@ define([ dataType: "json", contentType: 'application/json', success : function (json, status, xhr) { - that.events.trigger('notebook_rename_success.ContentManager', + that.events.trigger('notebook_rename_success.Contents', json); }, error : function (xhr, status, error) { - that.events.trigger('notebook_rename_error.ContentManager', + that.events.trigger('notebook_rename_error.Contents', [xhr, status, error]); } }; @@ -163,7 +163,7 @@ define([ $.ajax(url, settings); }; - ContentManager.prototype.save_notebook = function(path, name, content, + Contents.prototype.save_notebook = function(path, name, content, extra_settings) { var that = content; // Create a JSON model to be sent to the server. @@ -183,10 +183,10 @@ define([ data : JSON.stringify(model), contentType: 'application/json', success : $.proxy(this.events.trigger, this.events, - 'notebook_save_success.ContentManager', + 'notebook_save_success.Contents', $.extend(model, { start : start })), error : function (xhr, status, error) { - that.events.trigger('notebook_save_error.ContentManager', + that.events.trigger('notebook_save_error.Contents', [xhr, status, error, model]); } }; @@ -208,11 +208,11 @@ define([ * Checkpointing Functions */ - ContentManager.prototype.save_checkpoint = function() { + Contents.prototype.save_checkpoint = function() { // This is not necessary - integrated into save }; - ContentManager.prototype.restore_checkpoint = function(notebook, id) { + Contents.prototype.restore_checkpoint = function(notebook, id) { that = notebook; this.events.trigger('notebook_restoring.Notebook', checkpoint); var url = utils.url_join_encode( @@ -230,7 +230,7 @@ define([ ); }; - ContentManager.prototype.list_checkpoints = function(notebook) { + Contents.prototype.list_checkpoints = function(notebook) { that = notebook; var url = utils.url_join_encode( that.base_url, @@ -266,7 +266,7 @@ define([ * @param {Function} load_callback called with list of notebooks on success * @param {Function} error_callback called with ajax results on error */ - ContentManager.prototype.list_contents = function(path, load_callback, + Contents.prototype.list_contents = function(path, load_callback, error_callback) { var that = this; var settings = { @@ -284,7 +284,7 @@ define([ } - IPython.ContentManager = ContentManager; + IPython.Contents = Contents; - return {'ContentManager': ContentManager}; + return {'Contents': Contents}; }); diff --git a/IPython/html/static/notebook/js/main.js b/IPython/html/static/notebook/js/main.js index 4e5ca5ff2..486267de9 100644 --- a/IPython/html/static/notebook/js/main.js +++ b/IPython/html/static/notebook/js/main.js @@ -5,7 +5,7 @@ require([ 'base/js/namespace', 'jquery', 'notebook/js/notebook', - 'contentmanager', + 'contents', 'base/js/utils', 'base/js/page', 'notebook/js/layoutmanager', @@ -28,7 +28,7 @@ require([ IPython, $, notebook, - contentmanager, + contents, utils, page, layoutmanager, @@ -72,14 +72,14 @@ require([ var save_widget = new savewidget.SaveWidget('span#save_widget', { events: events, keyboard_manager: keyboard_manager}); - var content_manager = new contentmanager.ContentManager($.extend({ + var contents = new contents.Contents($.extend({ events: events}, common_options)); var notebook = new notebook.Notebook('div#notebook', $.extend({ events: events, keyboard_manager: keyboard_manager, save_widget: save_widget, - content_manager: content_manager, + contents: contents, config: user_config}, common_options)); var login_widget = new loginwidget.LoginWidget('span#login_widget', common_options); @@ -92,7 +92,7 @@ require([ notebook: notebook}); var menubar = new menubar.MenuBar('#menubar', $.extend({ notebook: notebook, - content_manager: content_manager, + contents: contents, layout_manager: layout_manager, events: events, save_widget: save_widget, @@ -138,7 +138,7 @@ require([ IPython.page = page; IPython.layout_manager = layout_manager; IPython.notebook = notebook; - IPython.content_manager = content_manager; + IPython.contents = contents; IPython.pager = pager; IPython.quick_help = quick_help; IPython.login_widget = login_widget; diff --git a/IPython/html/static/notebook/js/menubar.js b/IPython/html/static/notebook/js/menubar.js index 8ae3fd6d5..41a21cfaa 100644 --- a/IPython/html/static/notebook/js/menubar.js +++ b/IPython/html/static/notebook/js/menubar.js @@ -21,7 +21,7 @@ define([ // options: dictionary // Dictionary of keyword arguments. // notebook: Notebook instance - // content_manager: ContentManager instance + // contents: ContentManager instance // layout_manager: LayoutManager instance // events: $(Events) instance // save_widget: SaveWidget instance @@ -33,7 +33,7 @@ define([ this.base_url = options.base_url || utils.get_body_data("baseUrl"); this.selector = selector; this.notebook = options.notebook; - this.content_manager = options.content_manager; + this.contents = options.contents; this.layout_manager = options.layout_manager; this.events = options.events; this.save_widget = options.save_widget; @@ -89,7 +89,7 @@ define([ this.element.find('#new_notebook').click(function () { // Create a new notebook in the same path as the current // notebook's path. - that.content_manager.new_notebook(that.notebook.notebook_path); + that.contents.new_notebook(that.notebook.notebook_path); }); this.element.find('#open_notebook').click(function () { window.open(utils.url_join_encode( diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 9b349d3f9..ad04f9932 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -50,7 +50,7 @@ define([ // Dictionary of keyword arguments. // events: $(Events) instance // keyboard_manager: KeyboardManager instance - // content_manager: ContentManager instance + // contents: Contents instance // save_widget: SaveWidget instance // config: dictionary // base_url : string @@ -62,7 +62,7 @@ define([ this.notebook_name = options.notebook_name; this.events = options.events; this.keyboard_manager = options.keyboard_manager; - this.content_manager = options.content_manager; + this.contents = options.contents; this.save_widget = options.save_widget; this.tooltip = new tooltip.Tooltip(this.events); this.ws_url = options.ws_url; @@ -178,7 +178,7 @@ define([ Notebook.prototype.bind_events = function () { var that = this; - this.content_manager.events.on('notebook_rename_success.ContentManager', + this.contents.events.on('notebook_rename_success.Contents', function (event, data) { var name = that.notebook_name = data.name; var path = data.path; @@ -186,15 +186,15 @@ define([ that.events.trigger('notebook_renamed.Notebook', data); }); - this.content_manager.events.on('notebook_rename_error.ContentManager', + this.contents.events.on('notebook_rename_error.Contents', function (event, data) { that.rename_error(data[0], data[1], data[2]); }); - this.content_manager.events.on('notebook_save_success.ContentManager', + this.contents.events.on('notebook_save_success.Contents', $.proxy(this.save_notebook_success, this)); - this.content_manager.events.on('notebook_save_error.ContentManager', + this.contents.events.on('notebook_save_error.Contents', $.proxy(this.events.trigger, this.events, 'notebook_save_failed.Notebook')); @@ -1929,7 +1929,7 @@ define([ nbformat : this.nbformat, nbformat_minor : this.nbformat_minor }) - this.content_manager.save_notebook(this.notebook_path, + this.contents.save_notebook(this.notebook_path, this.notebook_name, content, extra_settings); @@ -2092,12 +2092,12 @@ define([ nbname = nbname + ".ipynb"; } - this.content_manager.rename_notebook(this.notebook_path, + this.contents.rename_notebook(this.notebook_path, this.notebook_name, nbname); }; Notebook.prototype.delete = function () { - this.content_manager.delete_notebook(this.notebook_name, + this.contents.delete_notebook(this.notebook_name, this.notebook_path); }; @@ -2142,7 +2142,7 @@ define([ Notebook.prototype.load_notebook = function (notebook_name, notebook_path) { this.notebook_name = notebook_name; this.notebook_path = notebook_path; - this.content_manager.load_notebook( + this.contents.load_notebook( notebook_path, notebook_name, $.proxy(this.load_notebook_success,this), diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index 853eabfb9..86ba36a43 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -7,7 +7,7 @@ require([ 'base/js/events', 'base/js/page', 'base/js/utils', - 'contentmanager', + 'contents', 'tree/js/notebooklist', 'tree/js/clusterlist', 'tree/js/sessionlist', @@ -24,7 +24,7 @@ require([ events, page, utils, - contentmanager, + contents, notebooklist, clusterlist, sesssionlist, @@ -41,11 +41,11 @@ require([ session_list = new sesssionlist.SesssionList($.extend({ events: events}, common_options)); - content_manager = new contentmanager.ContentManager($.extend({ + contents = new contents.Contents($.extend({ events: events}, common_options)); notebook_list = new notebooklist.NotebookList('#notebook_list', $.extend({ - content_manager: content_manager, + contents: contents, session_list: session_list}, common_options)); cluster_list = new clusterlist.ClusterList('#cluster_list', common_options); @@ -60,7 +60,7 @@ require([ login_widget = new loginwidget.LoginWidget('#login_widget', common_options); $('#new_notebook').button().click(function (e) { - content_manager.new_notebook(common_options.notebook_path); + contents.new_notebook(common_options.notebook_path); }); var interval_id=0; @@ -127,7 +127,7 @@ require([ // For backwards compatability. IPython.page = page; - IPython.content_manager = content_manager; + IPython.contents = contents; IPython.notebook_list = notebook_list; IPython.cluster_list = cluster_list; IPython.session_list = session_list; diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 3533b1b82..a37aac722 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -20,7 +20,7 @@ define([ // element_name: string // base_url: string // notebook_path: string - // content_manager: ContentManager instance + // contents: Contents instance var that = this; this.session_list = options.session_list; // allow code re-use by just changing element_name in kernellist.js @@ -35,15 +35,15 @@ define([ this.sessions = {}; this.base_url = options.base_url || utils.get_body_data("baseUrl"); this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath"); - this.content_manager = options.content_manager; + this.contents = options.contents; if (this.session_list && this.session_list.events) { this.session_list.events.on('sessions_loaded.Dashboard', function(e, d) { that.sessions_loaded(d); }); } - if (this.content_manager && this.content_manager.events) { - this.content_manager.events.on('notebook_deleted.ContentManager', + if (this.contents && this.contents.events) { + this.contents.events.on('notebook_deleted.Contents', function(e, d) { // Remove the deleted notebook. $( ":data(nbname)" ).each(function() { @@ -157,7 +157,7 @@ define([ NotebookList.prototype.load_list = function () { var that = this - this.content_manager.list_contents( + this.contents.list_contents( that.notebook_path, $.proxy(that.draw_notebook_list, that), $.proxy( function(xhr, status, error) { @@ -347,7 +347,7 @@ define([ Delete : { class: "btn-danger", click: function() { - notebooklist.content_manager.delete_notebook(nbname, path); + notebooklist.contents.delete_notebook(nbname, path); } }, Cancel : {} diff --git a/IPython/html/templates/page.html b/IPython/html/templates/page.html index ffad39634..a37aefd2e 100644 --- a/IPython/html/templates/page.html +++ b/IPython/html/templates/page.html @@ -30,7 +30,7 @@ moment: "components/moment/moment", codemirror: 'components/codemirror', termjs: "components/term.js/src/term" - contentmanager: '{{ contentmanager_js_source }}', + contents: '{{ contents_js_source }}', }, shim: { underscore: { From dab99c599fdc0cc77fa5e17d09fdb30a4290ed6b Mon Sep 17 00:00:00 2001 From: Jeff Hemmelgarn Date: Sun, 19 Oct 2014 07:37:52 -0400 Subject: [PATCH 26/54] Remove unnecessary backwards compatibility code --- IPython/html/static/tree/js/main.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index 86ba36a43..f56764739 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -124,14 +124,4 @@ require([ if (window.location.hash) { $("#tabs").find("a[href=" + window.location.hash + "]").click(); } - - // For backwards compatability. - IPython.page = page; - IPython.contents = contents; - IPython.notebook_list = notebook_list; - IPython.cluster_list = cluster_list; - IPython.session_list = session_list; - IPython.kernel_list = kernel_list; - IPython.login_widget = login_widget; - IPython.events = events; }); From 47a88f0e1dfaa16b9242ba8e9525abf22f97c8fa Mon Sep 17 00:00:00 2001 From: Jeff Hemmelgarn Date: Sun, 19 Oct 2014 07:40:11 -0400 Subject: [PATCH 27/54] Remove version --- IPython/html/static/base/js/contents.js | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/html/static/base/js/contents.js b/IPython/html/static/base/js/contents.js index e30a37a06..802f6dc00 100644 --- a/IPython/html/static/base/js/contents.js +++ b/IPython/html/static/base/js/contents.js @@ -19,7 +19,6 @@ define([ // Dictionary of keyword arguments. // events: $(Events) instance // base_url: string - this.version = 0.1; this.events = options.events; this.base_url = options.base_url; }; From c661c85abd0413705dc99f1ec3587bba000e54f8 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 23 Oct 2014 14:13:43 -0700 Subject: [PATCH 28/54] Add missing semicolon --- IPython/html/static/base/js/contents.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/html/static/base/js/contents.js b/IPython/html/static/base/js/contents.js index 802f6dc00..31a7d6cf4 100644 --- a/IPython/html/static/base/js/contents.js +++ b/IPython/html/static/base/js/contents.js @@ -280,7 +280,7 @@ define([ var url = utils.url_join_encode(this.base_url, 'api', 'contents', path); $.ajax(url, settings); - } + }; IPython.Contents = Contents; From 478648bde5491becb69edba1e651165925b69a9f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 23 Oct 2014 14:32:58 -0700 Subject: [PATCH 29/54] Page URL is /notebooks/..., not contents --- IPython/html/static/base/js/contents.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/html/static/base/js/contents.js b/IPython/html/static/base/js/contents.js index 31a7d6cf4..13791a27e 100644 --- a/IPython/html/static/base/js/contents.js +++ b/IPython/html/static/base/js/contents.js @@ -81,7 +81,7 @@ define([ window.open( utils.url_join_encode( base_url, - 'contents', + 'notebooks', path, notebook_name ), From 9538726b1667ca7ef5b2ce91fcb6b09e7a90b591 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 23 Oct 2014 15:14:10 -0700 Subject: [PATCH 30/54] Don't do UI stuff in contents API module --- IPython/html/static/base/js/contents.js | 29 ++++------------------ IPython/html/static/notebook/js/menubar.js | 24 +++++++++++++++++- IPython/html/static/tree/js/main.js | 24 +++++++++++++++++- 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/IPython/html/static/base/js/contents.js b/IPython/html/static/base/js/contents.js index 13791a27e..365dde65e 100644 --- a/IPython/html/static/base/js/contents.js +++ b/IPython/html/static/base/js/contents.js @@ -68,39 +68,20 @@ define([ * @method scroll_to_cell * @param {String} path The path to create the new notebook at */ - Contents.prototype.new_notebook = function(path) { + Contents.prototype.new_notebook = function(path, options) { var base_url = this.base_url; + var success_callback = options.success_callback || function(data, status, xhr) {}; + var error_callback = options.error_callback || function(xhr, status, error) {}; var settings = { processData : false, cache : false, type : "POST", dataType : "json", async : false, - success : function (data, status, xhr){ - var notebook_name = data.name; - window.open( - utils.url_join_encode( - base_url, - 'notebooks', - path, - notebook_name - ), - '_blank' - ); - }, + success : success_callback, error : function(xhr, status, error) { utils.log_ajax_error(xhr, status, error); - var msg; - if (xhr.responseJSON && xhr.responseJSON.message) { - msg = xhr.responseJSON.message; - } else { - msg = xhr.statusText; - } - dialog.modal({ - title : 'Creating Notebook Failed', - body : "The error was: " + msg, - buttons : {'OK' : {'class' : 'btn-primary'}} - }); + error_callback(xhr, status, error); } }; var url = utils.url_join_encode( diff --git a/IPython/html/static/notebook/js/menubar.js b/IPython/html/static/notebook/js/menubar.js index 41a21cfaa..6cbae0998 100644 --- a/IPython/html/static/notebook/js/menubar.js +++ b/IPython/html/static/notebook/js/menubar.js @@ -89,7 +89,29 @@ define([ this.element.find('#new_notebook').click(function () { // Create a new notebook in the same path as the current // notebook's path. - that.contents.new_notebook(that.notebook.notebook_path); + that.contents.new_notebook(that.notebook.notebook_path, + { + success_callback: function (data, status, xhr) { + window.open( + utils.url_join_encode( + common_options.base_url, 'notebooks', + data.path, data.name + ), '_blank'); + }, + error_callback: function(xhr, status, error) { + var msg; + if (xhr.responseJSON && xhr.responseJSON.message) { + msg = xhr.responseJSON.message; + } else { + msg = xhr.statusText; + } + dialog.modal({ + title : 'Creating Notebook Failed', + body : "The error was: " + msg, + buttons : {'OK' : {'class' : 'btn-primary'}} + }); + } + }); }); this.element.find('#open_notebook').click(function () { window.open(utils.url_join_encode( diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index f56764739..8244a1e20 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -60,7 +60,29 @@ require([ login_widget = new loginwidget.LoginWidget('#login_widget', common_options); $('#new_notebook').button().click(function (e) { - contents.new_notebook(common_options.notebook_path); + contents.new_notebook(common_options.notebook_path, + { + success_callback: function (data, status, xhr) { + window.open( + utils.url_join_encode( + common_options.base_url, 'notebooks', + data.path, data.name + ), '_blank'); + }, + error_callback: function(xhr, status, error) { + var msg; + if (xhr.responseJSON && xhr.responseJSON.message) { + msg = xhr.responseJSON.message; + } else { + msg = xhr.statusText; + } + dialog.modal({ + title : 'Creating Notebook Failed', + body : "The error was: " + msg, + buttons : {'OK' : {'class' : 'btn-primary'}} + }); + } + }); }); var interval_id=0; From a10dea4cd53139a5ea3505f16c7753fb0bd58a68 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 23 Oct 2014 15:27:49 -0700 Subject: [PATCH 31/54] Add Contents.api_url convenience function --- IPython/html/static/base/js/contents.js | 55 +++++++------------------ 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/IPython/html/static/base/js/contents.js b/IPython/html/static/base/js/contents.js index 365dde65e..dc8fd376a 100644 --- a/IPython/html/static/base/js/contents.js +++ b/IPython/html/static/base/js/contents.js @@ -22,7 +22,13 @@ define([ this.events = options.events; this.base_url = options.base_url; }; - + + Contents.prototype.api_url = function() { + var url_parts = [this.base_url, 'api/contents'].concat( + Array.prototype.slice.apply(arguments)); + return utils.url_join_encode.apply(null, url_parts); + }; + /** * Notebook Functions */ @@ -51,12 +57,7 @@ define([ error : error_callback, }; this.events.trigger('notebook_loading.Notebook'); - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - path, - name - ); + var url = this.api_url(path, name); $.ajax(url, settings); }; @@ -84,12 +85,7 @@ define([ error_callback(xhr, status, error); } }; - var url = utils.url_join_encode( - base_url, - 'api/contents', - path - ); - $.ajax(url,settings); + $.ajax(this.api_url(path), settings); }; Contents.prototype.delete_notebook = function(name, path) { @@ -106,12 +102,7 @@ define([ }), error : utils.log_ajax_error }; - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - path, - name - ); + var url = this.api_url(path, name); $.ajax(url, settings); }; @@ -134,12 +125,7 @@ define([ [xhr, status, error]); } }; - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - path, - name - ); + var url = this.api_url(path, name); $.ajax(url, settings); }; @@ -175,12 +161,7 @@ define([ settings[key] = extra_settings[key]; } } - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - path, - name - ); + var url = this.api_url(path, name); $.ajax(url, settings); }; @@ -195,9 +176,7 @@ define([ Contents.prototype.restore_checkpoint = function(notebook, id) { that = notebook; this.events.trigger('notebook_restoring.Notebook', checkpoint); - var url = utils.url_join_encode( - this.base_url, - 'api/contents', + var url = this.api_url( this.notebook_path, this.notebook_name, 'checkpoints', @@ -212,9 +191,7 @@ define([ Contents.prototype.list_checkpoints = function(notebook) { that = notebook; - var url = utils.url_join_encode( - that.base_url, - 'api/contents', + var url = this.api_url( that.notebook_path, that.notebook_name, 'checkpoints' @@ -258,9 +235,7 @@ define([ error : error_callback }; - var url = utils.url_join_encode(this.base_url, 'api', 'contents', - path); - $.ajax(url, settings); + $.ajax(this.api_url(path), settings); }; From 14106cbd66cf04f188c43e727d7bbad3d1125b71 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 23 Oct 2014 16:32:40 -0700 Subject: [PATCH 32/54] Move contents API module into services --- IPython/html/base/handlers.py | 4 ++-- IPython/html/static/{base/js => services}/contents.js | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename IPython/html/static/{base/js => services}/contents.js (100%) diff --git a/IPython/html/base/handlers.py b/IPython/html/base/handlers.py index fd8614e62..d32e1decc 100644 --- a/IPython/html/base/handlers.py +++ b/IPython/html/base/handlers.py @@ -140,9 +140,9 @@ class IPythonHandler(AuthenticatedHandler): @property def contents_js_source(self): self.log.debug("Using contents: %s", self.settings.get('contents_js_source', - 'base/js/contents')) + 'services/contents')) return self.settings.get('contents_js_source', - 'base/js/contents') + 'services/contents') #--------------------------------------------------------------- # Manager objects diff --git a/IPython/html/static/base/js/contents.js b/IPython/html/static/services/contents.js similarity index 100% rename from IPython/html/static/base/js/contents.js rename to IPython/html/static/services/contents.js From 29d88a91a6204c1bb58d12ca0bae31697b55b712 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 23 Oct 2014 17:12:09 -0700 Subject: [PATCH 33/54] Standardise JS checkpointing API, use it for notebooks --- IPython/html/services/contents/handlers.py | 3 - IPython/html/static/notebook/js/notebook.js | 126 +++++--------------- IPython/html/static/services/contents.js | 63 +++++----- 3 files changed, 63 insertions(+), 129 deletions(-) diff --git a/IPython/html/services/contents/handlers.py b/IPython/html/services/contents/handlers.py index aa02e18ae..a92d51bf9 100644 --- a/IPython/html/services/contents/handlers.py +++ b/IPython/html/services/contents/handlers.py @@ -205,9 +205,6 @@ class ContentsHandler(IPythonHandler): self._copy(copy_from, path, name) elif self.contents_manager.file_exists(name, path): self._save(model, path, name) - checkpoint = model.get('_checkpoint_after_save') - if checkpoint: - nbm.create_checkpoint(path, name) else: self._upload(model, path, name) else: diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index ad04f9932..6671c0de4 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -2357,18 +2357,13 @@ define([ * @method list_checkpoints */ Notebook.prototype.list_checkpoints = function () { - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - this.notebook_path, - this.notebook_name, - 'checkpoints' - ); - $.get(url).done( - $.proxy(this.list_checkpoints_success, this) - ).fail( - $.proxy(this.list_checkpoints_error, this) - ); + var that = this; + this.contents.list_checkpoints(this.notebook_path, this.notebook_name, { + success_callback: $.proxy(this.list_checkpoints_success, this), + error_callback: function(xhr, status, error_msg) { + that.events.trigger('list_checkpoints_failed.Notebook'); + } + }); }; /** @@ -2390,36 +2385,19 @@ define([ this.events.trigger('checkpoints_listed.Notebook', [data]); }; - /** - * Failure callback for listing a checkpoint. - * - * @method list_checkpoint_error - * @param {jqXHR} xhr jQuery Ajax object - * @param {String} status Description of response status - * @param {String} error_msg HTTP error message - */ - Notebook.prototype.list_checkpoints_error = function (xhr, status, error_msg) { - this.events.trigger('list_checkpoints_failed.Notebook'); - }; - /** * Create a checkpoint of this notebook on the server from the most recent save. * * @method create_checkpoint */ Notebook.prototype.create_checkpoint = function () { - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - this.notebook_path, - this.notebook_name, - 'checkpoints' - ); - $.post(url).done( - $.proxy(this.create_checkpoint_success, this) - ).fail( - $.proxy(this.create_checkpoint_error, this) - ); + var that = this; + this.contents.create_checkpoint(this.notebook_path, this.notebook_name, { + success_callback: $.proxy(this.create_checkpoint_success, this), + error_callback: function (xhr, status, error_msg) { + that.events.trigger('checkpoint_failed.Notebook'); + } + }); }; /** @@ -2436,18 +2414,6 @@ define([ this.events.trigger('checkpoint_created.Notebook', data); }; - /** - * Failure callback for creating a checkpoint. - * - * @method create_checkpoint_error - * @param {jqXHR} xhr jQuery Ajax object - * @param {String} status Description of response status - * @param {String} error_msg HTTP error message - */ - Notebook.prototype.create_checkpoint_error = function (xhr, status, error_msg) { - this.events.trigger('checkpoint_failed.Notebook'); - }; - Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) { var that = this; checkpoint = checkpoint || this.last_checkpoint; @@ -2497,19 +2463,14 @@ define([ */ Notebook.prototype.restore_checkpoint = function (checkpoint) { this.events.trigger('notebook_restoring.Notebook', checkpoint); - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - this.notebook_path, - this.notebook_name, - 'checkpoints', - checkpoint - ); - $.post(url).done( - $.proxy(this.restore_checkpoint_success, this) - ).fail( - $.proxy(this.restore_checkpoint_error, this) - ); + var that = this; + this.contents.restore_checkpoint(this.notebook_path, this.notebook_name, + checkpoint, { + success_callback: $.proxy(this.create_checkpoint_success, this), + error_callback: function (xhr, status, error_msg) { + that.events.trigger('checkpoint_restore_failed.Notebook'); + } + }); }; /** @@ -2525,18 +2486,6 @@ define([ this.load_notebook(this.notebook_name, this.notebook_path); }; - /** - * Failure callback for restoring a notebook to a checkpoint. - * - * @method restore_checkpoint_error - * @param {jqXHR} xhr jQuery Ajax object - * @param {String} status Description of response status - * @param {String} error_msg HTTP error message - */ - Notebook.prototype.restore_checkpoint_error = function (xhr, status, error_msg) { - this.events.trigger('checkpoint_restore_failed.Notebook'); - }; - /** * Delete a notebook checkpoint. * @@ -2545,18 +2494,13 @@ define([ */ Notebook.prototype.delete_checkpoint = function (checkpoint) { this.events.trigger('notebook_restoring.Notebook', checkpoint); - var url = utils.url_join_encode( - this.base_url, - 'api/contents', - this.notebook_path, - this.notebook_name, - 'checkpoints', - checkpoint - ); - $.ajax(url, { - type: 'DELETE', - success: $.proxy(this.delete_checkpoint_success, this), - error: $.proxy(this.delete_checkpoint_error, this) + var that = this; + this.contents.delete_checkpoint(this.notebook_path, this.notebook_name, + checkpoint, { + success_callback: $.proxy(this.create_checkpoint_success, this), + error_callback: function (xhr, status, error_msg) { + that.events.trigger('checkpoint_delete_failed.Notebook', [xhr, status, error]); + } }); }; @@ -2573,18 +2517,6 @@ define([ this.load_notebook(this.notebook_name, this.notebook_path); }; - /** - * Failure callback for deleting a notebook checkpoint. - * - * @method delete_checkpoint_error - * @param {jqXHR} xhr jQuery Ajax object - * @param {String} status Description of response status - * @param {String} error HTTP error message - */ - Notebook.prototype.delete_checkpoint_error = function (xhr, status, error) { - this.events.trigger('checkpoint_delete_failed.Notebook', [xhr, status, error]); - }; - // For backwards compatability. IPython.Notebook = Notebook; diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index dc8fd376a..85f3e93c0 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -169,38 +169,44 @@ define([ * Checkpointing Functions */ - Contents.prototype.save_checkpoint = function() { - // This is not necessary - integrated into save + Contents.prototype.create_checkpoint = function(path, name, options) { + var url = this.api_url(path, name, 'checkpoints'); + var settings = { + type : "POST", + success: options.success_callback || function(data, status, xhr) {}, + error: options.error_callback || function(xhr, status, error_msg) {} + }; + $.ajax(url, settings); }; - Contents.prototype.restore_checkpoint = function(notebook, id) { - that = notebook; - this.events.trigger('notebook_restoring.Notebook', checkpoint); - var url = this.api_url( - this.notebook_path, - this.notebook_name, - 'checkpoints', - checkpoint - ); - $.post(url).done( - $.proxy(that.restore_checkpoint_success, that) - ).fail( - $.proxy(that.restore_checkpoint_error, that) - ); + Contents.prototype.list_checkpoints = function(path, name, options) { + var url = this.api_url(path, name, 'checkpoints'); + var settings = { + type : "GET", + success: options.success_callback || function(data, status, xhr) {}, + error: options.error_callback || function(xhr, status, error_msg) {} + }; + $.ajax(url, settings); }; - Contents.prototype.list_checkpoints = function(notebook) { - that = notebook; - var url = this.api_url( - that.notebook_path, - that.notebook_name, - 'checkpoints' - ); - $.get(url).done( - $.proxy(that.list_checkpoints_success, that) - ).fail( - $.proxy(that.list_checkpoints_error, that) - ); + Contents.prototype.restore_checkpoint = function(path, name, checkpoint_id, options) { + var url = this.api_url(path, name, 'checkpoints', checkpoint_id); + var settings = { + type : "POST", + success: options.success_callback || function(data, status, xhr) {}, + error: options.error_callback || function(xhr, status, error_msg) {} + }; + $.ajax(url, settings); + }; + + Contents.prototype.delete_checkpoint = function(path, name, checkpoint_id, options) { + var url = this.api_url(path, name, 'checkpoints', checkpoint_id); + var settings = { + type : "DELETE", + success: options.success_callback || function(data, status, xhr) {}, + error: options.error_callback || function(xhr, status, error_msg) {} + }; + $.ajax(url, settings); }; /** @@ -225,7 +231,6 @@ define([ */ Contents.prototype.list_contents = function(path, load_callback, error_callback) { - var that = this; var settings = { processData : false, cache : false, From c9bd254735a45bedda4335f3f7064a69a4821875 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 23 Oct 2014 18:14:33 -0700 Subject: [PATCH 34/54] Make contents JS API consistent --- IPython/html/static/notebook/js/notebook.js | 56 +++++++--- IPython/html/static/services/contents.js | 111 +++++++------------- IPython/html/static/tree/js/notebooklist.js | 18 ++-- 3 files changed, 89 insertions(+), 96 deletions(-) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 6671c0de4..dfd01fa87 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -1929,10 +1929,27 @@ define([ nbformat : this.nbformat, nbformat_minor : this.nbformat_minor }) - this.contents.save_notebook(this.notebook_path, - this.notebook_name, - content, - extra_settings); + // Create a JSON model to be sent to the server. + var model = { + name : this.notebook_name, + path : this.notebook_path, + type : "notebook", + content : content + }; + // time the ajax call for autosave tuning purposes. + var start = new Date().getTime(); + + var that = this; + this.contents.save_file(this.notebook_path, this.notebook_name, model, { + extra_settings: extra_settings, + success_callback: $.proxy(this.events.trigger, this.events, + 'notebook_save_success.Contents', + $.extend(model, { start : start })), + error_callback: function (xhr, status, error) { + that.events.trigger('notebook_save_error.Contents', + [xhr, status, error, model]); + } + }); }; /** @@ -2087,18 +2104,26 @@ define([ $.ajax(url,settings); }; - Notebook.prototype.rename = function (nbname) { - if (!nbname.match(/\.ipynb$/)) { - nbname = nbname + ".ipynb"; + Notebook.prototype.rename = function (new_name) { + if (!new_name.match(/\.ipynb$/)) { + new_name = new_name + ".ipynb"; } - this.contents.rename_notebook(this.notebook_path, - this.notebook_name, nbname); + var that = this; + this.contents.rename_file(this.notebook_path, this.notebook_name, + this.notebook_path, new_name, { + success_callback: function (json, status, xhr) { + that.events.trigger('notebook_rename_success.Contents', json); + }, + error_callback: function (xhr, status, error) { + that.events.trigger('notebook_rename_error.Contents', + [xhr, status, error]); + } + }); }; Notebook.prototype.delete = function () { - this.contents.delete_notebook(this.notebook_name, - this.notebook_path); + this.contents.delete_file(this.notebook_name, this.notebook_path); }; Notebook.prototype.rename_error = function (xhr, status, error) { @@ -2142,11 +2167,10 @@ define([ Notebook.prototype.load_notebook = function (notebook_name, notebook_path) { this.notebook_name = notebook_name; this.notebook_path = notebook_path; - this.contents.load_notebook( - notebook_path, - notebook_name, - $.proxy(this.load_notebook_success,this), - $.proxy(this.load_notebook_error,this)); + this.contents.load_file(notebook_path, notebook_name, { + success_callback: $.proxy(this.load_notebook_success, this), + error_callback: $.proxy(this.load_notebook_error, this) + }); }; /** diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index 85f3e93c0..60bf5c347 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -30,14 +30,13 @@ define([ }; /** - * Notebook Functions + * File Functions (including notebook operations) */ /** - * Load a notebook. + * Load a file. * - * Calls success_callback with notebook JSON object (as string), or - * error_callback with error. + * Calls success_callback with file JSON model, or error_callback with error. * * @method load_notebook * @param {String} path @@ -45,16 +44,15 @@ define([ * @param {Function} success_callback * @param {Function} error_callback */ - Contents.prototype.load_notebook = function (path, name, success_callback, - error_callback) { + Contents.prototype.load_file = function (path, name, options) { // We do the call with settings so we can set cache to false. var settings = { processData : false, cache : false, type : "GET", dataType : "json", - success : success_callback, - error : error_callback, + success : options.success_callback, + error : options.error_callback || function() {} }; this.events.trigger('notebook_loading.Notebook'); var url = this.api_url(path, name); @@ -63,52 +61,44 @@ define([ /** - * Creates a new notebook file at the specified path, and - * opens that notebook in a new window. + * Creates a new notebook file at the specified directory path. * * @method scroll_to_cell * @param {String} path The path to create the new notebook at */ Contents.prototype.new_notebook = function(path, options) { - var base_url = this.base_url; - var success_callback = options.success_callback || function(data, status, xhr) {}; - var error_callback = options.error_callback || function(xhr, status, error) {}; + var error_callback = options.error_callback || function() {}; var settings = { processData : false, cache : false, type : "POST", dataType : "json", - async : false, - success : success_callback, - error : function(xhr, status, error) { - utils.log_ajax_error(xhr, status, error); - error_callback(xhr, status, error); - } + success : options.success_callback || function() {}, + error : options.error_callback || function() {} }; $.ajax(this.api_url(path), settings); }; - Contents.prototype.delete_notebook = function(name, path) { + Contents.prototype.delete_file = function(name, path, options) { + var error_callback = options.error_callback || function() {}; + var that = this; var settings = { processData : false, cache : false, type : "DELETE", dataType : "json", - success : $.proxy(this.events.trigger, this.events, - 'notebook_deleted.Contents', - { - name: name, - path: path - }), - error : utils.log_ajax_error + success : options.success_callback || function() {}, + error : function(xhr, status, error) { + utils.log_ajax_error(xhr, status, error); + error_callback(xhr, status, error); + } }; var url = this.api_url(path, name); $.ajax(url, settings); }; - Contents.prototype.rename_notebook = function(path, name, new_name) { - var that = this; - var data = {name: new_name}; + Contents.prototype.rename_file = function(path, name, new_path, new_name, options) { + var data = {name: new_name, path: new_path}; var settings = { processData : false, cache : false, @@ -116,31 +106,14 @@ define([ data : JSON.stringify(data), dataType: "json", contentType: 'application/json', - success : function (json, status, xhr) { - that.events.trigger('notebook_rename_success.Contents', - json); - }, - error : function (xhr, status, error) { - that.events.trigger('notebook_rename_error.Contents', - [xhr, status, error]); - } + success : options.success_callback || function() {}, + error : options.error_callback || function() {} }; var url = this.api_url(path, name); $.ajax(url, settings); }; - Contents.prototype.save_notebook = function(path, name, content, - extra_settings) { - var that = content; - // Create a JSON model to be sent to the server. - var model = { - name : name, - path : path, - type : "notebook", - content : content - }; - // time the ajax call for autosave tuning purposes. - var start = new Date().getTime(); + Contents.prototype.save_file = function(path, name, model, options) { // We do the call with settings so we can set cache to false. var settings = { processData : false, @@ -148,18 +121,11 @@ define([ type : "PUT", data : JSON.stringify(model), contentType: 'application/json', - success : $.proxy(this.events.trigger, this.events, - 'notebook_save_success.Contents', - $.extend(model, { start : start })), - error : function (xhr, status, error) { - that.events.trigger('notebook_save_error.Contents', - [xhr, status, error, model]); - } + success : options.success_callback || function() {}, + error : options.error_callback || function() {} }; - if (extra_settings) { - for (var key in extra_settings) { - settings[key] = extra_settings[key]; - } + if (options.extra_settings) { + $.extend(settings, options.extra_settings); } var url = this.api_url(path, name); $.ajax(url, settings); @@ -173,8 +139,8 @@ define([ var url = this.api_url(path, name, 'checkpoints'); var settings = { type : "POST", - success: options.success_callback || function(data, status, xhr) {}, - error: options.error_callback || function(xhr, status, error_msg) {} + success: options.success_callback || function() {}, + error: options.error_callback || function() {} }; $.ajax(url, settings); }; @@ -183,8 +149,8 @@ define([ var url = this.api_url(path, name, 'checkpoints'); var settings = { type : "GET", - success: options.success_callback || function(data, status, xhr) {}, - error: options.error_callback || function(xhr, status, error_msg) {} + success: options.success_callback, + error: options.error_callback || function() {} }; $.ajax(url, settings); }; @@ -193,8 +159,8 @@ define([ var url = this.api_url(path, name, 'checkpoints', checkpoint_id); var settings = { type : "POST", - success: options.success_callback || function(data, status, xhr) {}, - error: options.error_callback || function(xhr, status, error_msg) {} + success: options.success_callback || function() {}, + error: options.error_callback || function() {} }; $.ajax(url, settings); }; @@ -203,8 +169,8 @@ define([ var url = this.api_url(path, name, 'checkpoints', checkpoint_id); var settings = { type : "DELETE", - success: options.success_callback || function(data, status, xhr) {}, - error: options.error_callback || function(xhr, status, error_msg) {} + success: options.success_callback || function() {}, + error: options.error_callback || function() {} }; $.ajax(url, settings); }; @@ -229,15 +195,14 @@ define([ * @param {Function} load_callback called with list of notebooks on success * @param {Function} error_callback called with ajax results on error */ - Contents.prototype.list_contents = function(path, load_callback, - error_callback) { + Contents.prototype.list_contents = function(path, options) { var settings = { processData : false, cache : false, type : "GET", dataType : "json", - success : load_callback, - error : error_callback + success : options.success_callback, + error : options.error_callback || function() {} }; $.ajax(this.api_url(path), settings); diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index a37aac722..cc7e88cfe 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -157,14 +157,13 @@ define([ NotebookList.prototype.load_list = function () { var that = this - this.contents.list_contents( - that.notebook_path, - $.proxy(that.draw_notebook_list, that), - $.proxy( function(xhr, status, error) { + this.contents.list_contents(that.notebook_path, { + success_callback: $.proxy(this.draw_notebook_list, this), + error_callback: function(xhr, status, error) { utils.log_ajax_error(xhr, status, error); that.draw_notebook_list([], "Error connecting to server."); - }, that) - ); + } + }); }; /** @@ -347,7 +346,12 @@ define([ Delete : { class: "btn-danger", click: function() { - notebooklist.contents.delete_notebook(nbname, path); + notebooklist.contents.delete_file(nbname, path, { + success_callback: function() { + that.events.trigger('notebook_deleted.Contents', + {name: name, path: path}); + } + }); } }, Cancel : {} From cf828ccf4e60d8c5dd642d6bc1c9b5998aa7cd72 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 24 Oct 2014 11:35:47 -0700 Subject: [PATCH 35/54] Cut out some superfluous events --- IPython/html/static/notebook/js/notebook.js | 59 +++++---------------- 1 file changed, 12 insertions(+), 47 deletions(-) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index dfd01fa87..0f63b320a 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -178,26 +178,6 @@ define([ Notebook.prototype.bind_events = function () { var that = this; - this.contents.events.on('notebook_rename_success.Contents', - function (event, data) { - var name = that.notebook_name = data.name; - var path = data.path; - that.session.rename_notebook(name, path); - that.events.trigger('notebook_renamed.Notebook', data); - }); - - this.contents.events.on('notebook_rename_error.Contents', - function (event, data) { - that.rename_error(data[0], data[1], data[2]); - }); - - this.contents.events.on('notebook_save_success.Contents', - $.proxy(this.save_notebook_success, this)); - - this.contents.events.on('notebook_save_error.Contents', - $.proxy(this.events.trigger, this.events, - 'notebook_save_failed.Notebook')); - this.events.on('set_next_input.Notebook', function (event, data) { var index = that.find_cell_index(data.cell); var new_cell = that.insert_cell_below('code',index); @@ -1942,12 +1922,9 @@ define([ var that = this; this.contents.save_file(this.notebook_path, this.notebook_name, model, { extra_settings: extra_settings, - success_callback: $.proxy(this.events.trigger, this.events, - 'notebook_save_success.Contents', - $.extend(model, { start : start })), + success_callback: $.proxy(this.save_notebook_success, this, start), error_callback: function (xhr, status, error) { - that.events.trigger('notebook_save_error.Contents', - [xhr, status, error, model]); + that.events.trigger('notebook_save_failed.Notebook'); } }); }; @@ -1956,11 +1933,12 @@ define([ * Success callback for saving a notebook. * * @method save_notebook_success - * @param {Event} event The save notebook success event - * @param {Object} data dictionary of event data - * data.options start the time when the save request started + * @param {Integer} start Time when the save request start + * @param {Object} data JSON representation of a notebook + * @param {String} status Description of response status + * @param {jqXHR} xhr jQuery Ajax object */ - Notebook.prototype.save_notebook_success = function (event, data) { + Notebook.prototype.save_notebook_success = function (start, data, status, xhr) { this.set_dirty(false); if (data.message) { // save succeeded, but validation failed. @@ -1987,7 +1965,7 @@ define([ }); } this.events.trigger('notebook_saved.Notebook'); - this._update_autosave_interval(event.start); + this._update_autosave_interval(start); if (this._checkpoint_after_save) { this.create_checkpoint(); this._checkpoint_after_save = false; @@ -2013,18 +1991,6 @@ define([ } } }; - - /** - * Failure callback for saving a notebook. - * - * @method save_notebook_error - * @param {jqXHR} xhr jQuery Ajax object - * @param {String} status Description of response status - * @param {String} error HTTP error message - */ - Notebook.prototype.save_notebook_error = function (xhr, status, error) { - this.events.trigger('notebook_save_failed.Notebook', [xhr, status, error]); - }; /** * Explicitly trust the output of this notebook. @@ -2113,12 +2079,11 @@ define([ this.contents.rename_file(this.notebook_path, this.notebook_name, this.notebook_path, new_name, { success_callback: function (json, status, xhr) { - that.events.trigger('notebook_rename_success.Contents', json); + var name = that.notebook_name = json.name; + that.session.rename_notebook(name, json.path); + that.events.trigger('notebook_renamed.Notebook', json); }, - error_callback: function (xhr, status, error) { - that.events.trigger('notebook_rename_error.Contents', - [xhr, status, error]); - } + error_callback: $.proxy(this.rename_error, this) }); }; From c1c591336e7e9e3095caa782c0f26bb4ae787d29 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 24 Oct 2014 11:58:20 -0700 Subject: [PATCH 36/54] Some more event cleanup --- IPython/html/static/notebook/js/notebook.js | 1 + IPython/html/static/services/contents.js | 3 --- IPython/html/static/tree/js/notebooklist.js | 30 +++++++++------------ 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 0f63b320a..9527f89a8 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -2132,6 +2132,7 @@ define([ Notebook.prototype.load_notebook = function (notebook_name, notebook_path) { this.notebook_name = notebook_name; this.notebook_path = notebook_path; + this.events.trigger('notebook_loading.Notebook'); this.contents.load_file(notebook_path, notebook_name, { success_callback: $.proxy(this.load_notebook_success, this), error_callback: $.proxy(this.load_notebook_error, this) diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index 60bf5c347..d9535722c 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -17,9 +17,7 @@ define([ // Parameters: // options: dictionary // Dictionary of keyword arguments. - // events: $(Events) instance // base_url: string - this.events = options.events; this.base_url = options.base_url; }; @@ -54,7 +52,6 @@ define([ success : options.success_callback, error : options.error_callback || function() {} }; - this.events.trigger('notebook_loading.Notebook'); var url = this.api_url(path, name); $.ajax(url, settings); }; diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index cc7e88cfe..5361e190b 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -40,21 +40,6 @@ define([ this.session_list.events.on('sessions_loaded.Dashboard', function(e, d) { that.sessions_loaded(d); }); } - - - if (this.contents && this.contents.events) { - this.contents.events.on('notebook_deleted.Contents', - function(e, d) { - // Remove the deleted notebook. - $( ":data(nbname)" ).each(function() { - var element = $( this ); - if (element.data( "nbname" ) == d.name && - element.data( "path" ) == d.path) { - element.remove(); - } - }); - }); - } }; NotebookList.prototype.style = function () { @@ -348,9 +333,7 @@ define([ click: function() { notebooklist.contents.delete_file(nbname, path, { success_callback: function() { - that.events.trigger('notebook_deleted.Contents', - {name: name, path: path}); - } + notebooklist.notebook_deleted(path, nbname); }); } }, @@ -362,6 +345,17 @@ define([ item.find(".item_buttons").text("").append(delete_button); }; + NotebookList.prototype.notebook_deleted = function(path, name) { + // Remove the deleted notebook. + $( ":data(nbname)" ).each(function() { + var element = $( this ); + if (element.data( "nbname" ) == d.name && + element.data( "path" ) == d.path) { + element.remove(); + } + }); + } + NotebookList.prototype.add_upload_button = function (item, type) { var that = this; From 060dd1305cc9f54545a49469b92d6ea3864c3f1a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 24 Oct 2014 12:23:20 -0700 Subject: [PATCH 37/54] Miscellaneous JS fixes --- IPython/html/static/notebook/js/menubar.js | 2 +- IPython/html/static/tree/js/notebooklist.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/IPython/html/static/notebook/js/menubar.js b/IPython/html/static/notebook/js/menubar.js index 6cbae0998..6be9966d4 100644 --- a/IPython/html/static/notebook/js/menubar.js +++ b/IPython/html/static/notebook/js/menubar.js @@ -94,7 +94,7 @@ define([ success_callback: function (data, status, xhr) { window.open( utils.url_join_encode( - common_options.base_url, 'notebooks', + that.base_url, 'notebooks', data.path, data.name ), '_blank'); }, diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 5361e190b..115bd8458 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -334,7 +334,8 @@ define([ notebooklist.contents.delete_file(nbname, path, { success_callback: function() { notebooklist.notebook_deleted(path, nbname); - }); + } + }); } }, Cancel : {} From ea314a2a8661aa75a9f35e7b168f89dd0fd335ca Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 24 Oct 2014 14:54:04 -0700 Subject: [PATCH 38/54] Rename callback parameters to success/error --- IPython/html/static/notebook/js/menubar.js | 4 +- IPython/html/static/notebook/js/notebook.js | 28 +++++------ IPython/html/static/services/contents.js | 52 ++++++++++----------- IPython/html/static/tree/js/main.js | 4 +- IPython/html/static/tree/js/notebooklist.js | 6 +-- 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/IPython/html/static/notebook/js/menubar.js b/IPython/html/static/notebook/js/menubar.js index 6be9966d4..8e14bc2dc 100644 --- a/IPython/html/static/notebook/js/menubar.js +++ b/IPython/html/static/notebook/js/menubar.js @@ -91,14 +91,14 @@ define([ // notebook's path. that.contents.new_notebook(that.notebook.notebook_path, { - success_callback: function (data, status, xhr) { + success: function (data, status, xhr) { window.open( utils.url_join_encode( that.base_url, 'notebooks', data.path, data.name ), '_blank'); }, - error_callback: function(xhr, status, error) { + error: function(xhr, status, error) { var msg; if (xhr.responseJSON && xhr.responseJSON.message) { msg = xhr.responseJSON.message; diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 9527f89a8..8a774f5bc 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -1922,8 +1922,8 @@ define([ var that = this; this.contents.save_file(this.notebook_path, this.notebook_name, model, { extra_settings: extra_settings, - success_callback: $.proxy(this.save_notebook_success, this, start), - error_callback: function (xhr, status, error) { + success: $.proxy(this.save_notebook_success, this, start), + error: function (xhr, status, error) { that.events.trigger('notebook_save_failed.Notebook'); } }); @@ -2078,12 +2078,12 @@ define([ var that = this; this.contents.rename_file(this.notebook_path, this.notebook_name, this.notebook_path, new_name, { - success_callback: function (json, status, xhr) { + success: function (json, status, xhr) { var name = that.notebook_name = json.name; that.session.rename_notebook(name, json.path); that.events.trigger('notebook_renamed.Notebook', json); }, - error_callback: $.proxy(this.rename_error, this) + error: $.proxy(this.rename_error, this) }); }; @@ -2134,8 +2134,8 @@ define([ this.notebook_path = notebook_path; this.events.trigger('notebook_loading.Notebook'); this.contents.load_file(notebook_path, notebook_name, { - success_callback: $.proxy(this.load_notebook_success, this), - error_callback: $.proxy(this.load_notebook_error, this) + success: $.proxy(this.load_notebook_success, this), + error: $.proxy(this.load_notebook_error, this) }); }; @@ -2349,8 +2349,8 @@ define([ Notebook.prototype.list_checkpoints = function () { var that = this; this.contents.list_checkpoints(this.notebook_path, this.notebook_name, { - success_callback: $.proxy(this.list_checkpoints_success, this), - error_callback: function(xhr, status, error_msg) { + success: $.proxy(this.list_checkpoints_success, this), + error: function(xhr, status, error_msg) { that.events.trigger('list_checkpoints_failed.Notebook'); } }); @@ -2383,8 +2383,8 @@ define([ Notebook.prototype.create_checkpoint = function () { var that = this; this.contents.create_checkpoint(this.notebook_path, this.notebook_name, { - success_callback: $.proxy(this.create_checkpoint_success, this), - error_callback: function (xhr, status, error_msg) { + success: $.proxy(this.create_checkpoint_success, this), + error: function (xhr, status, error_msg) { that.events.trigger('checkpoint_failed.Notebook'); } }); @@ -2456,8 +2456,8 @@ define([ var that = this; this.contents.restore_checkpoint(this.notebook_path, this.notebook_name, checkpoint, { - success_callback: $.proxy(this.create_checkpoint_success, this), - error_callback: function (xhr, status, error_msg) { + success: $.proxy(this.create_checkpoint_success, this), + error: function (xhr, status, error_msg) { that.events.trigger('checkpoint_restore_failed.Notebook'); } }); @@ -2487,8 +2487,8 @@ define([ var that = this; this.contents.delete_checkpoint(this.notebook_path, this.notebook_name, checkpoint, { - success_callback: $.proxy(this.create_checkpoint_success, this), - error_callback: function (xhr, status, error_msg) { + success: $.proxy(this.create_checkpoint_success, this), + error: function (xhr, status, error_msg) { that.events.trigger('checkpoint_delete_failed.Notebook', [xhr, status, error]); } }); diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index d9535722c..7dda2a3f0 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -34,13 +34,13 @@ define([ /** * Load a file. * - * Calls success_callback with file JSON model, or error_callback with error. + * Calls success with file JSON model, or error with error. * * @method load_notebook * @param {String} path * @param {String} name - * @param {Function} success_callback - * @param {Function} error_callback + * @param {Function} success + * @param {Function} error */ Contents.prototype.load_file = function (path, name, options) { // We do the call with settings so we can set cache to false. @@ -49,8 +49,8 @@ define([ cache : false, type : "GET", dataType : "json", - success : options.success_callback, - error : options.error_callback || function() {} + success : options.success, + error : options.error || function() {} }; var url = this.api_url(path, name); $.ajax(url, settings); @@ -64,30 +64,30 @@ define([ * @param {String} path The path to create the new notebook at */ Contents.prototype.new_notebook = function(path, options) { - var error_callback = options.error_callback || function() {}; + var error = options.error || function() {}; var settings = { processData : false, cache : false, type : "POST", dataType : "json", - success : options.success_callback || function() {}, - error : options.error_callback || function() {} + success : options.success || function() {}, + error : options.error || function() {} }; $.ajax(this.api_url(path), settings); }; Contents.prototype.delete_file = function(name, path, options) { - var error_callback = options.error_callback || function() {}; + var error = options.error || function() {}; var that = this; var settings = { processData : false, cache : false, type : "DELETE", dataType : "json", - success : options.success_callback || function() {}, + success : options.success || function() {}, error : function(xhr, status, error) { utils.log_ajax_error(xhr, status, error); - error_callback(xhr, status, error); + error(xhr, status, error); } }; var url = this.api_url(path, name); @@ -103,8 +103,8 @@ define([ data : JSON.stringify(data), dataType: "json", contentType: 'application/json', - success : options.success_callback || function() {}, - error : options.error_callback || function() {} + success : options.success || function() {}, + error : options.error || function() {} }; var url = this.api_url(path, name); $.ajax(url, settings); @@ -118,8 +118,8 @@ define([ type : "PUT", data : JSON.stringify(model), contentType: 'application/json', - success : options.success_callback || function() {}, - error : options.error_callback || function() {} + success : options.success || function() {}, + error : options.error || function() {} }; if (options.extra_settings) { $.extend(settings, options.extra_settings); @@ -136,8 +136,8 @@ define([ var url = this.api_url(path, name, 'checkpoints'); var settings = { type : "POST", - success: options.success_callback || function() {}, - error: options.error_callback || function() {} + success: options.success || function() {}, + error: options.error || function() {} }; $.ajax(url, settings); }; @@ -146,8 +146,8 @@ define([ var url = this.api_url(path, name, 'checkpoints'); var settings = { type : "GET", - success: options.success_callback, - error: options.error_callback || function() {} + success: options.success, + error: options.error || function() {} }; $.ajax(url, settings); }; @@ -156,8 +156,8 @@ define([ var url = this.api_url(path, name, 'checkpoints', checkpoint_id); var settings = { type : "POST", - success: options.success_callback || function() {}, - error: options.error_callback || function() {} + success: options.success || function() {}, + error: options.error || function() {} }; $.ajax(url, settings); }; @@ -166,8 +166,8 @@ define([ var url = this.api_url(path, name, 'checkpoints', checkpoint_id); var settings = { type : "DELETE", - success: options.success_callback || function() {}, - error: options.error_callback || function() {} + success: options.success || function() {}, + error: options.error || function() {} }; $.ajax(url, settings); }; @@ -190,7 +190,7 @@ define([ * @method list_notebooks * @param {String} path The path to list notebooks in * @param {Function} load_callback called with list of notebooks on success - * @param {Function} error_callback called with ajax results on error + * @param {Function} error called with ajax results on error */ Contents.prototype.list_contents = function(path, options) { var settings = { @@ -198,8 +198,8 @@ define([ cache : false, type : "GET", dataType : "json", - success : options.success_callback, - error : options.error_callback || function() {} + success : options.success, + error : options.error || function() {} }; $.ajax(this.api_url(path), settings); diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index 8244a1e20..777f271cb 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -62,14 +62,14 @@ require([ $('#new_notebook').button().click(function (e) { contents.new_notebook(common_options.notebook_path, { - success_callback: function (data, status, xhr) { + success: function (data, status, xhr) { window.open( utils.url_join_encode( common_options.base_url, 'notebooks', data.path, data.name ), '_blank'); }, - error_callback: function(xhr, status, error) { + error: function(xhr, status, error) { var msg; if (xhr.responseJSON && xhr.responseJSON.message) { msg = xhr.responseJSON.message; diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 115bd8458..2b5fba499 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -143,8 +143,8 @@ define([ NotebookList.prototype.load_list = function () { var that = this this.contents.list_contents(that.notebook_path, { - success_callback: $.proxy(this.draw_notebook_list, this), - error_callback: function(xhr, status, error) { + success: $.proxy(this.draw_notebook_list, this), + error: function(xhr, status, error) { utils.log_ajax_error(xhr, status, error); that.draw_notebook_list([], "Error connecting to server."); } @@ -332,7 +332,7 @@ define([ class: "btn-danger", click: function() { notebooklist.contents.delete_file(nbname, path, { - success_callback: function() { + success: function() { notebooklist.notebook_deleted(path, nbname); } }); From f8ec8d4abeb212c38a3b1b889acee2a3bd01c1af Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 28 Oct 2014 09:00:03 -0700 Subject: [PATCH 39/54] Various minor fixes from review --- IPython/html/base/handlers.py | 3 +-- IPython/html/static/notebook/js/notebook.js | 2 +- IPython/html/static/tree/js/main.js | 2 +- IPython/html/static/tree/js/notebooklist.js | 8 ++++---- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/IPython/html/base/handlers.py b/IPython/html/base/handlers.py index d32e1decc..a52f1d6f9 100644 --- a/IPython/html/base/handlers.py +++ b/IPython/html/base/handlers.py @@ -141,8 +141,7 @@ class IPythonHandler(AuthenticatedHandler): def contents_js_source(self): self.log.debug("Using contents: %s", self.settings.get('contents_js_source', 'services/contents')) - return self.settings.get('contents_js_source', - 'services/contents') + return self.settings.get('contents_js_source', 'services/contents') #--------------------------------------------------------------- # Manager objects diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 8a774f5bc..fdc1c615b 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -1908,7 +1908,7 @@ define([ var content = $.extend(this.toJSON(), { nbformat : this.nbformat, nbformat_minor : this.nbformat_minor - }) + }); // Create a JSON model to be sent to the server. var model = { name : this.notebook_name, diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index 777f271cb..1f53a7f77 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -59,7 +59,7 @@ require([ login_widget = new loginwidget.LoginWidget('#login_widget', common_options); - $('#new_notebook').button().click(function (e) { + $('#new_notebook').click(function (e) { contents.new_notebook(common_options.notebook_path, { success: function (data, status, xhr) { diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 2b5fba499..c54c60e41 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -321,9 +321,9 @@ define([ // We use the filename from the parent list_item element's // data because the outer scope's values change as we iterate through the loop. var parent_item = that.parents('div.list_item'); - var nbname = parent_item.data('nbname'); + var name = parent_item.data('nbname'); var path = parent_item.data('path'); - var message = 'Are you sure you want to permanently delete the notebook: ' + nbname + '?'; + var message = 'Are you sure you want to permanently delete the file: ' + nbname + '?'; dialog.modal({ title : "Delete file", body : message, @@ -331,9 +331,9 @@ define([ Delete : { class: "btn-danger", click: function() { - notebooklist.contents.delete_file(nbname, path, { + notebooklist.contents.delete_file(name, path, { success: function() { - notebooklist.notebook_deleted(path, nbname); + notebooklist.notebook_deleted(path, name); } }); } From e1cbaf3d3c002337fb856ae0d4a14f3f7a6e7dcb Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 28 Oct 2014 09:00:58 -0700 Subject: [PATCH 40/54] Fix spelling --- IPython/html/static/tree/js/notebooklist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index c54c60e41..2e62f40b5 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -155,7 +155,7 @@ define([ * Draw the list of notebooks * @method draw_notebook_list * @param {Array} list An array of dictionaries representing files or - * direcotories. + * directories. * @param {String} error_msg An error message */ NotebookList.prototype.draw_notebook_list = function (list, error_msg) { From 89df33012942cc1eddbca14f7cd70d4b36894930 Mon Sep 17 00:00:00 2001 From: Kester Tong Date: Tue, 28 Oct 2014 21:03:44 -0400 Subject: [PATCH 41/54] Modifies Contents API to return Error objects Modfies the Contents class to return JavaScript Error objects instead of passing on the return values from $.ajax(). This has two advantages. First, it allows the content manager to parse errors and give more informative messages than the ajax response. Second, it makes the Contents interface more general, since other kinds of backends might generate client-side errors. --- IPython/html/static/base/js/utils.js | 18 ++++++ IPython/html/static/notebook/js/menubar.js | 12 +--- IPython/html/static/notebook/js/notebook.js | 70 ++++++++------------- IPython/html/static/services/contents.js | 67 +++++++++++++++----- IPython/html/static/tree/js/main.js | 12 +--- IPython/html/static/tree/js/notebooklist.js | 5 +- 6 files changed, 106 insertions(+), 78 deletions(-) diff --git a/IPython/html/static/base/js/utils.js b/IPython/html/static/base/js/utils.js index 22261f3e4..16f9a7068 100644 --- a/IPython/html/static/base/js/utils.js +++ b/IPython/html/static/base/js/utils.js @@ -563,6 +563,22 @@ define([ ); }; + /** Error type for wrapped XHR errors. */ + var XHR_ERROR = 'XhrError'; + + /** + * Wraps an AJAX error as an Error object. + */ + var wrap_ajax_error = function (jqXHR, status, error) { + var wrapped_error = new Error(ajax_error_msg(jqXHR)); + wrapped_error.name = XHR_ERROR; + // provide xhr response + wrapped_error.xhr = jqXHR; + wrapped_error.xhr_status = status; + wrapped_error.xhr_error = error; + return wrapped_error; + } + var utils = { regex_split : regex_split, uuid : uuid, @@ -588,6 +604,8 @@ define([ ajax_error_msg : ajax_error_msg, log_ajax_error : log_ajax_error, requireCodeMirrorMode : requireCodeMirrorMode, + XHR_ERROR : XHR_ERROR, + wrap_ajax_error : wrap_ajax_error }; // Backwards compatability. diff --git a/IPython/html/static/notebook/js/menubar.js b/IPython/html/static/notebook/js/menubar.js index 8e14bc2dc..01b09ae0e 100644 --- a/IPython/html/static/notebook/js/menubar.js +++ b/IPython/html/static/notebook/js/menubar.js @@ -91,23 +91,17 @@ define([ // notebook's path. that.contents.new_notebook(that.notebook.notebook_path, { - success: function (data, status, xhr) { + success: function (data) { window.open( utils.url_join_encode( that.base_url, 'notebooks', data.path, data.name ), '_blank'); }, - error: function(xhr, status, error) { - var msg; - if (xhr.responseJSON && xhr.responseJSON.message) { - msg = xhr.responseJSON.message; - } else { - msg = xhr.statusText; - } + error: function(error) { dialog.modal({ title : 'Creating Notebook Failed', - body : "The error was: " + msg, + body : "The error was: " + error.message, buttons : {'OK' : {'class' : 'btn-primary'}} }); } diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index fdc1c615b..05d1c06aa 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -1923,7 +1923,7 @@ define([ this.contents.save_file(this.notebook_path, this.notebook_name, model, { extra_settings: extra_settings, success: $.proxy(this.save_notebook_success, this, start), - error: function (xhr, status, error) { + error: function (error) { that.events.trigger('notebook_save_failed.Notebook'); } }); @@ -1935,10 +1935,8 @@ define([ * @method save_notebook_success * @param {Integer} start Time when the save request start * @param {Object} data JSON representation of a notebook - * @param {String} status Description of response status - * @param {jqXHR} xhr jQuery Ajax object */ - Notebook.prototype.save_notebook_success = function (start, data, status, xhr) { + Notebook.prototype.save_notebook_success = function (start, data) { this.set_dirty(false); if (data.message) { // save succeeded, but validation failed. @@ -2078,7 +2076,7 @@ define([ var that = this; this.contents.rename_file(this.notebook_path, this.notebook_name, this.notebook_path, new_name, { - success: function (json, status, xhr) { + success: function (json) { var name = that.notebook_name = json.name; that.session.rename_notebook(name, json.path); that.events.trigger('notebook_renamed.Notebook', json); @@ -2091,12 +2089,12 @@ define([ this.contents.delete_file(this.notebook_name, this.notebook_path); }; - Notebook.prototype.rename_error = function (xhr, status, error) { + Notebook.prototype.rename_error = function (error) { var that = this; var dialog_body = $('
').append( $("

").text('This notebook name already exists.') ); - this.events.trigger('notebook_rename_failed.Notebook', [xhr, status, error]); + this.events.trigger('notebook_rename_failed.Notebook', error); dialog.modal({ notebook: this, keyboard_manager: this.keyboard_manager, @@ -2146,10 +2144,8 @@ define([ * * @method load_notebook_success * @param {Object} data JSON representation of a notebook - * @param {String} status Description of response status - * @param {jqXHR} xhr jQuery Ajax object */ - Notebook.prototype.load_notebook_success = function (data, status, xhr) { + Notebook.prototype.load_notebook_success = function (data) { var failed; try { this.fromJSON(data); @@ -2281,20 +2277,18 @@ define([ * Failure callback for loading a notebook from the server. * * @method load_notebook_error - * @param {jqXHR} xhr jQuery Ajax object - * @param {String} status Description of response status - * @param {String} error HTTP error message - */ - Notebook.prototype.load_notebook_error = function (xhr, status, error) { - this.events.trigger('notebook_load_failed.Notebook', [xhr, status, error]); - utils.log_ajax_error(xhr, status, error); - var msg = $("

"); - if (xhr.status === 400) { - msg.text(utils.ajax_error_msg(xhr)); - } else if (xhr.status === 500) { - msg.text("An unknown error occurred while loading this notebook. " + + * @param {Error} error + */ + Notebook.prototype.load_notebook_error = function (error) { + this.events.trigger('notebook_load_failed.Notebook', error); + var msg; + if (error.name = utils.XHR_ERROR && error.xhr.status === 500) { + utils.log_ajax_error(error.xhr, error.xhr_status, error.xhr_error); + msg = "An unknown error occurred while loading this notebook. " + "This version can load notebook formats " + - "v" + this.nbformat + " or earlier. See the server log for details."); + "v" + this.nbformat + " or earlier. See the server log for details."; + } else { + msg = error.message; } dialog.modal({ notebook: this, @@ -2350,7 +2344,7 @@ define([ var that = this; this.contents.list_checkpoints(this.notebook_path, this.notebook_name, { success: $.proxy(this.list_checkpoints_success, this), - error: function(xhr, status, error_msg) { + error: function(error) { that.events.trigger('list_checkpoints_failed.Notebook'); } }); @@ -2361,10 +2355,8 @@ define([ * * @method list_checkpoint_success * @param {Object} data JSON representation of a checkpoint - * @param {String} status Description of response status - * @param {jqXHR} xhr jQuery Ajax object */ - Notebook.prototype.list_checkpoints_success = function (data, status, xhr) { + Notebook.prototype.list_checkpoints_success = function (data) { data = $.parseJSON(data); this.checkpoints = data; if (data.length) { @@ -2384,7 +2376,7 @@ define([ var that = this; this.contents.create_checkpoint(this.notebook_path, this.notebook_name, { success: $.proxy(this.create_checkpoint_success, this), - error: function (xhr, status, error_msg) { + error: function (error) { that.events.trigger('checkpoint_failed.Notebook'); } }); @@ -2395,10 +2387,8 @@ define([ * * @method create_checkpoint_success * @param {Object} data JSON representation of a checkpoint - * @param {String} status Description of response status - * @param {jqXHR} xhr jQuery Ajax object */ - Notebook.prototype.create_checkpoint_success = function (data, status, xhr) { + Notebook.prototype.create_checkpoint_success = function (data) { data = $.parseJSON(data); this.add_checkpoint(data); this.events.trigger('checkpoint_created.Notebook', data); @@ -2457,7 +2447,7 @@ define([ this.contents.restore_checkpoint(this.notebook_path, this.notebook_name, checkpoint, { success: $.proxy(this.create_checkpoint_success, this), - error: function (xhr, status, error_msg) { + error: function (error) { that.events.trigger('checkpoint_restore_failed.Notebook'); } }); @@ -2467,11 +2457,8 @@ define([ * Success callback for restoring a notebook to a checkpoint. * * @method restore_checkpoint_success - * @param {Object} data (ignored, should be empty) - * @param {String} status Description of response status - * @param {jqXHR} xhr jQuery Ajax object */ - Notebook.prototype.restore_checkpoint_success = function (data, status, xhr) { + Notebook.prototype.restore_checkpoint_success = function () { this.events.trigger('checkpoint_restored.Notebook'); this.load_notebook(this.notebook_name, this.notebook_path); }; @@ -2488,8 +2475,8 @@ define([ this.contents.delete_checkpoint(this.notebook_path, this.notebook_name, checkpoint, { success: $.proxy(this.create_checkpoint_success, this), - error: function (xhr, status, error_msg) { - that.events.trigger('checkpoint_delete_failed.Notebook', [xhr, status, error]); + error: function (error) { + that.events.trigger('checkpoint_delete_failed.Notebook', error); } }); }; @@ -2498,12 +2485,9 @@ define([ * Success callback for deleting a notebook checkpoint * * @method delete_checkpoint_success - * @param {Object} data (ignored, should be empty) - * @param {String} status Description of response status - * @param {jqXHR} xhr jQuery Ajax object */ - Notebook.prototype.delete_checkpoint_success = function (data, status, xhr) { - this.events.trigger('checkpoint_deleted.Notebook', data); + Notebook.prototype.delete_checkpoint_success = function () { + this.events.trigger('checkpoint_deleted.Notebook'); this.load_notebook(this.notebook_name, this.notebook_path); }; diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index 7dda2a3f0..69190316a 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -21,12 +21,47 @@ define([ this.base_url = options.base_url; }; + /** Error type */ + Contents.DIRECTORY_NOT_EMPTY_ERROR = 'DirectoryNotEmptyError'; + + Contents.DirectoryNotEmptyError = function() { + // Constructor + // + // An error representing the result of attempting to delete a non-empty + // directory. + this.message = 'A directory must be empty before being deleted.'; + } + Contents.DirectoryNotEmptyError.prototype = new Error; + Contents.DirectoryNotEmptyError.prototype.name = + Contents.DIRECTORY_NOTE_EMPTY_ERROR; + + Contents.prototype.api_url = function() { var url_parts = [this.base_url, 'api/contents'].concat( Array.prototype.slice.apply(arguments)); return utils.url_join_encode.apply(null, url_parts); }; + /** + * Creates a basic error handler that wraps a jqXHR error as an Error. + * + * Takes a callback that accepts an Error, and returns a callback that can + * be passed directly to $.ajax, which will wrap the error from jQuery + * as an Error, and pass that to the original callback. + * + * @method create_basic_error_handler + * @param{Function} callback + * @return{Function} + */ + Contents.prototype.create_basic_error_handler = function(callback) { + if (!callback) { + return function(xhr, status, error) { }; + } + return function(xhr, status, error) { + callback(utils.wrap_ajax_error(xhr, status, error)); + }; + } + /** * File Functions (including notebook operations) */ @@ -50,7 +85,7 @@ define([ type : "GET", dataType : "json", success : options.success, - error : options.error || function() {} + error : this.create_basic_error_handler(options.error) }; var url = this.api_url(path, name); $.ajax(url, settings); @@ -71,7 +106,7 @@ define([ type : "POST", dataType : "json", success : options.success || function() {}, - error : options.error || function() {} + error : this.create_basic_error_handler(options.error) }; $.ajax(this.api_url(path), settings); }; @@ -86,8 +121,12 @@ define([ dataType : "json", success : options.success || function() {}, error : function(xhr, status, error) { - utils.log_ajax_error(xhr, status, error); - error(xhr, status, error); + // TODO: update IPEP27 to specify errors more precisely, so + // that error types can be detected here with certainty. + if (xhr.status === 400) { + error(new Contents.DirectoryNotEmptyError()); + } + error(utils.wrap_ajax_error(xhr, status, error)); } }; var url = this.api_url(path, name); @@ -103,8 +142,8 @@ define([ data : JSON.stringify(data), dataType: "json", contentType: 'application/json', - success : options.success || function() {}, - error : options.error || function() {} + success : options.success || function() {}, + error : this.create_basic_error_handler(options.error) }; var url = this.api_url(path, name); $.ajax(url, settings); @@ -119,7 +158,7 @@ define([ data : JSON.stringify(model), contentType: 'application/json', success : options.success || function() {}, - error : options.error || function() {} + error : this.create_basic_error_handler(options.error) }; if (options.extra_settings) { $.extend(settings, options.extra_settings); @@ -137,7 +176,7 @@ define([ var settings = { type : "POST", success: options.success || function() {}, - error: options.error || function() {} + error : this.create_basic_error_handler(options.error) }; $.ajax(url, settings); }; @@ -147,7 +186,7 @@ define([ var settings = { type : "GET", success: options.success, - error: options.error || function() {} + error : this.create_basic_error_handler(options.error) }; $.ajax(url, settings); }; @@ -157,17 +196,17 @@ define([ var settings = { type : "POST", success: options.success || function() {}, - error: options.error || function() {} + error : this.create_basic_error_handler(options.error) }; $.ajax(url, settings); }; - Contents.prototype.delete_checkpoint = function(path, name, checkpoint_id, options) { + Contents.prototype.delete_checkpoint = function(path, name, checkpoint_id, options) { var url = this.api_url(path, name, 'checkpoints', checkpoint_id); var settings = { type : "DELETE", success: options.success || function() {}, - error: options.error || function() {} + error : this.create_basic_error_handler(options.error) }; $.ajax(url, settings); }; @@ -199,7 +238,7 @@ define([ type : "GET", dataType : "json", success : options.success, - error : options.error || function() {} + error : this.create_basic_error_handler(options.error) }; $.ajax(this.api_url(path), settings); @@ -209,4 +248,4 @@ define([ IPython.Contents = Contents; return {'Contents': Contents}; -}); +}); diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index 1f53a7f77..73ed8b18e 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -62,23 +62,17 @@ require([ $('#new_notebook').click(function (e) { contents.new_notebook(common_options.notebook_path, { - success: function (data, status, xhr) { + success: function (data) { window.open( utils.url_join_encode( common_options.base_url, 'notebooks', data.path, data.name ), '_blank'); }, - error: function(xhr, status, error) { - var msg; - if (xhr.responseJSON && xhr.responseJSON.message) { - msg = xhr.responseJSON.message; - } else { - msg = xhr.statusText; - } + error: function(error) { dialog.modal({ title : 'Creating Notebook Failed', - body : "The error was: " + msg, + body : "The error was: " + error.message, buttons : {'OK' : {'class' : 'btn-primary'}} }); } diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 2e62f40b5..a044025e2 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -144,9 +144,8 @@ define([ var that = this this.contents.list_contents(that.notebook_path, { success: $.proxy(this.draw_notebook_list, this), - error: function(xhr, status, error) { - utils.log_ajax_error(xhr, status, error); - that.draw_notebook_list([], "Error connecting to server."); + error: function(error) { + that.draw_notebook_list([], "Server error: " + error.message); } }); }; From 9797a6b7c0b26d4343f3a03f6857463f3c7afff7 Mon Sep 17 00:00:00 2001 From: Kester Tong Date: Tue, 28 Oct 2014 21:10:30 -0400 Subject: [PATCH 42/54] typo fix --- IPython/html/static/services/contents.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index 69190316a..cd04d49be 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -33,7 +33,7 @@ define([ } Contents.DirectoryNotEmptyError.prototype = new Error; Contents.DirectoryNotEmptyError.prototype.name = - Contents.DIRECTORY_NOTE_EMPTY_ERROR; + Contents.DIRECTORY_NOT_EMPTY_ERROR; Contents.prototype.api_url = function() { From b8f9dc07e2211cf206dcd6df01b14ed51281c1aa Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 29 Oct 2014 11:08:01 -0700 Subject: [PATCH 43/54] Fix error callback when deleting file --- IPython/html/static/services/contents.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index cd04d49be..aeff6af05 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -112,7 +112,7 @@ define([ }; Contents.prototype.delete_file = function(name, path, options) { - var error = options.error || function() {}; + var error_callback = options.error || function() {}; var that = this; var settings = { processData : false, @@ -124,9 +124,9 @@ define([ // TODO: update IPEP27 to specify errors more precisely, so // that error types can be detected here with certainty. if (xhr.status === 400) { - error(new Contents.DirectoryNotEmptyError()); + error_callback(new Contents.DirectoryNotEmptyError()); } - error(utils.wrap_ajax_error(xhr, status, error)); + error_callback(utils.wrap_ajax_error(xhr, status, error)); } }; var url = this.api_url(path, name); From 1ae6be218d54bf024b9c04697b9e06e00950cc5f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 29 Oct 2014 18:08:46 -0700 Subject: [PATCH 44/54] Fix require config --- IPython/html/templates/page.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/html/templates/page.html b/IPython/html/templates/page.html index a37aefd2e..e047424db 100644 --- a/IPython/html/templates/page.html +++ b/IPython/html/templates/page.html @@ -29,7 +29,7 @@ highlight: 'components/highlight.js/build/highlight.pack', moment: "components/moment/moment", codemirror: 'components/codemirror', - termjs: "components/term.js/src/term" + termjs: "components/term.js/src/term", contents: '{{ contents_js_source }}', }, shim: { From a2f3e23fd8a0cf6bcf4477c8b353cc8bcd7a904e Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 30 Oct 2014 13:22:58 -0700 Subject: [PATCH 45/54] Add copy_file to contents JS API --- IPython/html/static/notebook/js/notebook.js | 28 ++++++--------------- IPython/html/static/services/contents.js | 26 ++++++++++++++++++- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 05d1c06aa..5ef66c3a4 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -2041,31 +2041,17 @@ define([ }; Notebook.prototype.copy_notebook = function(){ - var path = this.notebook_path; var base_url = this.base_url; - var settings = { - processData : false, - cache : false, - type : "POST", - dataType : "json", - data : JSON.stringify({copy_from : this.notebook_name}), - async : false, - success : function (data, status, xhr) { + this.contents.copy_file(this.notebook_path, null, this.notebook_name, { + // synchronous so we can open a new window on success + extra_settings: {async: false}, + success: function (data) { window.open(utils.url_join_encode( - base_url, - 'notebooks', - data.path, - data.name + base_url, 'notebooks', data.path, data.name ), '_blank'); }, - error : utils.log_ajax_error, - }; - var url = utils.url_join_encode( - base_url, - 'api/contents', - path - ); - $.ajax(url,settings); + error : utils.log_ajax_error + }); }; Notebook.prototype.rename = function (new_name) { diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index aeff6af05..8494e2a58 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -153,7 +153,6 @@ define([ // We do the call with settings so we can set cache to false. var settings = { processData : false, - cache : false, type : "PUT", data : JSON.stringify(model), contentType: 'application/json', @@ -166,6 +165,31 @@ define([ var url = this.api_url(path, name); $.ajax(url, settings); }; + + Contents.prototype.copy_file = function(to_path, to_name, from, options) { + var url, method; + if (to_name) { + url = this.api_url(to_path, to_name); + method = "PUT"; + } else { + url = this.api_url(to_path); + method = "POST"; + } + + var settings = { + processData : false, + cache : false, + type: method, + data: JSON.stringify({copy_from: from}), + dataType : "json", + success: options.success || function() {}, + error: this.create_basic_error_handler(options.error) + }; + if (options.extra_settings) { + $.extend(settings, options.extra_settings); + } + $.ajax(url, settings); + }; /** * Checkpointing Functions From 2962a3ce17d57b0ff540d3e681a470ef0844cae6 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 30 Oct 2014 13:25:24 -0700 Subject: [PATCH 46/54] Remove some unnecessary cache: false parameters According to the jQuery docs, this is only needed for GET and HEAD requests. --- IPython/html/static/services/contents.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index 8494e2a58..ab9d4f46c 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -102,7 +102,6 @@ define([ var error = options.error || function() {}; var settings = { processData : false, - cache : false, type : "POST", dataType : "json", success : options.success || function() {}, @@ -116,7 +115,6 @@ define([ var that = this; var settings = { processData : false, - cache : false, type : "DELETE", dataType : "json", success : options.success || function() {}, @@ -178,7 +176,6 @@ define([ var settings = { processData : false, - cache : false, type: method, data: JSON.stringify({copy_from: from}), dataType : "json", From 658eb39c56777c57f7f1cf7e9d42d8b9271e04e3 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 30 Oct 2014 13:28:49 -0700 Subject: [PATCH 47/54] Remove one more unnecessary cache parameter --- IPython/html/static/services/contents.js | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index ab9d4f46c..9c82b54c9 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -135,7 +135,6 @@ define([ var data = {name: new_name, path: new_path}; var settings = { processData : false, - cache : false, type : "PATCH", data : JSON.stringify(data), dataType: "json", From 684516c79ffef791cff2c6e287188b000cf226a9 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 3 Nov 2014 10:21:38 -0800 Subject: [PATCH 48/54] Fix copy-paste mistakes --- IPython/html/static/notebook/js/notebook.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 5ef66c3a4..e612d266d 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -2432,7 +2432,7 @@ define([ var that = this; this.contents.restore_checkpoint(this.notebook_path, this.notebook_name, checkpoint, { - success: $.proxy(this.create_checkpoint_success, this), + success: $.proxy(this.restore_checkpoint_success, this), error: function (error) { that.events.trigger('checkpoint_restore_failed.Notebook'); } @@ -2460,7 +2460,7 @@ define([ var that = this; this.contents.delete_checkpoint(this.notebook_path, this.notebook_name, checkpoint, { - success: $.proxy(this.create_checkpoint_success, this), + success: $.proxy(this.delete_checkpoint_success, this), error: function (error) { that.events.trigger('checkpoint_delete_failed.Notebook', error); } From 4452754a6b43fcd9473a4a6091d938f41dd12124 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 3 Nov 2014 14:20:12 -0800 Subject: [PATCH 49/54] Set notebook nbformat in toJSON --- IPython/html/static/notebook/js/notebook.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index e612d266d..bcff039bb 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -1862,7 +1862,9 @@ define([ } var data = { cells: cell_array, - metadata : this.metadata + metadata: this.metadata, + nbformat: this.nbformat, + nbformat_minor: this.nbformat_minor }; if (trusted != this.trusted) { this.trusted = trusted; @@ -1905,16 +1907,12 @@ define([ * @method save_notebook */ Notebook.prototype.save_notebook = function (extra_settings) { - var content = $.extend(this.toJSON(), { - nbformat : this.nbformat, - nbformat_minor : this.nbformat_minor - }); // Create a JSON model to be sent to the server. var model = { name : this.notebook_name, path : this.notebook_path, type : "notebook", - content : content + content : this.toJSON() }; // time the ajax call for autosave tuning purposes. var start = new Date().getTime(); From 5279418acfb54116eb790d2f719703872d00b4ff Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 3 Nov 2014 14:29:39 -0800 Subject: [PATCH 50/54] Make Contents.new more generic --- IPython/html/static/notebook/js/menubar.js | 4 ++-- IPython/html/static/services/contents.js | 17 ++++++++++++++--- IPython/html/static/tree/js/main.js | 4 ++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/IPython/html/static/notebook/js/menubar.js b/IPython/html/static/notebook/js/menubar.js index 01b09ae0e..306059959 100644 --- a/IPython/html/static/notebook/js/menubar.js +++ b/IPython/html/static/notebook/js/menubar.js @@ -89,8 +89,8 @@ define([ this.element.find('#new_notebook').click(function () { // Create a new notebook in the same path as the current // notebook's path. - that.contents.new_notebook(that.notebook.notebook_path, - { + that.contents.new(that.notebook.notebook_path, null, { + ext: ".ipynb", success: function (data) { window.open( utils.url_join_encode( diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index 9c82b54c9..b9971c5dd 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -97,12 +97,23 @@ define([ * * @method scroll_to_cell * @param {String} path The path to create the new notebook at + * @param {String} name Name for new file. Chosen by server if unspecified. + * @param {Object} options: + * ext: file extension to use if name unspecified */ - Contents.prototype.new_notebook = function(path, options) { - var error = options.error || function() {}; + Contents.prototype.new = function(path, name, options) { + var method, data; + if (name) { + method = "PUT"; + } else { + method = "POST"; + data = JSON.stringify({ext: options.ext || ".ipynb"}); + } + var settings = { processData : false, - type : "POST", + type : method, + data: data, dataType : "json", success : options.success || function() {}, error : this.create_basic_error_handler(options.error) diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index 73ed8b18e..b2db0b3b4 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -60,8 +60,8 @@ require([ login_widget = new loginwidget.LoginWidget('#login_widget', common_options); $('#new_notebook').click(function (e) { - contents.new_notebook(common_options.notebook_path, - { + contents.new(common_options.notebook_path, null, { + ext: ".ipynb", success: function (data) { window.open( utils.url_join_encode( From a4f869aa8ba8e4a55c7a78a5a1964c697e835d8f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 3 Nov 2014 14:40:09 -0800 Subject: [PATCH 51/54] Rename methods to remove _file suffix --- IPython/html/static/notebook/js/notebook.js | 10 +++++----- IPython/html/static/services/contents.js | 8 ++++---- IPython/html/static/tree/js/notebooklist.js | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index bcff039bb..8eec42fe0 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -1918,7 +1918,7 @@ define([ var start = new Date().getTime(); var that = this; - this.contents.save_file(this.notebook_path, this.notebook_name, model, { + this.contents.save(this.notebook_path, this.notebook_name, model, { extra_settings: extra_settings, success: $.proxy(this.save_notebook_success, this, start), error: function (error) { @@ -2040,7 +2040,7 @@ define([ Notebook.prototype.copy_notebook = function(){ var base_url = this.base_url; - this.contents.copy_file(this.notebook_path, null, this.notebook_name, { + this.contents.copy(this.notebook_path, null, this.notebook_name, { // synchronous so we can open a new window on success extra_settings: {async: false}, success: function (data) { @@ -2058,8 +2058,8 @@ define([ } var that = this; - this.contents.rename_file(this.notebook_path, this.notebook_name, - this.notebook_path, new_name, { + this.contents.rename(this.notebook_path, this.notebook_name, + this.notebook_path, new_name, { success: function (json) { var name = that.notebook_name = json.name; that.session.rename_notebook(name, json.path); @@ -2070,7 +2070,7 @@ define([ }; Notebook.prototype.delete = function () { - this.contents.delete_file(this.notebook_name, this.notebook_path); + this.contents.delete(this.notebook_name, this.notebook_path); }; Notebook.prototype.rename_error = function (error) { diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index b9971c5dd..305798f4b 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -121,7 +121,7 @@ define([ $.ajax(this.api_url(path), settings); }; - Contents.prototype.delete_file = function(name, path, options) { + Contents.prototype.delete = function(name, path, options) { var error_callback = options.error || function() {}; var that = this; var settings = { @@ -142,7 +142,7 @@ define([ $.ajax(url, settings); }; - Contents.prototype.rename_file = function(path, name, new_path, new_name, options) { + Contents.prototype.rename = function(path, name, new_path, new_name, options) { var data = {name: new_name, path: new_path}; var settings = { processData : false, @@ -157,7 +157,7 @@ define([ $.ajax(url, settings); }; - Contents.prototype.save_file = function(path, name, model, options) { + Contents.prototype.save = function(path, name, model, options) { // We do the call with settings so we can set cache to false. var settings = { processData : false, @@ -174,7 +174,7 @@ define([ $.ajax(url, settings); }; - Contents.prototype.copy_file = function(to_path, to_name, from, options) { + Contents.prototype.copy = function(to_path, to_name, from, options) { var url, method; if (to_name) { url = this.api_url(to_path, to_name); diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index a044025e2..7d2b06456 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -330,7 +330,7 @@ define([ Delete : { class: "btn-danger", click: function() { - notebooklist.contents.delete_file(name, path, { + notebooklist.contents.delete(name, path, { success: function() { notebooklist.notebook_deleted(path, name); } From 1f2e4cc6c327dde8de283c7f831a65703e037864 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 3 Nov 2014 14:41:50 -0800 Subject: [PATCH 52/54] Fix passing empty list to draw_notebook_list() --- IPython/html/static/tree/js/notebooklist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/html/static/tree/js/notebooklist.js b/IPython/html/static/tree/js/notebooklist.js index 7d2b06456..b36116720 100644 --- a/IPython/html/static/tree/js/notebooklist.js +++ b/IPython/html/static/tree/js/notebooklist.js @@ -145,7 +145,7 @@ define([ this.contents.list_contents(that.notebook_path, { success: $.proxy(this.draw_notebook_list, this), error: function(error) { - that.draw_notebook_list([], "Server error: " + error.message); + that.draw_notebook_list({content: []}, "Server error: " + error.message); } }); }; From 2a497c16eb0212cebc66cb0c1022020ce04aa64d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 3 Nov 2014 14:46:49 -0800 Subject: [PATCH 53/54] load_file -> load --- IPython/html/static/notebook/js/notebook.js | 2 +- IPython/html/static/services/contents.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 8eec42fe0..f2e2b6732 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -2115,7 +2115,7 @@ define([ this.notebook_name = notebook_name; this.notebook_path = notebook_path; this.events.trigger('notebook_loading.Notebook'); - this.contents.load_file(notebook_path, notebook_name, { + this.contents.load(notebook_path, notebook_name, { success: $.proxy(this.load_notebook_success, this), error: $.proxy(this.load_notebook_error, this) }); diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index 305798f4b..9459da406 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -77,7 +77,7 @@ define([ * @param {Function} success * @param {Function} error */ - Contents.prototype.load_file = function (path, name, options) { + Contents.prototype.load = function (path, name, options) { // We do the call with settings so we can set cache to false. var settings = { processData : false, From b7a558d5b9386fb02efd3e50c4034f3eb674b605 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 3 Nov 2014 15:29:09 -0800 Subject: [PATCH 54/54] Use synchronous request for creating new notebooks To get round popup blockers --- IPython/html/static/notebook/js/menubar.js | 1 + IPython/html/static/services/contents.js | 3 +++ IPython/html/static/tree/js/main.js | 1 + 3 files changed, 5 insertions(+) diff --git a/IPython/html/static/notebook/js/menubar.js b/IPython/html/static/notebook/js/menubar.js index 306059959..fc6f26523 100644 --- a/IPython/html/static/notebook/js/menubar.js +++ b/IPython/html/static/notebook/js/menubar.js @@ -91,6 +91,7 @@ define([ // notebook's path. that.contents.new(that.notebook.notebook_path, null, { ext: ".ipynb", + extra_settings: {async: false}, // So we can open a new window afterwards success: function (data) { window.open( utils.url_join_encode( diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index 9459da406..3cc5f11e5 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -118,6 +118,9 @@ define([ success : options.success || function() {}, error : this.create_basic_error_handler(options.error) }; + if (options.extra_settings) { + $.extend(settings, options.extra_settings); + } $.ajax(this.api_url(path), settings); }; diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index b2db0b3b4..2396ad8db 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -62,6 +62,7 @@ require([ $('#new_notebook').click(function (e) { contents.new(common_options.notebook_path, null, { ext: ".ipynb", + extra_settings: {async: false}, // So we can open a new window afterwards success: function (data) { window.open( utils.url_join_encode(