Merge remote-tracking branch 'upstream/master'

Nathan Heijermans 11 years ago
commit 8d5cc15ea1

@ -611,9 +611,9 @@ class FileContentsManager(ContentsManager):
return "Serving notebooks from local directory: %s" % self.root_dir
def get_kernel_path(self, path, model=None):
"""Return the initial working dir a kernel associated with a given notebook"""
"""Return the initial API path of a kernel associated with a given notebook"""
if '/' in path:
parent_dir = path.rsplit('/', 1)[0]
else:
parent_dir = ''
return self._get_os_path(parent_dir)
return parent_dir

@ -187,8 +187,12 @@ class ContentsManager(LoggingConfigurable):
KernelManagers can turn this value into a filesystem path,
or ignore it altogether.
The default value here will start kernels in the directory of the
notebook server. FileContentsManager overrides this to use the
directory containing the notebook.
"""
return path
return ''
def increment_filename(self, filename, path='', insert=''):
"""Increment a filename until it is unique.

@ -54,14 +54,10 @@ class MappingKernelManager(MultiKernelManager):
def cwd_for_path(self, path):
"""Turn API path into absolute OS path."""
# short circuit for NotebookManagers that pass in absolute paths
if os.path.exists(path):
return path
os_path = to_os_path(path, self.root_dir)
# in the case of notebooks and kernels not being on the same filesystem,
# walk up to root_dir if the paths don't exist
while not os.path.exists(os_path) and os_path != self.root_dir:
while not os.path.isdir(os_path) and os_path != self.root_dir:
os_path = os.path.dirname(os_path)
return os_path

@ -7,8 +7,6 @@ from tornado import web
from ...base.handlers import IPythonHandler, json_errors
from IPython.kernel.kernelspec import _pythonfirst
class MainKernelSpecHandler(IPythonHandler):
SUPPORTED_METHODS = ('GET',)
@ -17,18 +15,21 @@ class MainKernelSpecHandler(IPythonHandler):
@json_errors
def get(self):
ksm = self.kernel_spec_manager
results = []
for kernel_name in sorted(ksm.find_kernel_specs(), key=_pythonfirst):
km = self.kernel_manager
model = {}
model['default'] = km.default_kernel_name
model['kernelspecs'] = specs = {}
for kernel_name in ksm.find_kernel_specs():
try:
d = ksm.get_kernel_spec(kernel_name).to_dict()
except Exception:
self.log.error("Failed to load kernel spec: '%s'", kernel_name, exc_info=True)
continue
d['name'] = kernel_name
results.append(d)
specs[kernel_name] = d
self.set_header("Content-Type", 'application/json')
self.finish(json.dumps(results))
self.finish(json.dumps(model))
class KernelSpecHandler(IPythonHandler):

@ -78,16 +78,22 @@ class APITest(NotebookTestBase):
with open(pjoin(bad_kernel_dir, 'kernel.json'), 'w') as f:
f.write("garbage")
specs = self.ks_api.list().json()
assert isinstance(specs, list)
model = self.ks_api.list().json()
assert isinstance(model, dict)
self.assertEqual(model['default'], NATIVE_KERNEL_NAME)
specs = model['kernelspecs']
assert isinstance(specs, dict)
# 2: the sample kernelspec created in setUp, and the native Python kernel
self.assertGreaterEqual(len(specs), 2)
shutil.rmtree(bad_kernel_dir)
def test_list_kernelspecs(self):
specs = self.ks_api.list().json()
assert isinstance(specs, list)
model = self.ks_api.list().json()
assert isinstance(model, dict)
self.assertEqual(model['default'], NATIVE_KERNEL_NAME)
specs = model['kernelspecs']
assert isinstance(specs, dict)
# 2: the sample kernelspec created in setUp, and the native Python kernel
self.assertGreaterEqual(len(specs), 2)
@ -98,8 +104,8 @@ class APITest(NotebookTestBase):
def is_default_kernelspec(s):
return s['name'] == NATIVE_KERNEL_NAME and s['display_name'].startswith("IPython")
assert any(is_sample_kernelspec(s) for s in specs), specs
assert any(is_default_kernelspec(s) for s in specs), specs
assert any(is_sample_kernelspec(s) for s in specs.values()), specs
assert any(is_default_kernelspec(s) for s in specs.values()), specs
def test_get_kernelspec(self):
spec = self.ks_api.kernel_spec_info('Sample').json() # Case insensitive

