Merge upstream changes

Cameron Bates 14 years ago
commit 7b3c01c667

1
.gitignore vendored

@ -7,6 +7,7 @@ docs/source/api/generated
docs/gh-pages
IPython/frontend/html/notebook/static/mathjax
*.py[co]
__pycache__
build
*.egg-info
*~

@ -149,13 +149,13 @@ class AuthenticatedHandler(RequestHandler):
"""A RequestHandler with an authenticated user."""
def get_current_user(self):
user_id = self.get_secure_cookie("username")
user_id = self.get_secure_cookie(self.settings['cookie_name'])
# For now the user_id should not return empty, but it could eventually
if user_id == '':
user_id = 'anonymous'
if user_id is None:
# prevent extra Invalid cookie sig warnings:
self.clear_cookie('username')
self.clear_cookie(self.settings['cookie_name'])
if not self.application.password and not self.application.read_only:
user_id = 'anonymous'
return user_id
@ -247,7 +247,7 @@ class LoginHandler(AuthenticatedHandler):
pwd = self.get_argument('password', default=u'')
if self.application.password:
if passwd_check(self.application.password, pwd):
self.set_secure_cookie('username', str(uuid.uuid4()))
self.set_secure_cookie(self.settings['cookie_name'], str(uuid.uuid4()))
else:
self._render(message={'error': 'Invalid password'})
return
@ -258,7 +258,7 @@ class LoginHandler(AuthenticatedHandler):
class LogoutHandler(AuthenticatedHandler):
def get(self):
self.clear_cookie('username')
self.clear_cookie(self.settings['cookie_name'])
if self.login_available:
message = {'info': 'Successfully logged out.'}
else:
@ -435,7 +435,7 @@ class AuthenticatedZMQStreamHandler(ZMQStreamHandler):
self.on_message = self.on_first_message
def get_current_user(self):
user_id = self.get_secure_cookie("username")
user_id = self.get_secure_cookie(self.settings['cookie_name'])
if user_id == '' or (user_id is None and not self.application.password):
user_id = 'anonymous'
return user_id

