File upload/import working from notebook browser.

This commit is contained in:
Brian E. Granger 2011-08-05 22:06:45 -07:00
parent e0cc1a6c48
commit 458c48b229
6 changed files with 243 additions and 71 deletions

View File

@ -89,8 +89,9 @@ class NotebookRootHandler(web.RequestHandler):
nbm = self.application.notebook_manager
body = self.request.body.strip()
format = self.get_argument('format', default='json')
name = self.get_argument('name', default=None)
if body:
notebook_id = nbm.save_new_notebook(body, format)
notebook_id = nbm.save_new_notebook(body, name=name, format=format)
else:
notebook_id = nbm.new_notebook()
self.set_header('Location', '/'+notebook_id)
@ -120,7 +121,8 @@ class NotebookHandler(web.RequestHandler):
def put(self, notebook_id):
nbm = self.application.notebook_manager
format = self.get_argument('format', default='json')
nbm.save_notebook(notebook_id, self.request.body, format)
name = self.get_argument('name', default=None)
nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
self.set_status(204)
self.finish()

View File

@ -124,30 +124,57 @@ class NotebookManager(Configurable):
raise web.HTTPError(404)
return last_modified, nb
def save_new_notebook(self, data, format=u'json'):
"""Save a new notebook and return its notebook_id."""
def save_new_notebook(self, data, name=None, format=u'json'):
"""Save a new notebook and return its notebook_id.
If a name is passed in, it overrides any values in the notebook data
and the value in the data is updated to use that value.
"""
if format not in self.allowed_formats:
raise web.HTTPError(415)
try:
nb = current.reads(data, format)
except:
raise web.HTTPError(400)
try:
name = nb.name
except AttributeError:
raise web.HTTPError(400)
if format == u'xml':
# v1 notebooks might come in with a format='xml' but be json.
try:
nb = current.reads(data, u'json')
except:
raise web.HTTPError(400)
else:
raise web.HTTPError(400)
if name is None:
try:
name = nb.name
except AttributeError:
raise web.HTTPError(400)
nb.name = name
notebook_id = self.new_notebook_id(name)
self.save_notebook_object(notebook_id, nb)
return notebook_id
def save_notebook(self, notebook_id, data, format=u'json'):
def save_notebook(self, notebook_id, data, name=None, format=u'json'):
"""Save an existing notebook by notebook_id."""
if format not in self.allowed_formats:
raise web.HTTPError(415)
try:
nb = current.reads(data, format)
except:
raise web.HTTPError(400)
if format == u'xml':
# v1 notebooks might come in with a format='xml' but be json.
try:
nb = current.reads(data, u'json')
except:
raise web.HTTPError(400)
else:
raise web.HTTPError(400)
if name is not None:
nb.name = name
self.save_notebook_object(notebook_id, nb)
def save_notebook_object(self, notebook_id, nb):

View File

@ -18,12 +18,22 @@ body {
overflow: auto;
}
#left_panel {
}
#drop_zone {
height: 200px;
width: 200px
}
#content_panel {
width: 600px;
}
#content_toolbar {
padding: 10px 5px;
padding: 10px 5px 5px 5px;
height: 25px;
line-height: 25px;
}
#header_border {
@ -35,6 +45,10 @@ body {
width: 100%;
}
#drag_info {
float: left;
}
#notebooks_buttons {
float: right;
}
@ -59,6 +73,10 @@ body {
float: right;
}
.item_buttons .upload_button {
color: darkred;
}
.highlight_text {
color: blue;
}

View File