@ -4,14 +4,17 @@
define([
'base/js/namespace',
'jquery',
], function(IPython, $){
'base/js/events',
], function(IPython, $, events){
"use strict";
var Page = function () {
this.bind_events();
this._resize_header();
};
Page.prototype.bind_events = function () {
events.on('resize-header.Page', $.proxy(this._resize_header, this));
};
Page.prototype.show = function () {
@ -41,6 +44,11 @@ define([
$('div#site').css('display','block');
};
Page.prototype._resize_header = function() {
// Update the header's size.
$('#header-spacer').height($('#header').height());
};
// Register self in the global namespace for convenience.
IPython.Page = Page;
return {'Page': Page};

@ -541,7 +541,16 @@ define([
if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
return OSName;
})();
var get_url_param = function (name) {
// get a URL parameter. I cannot believe we actually need this.
// Based on http://stackoverflow.com/a/25359264/938949
var match = new RegExp('[\?&]' + name + '=([^&]*)').exec(window.location.search);
if (match){
return decodeURIComponent(match[1] || '');
}
};
var is_or_has = function (a, b) {
/**
* Is b a child of a or a itself?
@ -632,6 +641,7 @@ define([
* Like $.ajax, but returning an ES6 promise. success and error settings
* will be ignored.
*/
settings = settings || {};
return new Promise(function(resolve, reject) {
settings.success = function(data, status, jqXHR) {
resolve(data);
@ -766,6 +776,33 @@ define([
};
};
var typeset = function(element, text) {
/**
* Apply MathJax rendering to an element, and optionally set its text
*
* If MathJax is not available, make no changes.
*
* Returns the output any number of typeset elements, or undefined if
* MathJax was not available.
*
* Parameters
* ----------
* element: Node, NodeList, or jQuery selection
* text: option string
*/
if(!window.MathJax){
return;
}
var $el = element.jquery ? element : $(element);
if(arguments.length > 1){
$el.text(text);
}
return $el.map(function(){
// MathJax takes a DOM node: $.map makes `this` the context
return MathJax.Hub.Queue(["Typeset", MathJax.Hub, this]);
});
};
var utils = {
regex_split : regex_split,
uuid : uuid,
@ -786,6 +823,7 @@ define([
from_absolute_cursor_pos : from_absolute_cursor_pos,
browser : browser,
platform: platform,
get_url_param: get_url_param,
is_or_has : is_or_has,
is_focused : is_focused,
mergeopt: mergeopt,
@ -799,6 +837,7 @@ define([
load_class: load_class,
resolve_promises_dict: resolve_promises_dict,
reject: reject,
typeset: typeset,
};
// Backwards compatability.

@ -20,11 +20,33 @@ body {
div#header {
/* Initially hidden to prevent FLOUC */
display: none;
margin-bottom: 0px;
padding-left: 30px;
padding-bottom: 5px;
border-bottom: 1px solid @navbar-default-border;
.border-box-sizing();
margin-bottom: -6px;
position: fixed;
top: 0;
width: 100%;
background-color: @body-bg;
min-height: 31px;
/* Display over codemirror */
z-index: 100;
#header-container {
margin-bottom: 0px;
padding-left: 30px;
padding-bottom: 5px;
.border-box-sizing();
}
.header-bar {
width: 100%;
height: 0px;
border-bottom: 1px solid @navbar-default-border;
}
}
#header-spacer {
width: 100%;
visibility: hidden;
}
#ipython_notebook {

@ -220,10 +220,7 @@ define([
* @method typeset
*/
Cell.prototype.typeset = function () {
if (window.MathJax) {
var cell_math = this.element.get(0);
MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]);
}
utils.typeset(this.element);
};
/**

@ -389,7 +389,7 @@ define([
* @private
*/
CodeCell.prototype._handle_set_next_input = function (payload) {
var data = {'cell': this, 'text': payload.text};
var data = {'cell': this, 'text': payload.text, replace: payload.replace};
this.events.trigger('set_next_input.Notebook', data);
};

@ -25,16 +25,27 @@ define([
KernelSelector.prototype.request_kernelspecs = function() {
var url = utils.url_join_encode(this.notebook.base_url, 'api/kernelspecs');
$.ajax(url, {success: $.proxy(this._got_kernelspecs, this)});
utils.promising_ajax(url).then($.proxy(this._got_kernelspecs, this));
};
KernelSelector.prototype._got_kernelspecs = function(data, status, xhr) {
this.kernelspecs = {};
KernelSelector.prototype._got_kernelspecs = function(data) {
this.kernelspecs = data.kernelspecs;
var menu = this.element.find("#kernel_selector");
var change_kernel_submenu = $("#menu-change-kernel-submenu");
for (var i = 0; i < data.length; i++) {
var ks = data[i];
this.kernelspecs[ks.name] = ks;
var keys = Object.keys(data.kernelspecs).sort(function (a, b) {
// sort by display_name
var da = data.kernelspecs[a].display_name;
var db = data.kernelspecs[b].display_name;
if (da === db) {
return 0;
} else if (da > db) {
return 1;
} else {
return -1;
}
});
for (var i = 0; i < keys.length; i++) {
var ks = this.kernelspecs[keys[i]];
var ksentry = $("<li>").attr("id", "kernel-" +ks.name).append($('<a>')
.attr('href', '#')
.click($.proxy(this.change_kernel, this, ks.name))

@ -9,7 +9,6 @@ require([
'services/config',
'base/js/utils',
'base/js/page',
'notebook/js/layoutmanager',
'base/js/events',
'auth/js/loginwidget',
'notebook/js/maintoolbar',
@ -34,7 +33,6 @@ require([
configmod,
utils,
page,
layoutmanager,
events,
loginwidget,
maintoolbar,
@ -66,9 +64,7 @@ require([
var user_config = $.extend({}, config.default_config);
var page = new page.Page();
var layout_manager = new layoutmanager.LayoutManager();
var pager = new pager.Pager('div#pager', 'div#pager_splitter', {
layout_manager: layout_manager,
var pager = new pager.Pager('div#pager', {
events: events});
var acts = new actions.init();
var keyboard_manager = new keyboardmanager.KeyboardManager({
@ -104,7 +100,6 @@ require([
var menubar = new menubar.MenuBar('#menubar', $.extend({
notebook: notebook,
contents: contents,
layout_manager: layout_manager,
events: events,
save_widget: save_widget,
quick_help: quick_help},
@ -132,9 +127,7 @@ require([
page.show();
layout_manager.do_resize();
var first_load = function () {
layout_manager.do_resize();
var hash = document.location.hash;
if (hash) {
document.location.hash = '';
@ -147,7 +140,6 @@ require([
events.on('notebook_loaded.Notebook', first_load);
IPython.page = page;
IPython.layout_manager = layout_manager;
IPython.notebook = notebook;
IPython.contents = contents;
IPython.pager = pager;

@ -24,7 +24,6 @@ define([
* Dictionary of keyword arguments.
* notebook: Notebook instance
* contents: ContentManager instance
* layout_manager: LayoutManager instance
* events: $(Events) instance
* save_widget: SaveWidget instance
* quick_help: QuickHelp instance
@ -37,7 +36,6 @@ define([
this.selector = selector;
this.notebook = options.notebook;
this.contents = options.contents;
this.layout_manager = options.layout_manager;
this.events = options.events;
this.save_widget = options.save_widget;
this.quick_help = options.quick_help;
@ -88,6 +86,13 @@ define([
}
};
MenuBar.prototype._size_header = function() {
/**
* Update header spacer size.
*/
this.events.trigger('resize-header.Page');
};
MenuBar.prototype.bind_events = function () {
/**
* File
@ -149,6 +154,10 @@ define([
that._nbconvert('pdf', true);
});
this.element.find('#download_script').click(function () {
that._nbconvert('script', true);
});
this.element.find('#rename_notebook').click(function () {
that.save_widget.rename_notebook({notebook: that.notebook});
});
@ -218,12 +227,12 @@ define([
// View
this.element.find('#toggle_header').click(function () {
$('div#header').toggle();
that.layout_manager.do_resize();
$('div#header-container').toggle();
that._size_header();
});
this.element.find('#toggle_toolbar').click(function () {
$('div#maintoolbar').toggle();
that.layout_manager.do_resize();
that._size_header();
});
// Insert
this.element.find('#insert_cell_above').click(function () {
@ -371,20 +380,6 @@ define([
var langname = (langinfo.name || 'Script')
langname = langname.charAt(0).toUpperCase()+langname.substr(1) // Capitalise
el.find('a').text(langname + ' ('+(langinfo.file_extension || 'txt')+')');
// Unregister any previously registered handlers
el.off('click');
if (langinfo.nbconvert_exporter) {
// Metadata specifies a specific exporter, e.g. 'python'
el.click(function() {
that._nbconvert(langinfo.nbconvert_exporter, true);
});
} else {
// Use generic 'script' exporter
el.click(function() {
that._nbconvert('script', true);
});
}
};
// Backwards compatability.

@ -210,9 +210,14 @@ define([
var that = this;
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);
new_cell.set_text(data.text);
if (data.replace) {
data.cell.set_text(data.text);
data.cell.clear_output();
} else {
var index = that.find_cell_index(data.cell);
var new_cell = that.insert_cell_below('code',index);
new_cell.set_text(data.text);
}
that.dirty = true;
});
@ -2326,9 +2331,13 @@ define([
// Create the session after the notebook is completely loaded to prevent
// code execution upon loading, which is a security risk.
if (this.session === null) {
var kernelspec = this.metadata.kernelspec || {};
var kernel_name = kernelspec.name;
var kernel_name;
if (this.metadata.kernelspec) {
var kernelspec = this.metadata.kernelspec || {};
kernel_name = kernelspec.name;
} else {
kernel_name = utils.get_url_param('kernel_name');
}
this.start_session(kernel_name);
}
// load our checkpoint list

@ -199,9 +199,7 @@ define([
// typeset with MathJax if MathJax is available
OutputArea.prototype.typeset = function () {
if (window.MathJax){
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
}
utils.typeset(this.element);
};

@ -8,48 +8,22 @@ define([
], function(IPython, $, utils) {
"use strict";
var Pager = function (pager_selector, pager_splitter_selector, options) {
var Pager = function (pager_selector, options) {
/**
* Constructor
*
* Parameters:
* pager_selector: string
* pager_splitter_selector: string
* options: dictionary
* Dictionary of keyword arguments.
* events: $(Events) instance
* layout_manager: LayoutManager instance
*/
this.events = options.events;
this.pager_element = $(pager_selector);
this.pager_button_area = $('#pager_button_area');
var that = this;
this.percentage_height = 0.40;
options.layout_manager.pager = this;
this.pager_splitter_element = $(pager_splitter_selector)
.draggable({
containment: 'window',
axis:'y',
helper: null ,
drag: function(event, ui) {
/**
* recalculate the amount of space the pager should take
*/
var pheight = ($(document.body).height()-event.clientY-4);
var downprct = pheight/options.layout_manager.app_height();
downprct = Math.min(0.9, downprct);
if (downprct < 0.1) {
that.percentage_height = 0.1;
that.collapse({'duration':0});
} else if (downprct > 0.2) {
that.percentage_height = downprct;
that.expand({'duration':0});
}
options.layout_manager.do_resize();
}
});
this.pager_button_area = $('#pager-button-area');
this._default_end_space = 200;
this.pager_element.resizable({handles: 'n', resize: $.proxy(this._resize, this)});
this.expanded = false;
this.style();
this.create_button_area();
this.bind_events();
};
@ -61,7 +35,6 @@ define([
.attr('title',"Open the pager in an external window")
.addClass('ui-button')
.click(function(){that.detach();})
.attr('style','position: absolute; right: 20px;')
.append(
$('<span>').addClass("ui-icon ui-icon-extlink")
)
@ -71,49 +44,37 @@ define([
.attr('title',"Close the pager")
.addClass('ui-button')
.click(function(){that.collapse();})
.attr('style','position: absolute; right: 5px;')
.append(
$('<span>').addClass("ui-icon ui-icon-close")
)
);
};
Pager.prototype.style = function () {
this.pager_splitter_element.addClass('ui-widget ui-state-default');
this.pager_splitter_element.attr('title', 'Click to Show/Hide pager area, drag to Resize');
};
Pager.prototype.bind_events = function () {
var that = this;
this.pager_element.bind('collapse_pager', function (event, extrap) {
var time = 'fast';
if (extrap && extrap.duration) {
time = extrap.duration;
}
that.pager_element.hide(time);
// Animate hiding of the pager.
var time = (extrap && extrap.duration) ? extrap.duration : 'fast';
that.pager_element.hide(time, function() {
$('.end_space').css('height', that._default_end_space);
});
});
this.pager_element.bind('expand_pager', function (event, extrap) {
var time = 'fast';
if (extrap && extrap.duration) {
time = extrap.duration;
}
that.pager_element.show(time);
});
this.pager_splitter_element.hover(
function () {
that.pager_splitter_element.addClass('ui-state-hover');
},
function () {
that.pager_splitter_element.removeClass('ui-state-hover');
}
);
this.pager_splitter_element.click(function () {
that.toggle();
// Clear the pager's height attr if it's set. This allows the
// pager to size itself according to its contents.
that.pager_element.height('initial');
// Animate the showing of the pager
var time = (extrap && extrap.duration) ? extrap.duration : 'fast';
that.pager_element.show(time, function() {
// Explicitly set pager height once the pager has shown itself.
// This allows the pager-contents div to use percentage sizing.
that.pager_element.height(that.pager_element.height());
that._resize();
});
});
this.events.on('open_with_text.Pager', function (event, payload) {
@ -130,7 +91,7 @@ define([
Pager.prototype.collapse = function (extrap) {
if (this.expanded === true) {
this.expanded = false;
this.pager_element.add($('div#notebook')).trigger('collapse_pager', extrap);
this.pager_element.trigger('collapse_pager', extrap);
}
};
@ -138,7 +99,7 @@ define([
Pager.prototype.expand = function (extrap) {
if (this.expanded !== true) {
this.expanded = true;
this.pager_element.add($('div#notebook')).trigger('expand_pager', extrap);
this.pager_element.trigger('expand_pager', extrap);
}
};
@ -184,6 +145,18 @@ define([
this.pager_element.find(".container").append($('<pre/>').html(utils.fixCarriageReturn(utils.fixConsole(text))));
};
Pager.prototype._resize = function() {
/**
* Update document based on pager size.
*/
// Make sure the padding at the end of the notebook is large
// enough that the user can scroll to the bottom of the
// notebook.
$('.end_space').css('height', Math.max(this.pager_element.height(), this._default_end_space));
};
// Backwards compatability.
IPython.Pager = Pager;

@ -1,12 +1,13 @@
#menubar {
margin-top: 0px;
margin-bottom: -19px;
margin-bottom: -24px;
position: relative;
.border-box-sizing();
.navbar {
border-top: 1px;
border-radius: 0px 0px @border-radius-base @border-radius-base;
margin-bottom: 23px;
}
.navbar-toggle {

@ -3,10 +3,6 @@ body {
background-color: @body-bg;
}
body.notebook_app {
overflow: hidden;
}
@media (max-width: 767px) {
// remove bootstrap-responsive's body padding on small screens
body.notebook_app {
@ -36,19 +32,17 @@ span#notebook_name {
div#notebook_panel {
margin: 0px 0px 0px 0px;
padding: 0px;
.box-shadow(@notebook-shadow);
.border-box-sizing();
}
div#notebook {
font-size: @notebook_font_size;
line-height: @notebook_line_height;
overflow-y: scroll;
overflow-y: hidden;
overflow-x: auto;
width: 100%;
/* This spaces the cell away from the edge of the notebook area */
padding: 1em 0 1em 0;
padding: 2em 0 2em 0;
margin: 0px;
border-top: 1px solid @navbar-default-border;
outline: none;
.border-box-sizing();
}
@ -86,3 +80,14 @@ p {
.end_space {
height: 200px;
}
.lower-header-bar {
width: 100%;
height: 0px;
border-bottom: 1px solid @navbar-default-border;
margin-bottom: -1px;
}
.notebook_app #header {
.box-shadow(@notebook-shadow);
}

@ -1,25 +1,51 @@
div#pager_splitter {
height: 8px;
.border-box-sizing();
}
#pager-container {
position: relative;
padding: 15px 0px;
.border-box-sizing();
}
div#pager {
background-color: @body-bg;
font-size: @notebook_font_size;
line-height: @notebook_line_height;
overflow: auto;
overflow: hidden;
display: none;
position: fixed;
bottom: 0px;
width: 100%;
max-height: 50%;
padding-top: 7px;
/* Display over codemirror */
z-index: 100;
/* Hack which prevents jquery ui resizable from changing top. */
top: inherit !important;
pre {
line-height: @code_line_height;
color: @text-color;
background-color: @cell_background;
padding: @code_padding;
line-height: @code_line_height;
color: @text-color;
background-color: @cell_background;
padding: @code_padding;
}
#pager-button-area {
position: absolute;
top: 7px;
right: 20px;
}
#pager-contents {
position: relative;
overflow: auto;
width: 100%;
height: 100%;
#pager-container {
position: relative;
padding: 15px 0px;
.border-box-sizing();
}
}
.ui-resizable-handle {
top: 0px;
height: 7px;
background: @light_border_color;
border-bottom: 1px solid @border_color;
}
.border-box-sizing();
}

@ -2,6 +2,7 @@
padding: 0px;
margin-left: -5px;
margin-top: -5px;
margin-bottom: 5px;
select, label {
width: auto;
@ -33,8 +34,8 @@
border: 0px;
min-height: 27px;
margin-left: 32px;
padding-top: 6px;
padding-bottom: 8px;
padding-top: 11px;
padding-bottom: 3px;
.navbar-text {
float: none;
@ -44,10 +45,6 @@
margin-right: 0px;
margin-top: 0px;
}
.toolbar {
margin-top: 0px;
}
}
.select-xs {

@ -10,7 +10,7 @@
@notebook_line_height: 20px;
@code_line_height: 1.21429em; // changed from 1.231 to get 17px even
@code_padding: 0.4em; // 5.6 px
@notebook-shadow: inset 1px 4px 9px -6px rgba(0,0,0,.25);
@notebook-shadow: 1px 4px 9px -6px rgba(0,0,0,.25);
@rendered_html_border_color: black;
@input_prompt_color: navy;
@output_prompt_color: darkred;

@ -7751,14 +7751,32 @@ body {
div#header {
/* Initially hidden to prevent FLOUC */
display: none;
margin-bottom: -6px;
position: fixed;
top: 0;
width: 100%;
background-color: #ffffff;
min-height: 31px;
/* Display over codemirror */
z-index: 100;
}
div#header #header-container {
margin-bottom: 0px;
padding-left: 30px;
padding-bottom: 5px;
border-bottom: 1px solid #e7e7e7;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
div#header .header-bar {
width: 100%;
height: 0px;
border-bottom: 1px solid #e7e7e7;
}
#header-spacer {
width: 100%;
visibility: hidden;
}
#ipython_notebook {
padding-left: 0px;
}
@ -7981,14 +7999,15 @@ span#login_widget > .button .badge,
margin: 0;
}
.alternate_upload input.fileinput {
background-color: red;
position: relative;
display: inline;
opacity: 0;
z-index: 2;
width: 295px;
margin-left: 163px;
cursor: pointer;
height: 26px;
width: 12ex;
margin-right: -12ex;
}
.alternate_upload .input-overlay {
display: inline-block;
font-weight: bold;
}
/**
* Primary styles
@ -8146,6 +8165,21 @@ input.engine_num_input {
.file_icon:before.pull-right {
margin-left: .3em;
}
ul#new-notebook-menu {
left: auto;
right: 0;
}
.kernel-menu-icon {
padding-right: 12px;
width: 24px;
content: "\f096";
}
.kernel-menu-icon:before {
content: "\f096";
}
.kernel-menu-icon-current:before {
content: "\f00c";
}
/*!
*
* IPython notebook
@ -9461,9 +9495,6 @@ h6:hover .anchor-link {
body {
background-color: #ffffff;
}
body.notebook_app {
overflow: hidden;
}
@media (max-width: 767px) {
body.notebook_app {
padding-left: 0px;
@ -9489,8 +9520,6 @@ span#notebook_name:hover {
div#notebook_panel {
margin: 0px 0px 0px 0px;
padding: 0px;
-webkit-box-shadow: inset 1px 4px 9px -6px rgba(0, 0, 0, 0.25);
box-shadow: inset 1px 4px 9px -6px rgba(0, 0, 0, 0.25);
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@ -9498,13 +9527,12 @@ div#notebook_panel {
div#notebook {
font-size: 14px;
line-height: 20px;
overflow-y: scroll;
overflow-y: hidden;
overflow-x: auto;
width: 100%;
/* This spaces the cell away from the edge of the notebook area */
padding: 1em 0 1em 0;
padding: 2em 0 2em 0;
margin: 0px;
border-top: 1px solid #e7e7e7;
outline: none;
box-sizing: border-box;
-moz-box-sizing: border-box;
@ -9542,6 +9570,16 @@ p {
.end_space {
height: 200px;
}
.lower-header-bar {
width: 100%;
height: 0px;
border-bottom: 1px solid #e7e7e7;
margin-bottom: -1px;
}
.notebook_app #header {
-webkit-box-shadow: 1px 4px 9px -6px rgba(0, 0, 0, 0.25);
box-shadow: 1px 4px 9px -6px rgba(0, 0, 0, 0.25);
}
/* CSS for the cell toolbar */
.celltoolbar {
border: thin solid #CFCFCF;
@ -9779,7 +9817,7 @@ fieldset[disabled] #kernel_selector_widget > button.active {
}
#menubar {
margin-top: 0px;
margin-bottom: -19px;
margin-bottom: -24px;
position: relative;
box-sizing: border-box;
-moz-box-sizing: border-box;
@ -9788,6 +9826,7 @@ fieldset[disabled] #kernel_selector_widget > button.active {
#menubar .navbar {
border-top: 1px;
border-radius: 0px 0px 4px 4px;
margin-bottom: 23px;
}
#menubar .navbar-toggle {
float: left;
@ -10256,27 +10295,21 @@ fieldset[disabled] .notification_widget.danger.active {
color: #d9534f;
background-color: #ffffff;
}
div#pager_splitter {
height: 8px;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
#pager-container {
position: relative;
padding: 15px 0px;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
div#pager {
background-color: #ffffff;
font-size: 14px;
line-height: 20px;
overflow: auto;
overflow: hidden;
display: none;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
position: fixed;
bottom: 0px;
width: 100%;
max-height: 50%;
padding-top: 7px;
/* Display over codemirror */
z-index: 100;
/* Hack which prevents jquery ui resizable from changing top. */
top: inherit !important;
}
div#pager pre {
line-height: 1.21429em;
@ -10284,6 +10317,30 @@ div#pager pre {
background-color: #f7f7f7;
padding: 0.4em;
}
div#pager #pager-button-area {
position: absolute;
top: 7px;
right: 20px;
}
div#pager #pager-contents {
position: relative;
overflow: auto;
width: 100%;
height: 100%;
}
div#pager #pager-contents #pager-container {
position: relative;
padding: 15px 0px;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
div#pager .ui-resizable-handle {
top: 0px;
height: 7px;
background: #cfcfcf;
border-bottom: 1px solid #ababab;
}
.quickhelp {
/* Old browsers */
display: -webkit-box;
@ -10350,6 +10407,7 @@ span#autosave_status {
padding: 0px;
margin-left: -5px;
margin-top: -5px;
margin-bottom: 5px;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@ -10380,8 +10438,8 @@ span#autosave_status {
border: 0px;
min-height: 27px;
margin-left: 32px;
padding-top: 6px;
padding-bottom: 8px;
padding-top: 11px;
padding-bottom: 3px;
}
#maintoolbar .navbar-text {
float: none;
@ -10391,9 +10449,6 @@ span#autosave_status {
margin-right: 0px;
margin-top: 0px;
}
#maintoolbar .toolbar {
margin-top: 0px;
}
.select-xs {
height: 24px;
}

@ -8,12 +8,14 @@ require([
'base/js/events',
'base/js/page',
'base/js/utils',
'services/config',
'contents',
'tree/js/notebooklist',
'tree/js/clusterlist',
'tree/js/sessionlist',
'tree/js/kernellist',
'tree/js/terminallist',
'tree/js/newnotebook',
'auth/js/loginwidget',
// only loaded, not used:
'jqueryui',
@ -26,12 +28,14 @@ require([
events,
page,
utils,
config,
contents_service,
notebooklist,
clusterlist,
sesssionlist,
notebooklist,
clusterlist,
sesssionlist,
kernellist,
terminallist,
newnotebook,
loginwidget){
"use strict";
@ -41,6 +45,10 @@ require([
base_url: utils.get_body_data("baseUrl"),
notebook_path: utils.get_body_data("notebookPath"),
};
var cfg = new config.ConfigSection('tree', common_options);
cfg.load();
common_options.config = cfg;
var session_list = new sesssionlist.SesssionList($.extend({
events: events},
common_options));
@ -63,24 +71,12 @@ require([
var login_widget = new loginwidget.LoginWidget('#login_widget', common_options);
$('#new_notebook').click(function (e) {
var w = window.open();
contents.new_untitled(common_options.notebook_path, {type: "notebook"}).then(
function (data) {
w.location = utils.url_join_encode(
common_options.base_url, 'notebooks', data.path
);
},
function(error) {
w.close();
dialog.modal({
title : 'Creating Notebook Failed',
body : "The error was: " + error.message,
buttons : {'OK' : {'class' : 'btn-primary'}}
});
}
);
});
var nnw = new newnotebook.NewNotebookWidget("#new-notebook-buttons",
$.extend(
{contents: contents},
common_options
)
);
var interval_id=0;
// auto refresh every xx secondes, no need to be fast,
@ -93,18 +89,18 @@ require([
*/
session_list.load_sessions();
cluster_list.load_list();
if (terminal_list) {
terminal_list.load_terminals();
}
if (terminal_list) {
terminal_list.load_terminals();
}
if (!interval_id){
interval_id = setInterval(function(){
session_list.load_sessions();
cluster_list.load_list();
if (terminal_list) {
terminal_list.load_terminals();
}
}, time_refresh*1000);
}
session_list.load_sessions();
cluster_list.load_list();
if (terminal_list) {
terminal_list.load_terminals();
}
}, time_refresh*1000);
}
};
var disable_autorefresh = function(){
@ -134,6 +130,7 @@ require([
IPython.session_list = session_list;
IPython.kernel_list = kernel_list;
IPython.login_widget = login_widget;
IPython.new_notebook_widget = nnw;
events.trigger('app_initialized.DashboardApp');

@ -0,0 +1,135 @@
// Copyright (c) IPython Development Team.
// Distributed under the terms of the Modified BSD License.
define([
'jquery',
'base/js/namespace',
'base/js/utils',
'base/js/dialog',
], function ($, IPython, utils, dialog) {
"use strict";
var NewNotebookWidget = function (selector, options) {
this.selector = selector;
this.base_url = options.base_url;
this.notebook_path = options.notebook_path;
this.contents = options.contents;
this.default_kernel = null;
this.config = options.config;
this.kernelspecs = {};
if (this.selector !== undefined) {
this.element = $(selector);
this.request_kernelspecs();
}
this.bind_events();
};
NewNotebookWidget.prototype.bind_events = function () {
var that = this;
this.element.find('#new_notebook').click(function () {
that.new_notebook();
});
};
NewNotebookWidget.prototype.request_kernelspecs = function () {
/** request and then load kernel specs */
var url = utils.url_join_encode(this.base_url, 'api/kernelspecs');
utils.promising_ajax(url).then($.proxy(this._load_kernelspecs, this));
};
NewNotebookWidget.prototype._load_kernelspecs = function (data) {
/** load kernelspec list */
var that = this;
this.kernelspecs = data.kernelspecs;
var menu = this.element.find("#new-notebook-menu");
var keys = Object.keys(data.kernelspecs).sort(function (a, b) {
var da = data.kernelspecs[a].display_name;
var db = data.kernelspecs[b].display_name;
if (da === db) {
return 0;
} else if (da > db) {
return 1;
} else {
return -1;
}
});
for (var i = 0; i < keys.length; i++) {
var ks = this.kernelspecs[keys[i]];
var li = $("<li>")
.attr("id", "kernel-" +ks.name)
.data('kernelspec', ks).append(
$('<a>')
.attr('href', '#')
.click($.proxy(this.new_notebook, this, ks.name))
.text(ks.display_name)
.attr('title', 'Create a new notebook with ' + ks.display_name)
);
menu.append(li);
}
this.config.loaded.then(function () {
that._load_default_kernelspec(data['default']);
});
};
NewNotebookWidget.prototype._load_default_kernelspec = function (default_name) {
/** load default kernelspec name from config, if defined */
if (this.config.data.NewNotebookWidget &&
this.config.data.NewNotebookWidget.default_kernel &&
this.kernelspecs[this.config.data.NewNotebookWidget.default_kernel] !== undefined
) {
default_name = this.config.data.NewNotebookWidget.default_kernel;
}
this.set_default_kernel(default_name);
};
NewNotebookWidget.prototype.set_default_kernel = function (kernel_name) {
/** select the current default kernel */
this.default_kernel = kernel_name;
this.config.update({
NewNotebookWidget: {
default_kernel: kernel_name
}
});
var spec = this.kernelspecs[kernel_name];
var display_name;
if (spec) {
display_name = spec.display_name;
this.element.find("#current-kernel")
.text(display_name)
.attr('title', display_name + " is the default kernel for new notebooks");
} else {
display_name = 'default kernel';
}
this.element.find("#new_notebook").attr('title',
'Create a new notebook with ' + display_name
);
};
NewNotebookWidget.prototype.new_notebook = function (kernel_name) {
/** create and open a new notebook */
var that = this;
kernel_name = kernel_name || this.default_kernel;
var w = window.open();
this.contents.new_untitled(that.notebook_path, {type: "notebook"}).then(
function (data) {
var url = utils.url_join_encode(
that.base_url, 'notebooks', data.path
);
if (kernel_name) {
url += "?kernel_name=" + kernel_name;
}
w.location = url;
},
function (error) {
w.close();
dialog.modal({
title : 'Creating Notebook Failed',
body : "The error was: " + error.message,
buttons : {'OK' : {'class' : 'btn-primary'}}
});
}
);
};
return {'NewNotebookWidget': NewNotebookWidget};
});

@ -15,12 +15,14 @@
.alternate_upload input.fileinput
{
background-color:red;
position:relative;
display: inline;
opacity: 0;
z-index: 2;
width: 295px;
margin-left:163px;
cursor: pointer;
height: 26px;
width: 12ex;
margin-right: -12ex;
}
.alternate_upload .input-overlay {
display: inline-block;
font-weight: bold;
}

@ -154,3 +154,23 @@ input.engine_num_input {
.file_icon:before {
.icon(@fa-var-file-o)
}
ul#new-notebook-menu {
// align right instead of left
left: auto;
right: 0;
}
.kernel-menu-icon {
padding-right: 12px;
width: 24px;
content: @fa-var-square-o;
}
.kernel-menu-icon:before {
content: @fa-var-square-o;
}
.kernel-menu-icon-current:before {
content: @fa-var-check;
}

@ -112,6 +112,7 @@ define([
return Promise.resolve(view.render()).then(function() {return view;});
}).catch(utils.reject("Couldn't create a view for model id '" + String(model.id) + "'", true));
});
model.views[utils.uuid()] = model.state_change;
return model.state_change;
};

@ -65,11 +65,12 @@ define(["widgets/js/manager",
delete this.comm.model; // Delete ref so GC will collect widget model.
delete this.comm;
delete this.model_id; // Delete id from model so widget manager cleans up.
for (var id in this.views) {
if (this.views.hasOwnProperty(id)) {
this.views[id].remove();
}
}
_.each(this.views, function(v, id, views) {
v.then(function(view) {
view.remove();
delete views[id];
});
});
},
_handle_comm_msg: function (msg) {
@ -318,8 +319,6 @@ define(["widgets/js/manager",
*/
this.model.on('change',this.update,this);
this.options = parameters.options;
this.id = this.id || utils.uuid();
this.model.views[this.id] = this;
this.on('displayed', function() {
this.is_displayed = true;
}, this);
@ -388,7 +387,7 @@ define(["widgets/js/manager",
} else {
this.on('displayed', callback, context);
}
},
}
});
@ -575,6 +574,10 @@ define(["widgets/js/manager",
}
return elements;
},
typeset: function(element, text){
utils.typeset.apply(null, arguments);
},
});

@ -62,8 +62,7 @@ define([
if (description.trim().length === 0) {
this.$label.hide();
} else {
this.$label.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
this.typeset(this.$label, description);
this.$label.show();
}
}

@ -319,8 +319,7 @@ define([
if (description.trim().length === 0) {
this.$title.html("&nbsp;"); // Preserve title height
} else {
this.$title.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$title.get(0)]);
this.typeset(this.$title, description);
}
var button_text = this.model.get('button_text');

@ -155,8 +155,7 @@ define([
if (description.length === 0) {
this.$label.hide();
} else {
this.$label.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
this.typeset(this.$label, description);
this.$label.show();
}
@ -323,8 +322,7 @@ define([
if (description.length === 0) {
this.$label.hide();
} else {
this.$label.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
this.typeset(this.$label, description);
this.$label.show();
}
}
@ -443,8 +441,7 @@ define([
if (description.length === 0) {
this.$label.hide();
} else {
this.$label.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
this.typeset(this.$label, description);
this.$label.show();
}
return ProgressView.__super__.update.apply(this);

@ -97,8 +97,7 @@ define([
if (description.length === 0) {
this.$label.hide();
} else {
this.$label.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
this.typeset(this.$label, description);
this.$label.show();
}
}
@ -231,7 +230,7 @@ define([
this.$label.hide();
} else {
this.$label.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
this.typeset(this.$label, description);
this.$label.show();
}
}
@ -345,8 +344,8 @@ define([
if (description.length === 0) {
this.$label.hide();
} else {
this.$label.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
this.$label.text();
this.typeset(this.$label, description);
this.$label.show();
}
}
@ -468,8 +467,7 @@ define([
if (description.length === 0) {
this.$label.hide();
} else {
this.$label.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
this.typeset(this.$label, description);
this.$label.show();
}
}

@ -43,9 +43,7 @@ define([
* Called when the model is changed. The model may have been
* changed by another view or by a state update from the back-end.
*/
this.$el.text(this.model.get('value'));
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$el.get(0)]);
this.typeset(this.$el, this.model.get('value'));
return LatexView.__super__.update.apply(this);
},
});
@ -116,8 +114,7 @@ define([
if (description.length === 0) {
this.$label.hide();
} else {
this.$label.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
this.typeset(this.$label, description);
this.$label.show();
}
}
@ -200,8 +197,7 @@ define([
if (description.length === 0) {
this.$label.hide();
} else {
this.$label.text(description);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
this.typeset(this.$label, description);
this.$label.show();
}
}

@ -32,7 +32,7 @@ class="notebook_app"
{% endblock %}
{% block header %}
{% block headercontainer %}
<span id="save_widget" class="nav pull-left">
@ -43,18 +43,16 @@ class="notebook_app"
<span id="kernel_selector_widget" class="pull-right dropdown">
<button class="dropdown-toggle" data-toggle="dropdown" type='button' id="current_kernel_spec">
<span class='kernel_name'>Python</span>
<span class='kernel_name'>Kernel</span>
<span class="caret"></span>
</button>
<ul id="kernel_selector" class="dropdown-menu">
</ul>
</span>
{% endblock %}
{% block site %}
{% endblock headercontainer %}
{% block header %}
<div id="menubar-container" class="container">
<div id="menubar">
<div id="menus" class="navbar navbar-default" role="navigation">
@ -292,6 +290,7 @@ class="notebook_app"
</div>
</div>
</div>
<div id="maintoolbar" class="navbar">
<div class="toolbar-inner navbar-inner navbar-nobg">
<div id="maintoolbar-container" class="container"></div>
@ -299,19 +298,25 @@ class="notebook_app"
</div>
</div>
<div id="ipython-main-app">
<div class="lower-header-bar"></div>
{% endblock header %}
{% block site %}
<div id="ipython-main-app">
<div id="notebook_panel">
<div id="notebook"></div>
<div id="pager_splitter"></div>
<div id="pager">
<div id='pager_button_area'>
</div>
<div id="pager-container" class="container"></div>
</div>
</div>
</div>
<div id="pager">
<div id="pager-contents">
<div id="pager-container" class="container"></div>
</div>
<div id='pager-button-area'></div>
</div>
<div id='tooltip' class='ipython_tooltip' style='display:none'></div>

@ -5,7 +5,7 @@
<meta charset="utf-8">
<title>{% block title %}IPython Notebook{% endblock %}</title>
<link rel="shortcut icon" type="image/x-icon" href="{{static_url("base/images/favicon.ico") }}">
{% block favicon %}<link rel="shortcut icon" type="image/x-icon" href="{{static_url("base/images/favicon.ico") }}">{% endblock %}
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<link rel="stylesheet" href="{{static_url("components/jquery-ui/themes/smoothness/jquery-ui.min.css") }}" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@ -81,7 +81,7 @@
</noscript>
<div id="header" class="navbar navbar-static-top">
<div class="container">
<div id="header-container" class="container">
<div id="ipython_notebook" class="nav navbar-brand pull-left"><a href="{{base_url}}tree" alt='dashboard'>{% block logo %}<img src='{{static_url("base/images/logo.png") }}' alt='Jupyter Notebook'/>{% endblock %}</a></div>
{% block login_widget %}
@ -96,10 +96,15 @@
{% endblock %}
{% block header %}
{% block headercontainer %}
{% endblock %}
</div>
<div class="header-bar"></div>
{% block header %}
{% endblock %}
</div>
<div id="header-spacer"></div>
<div id="site">
{% block site %}

@ -34,19 +34,31 @@ data-terminals-available="{{terminals_available}}"
<div class="tab-content">
<div id="notebooks" class="tab-pane active">
<div id="notebook_toolbar" class="row">
<div class="col-sm-8 no-padding">
<form id='alternate_upload' class='alternate_upload' >
<span id="notebook_list_info" style="position:absolute" >
To import a notebook, drag the file onto the listing below or <strong>click here</strong>.
<div class="col-sm-12 no-padding">
<form id='alternate_upload' class='alternate_upload'>
<span id="notebook_list_info">
To import a notebook, drag the file onto the listing below or
<span class="input-overlay">
<input type="file" name="datafile" class="fileinput" multiple='multiple'>
click here.
</span>
</span>
<input type="file" name="datafile" class="fileinput" multiple='multiple'>
</form>
</div>
<div class="col-sm-4 no-padding tree-buttons">
<span id="notebook_buttons" class="pull-right">
<button id="new_notebook" title="Create new notebook" class="btn btn-default btn-xs">New Notebook</button>
<button id="refresh_notebook_list" title="Refresh notebook list" class="btn btn-default btn-xs"><i class="fa fa-refresh"></i></button>
</span>
<span id="notebook_buttons" class="pull-right">
<div id="new-notebook-buttons" class="btn-group">
<button id="new_notebook" class="btn btn-default btn-xs">
New Notebook
</button>
<button class="dropdown-toggle btn btn-default btn-xs" data-toggle="dropdown">
<span id="current-kernel">Loading...</span>
<span class="caret"></span>
</button>
<ul id="new-notebook-menu" class="dropdown-menu"></ul>
</div>
<button id="refresh_notebook_list" title="Refresh notebook list" class="btn btn-default btn-xs"><i class="fa fa-refresh"></i></button>
</span>
</div>
</div>

@ -22,3 +22,8 @@ from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, In
from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
from .widget_selectioncontainer import TabWidget, AccordionWidget
from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
# Warn on import
from IPython.utils.warn import warn
warn("""The widget API is still considered experimental and
may change by the next major release of IPython.""")

@ -15,6 +15,7 @@ import argparse
import json
import multiprocessing.pool
import os
import stat
import re
import requests
import shutil
@ -170,6 +171,18 @@ class PyTestController(TestController):
# This means we won't get odd effects from our own matplotlib config
self.env['MPLCONFIGDIR'] = workingdir.name
# Add a non-accessible directory to PATH (see gh-7053)
noaccess = os.path.join(self.workingdir.name, "_no_access_")
self.noaccess = noaccess
os.mkdir(noaccess, 0)
PATH = os.environ.get('PATH', '')
if PATH:
PATH = noaccess + os.pathsep + PATH
else:
PATH = noaccess
self.env['PATH'] = PATH
# From options:
if self.options.xunit:
self.add_xunit()
@ -178,6 +191,14 @@ class PyTestController(TestController):
self.env['IPTEST_SUBPROC_STREAMS'] = self.options.subproc_streams
self.cmd.extend(self.options.extra_args)
def cleanup(self):
"""
Make the non-accessible directory created in setup() accessible
again, otherwise deleting the workingdir will fail.
"""
os.chmod(self.noaccess, stat.S_IRWXU)
TestController.cleanup(self)
@property
def will_run(self):
try:

@ -270,7 +270,7 @@ extras_require = dict(
test = ['nose>=0.10.1', 'requests'],
terminal = [],
nbformat = ['jsonschema>=2.0'],
notebook = ['tornado>=4.0', 'pyzmq>=2.1.11', 'jinja2', 'pygments', 'mistune>=0.3.1'],
notebook = ['tornado>=4.0', 'pyzmq>=2.1.11', 'jinja2', 'pygments', 'mistune>=0.5'],
nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1']
)

Loading…
Cancel
Save