diff --git a/IPython/core/display.py b/IPython/core/display.py
index 7f5cc6d..dc80c3a 100644
--- a/IPython/core/display.py
+++ b/IPython/core/display.py
@@ -298,6 +298,13 @@ class HTML(DisplayObject):
class Math(DisplayObject):
def _repr_latex_(self):
+ s = self.data.strip('$')
+ return "$$%s$$" % s
+
+
+class Latex(DisplayObject):
+
+ def _repr_latex_(self):
return self.data
diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py
index cadf59d..893e0a9 100644
--- a/IPython/core/formatters.py
+++ b/IPython/core/formatters.py
@@ -524,7 +524,8 @@ class LatexFormatter(BaseFormatter):
this.
The return value of this formatter should be a valid LaTeX equation,
- enclosed in either ```$``` or ```$$```.
+ enclosed in either ```$```, ```$$``` or another LaTeX equation
+ environment.
"""
format_type = Unicode('text/latex')
diff --git a/IPython/extensions/sympyprinting.py b/IPython/extensions/sympyprinting.py
index a7c4a43..a607ddd 100644
--- a/IPython/extensions/sympyprinting.py
+++ b/IPython/extensions/sympyprinting.py
@@ -58,9 +58,10 @@ def print_png(o):
def print_latex(o):
"""A function to generate the latex representation of sympy expressions."""
- s = latex(o, mode='equation', itex=True)
+ s = latex(o, mode='plain')
s = s.replace('\\dag','\\dagger')
- return s
+ s = s.strip('$')
+ return '$$%s$$' % s
_loaded = False
diff --git a/IPython/frontend/html/notebook/static/codemirror/README-IPython.rst b/IPython/frontend/html/notebook/static/codemirror/README-IPython.rst
index 5c5e8e6..1bd9184 100644
--- a/IPython/frontend/html/notebook/static/codemirror/README-IPython.rst
+++ b/IPython/frontend/html/notebook/static/codemirror/README-IPython.rst
@@ -5,7 +5,7 @@
We carry a mostly unmodified copy of CodeMirror. The current version we use
is (*please update this information when updating versions*)::
- CodeMirror 7f93a5c
+ CodeMirror c813c94
The only changes we've applied so far are these::
diff --git a/IPython/frontend/html/notebook/static/codemirror/lib/codemirror.js b/IPython/frontend/html/notebook/static/codemirror/lib/codemirror.js
index e3b210f..7a88564 100755
--- a/IPython/frontend/html/notebook/static/codemirror/lib/codemirror.js
+++ b/IPython/frontend/html/notebook/static/codemirror/lib/codemirror.js
@@ -149,8 +149,10 @@ var CodeMirror = (function() {
else if (option == "theme") themeChanged();
else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
else if (option == "tabSize") operation(tabsChanged)();
- if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme")
+ if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") {
+ gutterChanged();
updateDisplay(true);
+ }
},
getOption: function(option) {return options[option];},
undo: operation(undo),
@@ -278,8 +280,8 @@ var CodeMirror = (function() {
return index;
},
scrollTo: function(x, y) {
- if (x != null) scroller.scrollTop = x;
- if (y != null) scroller.scrollLeft = y;
+ if (x != null) scroller.scrollLeft = x;
+ if (y != null) scroller.scrollTop = y;
updateDisplay([]);
},
@@ -440,10 +442,10 @@ var CodeMirror = (function() {
try {
var text = e.dataTransfer.getData("Text");
if (text) {
- var end = replaceRange(text, pos, pos);
- var curFrom = sel.from, curTo = sel.to;
- setSelectionUser(pos, end);
+ var curFrom = sel.from, curTo = sel.to;
+ setSelectionUser(pos, pos);
if (draggingText) replaceRange("", curFrom, curTo);
+ replaceSelection(text);
focusInput();
}
}
@@ -511,9 +513,9 @@ var CodeMirror = (function() {
}
}
function onKeyPress(e) {
+ if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
if (window.opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
- if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
if (window.opera && !e.which && handleKeyBinding(e)) return;
if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
@@ -565,20 +567,22 @@ var CodeMirror = (function() {
}
updateLinesNoUndo(from, to, newText, selFrom, selTo);
}
- function unredoHelper(from, to) {
- var change = from.pop();
- if (change) {
+ function unredoHelper(from, to, dir) {
+ var set = from.pop(), len = set ? set.length : 0, out = [];
+ for (var i = dir > 0 ? 0 : len - 1, e = dir > 0 ? len : -1; i != e; i += dir) {
+ var change = set[i];
var replaced = [], end = change.start + change.added;
doc.iter(change.start, end, function(line) { replaced.push(line.text); });
- to.push({start: change.start, added: change.old.length, old: replaced});
+ out.push({start: change.start, added: change.old.length, old: replaced});
var pos = clipPos({line: change.start + change.old.length - 1,
ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])});
updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
- updateInput = true;
}
+ updateInput = true;
+ to.push(out);
}
- function undo() {unredoHelper(history.done, history.undone);}
- function redo() {unredoHelper(history.undone, history.done);}
+ function undo() {unredoHelper(history.done, history.undone, -1);}
+ function redo() {unredoHelper(history.undone, history.done, 1);}
function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
if (suppressEdits) return;
@@ -780,7 +784,7 @@ var CodeMirror = (function() {
if (!posEq(sel.from, sel.to)) {
prevInput = "";
input.value = getSelection();
- input.select();
+ selectInput(input);
} else if (user) prevInput = input.value = "";
}
@@ -1537,7 +1541,7 @@ var CodeMirror = (function() {
leaveInputAlone = true;
var val = input.value = getSelection();
focusInput();
- input.select();
+ selectInput(input);
function rehide() {
var newVal = splitLines(input.value).join("\n");
if (newVal != val) operation(replaceSelection)(newVal, "end");
@@ -2551,11 +2555,13 @@ var CodeMirror = (function() {
History.prototype = {
addChange: function(start, added, old) {
this.undone.length = 0;
- var time = +new Date, last = this.done[this.done.length - 1];
- if (time - this.time > 400 || !last ||
- last.start > start + added || last.start + last.added < start - last.added + last.old.length)
- this.done.push({start: start, added: added, old: old});
- else {
+ var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1];
+ var dtime = time - this.time;
+ if (dtime > 400 || !last) {
+ this.done.push([{start: start, added: added, old: old}]);
+ } else if (last.start > start + added || last.start + last.added < start - last.added + last.old.length) {
+ cur.push({start: start, added: added, old: old});
+ } else {
var oldoff = 0;
if (start < last.start) {
for (var i = last.start - start - 1; i >= 0; --i)
diff --git a/IPython/frontend/html/notebook/static/codemirror/mode/markdown/markdown.js b/IPython/frontend/html/notebook/static/codemirror/mode/markdown/markdown.js
index 455bb43..1385bb5 100755
--- a/IPython/frontend/html/notebook/static/codemirror/mode/markdown/markdown.js
+++ b/IPython/frontend/html/notebook/static/codemirror/mode/markdown/markdown.js
@@ -15,7 +15,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
var hrRE = /^[*-=_]/
, ulRE = /^[*-+]\s+/
- , olRE = /^[0-9]\.\s+/
+ , olRE = /^[0-9]+\.\s+/
, headerRE = /^(?:\={3,}|-{3,})$/
, codeRE = /^(k:\t|\s{4,})/
, textRE = /^[^\[*_\\<>`]+/;
@@ -213,6 +213,10 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
token: function(stream, state) {
if (stream.sol()) {
+ // Reset EM state
+ state.em = false;
+ // Reset STRONG state
+ state.strong = false;
state.f = state.block;
var previousIndentation = state.indentation
, currentIndentation = 0;
diff --git a/IPython/frontend/html/notebook/static/css/notebook.css b/IPython/frontend/html/notebook/static/css/notebook.css
index 73bc5be..6fa3ab9 100644
--- a/IPython/frontend/html/notebook/static/css/notebook.css
+++ b/IPython/frontend/html/notebook/static/css/notebook.css
@@ -55,6 +55,19 @@ span#notebook_name {
margin: 0.3em 0;
}
+#menubar_container {
+ position: relative;
+}
+
+#notification {
+ position: absolute;
+ right: 3px;
+ top: 3px;
+ height: 25px;
+ padding: 3px 6px;
+ z-index: 10;
+}
+
#toolbar {
/* Initially hidden to prevent FLOUC */
display: none;
@@ -71,31 +84,6 @@ span#quick_help_area {
margin: 0px 0px 0px 0px;
}
-span#kernel_status {
- position: absolute;
- padding: 8px 5px 5px 5px;
- right: 10px;
- font-weight: bold;
-}
-
-
-.status_idle {
- color: gray;
- visibility: hidden;
-}
-
-.status_busy {
- color: red;
-}
-
-.status_restarting {
- color: black;
-}
-
-#kernel_persist {
- float: right;
-}
-
.help_string {
float: right;
width: 170px;
diff --git a/IPython/frontend/html/notebook/static/js/cell.js b/IPython/frontend/html/notebook/static/js/cell.js
index e24be0e..613dd9f 100644
--- a/IPython/frontend/html/notebook/static/js/cell.js
+++ b/IPython/frontend/html/notebook/static/js/cell.js
@@ -142,6 +142,16 @@ var IPython = (function (IPython) {
};
+ Cell.prototype.toggle_line_numbers = function () {
+ if (this.code_mirror.getOption('lineNumbers') == false) {
+ this.code_mirror.setOption('lineNumbers', true);
+ } else {
+ this.code_mirror.setOption('lineNumbers', false);
+ }
+ this.code_mirror.refresh();
+ };
+
+
IPython.Cell = Cell;
return IPython;
diff --git a/IPython/frontend/html/notebook/static/js/codecell.js b/IPython/frontend/html/notebook/static/js/codecell.js
index 29e2e3f..eac9a28 100644
--- a/IPython/frontend/html/notebook/static/js/codecell.js
+++ b/IPython/frontend/html/notebook/static/js/codecell.js
@@ -79,11 +79,11 @@ var IPython = (function (IPython) {
var that = this;
// whatever key is pressed, first, cancel the tooltip request before
// they are sent, and remove tooltip if any
- if(event.type === 'keydown' ){
+ if(event.type === 'keydown' ) {
that.remove_and_cancel_tooltip();
- }
-
-
+ };
+
+
if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
// Always ignore shift-enter in CodeMirror as we handle it.
return true;
@@ -123,6 +123,10 @@ var IPython = (function (IPython) {
return false;
} else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
that.request_tooltip_after_time(pre_cursor,0);
+ // Prevent the event from bubbling up.
+ event.stop();
+ // Prevent CodeMirror from handling the tab.
+ return true;
} else {
pre_cursor.trim();
// Autocomplete the current line.
@@ -132,7 +136,7 @@ var IPython = (function (IPython) {
this.completion_cursor = cur;
IPython.notebook.complete_cell(this, line, cur.ch);
return true;
- }
+ };
} else if (event.keyCode === 8 && event.type == 'keydown') {
// If backspace and the line ends with 4 spaces, remove them.
var cur = editor.getCursor();
@@ -147,13 +151,8 @@ var IPython = (function (IPython) {
return true;
} else {
return false;
- }
- } else if (event.keyCode === 76 && event.ctrlKey && event.shiftKey
- && event.type == 'keydown') {
- // toggle line numbers with Ctrl-Shift-L
- this.toggle_line_numbers();
- }
- else {
+ };
+ } else {
// keypress/keyup also trigger on TAB press, and we don't want to
// use those to disable tab completion.
if (this.is_completing && event.keyCode !== 9) {
@@ -162,8 +161,8 @@ var IPython = (function (IPython) {
if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) {
this.is_completing = false;
this.completion_cursor = null;
- }
- }
+ };
+ };
return false;
};
return false;
@@ -545,16 +544,6 @@ var IPython = (function (IPython) {
};
- CodeCell.prototype.toggle_line_numbers = function () {
- if (this.code_mirror.getOption('lineNumbers') == false) {
- this.code_mirror.setOption('lineNumbers', true);
- } else {
- this.code_mirror.setOption('lineNumbers', false);
- }
- this.code_mirror.refresh();
- };
-
-
CodeCell.prototype.select = function () {
IPython.Cell.prototype.select.apply(this);
this.code_mirror.refresh();
diff --git a/IPython/frontend/html/notebook/static/js/events.js b/IPython/frontend/html/notebook/static/js/events.js
new file mode 100644
index 0000000..0ff950d
--- /dev/null
+++ b/IPython/frontend/html/notebook/static/js/events.js
@@ -0,0 +1,31 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2008-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.
+//----------------------------------------------------------------------------
+
+//============================================================================
+// Events
+//============================================================================
+
+// Give us an object to bind all events to. This object should be created
+// before all other objects so it exists when others register event handlers.
+// To trigger an event handler:
+// $([IPython.events]).trigger('event.Namespace);
+// To handle it:
+// $([IPython.events]).on('event.Namespace',function () {});
+
+var IPython = (function (IPython) {
+
+ var utils = IPython.utils;
+
+ var Events = function () {};
+
+ IPython.Events = Events;
+ IPython.events = new Events();
+
+ return IPython;
+
+}(IPython));
+
diff --git a/IPython/frontend/html/notebook/static/js/kernel.js b/IPython/frontend/html/notebook/static/js/kernel.js
index 6f00922..99ac624 100644
--- a/IPython/frontend/html/notebook/static/js/kernel.js
+++ b/IPython/frontend/html/notebook/static/js/kernel.js
@@ -62,7 +62,7 @@ var IPython = (function (IPython) {
Kernel.prototype.restart = function (callback) {
- IPython.kernel_status_widget.status_restarting();
+ $([IPython.events]).trigger('status_restarting.Kernel');
var url = this.kernel_url + "/restart";
var that = this;
if (this.running) {
@@ -84,20 +84,19 @@ var IPython = (function (IPython) {
this.kernel_url = this.base_url + "/" + this.kernel_id;
this.start_channels();
callback();
- IPython.kernel_status_widget.status_idle();
};
Kernel.prototype._websocket_closed = function(ws_url, early){
var msg;
var parent_item = $('body');
if (early) {
- msg = "Websocket connection to " + ws_url + " could not be established.
" +
- " You will NOT be able to run code.
" +
+ msg = "Websocket connection to " + ws_url + " could not be established." +
+ " You will NOT be able to run code." +
" Your browser may not be compatible with the websocket version in the server," +
" or if the url does not look right, there could be an error in the" +
" server's configuration.";
} else {
- msg = "Websocket connection closed unexpectedly.
" +
+ msg = "Websocket connection closed unexpectedly." +
" The kernel will no longer be responsive.";
}
var dialog = $('
');
@@ -107,8 +106,10 @@ var IPython = (function (IPython) {
resizable: false,
modal: true,
title: "Websocket closed",
+ closeText: "",
+ close: function(event, ui) {$(this).dialog('destroy').remove();},
buttons : {
- "Okay": function () {
+ "OK": function () {
$(this).dialog('close');
}
}
@@ -211,6 +212,7 @@ var IPython = (function (IPython) {
Kernel.prototype.interrupt = function () {
if (this.running) {
+ $([IPython.events]).trigger('status_interrupting.Kernel');
$.post(this.kernel_url + "/interrupt");
};
};
diff --git a/IPython/frontend/html/notebook/static/js/kernelstatus.js b/IPython/frontend/html/notebook/static/js/kernelstatus.js
deleted file mode 100644
index 5b61157..0000000
--- a/IPython/frontend/html/notebook/static/js/kernelstatus.js
+++ /dev/null
@@ -1,65 +0,0 @@
-//----------------------------------------------------------------------------
-// Copyright (C) 2008-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.
-//----------------------------------------------------------------------------
-
-//============================================================================
-// Kernel Status widget
-//============================================================================
-
-var IPython = (function (IPython) {
-
- var utils = IPython.utils;
-
- var KernelStatusWidget = function (selector) {
- this.selector = selector;
- if (this.selector !== undefined) {
- this.element = $(selector);
- this.style();
- }
- };
-
-
- KernelStatusWidget.prototype.style = function () {
- this.element.addClass('ui-widget');
- this.element.attr('title', "The kernel execution status." +
- " If 'Busy', the kernel is currently running code." +
- " If 'Idle', it is available for execution.");
- };
-
-
- KernelStatusWidget.prototype.status_busy = function () {
- this.element.removeClass("status_idle");
- this.element.removeClass("status_restarting");
- this.element.addClass("status_busy");
- window.document.title='(Busy) '+window.document.title;
- this.element.text("Busy");
- };
-
-
- KernelStatusWidget.prototype.status_idle = function () {
- this.element.removeClass("status_busy");
- this.element.removeClass("status_restarting");
- this.element.addClass("status_idle");
- IPython.save_widget.set_document_title();
- this.element.text("Idle");
- };
-
- KernelStatusWidget.prototype.status_restarting = function () {
- this.element.removeClass("status_busy");
- this.element.removeClass("status_idle");
- this.element.addClass("status_restarting");
- this.element.text("Restarting");
- };
-
-
-
-
- IPython.KernelStatusWidget = KernelStatusWidget;
-
- return IPython;
-
-}(IPython));
-
diff --git a/IPython/frontend/html/notebook/static/js/menubar.js b/IPython/frontend/html/notebook/static/js/menubar.js
index b513ecd..eef2e44 100644
--- a/IPython/frontend/html/notebook/static/js/menubar.js
+++ b/IPython/frontend/html/notebook/static/js/menubar.js
@@ -45,21 +45,21 @@ var IPython = (function (IPython) {
IPython.save_widget.rename_notebook();
});
this.element.find('#copy_notebook').click(function () {
- var notebook_id = IPython.save_widget.get_notebook_id();
+ var notebook_id = IPython.notebook.get_notebook_id();
var url = $('body').data('baseProjectUrl') + notebook_id + '/copy';
window.open(url,'_newtab');
});
this.element.find('#save_notebook').click(function () {
- IPython.save_widget.save_notebook();
+ IPython.notebook.save_notebook();
});
this.element.find('#download_ipynb').click(function () {
- var notebook_id = IPython.save_widget.get_notebook_id();
+ var notebook_id = IPython.notebook.get_notebook_id();
var url = $('body').data('baseProjectUrl') + 'notebooks/' +
notebook_id + '?format=json';
window.open(url,'_newtab');
});
this.element.find('#download_py').click(function () {
- var notebook_id = IPython.save_widget.get_notebook_id();
+ var notebook_id = IPython.notebook.get_notebook_id();
var url = $('body').data('baseProjectUrl') + 'notebooks/' +
notebook_id + '?format=py';
window.open(url,'_newtab');
diff --git a/IPython/frontend/html/notebook/static/js/notebook.js b/IPython/frontend/html/notebook/static/js/notebook.js
index df20219..898672b 100644
--- a/IPython/frontend/html/notebook/static/js/notebook.js
+++ b/IPython/frontend/html/notebook/static/js/notebook.js
@@ -26,6 +26,10 @@ var IPython = (function (IPython) {
this.msg_cell_map = {};
this.metadata = {};
this.control_key_active = false;
+ this.notebook_id = null;
+ this.notebook_name = null;
+ this.notebook_name_blacklist_re = /[\/\\]/;
+ this.nbformat = 3 // Increment this when changing the nbformat
this.style();
this.create_elements();
this.bind_events();
@@ -66,7 +70,7 @@ var IPython = (function (IPython) {
// Save (CTRL+S) or (AppleKey+S)
//metaKey = applekey on mac
if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
- IPython.save_widget.save_notebook();
+ that.save_notebook();
event.preventDefault();
return false;
} else if (event.which === 27) {
@@ -92,7 +96,7 @@ var IPython = (function (IPython) {
} else if (event.which === 13 && event.ctrlKey) {
that.execute_selected_cell({terminal:true});
return false;
- } else if (event.which === 77 && event.ctrlKey) {
+ } else if (event.which === 77 && event.ctrlKey && that.control_key_active == false) {
that.control_key_active = true;
return false;
} else if (event.which === 88 && that.control_key_active) {
@@ -177,7 +181,7 @@ var IPython = (function (IPython) {
return false;
} else if (event.which === 83 && that.control_key_active) {
// Save notebook = s
- IPython.save_widget.save_notebook();
+ that.save_notebook();
that.control_key_active = false;
return false;
} else if (event.which === 74 && that.control_key_active) {
@@ -207,12 +211,12 @@ var IPython = (function (IPython) {
return false;
} else if (event.which === 73 && that.control_key_active) {
// Interrupt kernel = i
- IPython.notebook.kernel.interrupt();
+ that.kernel.interrupt();
that.control_key_active = false;
return false;
} else if (event.which === 190 && that.control_key_active) {
// Restart kernel = . # matches qt console
- IPython.notebook.restart_kernel();
+ that.restart_kernel();
that.control_key_active = false;
return false;
} else if (event.which === 72 && that.control_key_active) {
@@ -402,10 +406,14 @@ var IPython = (function (IPython) {
var cell = this.get_cell(index)
cell.select();
if (cell.cell_type === 'heading') {
- IPython.toolbar.set_cell_type(cell.cell_type+cell.level);
+ $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
+ {'cell_type':cell.cell_type,level:cell.level}
+ );
} else {
- IPython.toolbar.set_cell_type(cell.cell_type)
- }
+ $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
+ {'cell_type':cell.cell_type}
+ );
+ };
};
return this;
};
@@ -676,7 +684,9 @@ var IPython = (function (IPython) {
source_element.remove();
this.dirty = true;
};
- IPython.toolbar.set_cell_type("heading"+level);
+ $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
+ {'cell_type':'heading',level:level}
+ );
};
};
@@ -880,15 +890,12 @@ var IPython = (function (IPython) {
Notebook.prototype.start_kernel = function () {
this.kernel = new IPython.Kernel();
- var notebook_id = IPython.save_widget.get_notebook_id();
- this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
+ this.kernel.start(this.notebook_id, $.proxy(this.kernel_started, this));
};
Notebook.prototype.restart_kernel = function () {
var that = this;
- var notebook_id = IPython.save_widget.get_notebook_id();
-
var dialog = $('');
dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
$(document).append(dialog);
@@ -976,8 +983,8 @@ var IPython = (function (IPython) {
var cell = this.cell_for_msg(reply.parent_header.msg_id);
if (msg_type !== 'status' && !cell){
// message not from this notebook, but should be attached to a cell
- console.log("Received IOPub message not caused by one of my cells");
- console.log(reply);
+ // console.log("Received IOPub message not caused by one of my cells");
+ // console.log(reply);
return;
}
var output_types = ['stream','display_data','pyout','pyerr'];
@@ -985,9 +992,10 @@ var IPython = (function (IPython) {
this.handle_output(cell, msg_type, content);
} else if (msg_type === 'status') {
if (content.execution_state === 'busy') {
+ $([IPython.events]).trigger('status_busy.Kernel');
IPython.kernel_status_widget.status_busy();
} else if (content.execution_state === 'idle') {
- IPython.kernel_status_widget.status_idle();
+ $([IPython.events]).trigger('status_idle.Kernel');
} else if (content.execution_state === 'dead') {
this.handle_status_dead();
};
@@ -1142,8 +1150,33 @@ var IPython = (function (IPython) {
this.msg_cell_map[msg_id] = cell.cell_id;
};
+
// Persistance and loading
+ Notebook.prototype.get_notebook_id = function () {
+ return this.notebook_id;
+ };
+
+
+ Notebook.prototype.get_notebook_name = function () {
+ return this.notebook_name;
+ };
+
+
+ Notebook.prototype.set_notebook_name = function (name) {
+ this.notebook_name = name;
+ };
+
+
+ Notebook.prototype.test_notebook_name = function (nbname) {
+ nbname = nbname || '';
+ if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
+ return true;
+ } else {
+ return false;
+ };
+ };
+
Notebook.prototype.fromJSON = function (data) {
var ncells = this.ncells();
@@ -1152,8 +1185,9 @@ var IPython = (function (IPython) {
// Always delete cell 0 as they get renumbered as they are deleted.
this.delete_cell(0);
};
- // Save the metadata
+ // Save the metadata and name.
this.metadata = data.metadata;
+ this.notebook_name = data.metadata.name;
// Only handle 1 worksheet for now.
var worksheet = data.worksheets[0];
if (worksheet !== undefined) {
@@ -1186,12 +1220,10 @@ var IPython = (function (IPython) {
};
Notebook.prototype.save_notebook = function () {
- var notebook_id = IPython.save_widget.get_notebook_id();
- var nbname = IPython.save_widget.get_notebook_name();
// We may want to move the name/id/nbformat logic inside toJSON?
var data = this.toJSON();
- data.metadata.name = nbname;
- data.nbformat = 3;
+ data.metadata.name = this.notebook_name;
+ data.nbformat = this.nbformat;
// We do the call with settings so we can set cache to false.
var settings = {
processData : false,
@@ -1199,63 +1231,108 @@ var IPython = (function (IPython) {
type : "PUT",
data : JSON.stringify(data),
headers : {'Content-Type': 'application/json'},
- success : $.proxy(this.notebook_saved,this),
- error : $.proxy(this.notebook_save_failed,this)
+ success : $.proxy(this.save_notebook_success,this),
+ error : $.proxy(this.save_notebook_error,this)
};
- IPython.save_widget.status_saving();
- var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id;
+ $([IPython.events]).trigger('notebook_saving.Notebook');
+ var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
$.ajax(url, settings);
};
- Notebook.prototype.notebook_saved = function (data, status, xhr) {
+ Notebook.prototype.save_notebook_success = function (data, status, xhr) {
this.dirty = false;
- IPython.save_widget.notebook_saved();
- IPython.save_widget.status_last_saved();
+ $([IPython.events]).trigger('notebook_saved.Notebook');
};
- Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) {
- IPython.save_widget.status_save_failed();
+ Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
+ $([IPython.events]).trigger('notebook_save_failed.Notebook');
};
- Notebook.prototype.load_notebook = function () {
+ Notebook.prototype.load_notebook = function (notebook_id) {
var that = this;
- var notebook_id = IPython.save_widget.get_notebook_id();
+ this.notebook_id = notebook_id;
// We do the call with settings so we can set cache to false.
var settings = {
processData : false,
cache : false,
type : "GET",
dataType : "json",
- success : function (data, status, xhr) {
- that.notebook_loaded(data, status, xhr);
- }
+ success : $.proxy(this.load_notebook_success,this),
+ error : $.proxy(this.load_notebook_error,this),
};
- IPython.save_widget.status_loading();
- var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id;
+ $([IPython.events]).trigger('notebook_loading.Notebook');
+ var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
$.ajax(url, settings);
};
- Notebook.prototype.notebook_loaded = function (data, status, xhr) {
+ Notebook.prototype.load_notebook_success = function (data, status, xhr) {
this.fromJSON(data);
if (this.ncells() === 0) {
this.insert_cell_below('code');
};
- IPython.save_widget.status_last_saved();
- IPython.save_widget.set_notebook_name(data.metadata.name);
this.dirty = false;
if (! this.read_only) {
this.start_kernel();
}
this.select(0);
this.scroll_to_top();
- IPython.save_widget.update_url();
- IPython.layout_manager.do_resize();
- };
-
+ if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
+ msg = "This notebook has been converted from an older " +
+ "notebook format (v"+data.orig_nbformat+") to the current notebook " +
+ "format (v"+data.nbformat+"). The next time you save this notebook, the " +
+ "newer notebook format will be used and older verions of IPython " +
+ "may not be able to read it. To keep the older version, close the " +
+ "notebook without saving it.";
+ var dialog = $('');
+ dialog.html(msg);
+ this.element.append(dialog);
+ dialog.dialog({
+ resizable: false,
+ modal: true,
+ title: "Notebook converted",
+ closeText: "",
+ close: function(event, ui) {$(this).dialog('destroy').remove();},
+ buttons : {
+ "OK": function () {
+ $(this).dialog('close');
+ }
+ },
+ width: 400
+ });
+ }
+ $([IPython.events]).trigger('notebook_loaded.Notebook');
+ };
+
+
+ Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
+ if (xhr.status === 500) {
+ msg = "An error occurred while loading this notebook. Most likely " +
+ "this notebook is in a newer format than is supported by this " +
+ "version of IPython. This version can load notebook formats " +
+ "v"+this.nbformat+" or earlier.";
+ var dialog = $('');
+ dialog.html(msg);
+ this.element.append(dialog);
+ dialog.dialog({
+ resizable: false,
+ modal: true,
+ title: "Error loading notebook",
+ closeText: "",
+ close: function(event, ui) {$(this).dialog('destroy').remove();},
+ buttons : {
+ "OK": function () {
+ $(this).dialog('close');
+ }
+ },
+ width: 400
+ });
+ }
+ }
+
IPython.Notebook = Notebook;
diff --git a/IPython/frontend/html/notebook/static/js/notebookmain.js b/IPython/frontend/html/notebook/static/js/notebookmain.js
index bb5fd46..34cd61c 100644
--- a/IPython/frontend/html/notebook/static/js/notebookmain.js
+++ b/IPython/frontend/html/notebook/static/js/notebookmain.js
@@ -82,14 +82,13 @@ $(document).ready(function () {
IPython.layout_manager = new IPython.LayoutManager();
IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
- IPython.save_widget = new IPython.SaveWidget('span#save_widget');
IPython.quick_help = new IPython.QuickHelp('span#quick_help_area');
IPython.login_widget = new IPython.LoginWidget('span#login_widget');
IPython.notebook = new IPython.Notebook('div#notebook');
- IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status');
+ IPython.save_widget = new IPython.SaveWidget('span#save_widget');
IPython.menubar = new IPython.MenuBar('#menubar')
IPython.toolbar = new IPython.ToolBar('#toolbar')
- IPython.kernel_status_widget.status_idle();
+ IPython.notification_widget = new IPython.NotificationWidget('#notification')
IPython.layout_manager.do_resize();
@@ -111,7 +110,11 @@ $(document).ready(function () {
$('div#main_app').css('display','block');
IPython.layout_manager.do_resize();
- IPython.notebook.load_notebook();
+ $([IPython.events]).on('notebook_loaded.Notebook', function () {
+ IPython.layout_manager.do_resize();
+ IPython.save_widget.update_url();
+ })
+ IPython.notebook.load_notebook($('body').data('notebookId'));
});
diff --git a/IPython/frontend/html/notebook/static/js/notificationwidget.js b/IPython/frontend/html/notebook/static/js/notificationwidget.js
new file mode 100644
index 0000000..9147afc
--- /dev/null
+++ b/IPython/frontend/html/notebook/static/js/notificationwidget.js
@@ -0,0 +1,102 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2008-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.
+//----------------------------------------------------------------------------
+
+//============================================================================
+// Notification widget
+//============================================================================
+
+var IPython = (function (IPython) {
+
+ var utils = IPython.utils;
+
+
+ var NotificationWidget = function (selector) {
+ this.selector = selector;
+ this.timeout = null;
+ this.busy = false;
+ if (this.selector !== undefined) {
+ this.element = $(selector);
+ this.style();
+ this.bind_events();
+ }
+ };
+
+
+ NotificationWidget.prototype.style = function () {
+ this.element.addClass('ui-widget ui-widget-content ui-corner-all');
+ this.element.addClass('border-box-sizing');
+ };
+
+
+ NotificationWidget.prototype.bind_events = function () {
+ var that = this;
+ // Kernel events
+ $([IPython.events]).on('status_idle.Kernel',function () {
+ IPython.save_widget.update_document_title();
+ if (that.get_message() === 'Kernel busy') {
+ that.element.fadeOut(100, function () {
+ that.element.html('');
+ });
+ };
+ });
+ $([IPython.events]).on('status_busy.Kernel',function () {
+ window.document.title='(Busy) '+window.document.title;
+ that.set_message("Kernel busy");
+ });
+ $([IPython.events]).on('status_restarting.Kernel',function () {
+ that.set_message("Restarting kernel",500);
+ });
+ $([IPython.events]).on('status_interrupting.Kernel',function () {
+ that.set_message("Interrupting kernel",500);
+ });
+ // Notebook events
+ $([IPython.events]).on('notebook_loading.Notebook', function () {
+ that.set_message("Loading notebook",500);
+ });
+ $([IPython.events]).on('notebook_loaded.Notebook', function () {
+ that.set_message("Notebook loaded",500);
+ });
+ $([IPython.events]).on('notebook_saving.Notebook', function () {
+ that.set_message("Saving notebook",500);
+ });
+ $([IPython.events]).on('notebook_saved.Notebook', function () {
+ that.set_message("Notebook saved",500);
+ });
+ $([IPython.events]).on('notebook_save_failed.Notebook', function () {
+ that.set_message("Notebook save failed",500);
+ });
+ };
+
+
+ NotificationWidget.prototype.set_message = function (msg, timeout) {
+ var that = this;
+ this.element.html(msg);
+ this.element.fadeIn(100);
+ if (this.timeout !== null) {
+ clearTimeout(this.timeout);
+ this.timeout = null;
+ };
+ if (timeout !== undefined) {
+ this.timeout = setTimeout(function () {
+ that.element.fadeOut(100, function () {that.element.html('');});
+ that.timeout = null;
+ }, timeout)
+ };
+ };
+
+
+ NotificationWidget.prototype.get_message = function () {
+ return this.element.html();
+ };
+
+
+ IPython.NotificationWidget = NotificationWidget;
+
+ return IPython;
+
+}(IPython));
+
diff --git a/IPython/frontend/html/notebook/static/js/printnotebookmain.js b/IPython/frontend/html/notebook/static/js/printnotebookmain.js
index ce5ec98..55f168c 100644
--- a/IPython/frontend/html/notebook/static/js/printnotebookmain.js
+++ b/IPython/frontend/html/notebook/static/js/printnotebookmain.js
@@ -79,16 +79,15 @@ $(document).ready(function () {
$('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
$('div#notebook_panel').addClass('border-box-sizing ui-widget');
- IPython.save_widget = new IPython.SaveWidget('span#save_widget');
IPython.login_widget = new IPython.LoginWidget('span#login_widget');
IPython.notebook = new IPython.Notebook('div#notebook');
+ IPython.save_widget = new IPython.SaveWidget('span#save_widget');
// These have display: none in the css file and are made visible here to prevent FLOUC.
$('div#header').css('display','block');
$('div#main_app').css('display','block');
- // Perform these actions after the notebook has been loaded.
- IPython.notebook.load_notebook(function () {});
+ IPython.notebook.load_notebook($('body').data('notebookId'));
});
diff --git a/IPython/frontend/html/notebook/static/js/savewidget.js b/IPython/frontend/html/notebook/static/js/savewidget.js
index ad1f5f3..2ffaf31 100644
--- a/IPython/frontend/html/notebook/static/js/savewidget.js
+++ b/IPython/frontend/html/notebook/static/js/savewidget.js
@@ -15,8 +15,6 @@ var IPython = (function (IPython) {
var SaveWidget = function (selector) {
this.selector = selector;
- this.notebook_name_blacklist_re = /[\/\\]/;
- this.last_saved_name = '';
if (this.selector !== undefined) {
this.element = $(selector);
this.style();
@@ -43,11 +41,19 @@ var IPython = (function (IPython) {
}, function () {
$(this).removeClass("ui-state-hover");
});
- };
-
-
- SaveWidget.prototype.save_notebook = function () {
- IPython.notebook.save_notebook();
+ $([IPython.events]).on('notebook_loaded.Notebook', function () {
+ that.set_last_saved();
+ that.update_notebook_name();
+ that.update_document_title();
+ });
+ $([IPython.events]).on('notebook_saved.Notebook', function () {
+ that.set_last_saved();
+ that.update_notebook_name();
+ that.update_document_title();
+ });
+ $([IPython.events]).on('notebook_save_failed.Notebook', function () {
+ that.set_save_status('');
+ });
};
@@ -61,7 +67,7 @@ var IPython = (function (IPython) {
dialog.append(
$('').attr('type','text').attr('size','25')
.addClass('ui-widget ui-widget-content')
- .attr('value',that.get_notebook_name())
+ .attr('value',IPython.notebook.get_notebook_name())
);
// $(document).append(dialog);
dialog.dialog({
@@ -73,15 +79,15 @@ var IPython = (function (IPython) {
buttons : {
"OK": function () {
var new_name = $(this).find('input').attr('value');
- if (!that.test_notebook_name(new_name)) {
+ if (!IPython.notebook.test_notebook_name(new_name)) {
$(this).find('h3').html(
"Invalid notebook name. Notebook names must "+
"have 1 or more characters and can contain any characters " +
"except / and \\. Please enter a new notebook name:"
);
} else {
- that.set_notebook_name(new_name);
- that.save_notebook();
+ IPython.notebook.set_notebook_name(new_name);
+ IPython.notebook.save_notebook();
$(this).dialog('close');
}
},
@@ -92,82 +98,36 @@ var IPython = (function (IPython) {
});
}
- SaveWidget.prototype.notebook_saved = function () {
- this.set_document_title();
- this.last_saved_name = this.get_notebook_name();
- };
-
- SaveWidget.prototype.get_notebook_name = function () {
- return this.element.find('span#notebook_name').html();
- };
-
-
- SaveWidget.prototype.set_notebook_name = function (nbname) {
+ SaveWidget.prototype.update_notebook_name = function () {
+ var nbname = IPython.notebook.get_notebook_name();
this.element.find('span#notebook_name').html(nbname);
- this.set_document_title();
- this.last_saved_name = nbname;
};
- SaveWidget.prototype.set_document_title = function () {
- nbname = this.get_notebook_name();
+ SaveWidget.prototype.update_document_title = function () {
+ var nbname = IPython.notebook.get_notebook_name();
document.title = nbname;
};
-
-
- SaveWidget.prototype.get_notebook_id = function () {
- return $('body').data('notebookId');
- };
SaveWidget.prototype.update_url = function () {
- var notebook_id = this.get_notebook_id();
- if (notebook_id !== '') {
+ var notebook_id = IPython.notebook.get_notebook_id();
+ if (notebook_id !== null) {
var new_url = $('body').data('baseProjectUrl') + notebook_id;
window.history.replaceState({}, '', new_url);
};
};
- SaveWidget.prototype.test_notebook_name = function (nbname) {
- nbname = nbname || '';
- if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
- return true;
- } else {
- return false;
- };
- };
+ SaveWidget.prototype.set_save_status = function (msg) {
+ this.element.find('span#save_status').html(msg);
+ }
SaveWidget.prototype.set_last_saved = function () {
var d = new Date();
- $('#save_status').html('Last saved: '+d.format('mmm dd h:MM TT'));
-
- };
-
- SaveWidget.prototype.reset_status = function () {
- this.element.find('span#save_status').html('');
- };
-
-
- SaveWidget.prototype.status_last_saved = function () {
- this.set_last_saved();
- };
-
-
- SaveWidget.prototype.status_saving = function () {
- this.element.find('span#save_status').html('Saving...');
- };
-
-
- SaveWidget.prototype.status_save_failed = function () {
- this.element.find('span#save_status').html('Save failed');
- };
-
-
- SaveWidget.prototype.status_loading = function () {
- this.element.find('span#save_status').html('Loading...');
+ this.set_save_status('Last saved: '+d.format('mmm dd h:MM TT'));
};
diff --git a/IPython/frontend/html/notebook/static/js/textcell.js b/IPython/frontend/html/notebook/static/js/textcell.js
index 1c98dea..f48f452 100644
--- a/IPython/frontend/html/notebook/static/js/textcell.js
+++ b/IPython/frontend/html/notebook/static/js/textcell.js
@@ -49,7 +49,7 @@ var IPython = (function (IPython) {
IPython.Cell.prototype.bind_events.apply(this);
var that = this;
this.element.keydown(function (event) {
- if (event.which === 13) {
+ if (event.which === 13 && !event.shiftKey) {
if (that.rendered) {
that.edit();
return false;
diff --git a/IPython/frontend/html/notebook/static/js/toolbar.js b/IPython/frontend/html/notebook/static/js/toolbar.js
index df0de25..2ecdfa0 100644
--- a/IPython/frontend/html/notebook/static/js/toolbar.js
+++ b/IPython/frontend/html/notebook/static/js/toolbar.js
@@ -72,8 +72,9 @@ var IPython = (function (IPython) {
ToolBar.prototype.bind_events = function () {
+ var that = this;
this.element.find('#save_b').click(function () {
- IPython.save_widget.save_notebook();
+ IPython.notebook.save_notebook();
});
this.element.find('#cut_b').click(function () {
IPython.notebook.cut_cell();
@@ -124,12 +125,13 @@ var IPython = (function (IPython) {
IPython.notebook.to_heading(undefined, 6);
};
});
-
- };
-
-
- ToolBar.prototype.set_cell_type = function (cell_type) {
- this.element.find('#cell_type').val(cell_type);
+ $([IPython.events]).on('selected_cell_type_changed', function (event, data) {
+ if (data.cell_type === 'heading') {
+ that.element.find('#cell_type').val(data.cell_type+data.level);
+ } else {
+ that.element.find('#cell_type').val(data.cell_type);
+ }
+ });
};
diff --git a/IPython/frontend/html/notebook/templates/notebook.html b/IPython/frontend/html/notebook/templates/notebook.html
index 242a5d0..7b0b087 100644
--- a/IPython/frontend/html/notebook/templates/notebook.html
+++ b/IPython/frontend/html/notebook/templates/notebook.html
@@ -54,10 +54,9 @@
{% end %}
-
- Idle
+
+
@@ -220,12 +222,12 @@
+
-
@@ -234,6 +236,7 @@
+