@ -10,14 +10,17 @@ $(document).ready(function () {
$('div#header_border').addClass('border-box-sizing ui-widget ui-widget-content');
$('div#main_app').addClass('border-box-sizing ui-widget');
$('div#app_hbox').addClass('hbox center');
$('div#app_hbox').addClass('hbox');
$('div#content_toolbar').addClass('ui-widget ui-helper-clearfix');
$('#new_notebook').click(function (e) {
$('#new_notebook').button().click(function (e) {
window.open('/new');
});
$('div#left_panel').addClass('box-flex');
$('div#right_panel').addClass('box-flex');
IPython.notebook_list = new IPython.NotebookList('div#notebook_list');
IPython.notebook_list.load_list();

View File

@ -21,7 +21,35 @@ var IPython = (function (IPython) {
NotebookList.prototype.bind_events = function () {
var that = this;
this.element.bind('dragover', function () {
return false;
});
this.element.bind('drop', function (event) {
var files = event.originalEvent.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
reader.readAsText(f);
var fname = f.name.split('.');
var nbname = fname[0];
var nbformat = fname[1];
if (nbformat === 'ipynb') {nbformat = 'xml';};
if (nbformat === 'xml' || nbformat === 'py' || nbformat === 'json') {
var item = that.new_notebook_item(0);
that.add_name_input(nbname, item);
item.data('nbformat', nbformat);
// Store the notebook item in the reader so we can use it later
// to know which item it belongs to.
$(reader).data('item', item);
reader.onload = function (event) {
var nbitem = $(event.target).data('item');
that.add_notebook_data(event.target.result, nbitem);
that.add_upload_button(nbitem);
};
};
}
return false;
});
};
@ -31,7 +59,7 @@ var IPython = (function (IPython) {
cache : false,
type : "GET",
dataType : "json",
success : $.proxy(this.list_loaded,this)
success : $.proxy(this.list_loaded, this)
};
$.ajax("/notebooks", settings);
};
@ -39,64 +67,157 @@ var IPython = (function (IPython) {
NotebookList.prototype.list_loaded = function (data, status, xhr) {
var len = data.length;
// Todo: remove old children
for (var i=0; i<len; i++) {
var notebook_id = data[i].notebook_id;
var nbname = data[i].name;
var item = this.new_notebook_item(i);
this.add_link(notebook_id, nbname, item);
this.add_delete_button(item);
};
};
var item = $('<div/>');
item.addClass('notebook_item ui-widget ui-widget-content ui-helper-clearfix');
var item_name = $('<span/>').addClass('item_name').append(
$('<a/>').attr('href','/'+notebook_id).
attr('target','_blank').
text(nbname)
);
// Store the nbname and notebook_id on the item for later usage. We have to do this
// because the loop over elements changes the values of the local nbname and notebook_id
// variables.
item.data('notebook_id',notebook_id);
item.data('nbname',nbname);
var buttons = $('<span/>').addClass('item_buttons');
var delete_button = $('<button>Delete</button>').button().
click(function (e) {
// $(this) is the button that was clicked.
var that = $(this);
// We use the nbname and notebook_id from the parent notebook_item element's
// data because the outer scopes values change as we iterate through the loop.
var parent_item = that.parents('div.notebook_item');
var nbname = parent_item.data('nbname');
var notebook_id = parent_item.data('notebook_id');
var dialog = $('<div/>');
dialog.html('Are you sure you want to permanently delete the notebook: ' + nbname + '?');
parent_item.append(dialog);
dialog.dialog({
resizable: false,
modal: true,
title: "Delete notebook",
buttons : {
"Delete": function () {
var settings = {
processData : false,
cache : false,
type : "DELETE",
dataType : "json",
success : function (data, status, xhr) {
parent_item.remove();
}
};
$.ajax("/notebooks/" + notebook_id, settings);
$(this).dialog('close');
},
"Cancel": function () {
$(this).dialog('close');
}
}
});
});
buttons.append(delete_button);
item.append(item_name).append(buttons);
NotebookList.prototype.new_notebook_item = function (index) {
var item = $('<div/>');
item.addClass('notebook_item ui-widget ui-widget-content ui-helper-clearfix');
var item_name = $('<span/>').addClass('item_name');
item.append(item_name);
if (index === -1) {
this.element.append(item);
} else {
this.element.children().eq(index).after(item);
}
return item;
};
NotebookList.prototype.add_link = function (notebook_id, nbname, item) {
item.data('nbname', nbname);
item.data('notebook_id', notebook_id);
var new_item_name = $('<span/>').addClass('item_name');
new_item_name.append(
$('<a/>').
attr('href','/'+notebook_id).
attr('target','_blank').
text(nbname)
);
var e = item.find('.item_name');
if (e.length === 0) {
item.append(new_item_name);
} else {
e.replaceWith(new_item_name);
};
};
NotebookList.prototype.add_name_input = function (nbname, item) {
item.data('nbname', nbname);
var new_item_name = $('<span/>').addClass('item_name');
new_item_name.append(
$('<input/>').addClass('ui-widget ui-widget-content').
attr('value', nbname).
attr('size', '30').
attr('type', 'text')
);
var e = item.find('.item_name');
if (e.length === 0) {
item.append(new_item_name);
} else {
e.replaceWith(new_item_name);
};
};
NotebookList.prototype.add_notebook_data = function (data, item) {
item.data('nbdata',data);
};
NotebookList.prototype.add_delete_button = function (item) {
var new_buttons = $('<span/>').addClass('item_buttons');
var delete_button = $('<button>Delete</button>').button().
click(function (e) {
// $(this) is the button that was clicked.
var that = $(this);
// We use the nbname and notebook_id from the parent notebook_item element's
// data because the outer scopes values change as we iterate through the loop.
var parent_item = that.parents('div.notebook_item');
var nbname = parent_item.data('nbname');
var notebook_id = parent_item.data('notebook_id');
var dialog = $('<div/>');
dialog.html('Are you sure you want to permanently delete the notebook: ' + nbname + '?');
parent_item.append(dialog);
dialog.dialog({
resizable: false,
modal: true,
title: "Delete notebook",
buttons : {
"Delete": function () {
var settings = {
processData : false,
cache : false,
type : "DELETE",
dataType : "json",
success : function (data, status, xhr) {
parent_item.remove();
}
};
$.ajax("/notebooks/" + notebook_id, settings);
$(this).dialog('close');
},
"Cancel": function () {
$(this).dialog('close');
}
}
});
});
new_buttons.append(delete_button);
var e = item.find('.item_buttons');
if (e.length === 0) {
item.append(new_buttons);
} else {
e.replaceWith(new_buttons);
};
};
NotebookList.prototype.add_upload_button = function (item) {
var that = this;
var new_buttons = $('<span/>').addClass('item_buttons');
var upload_button = $('<button>Upload</button>').button().
click(function (e) {
var nbname = item.find('.item_name > input').attr('value');
var nbformat = item.data('nbformat');
var nbdata = item.data('nbdata');
var settings = {
processData : false,
cache : false,
type : "POST",
dataType : "json",
data : nbdata,
success : function (data, status, xhr) {
that.add_link(data, nbname, item);
that.add_delete_button(item);
}
};
var qs = $.param({name:nbname, format:nbformat});
$.ajax("/notebooks?" + qs, settings);
});
var cancel_button = $('<button>Cancel</button>').button().
click(function (e) {
item.remove();
});
upload_button.addClass('upload_button');
new_buttons.append(upload_button).append(cancel_button);
var e = item.find('.item_buttons');
if (e.length === 0) {
item.append(new_buttons);
} else {
e.replaceWith(new_buttons);
};
};

View File

@ -29,11 +29,12 @@
<div id="app_hbox">
<!-- <div id="left_panel">-->
<!-- </div>-->
<div id="left_panel">
</div>
<div id="content_panel">
<div id="content_toolbar">
<span id="drag_info">Drag files onto the list to import notebooks.</span>
<span id="notebooks_buttons">
<button id="new_notebook">New Notebook</button>
</span>
@ -44,8 +45,8 @@
</div>
<!-- <div id="right_panel">-->
<!-- </div>-->
<div id="right_panel">
</div>
</div>