@ -42,6 +42,11 @@ class NotebookManager(LoggingConfigurable):
""")
def _notebook_dir_changed(self, name, old, new):
"""do a bit of validation of the notebook dir"""
if not os.path.isabs(new):
# If we receive a non-absolute path, make it absolute.
abs_new = os.path.abspath(new)
self.notebook_dir = abs_new
return
if os.path.exists(new) and not os.path.isdir(new):
raise TraitError("notebook dir %r is not a directory" % new)
if not os.path.exists(new):
@ -117,7 +122,7 @@ class NotebookManager(LoggingConfigurable):
# should match the Python in-memory format.
kwargs['split_lines'] = False
data = current.writes(nb, format, **kwargs)
name = nb.get('name','notebook')
name = nb.metadata.get('name','notebook')
return last_modified, name, data
def read_notebook_object(self, notebook_id):

@ -28,6 +28,7 @@ import socket
import sys
import threading
import time
import uuid
import webbrowser
# Third party
@ -164,6 +165,7 @@ class NotebookWebApplication(web.Application):
static_handler_class = FileFindHandler,
cookie_secret=os.urandom(1024),
login_url="%s/login"%(base_project_url.rstrip('/')),
cookie_name='username-%s' % uuid.uuid4(),
)
# allow custom overrides for the tornado web app.
@ -468,11 +470,14 @@ class NotebookApp(BaseIPythonApplication):
ssl_options = None
self.web_app.password = self.password
self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
if ssl_options is None and not self.ip and not (self.read_only and not self.password):
self.log.critical('WARNING: the notebook server is listening on all IP addresses '
'but not using any encryption or authentication. This is highly '
'insecure and not recommended.')
if not self.ip:
warning = "WARNING: The notebook server is listening on all IP addresses"
if ssl_options is None:
self.log.critical(warning + " and not using encryption. This"
"is not recommended.")
if not self.password and not self.read_only:
self.log.critical(warning + "and not using authentication."
"This is highly insecure and not recommended.")
success = None
for port in random_ports(self.port, self.port_retries+1):
try:

@ -70,7 +70,7 @@ span#notebook_name {
z-index: 10;
}
#toolbar {
.toolbar {
padding: 3px 15px;
}
@ -122,6 +122,10 @@ div#pager_splitter {
height: 8px;
}
#pager_container {
position : relative;
}
div#pager {
padding: 15px;
overflow: auto;
@ -234,7 +238,7 @@ div.output_area {
/* This class is for the output subarea inside the output_area and after
the prompt div. */
div.output_subarea {
padding: 0.4em 0.4em 0.4em 0.4em;
padding: 0.44em 0.4em 0.4em 1px;
}
/* The rest of the output_* classes are for special styling of the different

@ -33,7 +33,7 @@ span#ipython_notebook {
padding: 2px 2px 2px 5px;
}
span#ipython_notebook h1 img {
span#ipython_notebook img {
font-family: Verdana, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
height: 24px;
text-decoration:none;

@ -44,7 +44,7 @@
opacity: 1;
}
}
.tooltip a {
.ipython_tooltip a {
float: right;
}
/*properties of tooltip after "expand"*/
@ -81,7 +81,7 @@
padding-right: 30px;
}
.tooltip {
.ipython_tooltip {
max-width: 700px;
border-radius: 4px;
-moz-box-shadow: 0px 6px 10px -1px #adadad;

@ -20,6 +20,8 @@ var IPython = (function (IPython) {
this.selected = false;
this.element = null;
this.metadata = {};
// load this from metadata later ?
this.user_highlight == 'auto';
this.create_element();
if (this.element !== null) {
this.element.data("cell", this);
@ -48,15 +50,13 @@ var IPython = (function (IPython) {
});
};
// typeset with MathJax if MathJax is available
Cell.prototype.typeset = function () {
if (window.MathJax){
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
var cell_math = this.element.get(0);
MathJax.Hub.Queue(["Typeset",MathJax.Hub,cell_math]);
}
};
Cell.prototype.select = function () {
this.element.addClass('ui-widget-content ui-corner-all');
this.selected = true;
@ -154,6 +154,61 @@ var IPython = (function (IPython) {
this.code_mirror.refresh();
};
Cell.prototype.force_highlight = function(mode) {
this.user_highlight = mode;
this.auto_highlight();
};
Cell.prototype._auto_highlight = function (modes) {
//Here we handle manually selected modes
if( this.user_highlight != undefined && this.user_highlight != 'auto' )
{
var mode = this.user_highlight;
CodeMirror.autoLoadMode(this.code_mirror, mode);
this.code_mirror.setOption('mode', mode);
return;
}
var first_line = this.code_mirror.getLine(0);
// loop on every pairs
for( var mode in modes) {
var regs = modes[mode]['reg'];
// only one key every time but regexp can't be keys...
for(var reg in regs ) {
// here we handle non magic_modes
if(first_line.match(regs[reg]) != null) {
if (mode.search('magic_') != 0) {
this.code_mirror.setOption('mode',mode);
CodeMirror.autoLoadMode(this.code_mirror, mode);
return;
}
var open = modes[mode]['open']|| "%%";
var close = modes[mode]['close']|| "%%end";
var mmode = mode;
mode = mmode.substr(6);
CodeMirror.autoLoadMode(this.code_mirror, mode);
// create on the fly a mode that swhitch between
// plain/text and smth else otherwise `%%` is
// source of some highlight issues.
// we use patchedGetMode to circumvent a bug in CM
CodeMirror.defineMode(mmode , function(config) {
return CodeMirror.multiplexingMode(
CodeMirror.patchedGetMode(config, 'text/plain'),
// always set someting on close
{open: open, close: close,
mode: CodeMirror.patchedGetMode(config, mode),
delimStyle: "delimit"
}
);
});
this.code_mirror.setOption('mode', mmode);
return;
}
}
}
// fallback on default (python)
var default_mode = this.default_mode || 'text/plain';
this.code_mirror.setOption('mode', default_mode);
};
IPython.Cell = Cell;

@ -14,6 +14,7 @@ var IPython = (function (IPython) {
var utils = IPython.utils;
var key = IPython.utils.keycodes;
CodeMirror.modeURL = "/static/codemirror/mode/%N/%N.js";
var CodeCell = function (kernel) {
// The kernel doesn't have to be set at creation time, in that case
@ -23,13 +24,23 @@ var IPython = (function (IPython) {
this.input_prompt_number = null;
this.tooltip_on_tab = true;
this.collapsed = false;
this.default_mode = 'python';
IPython.Cell.apply(this, arguments);
var that = this;
this.element.focusout(
function() { that.auto_highlight(); }
);
};
CodeCell.prototype = new IPython.Cell();
CodeCell.prototype.auto_highlight = function () {
this._auto_highlight(IPython.config.cell_magic_highlight)
};
CodeCell.prototype.create_element = function () {
var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
cell.attr('tabindex','2');
@ -76,6 +87,9 @@ var IPython = (function (IPython) {
};
var cur = editor.getCursor();
if (event.keyCode === key.ENTER){
this.auto_highlight();
}
if (event.keyCode === key.ENTER && (event.shiftKey || event.ctrlKey)) {
// Always ignore shift-enter in CodeMirror as we handle it.
@ -109,6 +123,7 @@ var IPython = (function (IPython) {
} else if (event.keyCode === key.TAB && event.type == 'keydown') {
// Tab completion.
//Do not trim here because of tooltip
if (editor.somethingSelected()){return false}
var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
if (pre_cursor.trim() === "") {
// Don't autocomplete if the part of the line before the cursor
@ -172,6 +187,7 @@ var IPython = (function (IPython) {
IPython.Cell.prototype.select.apply(this);
this.code_mirror.refresh();
this.code_mirror.focus();
this.auto_highlight();
// We used to need an additional refresh() after the focus, but
// it appears that this has been fixed in CM. This bug would show
// up on FF when a newly loaded markdown cell was edited.
@ -210,10 +226,31 @@ var IPython = (function (IPython) {
};
CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
var ns = prompt_value || "&nbsp;";
return 'In&nbsp;[' + ns + ']:'
};
CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
for(var i=1; i < lines_number; i++){html.push(['...:'])};
return html.join('</br>')
};
CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
CodeCell.prototype.set_input_prompt = function (number) {
var nline = 1
if( this.code_mirror != undefined) {
nline = this.code_mirror.lineCount();
}
this.input_prompt_number = number;
var ns = number || "&nbsp;";
this.element.find('div.input_prompt').html('In&nbsp;[' + ns + ']:');
var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
this.element.find('div.input_prompt').html(prompt_html);
};
@ -267,6 +304,7 @@ var IPython = (function (IPython) {
// make this value the starting point, so that we can only undo
// to this state, instead of a blank cell
this.code_mirror.clearHistory();
this.auto_highlight();
}
if (data.prompt_number !== undefined) {
this.set_input_prompt(data.prompt_number);

@ -64,7 +64,7 @@ var IPython = (function (IPython) {
Kernel.prototype.restart = function () {
$([IPython.events]).trigger({type: 'status_restarting.Kernel', kernel: this});
$([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
var that = this;
if (this.running) {
this.stop_channels();
@ -86,6 +86,7 @@ var IPython = (function (IPython) {
this.start_channels();
this.shell_channel.onmessage = $.proxy(this._handle_shell_reply,this);
this.iopub_channel.onmessage = $.proxy(this._handle_iopub_reply,this);
$([IPython.events]).trigger('status_started.Kernel', {kernel: this});
};
@ -245,7 +246,8 @@ var IPython = (function (IPython) {
user_expressions : {},
allow_stdin : false
};
$.extend(true, content, options)
$.extend(true, content, options)
$([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content});
var msg = this._get_msg("execute_request", content);
this.shell_channel.send(JSON.stringify(msg));
this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
@ -279,7 +281,7 @@ var IPython = (function (IPython) {
Kernel.prototype.interrupt = function () {
if (this.running) {
$([IPython.events]).trigger({type: 'status_interrupting.Kernel', kernel: this});
$([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
$.post(this.kernel_url + "/interrupt");
};
};
@ -312,6 +314,7 @@ var IPython = (function (IPython) {
Kernel.prototype._handle_shell_reply = function (e) {
reply = $.parseJSON(e.data);
$([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply});
var header = reply.header;
var content = reply.content;
var metadata = reply.metadata;
@ -367,12 +370,12 @@ var IPython = (function (IPython) {
}
} else if (msg_type === 'status') {
if (content.execution_state === 'busy') {
$([IPython.events]).trigger({type: 'status_busy.Kernel', kernel: this});
$([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
} else if (content.execution_state === 'idle') {
$([IPython.events]).trigger({type: 'status_idle.Kernel', kernel: this});
$([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
} else if (content.execution_state === 'dead') {
this.stop_channels();
$([IPython.events]).trigger({type: 'status_dead.Kernel', kernel: this});
$([IPython.events]).trigger('status_dead.Kernel', {kernel: this});
};
} else if (msg_type === 'clear_output') {
var cb = callbacks['clear_output'];

@ -0,0 +1,179 @@
//----------------------------------------------------------------------------
// 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.
//----------------------------------------------------------------------------
//============================================================================
// ToolBar
//============================================================================
var IPython = (function (IPython) {
var MainToolBar = function (selector) {
this.selector = selector;
IPython.ToolBar.apply(this, arguments);
this.construct();
this.add_drop_down_list();
this.bind_events();
};
MainToolBar.prototype = new IPython.ToolBar();
MainToolBar.prototype.construct = function () {
this.add_buttons_group([
{
id : 'save_b',
label : 'Save',
icon : 'ui-icon-disk',
callback : function () {
IPython.notebook.save_notebook();
}
}
]);
this.add_buttons_group([
{
id : 'cut_b',
label : 'Cut Cell',
icon : 'ui-icon-scissors',
callback : function () {
IPython.notebook.cut_cell();
}
},
{
id : 'copy_b',
label : 'Copy Cell',
icon : 'ui-icon-copy',
callback : function () {
IPython.notebook.copy_cell();
}
},
{
id : 'paste_b',
label : 'Paste Cell Below',
icon : 'ui-icon-clipboard',
callback : function () {
IPython.notebook.paste_cell_below();
}
}
],'cut_copy_paste');
this.add_buttons_group([
{
id : 'move_up_b',
label : 'Move Cell Up',
icon : 'ui-icon-arrowthick-1-n',
callback : function () {
IPython.notebook.move_cell_up();
}
},
{
id : 'move_down_b',
label : 'Move Cell Down',
icon : 'ui-icon-arrowthick-1-s',
callback : function () {
IPython.notebook.move_cell_down();
}
}
],'move_up_down');
this.add_buttons_group([
{
id : 'insert_above_b',
label : 'Insert Cell Above',
icon : 'ui-icon-arrowthickstop-1-n',
callback : function () {
IPython.notebook.insert_cell_above('code');
}
},
{
id : 'insert_below_b',
label : 'Insert Cell Below',
icon : 'ui-icon-arrowthickstop-1-s',
callback : function () {
IPython.notebook.insert_cell_below('code');
}
}
],'insert_above_below');
this.add_buttons_group([
{
id : 'run_b',
label : 'Run Cell',
icon : 'ui-icon-play',
callback : function () {
IPython.notebook.execute_selected_cell();
}
},
{
id : 'interrupt_b',
label : 'Interrupt',
icon : 'ui-icon-stop',
callback : function () {
IPython.notebook.kernel.interrupt();
}
}
],'run_int');
};
MainToolBar.prototype.add_drop_down_list = function () {
var select = $(this.selector)
.append($('<select/>')
.attr('id','cell_type')
.addClass('ui-widget ui-widget-content')
.append($('<option/>').attr('value','code').text('Code'))
.append($('<option/>').attr('value','markdown').text('Markdown'))
.append($('<option/>').attr('value','raw').text('Raw Text'))
.append($('<option/>').attr('value','heading1').text('Heading 1'))
.append($('<option/>').attr('value','heading2').text('Heading 2'))
.append($('<option/>').attr('value','heading3').text('Heading 3'))
.append($('<option/>').attr('value','heading4').text('Heading 4'))
.append($('<option/>').attr('value','heading5').text('Heading 5'))
.append($('<option/>').attr('value','heading6').text('Heading 6'))
.append($('<option/>').attr('value','heading7').text('Heading 7'))
.append($('<option/>').attr('value','heading8').text('Heading 8'))
);
};
MainToolBar.prototype.bind_events = function () {
var that = this;
this.element.find('#cell_type').change(function () {
var cell_type = $(this).val();
if (cell_type === 'code') {
IPython.notebook.to_code();
} else if (cell_type === 'markdown') {
IPython.notebook.to_markdown();
} else if (cell_type === 'raw') {
IPython.notebook.to_raw();
} else if (cell_type === 'heading1') {
IPython.notebook.to_heading(undefined, 1);
} else if (cell_type === 'heading2') {
IPython.notebook.to_heading(undefined, 2);
} else if (cell_type === 'heading3') {
IPython.notebook.to_heading(undefined, 3);
} else if (cell_type === 'heading4') {
IPython.notebook.to_heading(undefined, 4);
} else if (cell_type === 'heading5') {
IPython.notebook.to_heading(undefined, 5);
} else if (cell_type === 'heading6') {
IPython.notebook.to_heading(undefined, 6);
}
});
$([IPython.events]).on('selected_cell_type_changed.Notebook', 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);
}
});
};
IPython.MainToolBar = MainToolBar;
return IPython;
}(IPython));

@ -0,0 +1,241 @@
//----------------------------------------------------------------------------
// Copyright (C) 2008-2012 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.
//----------------------------------------------------------------------------
//============================================================================
// MathJax utility functions
//============================================================================
IPython.namespace('IPython.mathjaxutils');
IPython.mathjaxutils = (function (IPython) {
var init = function () {
if (window.MathJax) {
// MathJax loaded
MathJax.Hub.Config({
tex2jax: {
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
processEnvironments: true
},
displayAlign: 'left', // Change this to 'center' to center equations.
"HTML-CSS": {
styles: {'.MathJax_Display': {"margin": 0}}
}
});
MathJax.Hub.Configured();
} else if (window.mathjax_url != "") {
// Don't have MathJax, but should. Show dialog.
var dialog = $('<div></div>')
.append(
$("<p></p>").addClass('dialog').html(
"Math/LaTeX rendering will be disabled."
)
).append(
$("<p></p>").addClass('dialog').html(
"If you have administrative access to the notebook server and" +
" a working internet connection, you can install a local copy" +
" of MathJax for offline use with the following command on the server" +
" at a Python or IPython prompt:"
)
).append(
$("<pre></pre>").addClass('dialog').html(
">>> from IPython.external import mathjax; mathjax.install_mathjax()"
)
).append(
$("<p></p>").addClass('dialog').html(
"This will try to install MathJax into the IPython source directory."
)
).append(
$("<p></p>").addClass('dialog').html(
"If IPython is installed to a location that requires" +
" administrative privileges to write, you will need to make this call as" +
" an administrator, via 'sudo'."
)
).append(
$("<p></p>").addClass('dialog').html(
"When you start the notebook server, you can instruct it to disable MathJax support altogether:"
)
).append(
$("<pre></pre>").addClass('dialog').html(
"$ ipython notebook --no-mathjax"
)
).append(
$("<p></p>").addClass('dialog').html(
"which will prevent this dialog from appearing."
)
).dialog({
title: "Failed to retrieve MathJax from '" + window.mathjax_url + "'",
width: "70%",
modal: true,
})
} else {
// No MathJax, but none expected. No dialog.
};
};
// Some magic for deferring mathematical expressions to MathJax
// by hiding them from the Markdown parser.
// Some of the code here is adapted with permission from Davide Cervone
// under the terms of the Apache2 license governing the MathJax project.
// Other minor modifications are also due to StackExchange and are used with
// permission.
var inline = "$"; // the inline math delimiter
var blocks, start, end, last, braces; // used in searching for math
var math; // stores math until pagedown (Markdown parser) is done
// MATHSPLIT contains the pattern for math delimiters and special symbols
// needed for searching for math in the text input.
var MATHSPLIT = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i;
// The math is in blocks i through j, so
// collect it into one block and clear the others.
// Replace &, <, and > by named entities.
// For IE, put <br> at the ends of comments since IE removes \n.
// Clear the current math positions and store the index of the
// math, then push the math string onto the storage array.
// The preProcess function is called on all blocks if it has been passed in
var process_math = function (i, j, pre_process) {
var hub = MathJax.Hub;
var block = blocks.slice(i, j + 1).join("").replace(/&/g, "&amp;") // use HTML entity for &
.replace(/</g, "&lt;") // use HTML entity for <
.replace(/>/g, "&gt;") // use HTML entity for >
;
if (hub.Browser.isMSIE) {
block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n")
}
while (j > i) {
blocks[j] = "";
j--;
}
blocks[i] = "@@" + math.length + "@@"; // replace the current block text with a unique tag to find later
if (pre_process)
block = pre_process(block);
math.push(block);
start = end = last = null;
}
// Break up the text into its component parts and search
// through them for math delimiters, braces, linebreaks, etc.
// Math delimiters must match and braces must balance.
// Don't allow math to pass through a double linebreak
// (which will be a paragraph).
//
var remove_math = function (text) {
if (!window.MathJax) {
return text;
}
start = end = last = null; // for tracking math delimiters
math = []; // stores math strings for later
// Except for extreme edge cases, this should catch precisely those pieces of the markdown
// source that will later be turned into code spans. While MathJax will not TeXify code spans,
// we still have to consider them at this point; the following issue has happened several times:
//
// `$foo` and `$bar` are varibales. --> <code>$foo ` and `$bar</code> are variables.
var hasCodeSpans = /`/.test(text),
de_tilde;
if (hasCodeSpans) {
text = text.replace(/~/g, "~T").replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, function (wholematch) {
return wholematch.replace(/\$/g, "~D");
});
de_tilde = function (text) { return text.replace(/~([TD])/g, function (wholematch, character) { return { T: "~", D: "$" }[character]; }) };
} else {
de_tilde = function (text) { return text; };
}
blocks = IPython.utils.regex_split(text.replace(/\r\n?/g, "\n"),MATHSPLIT);
for (var i = 1, m = blocks.length; i < m; i += 2) {
var block = blocks[i];
if (block.charAt(0) === "@") {
//
// Things that look like our math markers will get
// stored and then retrieved along with the math.
//
blocks[i] = "@@" + math.length + "@@";
math.push(block);
}
else if (start) {
//
// If we are in math, look for the end delimiter,
// but don't go past double line breaks, and
// and balance braces within the math.
//
if (block === end) {
if (braces) {
last = i
}
else {
process_math(start, i, de_tilde)
}
}
else if (block.match(/\n.*\n/)) {
if (last) {
i = last;
process_math(start, i, de_tilde)
}
start = end = last = null;
braces = 0;
}
else if (block === "{") {
braces++
}
else if (block === "}" && braces) {
braces--
}
}
else {
//
// Look for math start delimiters and when
// found, set up the end delimiter.
//
if (block === inline || block === "$$") {
start = i;
end = block;
braces = 0;
}
else if (block.substr(1, 5) === "begin") {
start = i;
end = "\\end" + block.substr(6);
braces = 0;
}
}
}
if (last) {
process_math(start, last, de_tilde)
}
return de_tilde(blocks.join(""));
}
//
// Put back the math strings that were saved,
// and clear the math array (no need to keep it around).
//
var replace_math = function (text) {
if (!window.MathJax) {
return text;
}
text = text.replace(/@@(\d+)@@/g, function (match, n) {
return math[n]
});
math = null;
return text;
}
return {
init : init,
process_math : process_math,
remove_math : remove_math,
replace_math : replace_math
};
}(IPython));

@ -128,7 +128,13 @@ var IPython = (function (IPython) {
});
this.element.find('#run_all_cells').click(function () {
IPython.notebook.execute_all_cells();
});
}).attr('title', 'Run all cells in the notebook');
this.element.find('#run_all_cells_above').click(function () {
IPython.notebook.execute_cells_above();
}).attr('title', 'Run all cells above (but not including) this cell');
this.element.find('#run_all_cells_below').click(function () {
IPython.notebook.execute_cells_below();
}).attr('title', 'Run this cell and all cells below it');
this.element.find('#to_code').click(function () {
IPython.notebook.to_code();
});

@ -22,6 +22,9 @@ var IPython = (function (IPython) {
this.next_prompt_number = 1;
this.kernel = null;
this.clipboard = null;
this.undelete_backup = null;
this.undelete_index = null;
this.undelete_below = false;
this.paste_enabled = false;
this.dirty = false;
this.metadata = {};
@ -139,8 +142,8 @@ var IPython = (function (IPython) {
that.control_key_active = false;
return false;
} else if (event.which === 86 && that.control_key_active) {
// Paste selected cell = v
that.paste_cell();
// Paste below selected cell = v
that.paste_cell_below();
that.control_key_active = false;
return false;
} else if (event.which === 68 && that.control_key_active) {
@ -257,6 +260,11 @@ var IPython = (function (IPython) {
IPython.quick_help.show_keyboard_shortcuts();
that.control_key_active = false;
return false;
} else if (event.which === 90 && that.control_key_active) {
// Undo last cell delete = z
that.undelete();
that.control_key_active = false;
return false;
} else if (that.control_key_active) {
that.control_key_active = false;
return true;
@ -304,6 +312,16 @@ var IPython = (function (IPython) {
});
};
Notebook.prototype.scroll_to_cell = function (cell_number, time) {
var cells = this.get_cells();
var time = time || 0;
cell_number = Math.min(cells.length-1,cell_number);
cell_number = Math.max(0 ,cell_number);
scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ;
this.element.animate({scrollTop:scroll_value}, time);
return scroll_value;
};
Notebook.prototype.scroll_to_bottom = function () {
this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
@ -526,13 +544,19 @@ var IPython = (function (IPython) {
Notebook.prototype.delete_cell = function (index) {
var i = this.index_or_selected(index);
var cell = this.get_selected_cell();
this.undelete_backup = cell.toJSON();
if (this.is_valid_cell_index(i)) {
var ce = this.get_cell_element(i);
ce.remove();
if (i === (this.ncells())) {
this.select(i-1);
this.undelete_index = i - 1;
this.undelete_below = true;
} else {
this.select(i);
this.undelete_index = i;
this.undelete_below = false;
};
this.dirty = true;
};
@ -540,11 +564,21 @@ var IPython = (function (IPython) {
};
Notebook.prototype.insert_cell_at_bottom = function (type){
var len = this.ncells();
return this.insert_cell_below(type,len-1);
}
Notebook.prototype.insert_cell_below = function (type, index) {
// type = ('code','html','markdown')
// index = cell index or undefined to insert below selected
index = this.index_or_selected(index);
var cell = null;
// This is intentionally < rather than <= for the sake of more
// sensible behavior in some cases.
if (this.undelete_index !== null && index < this.undelete_index) {
this.undelete_index = this.undelete_index + 1;
}
if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
if (type === 'code') {
cell = new IPython.CodeCell(this.kernel);
@ -579,6 +613,9 @@ var IPython = (function (IPython) {
// index = cell index or undefined to insert above selected
index = this.index_or_selected(index);
var cell = null;
if (this.undelete_index !== null && index <= this.undelete_index) {
this.undelete_index = this.undelete_index + 1;
}
if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
if (type === 'code') {
cell = new IPython.CodeCell(this.kernel);
@ -741,8 +778,8 @@ var IPython = (function (IPython) {
Notebook.prototype.enable_paste = function () {
var that = this;
if (!this.paste_enabled) {
$('#paste_cell').removeClass('ui-state-disabled')
.on('click', function () {that.paste_cell();});
$('#paste_cell_replace').removeClass('ui-state-disabled')
.on('click', function () {that.paste_cell_replace();});
$('#paste_cell_above').removeClass('ui-state-disabled')
.on('click', function () {that.paste_cell_above();});
$('#paste_cell_below').removeClass('ui-state-disabled')
@ -754,7 +791,7 @@ var IPython = (function (IPython) {
Notebook.prototype.disable_paste = function () {
if (this.paste_enabled) {
$('#paste_cell').addClass('ui-state-disabled').off('click');
$('#paste_cell_replace').addClass('ui-state-disabled').off('click');
$('#paste_cell_above').addClass('ui-state-disabled').off('click');
$('#paste_cell_below').addClass('ui-state-disabled').off('click');
this.paste_enabled = false;
@ -774,7 +811,7 @@ var IPython = (function (IPython) {
};
Notebook.prototype.paste_cell = function () {
Notebook.prototype.paste_cell_replace = function () {
if (this.clipboard !== null && this.paste_enabled) {
var cell_data = this.clipboard;
var new_cell = this.insert_cell_above(cell_data.cell_type);
@ -803,6 +840,33 @@ var IPython = (function (IPython) {
};
};
// Cell undelete
Notebook.prototype.undelete = function() {
if (this.undelete_backup !== null && this.undelete_index !== null) {
var current_index = this.get_selected_index();
if (this.undelete_index < current_index) {
current_index = current_index + 1;
}
if (this.undelete_index >= this.ncells()) {
this.select(this.ncells() - 1);
}
else {
this.select(this.undelete_index);
}
var cell_data = this.undelete_backup;
var new_cell = null;
if (this.undelete_below) {
new_cell = this.insert_cell_below(cell_data.cell_type);
} else {
new_cell = this.insert_cell_above(cell_data.cell_type);
}
new_cell.fromJSON(cell_data);
this.select(current_index);
this.undelete_backup = null;
this.undelete_index = null;
}
}
// Split/merge
@ -1034,13 +1098,25 @@ var IPython = (function (IPython) {
};
Notebook.prototype.execute_cells_below = function () {
this.execute_cell_range(this.get_selected_index(), this.ncells());
that.scroll_to_bottom();
};
Notebook.prototype.execute_cells_above = function () {
this.execute_cell_range(0, this.get_selected_index());
};
Notebook.prototype.execute_all_cells = function () {
var ncells = this.ncells();
for (var i=0; i<ncells; i++) {
this.execute_cell_range(0, this.ncells());
that.scroll_to_bottom();
};
Notebook.prototype.execute_cell_range = function (start, end) {
for (var i=start; i<end; i++) {
this.select(i);
this.execute_selected_cell({add_new:false});
};
this.scroll_to_bottom();
};
// Persistance and loading

@ -1,5 +1,5 @@
//----------------------------------------------------------------------------
// Copyright (C) 2008-2011 The IPython Development Team
// 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.
@ -12,7 +12,26 @@
$(document).ready(function () {
IPython.init_mathjax();
// monkey patch CM to be able to syntax highlight cell magics
// bug reported upstream,
// see https://github.com/marijnh/CodeMirror2/issues/670
if(CodeMirror.getMode(1,'text/plain').indent == undefined ){
console.log('patching CM for undefined indent');
CodeMirror.modes.null = function() { return {token: function(stream) {stream.skipToEnd();},indent : function(){return 0}}}
}
CodeMirror.patchedGetMode = function(config, mode){
var cmmode = CodeMirror.getMode(config, mode);
if(cmmode.indent == null)
{
console.log('patch mode "' , mode, '" on the fly');
cmmode.indent = function(){return 0};
}
return cmmode;
}
// end monkey patching CodeMirror
IPython.mathjaxutils.init();
IPython.read_only = $('body').data('readOnly') === 'True';
$('div#main_app').addClass('border-box-sizing ui-widget');
@ -29,7 +48,7 @@ $(document).ready(function () {
IPython.notebook = new IPython.Notebook('div#notebook');
IPython.save_widget = new IPython.SaveWidget('span#save_widget');
IPython.menubar = new IPython.MenuBar('#menubar')
IPython.toolbar = new IPython.ToolBar('#toolbar')
IPython.toolbar = new IPython.MainToolBar('#maintoolbar')
IPython.tooltip = new IPython.Tooltip()
IPython.notification_area = new IPython.NotificationArea('#notification_area')
IPython.notification_area.init_notification_widgets();

@ -379,8 +379,10 @@ var IPython = (function (IPython) {
OutputArea.prototype.append_text = function (data, element, extra_class) {
var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_text");
// escape ANSI & HTML specials in plaintext:
data = utils.wrapUrls(data);
data = utils.fixConsole(data);
data = utils.fixCarriageReturn(data);
data = utils.autoLinkUrls(data);
if (extra_class){
toinsert.addClass(extra_class);
}

@ -15,6 +15,7 @@ var IPython = (function (IPython) {
var Pager = function (pager_selector, pager_splitter_selector) {
this.pager_element = $(pager_selector);
this.pager_button_area = $('#pager_button_area');
var that = this;
this.percentage_height = 0.40;
this.pager_splitter_element = $(pager_splitter_selector)
@ -39,9 +40,24 @@ var IPython = (function (IPython) {
});
this.expanded = false;
this.style();
this.create_button_area();
this.bind_events();
};
Pager.prototype.create_button_area = function(){
var that = this;
this.pager_button_area.append(
$('<a>').attr('role', "button")
.attr('title',"open the pager in an external window")
.addClass('ui-button')
.click(function(){that.detach()})
.attr('style','position: absolute; right: 10px;')
.append(
$('<span>').addClass("ui-icon ui-icon-extlink")
)
)
};
Pager.prototype.style = function () {
this.pager_splitter_element.addClass('border-box-sizing ui-widget ui-state-default');
this.pager_element.addClass('border-box-sizing ui-widget');
@ -114,6 +130,26 @@ var IPython = (function (IPython) {
this.pager_element.empty();
};
Pager.prototype.detach = function(){
var w = window.open("","_blank")
$(w.document.head)
.append(
$('<link>')
.attr('rel',"stylesheet")
.attr('href',"/static/css/notebook.css")
.attr('type',"text/css")
)
.append(
$('<title>').text("IPython Pager")
);
var pager_body = $(w.document.body)
pager_body.attr('style','overflow:scroll');
pager_body.append(this.pager_element.children())
w.document.close();
this.collapse();
}
Pager.prototype.append_text = function (text) {
var toinsert = $("<div/>").addClass("output_area output_stream");

@ -33,6 +33,7 @@ var IPython = (function (IPython) {
{key: 'Ctrl-m c', help: 'copy cell'},
{key: 'Ctrl-m v', help: 'paste cell'},
{key: 'Ctrl-m d', help: 'delete cell'},
{key: 'Ctrl-m z', help: 'undo last cell deletion'},
{key: 'Ctrl-m a', help: 'insert cell above'},
{key: 'Ctrl-m b', help: 'insert cell below'},
{key: 'Ctrl-m o', help: 'toggle output'},

@ -1,5 +1,5 @@
//----------------------------------------------------------------------------
// Copyright (C) 2008-2011 The IPython Development Team
// Copyright (C) 2008-2012 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.
@ -221,7 +221,9 @@ var IPython = (function (IPython) {
if (this.rendered === false) {
var text = this.get_text();
if (text === "") { text = this.placeholder; }
text = IPython.mathjaxutils.remove_math(text)
var html = IPython.markdown_converter.makeHtml(text);
html = IPython.mathjaxutils.replace_math(html)
try {
this.set_rendered(html);
} catch (e) {
@ -231,7 +233,6 @@ var IPython = (function (IPython) {
"Error rendering Markdown!<br/>" + e.toString())
);
}
this.typeset()
this.element.find('div.text_cell_input').hide();
this.element.find("div.text_cell_render").show();
var code_snippets = this.element.find("pre > code");
@ -246,6 +247,7 @@ var IPython = (function (IPython) {
return '<code class="prettyprint">' + code + '</code>';
});
this.typeset()
this.rendered = true;
}
};
@ -258,11 +260,19 @@ var IPython = (function (IPython) {
this.code_mirror_mode = 'rst';
IPython.TextCell.apply(this, arguments);
this.cell_type = 'raw';
var that = this
this.element.focusout(
function() { that.auto_highlight(); }
);
};
RawCell.prototype = new TextCell();
RawCell.prototype.auto_highlight = function () {
this._auto_highlight(IPython.config.raw_cell_highlight);
};
RawCell.prototype.render = function () {
this.rendered = true;

@ -1,5 +1,5 @@
//----------------------------------------------------------------------------
// Copyright (C) 2008-2011 The IPython Development Team
// Copyright (C) 2008 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.
@ -16,132 +16,76 @@ var IPython = (function (IPython) {
if (this.selector !== undefined) {
this.element = $(selector);
this.style();
this.bind_events();
}
};
// add a group of button into the current toolbar.
//
// First argument : Mandatory
// list of dict as argument, each dict should contain
// 3 mandatory keys and values :
// label : string -- the text to show on hover
// icon : string -- the jQuery-ui icon to add on this button
// callback : function -- the callback to execute on a click
//
// and optionally an 'id' key that is assigned to the button element
//
// Second Argument, optional,
// string reprensenting the id to give to the button group.
//
// Example
//
// IPython.toolbar.add_button_group([
// {label:'my button',
// icon:'ui-icon-disk',
// callback:function(){alert('hoho'),
// id : 'my_button_id', // this is optional
// }
// },
// {label:'my second button',
// icon:'ui-icon-scissors',
// callback:function(){alert('be carefull I cut')}
// }
// ],
// "my_button_group_id"
// )
//
ToolBar.prototype.add_buttons_group = function (list, group_id) {
var span_group = $('<span/>');
if( group_id != undefined ) {
span_group.attr('id',group_id);
}
for(var el in list) {
var button = $('<button/>').button({
icons : {primary : list[el].icon},
text : false,
label : list[el].label
});
var id = list[el].id;
if( id != undefined )
button.attr('id',id);
var fun = list[el].callback;
button.click(fun);
span_group.append(button);
}
span_group.buttonset();
$(this.selector).append(span_group);
};
ToolBar.prototype.style = function () {
this.element.addClass('border-box-sizing').
addClass('ui-widget ui-widget-content').
addClass('ui-widget ui-widget-content toolbar').
css('border-top-style','none').
css('border-left-style','none').
css('border-right-style','none');
this.element.find('#cell_type').addClass('ui-widget ui-widget-content');
this.element.find('#save_b').button({
icons : {primary: 'ui-icon-disk'},
text : false
});
this.element.find('#cut_b').button({
icons: {primary: 'ui-icon-scissors'},
text : false
});
this.element.find('#copy_b').button({
icons: {primary: 'ui-icon-copy'},
text : false
});
this.element.find('#paste_b').button({
icons: {primary: 'ui-icon-clipboard'},
text : false
});
this.element.find('#cut_copy_paste').buttonset();
this.element.find('#move_up_b').button({
icons: {primary: 'ui-icon-arrowthick-1-n'},
text : false
});
this.element.find('#move_down_b').button({
icons: {primary: 'ui-icon-arrowthick-1-s'},
text : false
});
this.element.find('#move_up_down').buttonset();
this.element.find('#insert_above_b').button({
icons: {primary: 'ui-icon-arrowthickstop-1-n'},
text : false
});
this.element.find('#insert_below_b').button({
icons: {primary: 'ui-icon-arrowthickstop-1-s'},
text : false
});
this.element.find('#insert_above_below').buttonset();
this.element.find('#run_b').button({
icons: {primary: 'ui-icon-play'},
text : false
});
this.element.find('#interrupt_b').button({
icons: {primary: 'ui-icon-stop'},
text : false
});
this.element.find('#run_int').buttonset();
};
ToolBar.prototype.bind_events = function () {
var that = this;
this.element.find('#save_b').click(function () {
IPython.notebook.save_notebook();
});
this.element.find('#cut_b').click(function () {
IPython.notebook.cut_cell();
});
this.element.find('#copy_b').click(function () {
IPython.notebook.copy_cell();
});
this.element.find('#paste_b').click(function () {
IPython.notebook.paste_cell();
});
this.element.find('#move_up_b').click(function () {
IPython.notebook.move_cell_up();
});
this.element.find('#move_down_b').click(function () {
IPython.notebook.move_cell_down();
});
this.element.find('#insert_above_b').click(function () {
IPython.notebook.insert_cell_above('code');
});
this.element.find('#insert_below_b').click(function () {
IPython.notebook.insert_cell_below('code');
});
this.element.find('#run_b').click(function () {
IPython.notebook.execute_selected_cell();
});
this.element.find('#interrupt_b').click(function () {
IPython.notebook.kernel.interrupt();
});
this.element.find('#cell_type').change(function () {
var cell_type = $(this).val();
if (cell_type === 'code') {
IPython.notebook.to_code();
} else if (cell_type === 'markdown') {
IPython.notebook.to_markdown();
} else if (cell_type === 'raw') {
IPython.notebook.to_raw();
} else if (cell_type === 'heading1') {
IPython.notebook.to_heading(undefined, 1);
} else if (cell_type === 'heading2') {
IPython.notebook.to_heading(undefined, 2);
} else if (cell_type === 'heading3') {
IPython.notebook.to_heading(undefined, 3);
} else if (cell_type === 'heading4') {
IPython.notebook.to_heading(undefined, 4);
} else if (cell_type === 'heading5') {
IPython.notebook.to_heading(undefined, 5);
} else if (cell_type === 'heading6') {
IPython.notebook.to_heading(undefined, 6);
};
});
$([IPython.events]).on('selected_cell_type_changed.Notebook', 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);
}
});
};
ToolBar.prototype.toggle = function () {
this.element.toggle();
IPython.layout_manager.do_resize();
if (IPython.layout_manager != undefined) {
IPython.layout_manager.do_resize();
}
};

@ -104,13 +104,10 @@ var IPython = (function (IPython) {
// function that will be called if you press tab 1, 2, 3... times in a row
this.tabs_functions = [function (cell, text) {
that._request_tooltip(cell, text);
IPython.notification_widget.set_message('tab again to expand pager', 2500);
}, function () {
that.expand();
IPython.notification_widget.set_message('tab again to make pager sticky for 10s', 2500);
}, function () {
that.stick();
IPython.notification_widget.set_message('tab again to open help in pager', 2500);
}, function (cell) {
that.cancel_stick();
that.showInPager(cell);

@ -1,5 +1,5 @@
//----------------------------------------------------------------------------
// Copyright (C) 2008-2011 The IPython Development Team
// Copyright (C) 2008-2012 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.
@ -13,6 +13,123 @@ IPython.namespace('IPython.utils');
IPython.utils = (function (IPython) {
//============================================================================
// Cross-browser RegEx Split
//============================================================================
// This code has been MODIFIED from the code licensed below to not replace the
// default browser split. The license is reproduced here.
// see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
/*!
* Cross-Browser Split 1.1.1
* Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
* Available under the MIT License
* ECMAScript compliant, uniform cross-browser split method
*/
/**
* Splits a string into an array of strings using a regex or string
* separator. Matches of the separator are not included in the result array.
* However, if `separator` is a regex that contains capturing groups,
* backreferences are spliced into the result each time `separator` is
* matched. Fixes browser bugs compared to the native
* `String.prototype.split` and can be used reliably cross-browser.
* @param {String} str String to split.
* @param {RegExp|String} separator Regex or string to use for separating
* the string.
* @param {Number} [limit] Maximum number of items to include in the result
* array.
* @returns {Array} Array of substrings.
* @example
*
* // Basic use
* regex_split('a b c d', ' ');
* // -> ['a', 'b', 'c', 'd']
*
* // With limit
* regex_split('a b c d', ' ', 2);
* // -> ['a', 'b']
*
* // Backreferences in result array
* regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
* // -> ['..', 'word', '1', ' ', 'word', '2', '..']
*/
var regex_split = function (str, separator, limit) {
// If `separator` is not a regex, use `split`
if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
return split.call(str, separator, limit);
}
var output = [],
flags = (separator.ignoreCase ? "i" : "") +
(separator.multiline ? "m" : "") +
(separator.extended ? "x" : "") + // Proposed for ES6
(separator.sticky ? "y" : ""), // Firefox 3+
lastLastIndex = 0,
// Make `global` and avoid `lastIndex` issues by working with a copy
separator = new RegExp(separator.source, flags + "g"),
separator2, match, lastIndex, lastLength;
str += ""; // Type-convert
compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined"
if (!compliantExecNpcg) {
// Doesn't need flags gy, but they don't hurt
separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
}
/* Values for `limit`, per the spec:
* If undefined: 4294967295 // Math.pow(2, 32) - 1
* If 0, Infinity, or NaN: 0
* If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
* If negative number: 4294967296 - Math.floor(Math.abs(limit))
* If other: Type-convert, then use the above rules
*/
limit = typeof(limit) === "undefined" ?
-1 >>> 0 : // Math.pow(2, 32) - 1
limit >>> 0; // ToUint32(limit)
while (match = separator.exec(str)) {
// `separator.lastIndex` is not reliable cross-browser
lastIndex = match.index + match[0].length;
if (lastIndex > lastLastIndex) {
output.push(str.slice(lastLastIndex, match.index));
// Fix browsers whose `exec` methods don't consistently return `undefined` for
// nonparticipating capturing groups
if (!compliantExecNpcg && match.length > 1) {
match[0].replace(separator2, function () {
for (var i = 1; i < arguments.length - 2; i++) {
if (typeof(arguments[i]) === "undefined") {
match[i] = undefined;
}
}
});
}
if (match.length > 1 && match.index < str.length) {
Array.prototype.push.apply(output, match.slice(1));
}
lastLength = match[0].length;
lastLastIndex = lastIndex;
if (output.length >= limit) {
break;
}
}
if (separator.lastIndex === match.index) {
separator.lastIndex++; // Avoid an infinite loop
}
}
if (lastLastIndex === str.length) {
if (lastLength || !separator.test("")) {
output.push("");
}
} else {
output.push(str.slice(lastLastIndex));
}
return output.length > limit ? output.slice(0, limit) : output;
};
//============================================================================
// End contributed Cross-browser RegEx Split
//============================================================================
var uuid = function () {
// http://www.ietf.org/rfc/rfc4122.txt
var s = [];
@ -78,11 +195,30 @@ IPython.utils = (function (IPython) {
tmp = txt;
do {
txt = tmp;
tmp = txt.replace(/^.*\r(?!\n)/gm, '');
tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line
} while (tmp.length < txt.length);
return txt;
}
// Locate URLs in plain text and wrap them in spaces so that they can be
// better picked out by autoLinkUrls even after the text has been
// converted to HTML
function wrapUrls(txt) {
// Note this regexp is a modified version of one from
// Markdown.Converter For now it only supports http(s) and ftp URLs,
// but could easily support others (though file:// should maybe be
// avoided)
var url_re = /(^|\W)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi;
return txt.replace(url_re, "$1 $2$3 $4");
}
// Locate a URL with spaces around it and convert that to a anchor tag
function autoLinkUrls(txt) {
return txt.replace(/ ((https?|ftp):[^'">\s]+) /gi,
"<a target=\"_blank\" href=\"$1\">$1</a>");
}
grow = function(element) {
// Grow the cell by hand. This is used upon reloading from JSON, when the
// autogrow handler is not called.
@ -138,11 +274,14 @@ IPython.utils = (function (IPython) {
return {
regex_split : regex_split,
uuid : uuid,
fixConsole : fixConsole,
keycodes : keycodes,
grow : grow,
fixCarriageReturn : fixCarriageReturn,
wrapUrls : wrapUrls,
autoLinkUrls : autoLinkUrls,
points_to_pixels : points_to_pixels
};

@ -3,7 +3,7 @@
{% block stylesheet %}
{% if mathjax_url %}
<script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
<script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
{% endif %}
<script type="text/javascript">
// MathJax disabled, set as null to distingish from *missing* MathJax,
@ -74,9 +74,9 @@ data-notebook-id={{notebook_id}}
<ul>
<li id="cut_cell"><a href="#">Cut Cell</a></li>
<li id="copy_cell"><a href="#">Copy Cell</a></li>
<li id="paste_cell" class="ui-state-disabled"><a href="#">Paste Cell</a></li>
<li id="paste_cell_above" class="ui-state-disabled"><a href="#">Paste Cell Above</a></li>
<li id="paste_cell_below" class="ui-state-disabled"><a href="#">Paste Cell Below</a></li>
<li id="paste_cell_replace" class="ui-state-disabled"><a href="#">Paste Cell &amp; Replace</a></li>
<li id="delete_cell"><a href="#">Delete</a></li>
<hr/>
<li id="split_cell"><a href="#">Split Cell</a></li>
@ -107,6 +107,8 @@ data-notebook-id={{notebook_id}}
<li id="run_cell"><a href="#">Run</a></li>
<li id="run_cell_in_place"><a href="#">Run in Place</a></li>
<li id="run_all_cells"><a href="#">Run All</a></li>
<li id="run_all_cells_above"><a href="#">Run All Above</a></li>
<li id="run_all_cells_below"><a href="#">Run All Below</a></li>
<hr/>
<li id="to_code"><a href="#">Code</a></li>
<li id="to_markdown"><a href="#">Markdown </a></li>
@ -156,54 +158,22 @@ data-notebook-id={{notebook_id}}
</div>
<div id="toolbar">
<span>
<button id="save_b">Save</button>
</span>
<span id="cut_copy_paste">
<button id="cut_b" title="Cut Cell">Cut Cell</button>
<button id="copy_b" title="Copy Cell">Copy Cell</button>
<button id="paste_b" title="Paste Cell">Paste Cell</button>
</span>
<span id="move_up_down">
<button id="move_up_b" title="Move Cell Up">Move Cell Up</button>
<button id="move_down_b" title="Move Cell Down">Move Down</button>
</span>
<span id="insert_above_below">
<button id="insert_above_b" title="Insert Cell Above">Insert Cell Above</button>
<button id="insert_below_b" title="Insert Cell Below">Insert Cell Below</button>
</span>
<span id="run_int">
<button id="run_b" title="Run Cell">Run Cell</button>
<button id="interrupt_b" title="Interrupt">Interrupt</button>
</span>
<span>
<select id="cell_type">
<option value="code">Code</option>
<option value="markdown">Markdown</option>
<option value="raw">Raw Text</option>
<option value="heading1">Heading 1</option>
<option value="heading2">Heading 2</option>
<option value="heading3">Heading 3</option>
<option value="heading4">Heading 4</option>
<option value="heading5">Heading 5</option>
<option value="heading6">Heading 6</option>
</select>
</span>
</div>
<div id="maintoolbar"></div>
<div id="main_app">
<div id="notebook_panel">
<div id="notebook"></div>
<div id="pager_splitter"></div>
<div id="pager"></div>
<div id="pager_container">
<div id='pager_button_area'>
</div>
<div id="pager"></div>
</div>
</div>
</div>
<div id='tooltip' class='tooltip ui-corner-all' style='display:none'></div>
<div id='tooltip' class='ipython_tooltip ui-corner-all' style='display:none'></div>
{% endblock %}
@ -212,6 +182,8 @@ data-notebook-id={{notebook_id}}
{% block script %}
<script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
<script src="{{ static_url("codemirror/lib/util/loadmode.js") }}" charset="utf-8"></script>
<script src="{{ static_url("codemirror/lib/util/multiplex.js") }}" charset="utf-8"></script>
<script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
<script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
<script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
@ -228,7 +200,7 @@ data-notebook-id={{notebook_id}}
<script src="{{ static_url("js/events.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/initmathjax.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
@ -240,10 +212,12 @@ data-notebook-id={{notebook_id}}
<script src="{{ static_url("js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/config.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/notebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("js/contexthint.js") }}" charset="utf-8"></script>

@ -28,7 +28,7 @@
<body {% block params %}{% endblock %}>
<div id="header">
<span id="ipython_notebook"><h1><a href={{base_project_url}} alt='dashboard'><img src='{{static_url("ipynblogo.png") }}' alt='IPython Notebook'/></a></h1></span>
<span id="ipython_notebook"><div><a href={{base_project_url}} alt='dashboard'><img src='{{static_url("ipynblogo.png") }}' alt='IPython Notebook'/></a></div></span>
{% block login_widget %}

@ -396,6 +396,8 @@ class IPTester(object):
"""Run the stored commands"""
try:
retcode = self._run_cmd()
except KeyboardInterrupt:
return -signal.SIGINT
except:
import traceback
traceback.print_exc()
@ -412,17 +414,22 @@ class IPTester(object):
continue # process is already dead
try:
print('Cleaning stale PID: %d' % subp.pid)
print('Cleaning up stale PID: %d' % subp.pid)
subp.kill()
except: # (OSError, WindowsError) ?
# This is just a best effort, if we fail or the process was
# really gone, ignore it.
pass
else:
for i in range(10):
if subp.poll() is None:
time.sleep(0.1)
else:
break
if subp.poll() is None:
# The process did not die...
print('... failed. Manual cleanup may be required.'
% subp.pid)
print('... failed. Manual cleanup may be required.')
def make_runners(inc_slow=False):
"""Define the top-level packages that need to be tested.
@ -476,6 +483,8 @@ def run_iptest():
# setuptools devs refuse to fix this problem!
'--exe',
]
if '-a' not in argv and '-A' not in argv:
argv = argv + ['-a', '!crash']
if nose.__version__ >= '0.11':
# I don't fully understand why we need this one, but depending on what
@ -533,6 +542,9 @@ def run_iptestall(inc_slow=False):
res = runner.run()
if res:
failed.append( (name, runner) )
if res == -signal.SIGINT:
print("Interrupted")
break
finally:
os.chdir(curdir)
t_end = time.time()

