##// END OF EJS Templates
Backport PR #5459: Fix interact animation page jump FF...
Backport PR #5459: Fix interact animation page jump FF Firefox doesn't render images immediately as the data is available. When animating the way that we animate, this causes the output area to collapse quickly before returning to its original size. When the output area collapses, FireFox scrolls upwards in attempt to compensate for the lost vertical content (so it looks like you are on the same spot in the page, with respect to the contents below the image's prior location). The solution is to resize the image output after the `img onload` event has fired. This PR: - Releases the `clear_output` height lock after the image has been loaded (instead of immediately or using a timeout). - Removes a `setTimeout` call in the `append_output` method. - `clear_output` in zmqshell no longer sends `\r` to the stream outputs. closes #5128

File last commit:

r15518:e265dff7
r16229:ff1462d3
Show More
notebooklist.js
412 lines | 14.6 KiB | application/javascript | JavascriptLexer
//----------------------------------------------------------------------------
// Copyright (C) 2011 The IPython Development Team
//
// Distributed under the terms of the BSD License. The full license is in
// the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------
//============================================================================
// NotebookList
//============================================================================
var IPython = (function (IPython) {
"use strict";
var utils = IPython.utils;
var NotebookList = function (selector, options, element_name) {
var that = this
// allow code re-use by just changing element_name in kernellist.js
this.element_name = element_name || 'notebook';
this.selector = selector;
if (this.selector !== undefined) {
this.element = $(selector);
this.style();
this.bind_events();
}
this.notebooks_list = [];
this.sessions = {};
this.base_url = options.base_url || utils.get_body_data("baseUrl");
this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
$([IPython.events]).on('sessions_loaded.Dashboard',
function(e, d) { that.sessions_loaded(d); });
};
NotebookList.prototype.style = function () {
var prefix = '#' + this.element_name
$(prefix + '_toolbar').addClass('list_toolbar');
$(prefix + '_list_info').addClass('toolbar_info');
$(prefix + '_buttons').addClass('toolbar_buttons');
$(prefix + '_list_header').addClass('list_header');
this.element.addClass("list_container");
};
NotebookList.prototype.bind_events = function () {
var that = this;
$('#refresh_' + this.element_name + '_list').click(function () {
that.load_sessions();
});
this.element.bind('dragover', function () {
return false;
});
this.element.bind('drop', function(event){
that.handleFilesUpload(event,'drop');
return false;
});
};
NotebookList.prototype.handleFilesUpload = function(event, dropOrForm) {
var that = this;
var files;
if(dropOrForm =='drop'){
files = event.originalEvent.dataTransfer.files;
} else
{
files = event.originalEvent.target.files;
}
for (var i = 0; i < files.length; i++) {
var f = files[i];
var reader = new FileReader();
reader.readAsText(f);
var name_and_ext = utils.splitext(f.name);
var file_ext = name_and_ext[1];
if (file_ext === '.ipynb') {
var item = that.new_notebook_item(0);
that.add_name_input(f.name, item);
// 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);
};
} else {
var dialog = 'Uploaded notebooks must be .ipynb files';
IPython.dialog.modal({
title : 'Invalid file type',
body : dialog,
buttons : {'OK' : {'class' : 'btn-primary'}}
});
}
}
// Replace the file input form wth a clone of itself. This is required to
// reset the form. Otherwise, if you upload a file, delete it and try to
// upload it again, the changed event won't fire.
var form = $('input.fileinput');
form.replaceWith(form.clone(true));
return false;
};
NotebookList.prototype.clear_list = function () {
this.element.children('.list_item').remove();
};
NotebookList.prototype.load_sessions = function(){
IPython.session_list.load_sessions();
};
NotebookList.prototype.sessions_loaded = function(data){
this.sessions = data;
this.load_list();
};
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(){
that.list_loaded([], null, null, {msg:"Error connecting to server."});
},this)
};
var url = utils.url_join_encode(
this.base_url,
'api',
'notebooks',
this.notebook_path
);
$.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;
}
var item = null;
var len = data.length;
this.clear_list();
if (len === 0) {
item = this.new_notebook_item(0);
var span12 = item.children().first();
span12.empty();
span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
}
var path = this.notebook_path;
var offset = 0;
if (path !== '') {
item = this.new_notebook_item(0);
this.add_dir(path, '..', item);
offset = 1;
}
for (var i=0; i<len; i++) {
if (data[i].type === 'directory') {
var name = data[i].name;
item = this.new_notebook_item(i+offset);
this.add_dir(path, name, item);
} else {
var name = data[i].name;
item = this.new_notebook_item(i+offset);
this.add_link(path, name, item);
name = utils.url_path_join(path, name);
if(this.sessions[name] === undefined){
this.add_delete_button(item);
} else {
this.add_shutdown_button(item,this.sessions[name]);
}
}
}
};
NotebookList.prototype.new_notebook_item = function (index) {
var item = $('<div/>').addClass("list_item").addClass("row-fluid");
// item.addClass('list_item ui-widget ui-widget-content ui-helper-clearfix');
// item.css('border-top-style','none');
item.append($("<div/>").addClass("span12").append(
$('<i/>').addClass('item_icon')
).append(
$("<a/>").addClass("item_link").append(
$("<span/>").addClass("item_name")
)
).append(
$('<div/>').addClass("item_buttons btn-group pull-right")
));
if (index === -1) {
this.element.append(item);
} else {
this.element.children().eq(index).after(item);
}
return item;
};
NotebookList.prototype.add_dir = function (path, name, item) {
item.data('name', name);
item.data('path', path);
item.find(".item_name").text(name);
item.find(".item_icon").addClass('icon-folder-open');
item.find("a.item_link")
.attr('href',
utils.url_join_encode(
this.base_url,
"tree",
path,
name
)
);
};
NotebookList.prototype.add_link = function (path, nbname, item) {
item.data('nbname', nbname);
item.data('path', path);
item.find(".item_name").text(nbname);
item.find(".item_icon").addClass('icon-book');
item.find("a.item_link")
.attr('href',
utils.url_join_encode(
this.base_url,
"notebooks",
path,
nbname
)
).attr('target','_blank');
};
NotebookList.prototype.add_name_input = function (nbname, item) {
item.data('nbname', nbname);
item.find(".item_icon").addClass('icon-book');
item.find(".item_name").empty().append(
$('<input/>')
.addClass("nbname_input")
.attr('value', utils.splitext(nbname)[0])
.attr('size', '30')
.attr('type', 'text')
);
};
NotebookList.prototype.add_notebook_data = function (data, item) {
item.data('nbdata', data);
};
NotebookList.prototype.add_shutdown_button = function (item, session) {
var that = this;
var shutdown_button = $("<button/>").text("Shutdown").addClass("btn btn-mini btn-danger").
click(function (e) {
var settings = {
processData : false,
cache : false,
type : "DELETE",
dataType : "json",
success : function () {
that.load_sessions();
}
};
var url = utils.url_join_encode(
that.base_url,
'api/sessions',
session
);
$.ajax(url, settings);
return false;
});
// var new_buttons = item.find('a'); // shutdown_button;
item.find(".item_buttons").text("").append(shutdown_button);
};
NotebookList.prototype.add_delete_button = function (item) {
var new_buttons = $('<span/>').addClass("btn-group pull-right");
var notebooklist = this;
var delete_button = $("<button/>").text("Delete").addClass("btn btn-mini").
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.list_item');
var nbname = parent_item.data('nbname');
var message = 'Are you sure you want to permanently delete the notebook: ' + nbname + '?';
IPython.dialog.modal({
title : "Delete notebook",
body : message,
buttons : {
Delete : {
class: "btn-danger",
click: function() {
var settings = {
processData : false,
cache : false,
type : "DELETE",
dataType : "json",
success : function (data, status, xhr) {
parent_item.remove();
}
};
var url = utils.url_join_encode(
notebooklist.base_url,
'api/notebooks',
notebooklist.notebook_path,
nbname
);
$.ajax(url, settings);
}
},
Cancel : {}
}
});
return false;
});
item.find(".item_buttons").text("").append(delete_button);
};
NotebookList.prototype.add_upload_button = function (item) {
var that = this;
var upload_button = $('<button/>').text("Upload")
.addClass('btn btn-primary btn-mini upload_button')
.click(function (e) {
var nbname = item.find('.item_name > input').val();
if (nbname.slice(nbname.length-6, nbname.length) != ".ipynb") {
nbname = nbname + ".ipynb";
}
var path = that.notebook_path;
var nbdata = item.data('nbdata');
var content_type = 'application/json';
var model = {
content : JSON.parse(nbdata),
};
var settings = {
processData : false,
cache : false,
type : 'PUT',
dataType : 'json',
data : JSON.stringify(model),
headers : {'Content-Type': content_type},
success : function (data, status, xhr) {
that.add_link(path, nbname, item);
that.add_delete_button(item);
},
error : function (data, status, xhr) {
console.log(data, status);
}
};
var url = utils.url_join_encode(
that.base_url,
'api/notebooks',
that.notebook_path,
nbname
);
$.ajax(url, settings);
return false;
});
var cancel_button = $('<button/>').text("Cancel")
.addClass("btn btn-mini")
.click(function (e) {
console.log('cancel click');
item.remove();
return false;
});
item.find(".item_buttons").empty()
.append(upload_button)
.append(cancel_button);
};
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'
);
}
};
var url = utils.url_join_encode(
base_url,
'api/notebooks',
path
);
$.ajax(url, settings);
};
IPython.NotebookList = NotebookList;
return IPython;
}(IPython));