partial refactor, can't quite get environments working

Aron Ahmadia 13 years ago
parent bcdec179f8
commit 0caac8cd28

@ -0,0 +1,230 @@
//----------------------------------------------------------------------------
// 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({
TeX: { equationNumbers: { autoNumber: "AMS", useLabelIds: true },
extensions: ["autoload-all.js"] },
tex2jax: {
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
processEnvironments: true
},
displayAlign: 'left', // Change this to 'center' to center equations.
"HTML-CSS": {
styles: {'.MathJax_Display': {"margin": 0}}
}
});
} 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
// Some of the code here is adapted with permission from Stack Exchange Inc.
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
var HUB = MathJax.Hub;
// 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
function processMath(i, j, preProcess) {
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 (preProcess)
block = preProcess(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).
//
function removeMath(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),
deTilde;
if (hasCodeSpans) {
text = text.replace(/~/g, "~T").replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, function (wholematch) {
return wholematch.replace(/\$/g, "~D");
});
deTilde = function (text) { return text.replace(/~([TD])/g, function (wholematch, character) { return { T: "~", D: "$" }[character]; }) };
} else {
deTilde = 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 {
processMath(start, i, deTilde)
}
}
else if (block.match(/\n.*\n/)) {
if (last) {
i = last;
processMath(start, i, deTilde)
}
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) {
processMath(start, last, deTilde)
}
return deTilde(blocks.join(""));
}
//
// Put back the math strings that were saved,
// and clear the math array (no need to keep it around).
//
function replaceMath(text) {
text = text.replace(/@@(\d+)@@/g, function (match, n) {
return math[n]
});
math = null;
return text;
}
return {
init : init,
processMath : processMath,
removeMath : removeMath,
replaceMath : replaceMath,
};
}(IPython));

@ -31,7 +31,7 @@ $(document).ready(function () {
}
// end monkey patching CodeMirror
IPython.init_mathjax();
IPython.mathjaxutils.init();
IPython.read_only = $('body').data('readOnly') === 'True';
$('div#main_app').addClass('border-box-sizing ui-widget');

@ -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,11 @@ var IPython = (function (IPython) {
if (this.rendered === false) {
var text = this.get_text();
if (text === "") { text = this.placeholder; }
text = IPython.mathjaxutils.removeMath(text)
var html = IPython.markdown_converter.makeHtml(text);
html = IPython.mathjaxutils.replaceMath(html)
try {
this.set_rendered(html);
} catch (e) {

@ -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 = [];
@ -138,6 +255,7 @@ IPython.utils = (function (IPython) {
return {
regex_split : regex_split,
uuid : uuid,
fixConsole : fixConsole,
keycodes : keycodes,

@ -199,7 +199,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>

Loading…
Cancel
Save