@ -0,0 +1,259 @@
{
"metadata": {
"name": "Typesetting Math Using MathJax"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The Markdown parser included in IPython is MathJax-aware. This means that you can freely mix in mathematical expressions using the [MathJax subset of Tex and LaTeX](http://docs.mathjax.org/en/latest/tex.html#tex-support). [Some examples from the MathJax site](http://www.mathjax.org/demos/tex-samples/) are reproduced below, as well as the Markdown+TeX source."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Motivating Examples\n",
"\n",
"---\n",
"\n",
"## The Lorenz Equations\n",
"### Source\n",
"```\\begin{aligned}\n",
"\\dot{x} & = \\sigma(y-x) \\\\\n",
"\\dot{y} & = \\rho x - y - xz \\\\\n",
"\\dot{z} & = -\\beta z + xy\n",
"\\end{aligned}\n",
"```\n",
"### Display\n",
"\\begin{aligned}\n",
"\\dot{x} & = \\sigma(y-x) \\\\\n",
"\\dot{y} & = \\rho x - y - xz \\\\\n",
"\\dot{z} & = -\\beta z + xy\n",
"\\end{aligned}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The Cauchy-Schwarz Inequality\n",
"### Source\n",
"```\\begin{equation*}\n",
"\\left( \\sum_{k=1}^n a_k b_k \\right)^2 \\leq \\left( \\sum_{k=1}^n a_k^2 \\right) \\left( \\sum_{k=1}^n b_k^2 \\right)\n",
"\\end{equation*}\n",
"```\n",
"### Display\n",
"\\begin{equation*}\n",
"\\left( \\sum_{k=1}^n a_k b_k \\right)^2 \\leq \\left( \\sum_{k=1}^n a_k^2 \\right) \\left( \\sum_{k=1}^n b_k^2 \\right)\n",
"\\end{equation*}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A Cross Product Formula\n",
"### Source\n",
"```\\begin{equation*}\n",
"\\mathbf{V}_1 \\times \\mathbf{V}_2 = \\begin{vmatrix}\n",
"\\mathbf{i} & \\mathbf{j} & \\mathbf{k} \\\\\n",
"\\frac{\\partial X}{\\partial u} & \\frac{\\partial Y}{\\partial u} & 0 \\\\\n",
"\\frac{\\partial X}{\\partial v} & \\frac{\\partial Y}{\\partial v} & 0\n",
"\\end{vmatrix} \n",
"\\end{equation*}\n",
"```\n",
"### Display\n",
"\\begin{equation*}\n",
"\\mathbf{V}_1 \\times \\mathbf{V}_2 = \\begin{vmatrix}\n",
"\\mathbf{i} & \\mathbf{j} & \\mathbf{k} \\\\\n",
"\\frac{\\partial X}{\\partial u} & \\frac{\\partial Y}{\\partial u} & 0 \\\\\n",
"\\frac{\\partial X}{\\partial v} & \\frac{\\partial Y}{\\partial v} & 0\n",
"\\end{vmatrix} \n",
"\\end{equation*}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The probability of getting \\(k\\) heads when flipping \\(n\\) coins is\n",
"### Source\n",
"```\\begin{equation*}\n",
"P(E) = {n \\choose k} p^k (1-p)^{ n-k} \n",
"\\end{equation*}\n",
"```\n",
"### Display\n",
"\\begin{equation*}\n",
"P(E) = {n \\choose k} p^k (1-p)^{ n-k} \n",
"\\end{equation*}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## An Identity of Ramanujan\n",
"### Source\n",
"```\\begin{equation*}\n",
"\\frac{1}{\\Bigl(\\sqrt{\\phi \\sqrt{5}}-\\phi\\Bigr) e^{\\frac25 \\pi}} =\n",
"1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} {1+\\frac{e^{-6\\pi}}\n",
"{1+\\frac{e^{-8\\pi}} {1+\\ldots} } } } \n",
"\\end{equation*}\n",
"```\n",
"### Display\n",
"\\begin{equation*}\n",
"\\frac{1}{\\Bigl(\\sqrt{\\phi \\sqrt{5}}-\\phi\\Bigr) e^{\\frac25 \\pi}} =\n",
"1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} {1+\\frac{e^{-6\\pi}}\n",
"{1+\\frac{e^{-8\\pi}} {1+\\ldots} } } } \n",
"\\end{equation*}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A Rogers-Ramanujan Identity\n",
"### Source\n",
"```\\begin{equation*}\n",
"1 + \\frac{q^2}{(1-q)}+\\frac{q^6}{(1-q)(1-q^2)}+\\cdots =\n",
"\\prod_{j=0}^{\\infty}\\frac{1}{(1-q^{5j+2})(1-q^{5j+3})},\n",
"\\quad\\quad \\text{for $|q|<1$}. \n",
"\\end{equation*}\n",
"```\n",
"### Display\n",
"\\begin{equation*}\n",
"1 + \\frac{q^2}{(1-q)}+\\frac{q^6}{(1-q)(1-q^2)}+\\cdots =\n",
"\\prod_{j=0}^{\\infty}\\frac{1}{(1-q^{5j+2})(1-q^{5j+3})},\n",
"\\quad\\quad \\text{for $|q|<1$}. \n",
"\\end{equation*}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Maxwell's Equations\n",
"### Source\n",
"```\\begin{aligned}\n",
"\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} & = \\frac{4\\pi}{c}\\vec{\\mathbf{j}} \\\\ \\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\\n",
"\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\\n",
"\\nabla \\cdot \\vec{\\mathbf{B}} & = 0 \n",
"\\end{aligned}\n",
"```\n",
"### Display\n",
"\\begin{aligned}\n",
"\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} & = \\frac{4\\pi}{c}\\vec{\\mathbf{j}} \\\\ \\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\\n",
"\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\\n",
"\\nabla \\cdot \\vec{\\mathbf{B}} & = 0 \n",
"\\end{aligned}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Equation Numbering and References\n",
"\n",
"---\n",
"\n",
"Equation numbering and referencing will be available in a future version of IPython."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Inline Typesetting (Mixing Markdown and TeX)\n",
"\n",
"---\n",
"\n",
"While display equations look good for a page of samples, the ability to mix math and *formatted* **text** in a paragraph is also important.\n",
"\n",
"## Source\n",
"``` This expression $\\sqrt{3x-1}+(1+x)^2$ is an example of a TeX inline equation in a **[Markdown-formatted](http://daringfireball.net/projects/markdown/)** sentence. \n",
"```\n",
"## Display\n",
"This expression $\\sqrt{3x-1}+(1+x)^2$ is an example of a TeX inline equation in a **[Markdown-formatted](http://daringfireball.net/projects/markdown/)** sentence. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Other Syntax\n",
"\n",
"---\n",
"\n",
"You will notice in other places on the web that `$$` are needed explicitly to begin and end MathJax typesetting. This is **not** required if you will be using TeX environments, but the IPython notebook will accept this syntax on legacy notebooks. \n",
"\n",
"### Source\n",
"```$$\n",
"\\begin{array}{c}\n",
"y_1 \\\\\\\n",
"y_2 \\mathtt{t}_i \\\\\\\n",
"z_{3,4}\n",
"\\end{array}\n",
"$$\n",
"```\n",
"\n",
"```\n",
"$$\n",
"\\begin{array}{c}\n",
"y_1 \\cr\n",
"y_2 \\mathtt{t}_i \\cr\n",
"y_{3}\n",
"\\end{array}\n",
"$$\n",
"```\n",
"\n",
"```\n",
"$$\\begin{eqnarray} \n",
"x' &=& &x \\sin\\phi &+& z \\cos\\phi \\\\\n",
"z' &=& - &x \\cos\\phi &+& z \\sin\\phi \\\\\n",
"\\end{eqnarray}$$\n",
"```\n",
"\n",
"```\n",
"$$\n",
"x=4\n",
"$$\n",
"```\n",
"\n",
"### Display\n",
"$$\n",
"\\begin{array}{c}\n",
"y_1 \\\\\\\n",
"y_2 \\mathtt{t}_i \\\\\\\n",
"z_{3,4}\n",
"\\end{array}\n",
"$$\n",
"\n",
"$$\n",
"\\begin{array}{c}\n",
"y_1 \\cr\n",
"y_2 \\mathtt{t}_i \\cr\n",
"y_{3}\n",
"\\end{array}\n",
"$$\n",
"\n",
"$$\\begin{eqnarray} \n",
"x' &=& &x \\sin\\phi &+& z \\cos\\phi \\\\\n",
"z' &=& - &x \\cos\\phi &+& z \\sin\\phi \\\\\n",
"\\end{eqnarray}$$\n",
"\n",
"$$\n",
"x=4\n",
"$$"
]
}
],
"metadata": {}
}
]
}

@ -230,6 +230,7 @@ if 'setuptools' in sys.modules:
setuptools_extra_args['entry_points'] = find_scripts(True)
setup_args['extras_require'] = dict(
parallel = 'pyzmq>=2.1.4',
qtconsole = 'pygments',
zmq = 'pyzmq>=2.1.4',
doc = 'Sphinx>=0.3',
test = 'nose>=0.10.1',

@ -204,12 +204,12 @@ def find_data_files():
manpagebase = pjoin('share', 'man', 'man1')
# Simple file lists can be made by hand
manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
if not manpages:
# When running from a source tree, the manpages aren't gzipped
manpages = filter(isfile, glob(pjoin('docs','man','*.1')))
igridhelpfiles = filter(isfile,
glob(pjoin('IPython','extensions','igrid_help.*')))
manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
igridhelpfiles = [f for f in glob(pjoin('IPython','extensions','igrid_help.*')) if isfile(f)]
# For nested structures, use the utility above
example_files = make_dir_struct(

Loading…
Cancel
Save