diff --git a/IPython/frontend/html/notebook/static/js/mathjaxutils.js b/IPython/frontend/html/notebook/static/js/mathjaxutils.js new file mode 100644 index 000000000..8eeeb7fb5 --- /dev/null +++ b/IPython/frontend/html/notebook/static/js/mathjaxutils.js @@ -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 = $('
') + .append( + $("").addClass('dialog').html( + "Math/LaTeX rendering will be disabled." + ) + ).append( + $("").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( + $("").addClass('dialog').html( + ">>> from IPython.external import mathjax; mathjax.install_mathjax()" + ) + ).append( + $("").addClass('dialog').html( + "This will try to install MathJax into the IPython source directory." + ) + ).append( + $("").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( + $("").addClass('dialog').html( + "When you start the notebook server, you can instruct it to disable MathJax support altogether:" + ) + ).append( + $("").addClass('dialog').html( + "$ ipython notebook --no-mathjax" + ) + ).append( + $("").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$foo ` and `$bar 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));
\ No newline at end of file
diff --git a/IPython/frontend/html/notebook/static/js/notebookmain.js b/IPython/frontend/html/notebook/static/js/notebookmain.js
index a7d7d4362..13059fc0e 100644
--- a/IPython/frontend/html/notebook/static/js/notebookmain.js
+++ b/IPython/frontend/html/notebook/static/js/notebookmain.js
@@ -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');
diff --git a/IPython/frontend/html/notebook/static/js/textcell.js b/IPython/frontend/html/notebook/static/js/textcell.js
index 14704d10c..54bc5a3b9 100644
--- a/IPython/frontend/html/notebook/static/js/textcell.js
+++ b/IPython/frontend/html/notebook/static/js/textcell.js
@@ -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) {
diff --git a/IPython/frontend/html/notebook/static/js/utils.js b/IPython/frontend/html/notebook/static/js/utils.js
index 9dfa47842..d38d6da06 100644
--- a/IPython/frontend/html/notebook/static/js/utils.js
+++ b/IPython/frontend/html/notebook/static/js/utils.js
@@ -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