##// END OF EJS Templates
don't require mathjax on the page in mathjax utils...
MinRK -
Show More
@@ -1,259 +1,251 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2012 The IPython Development Team
2 // Copyright (C) 2008-2012 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // MathJax utility functions
9 // MathJax utility functions
10 //============================================================================
10 //============================================================================
11
11
12
12
13 IPython.namespace('IPython.mathjaxutils');
13 IPython.namespace('IPython.mathjaxutils');
14
14
15 IPython.mathjaxutils = (function (IPython) {
15 IPython.mathjaxutils = (function (IPython) {
16 "use strict";
16 "use strict";
17
17
18 var init = function () {
18 var init = function () {
19 if (window.MathJax) {
19 if (window.MathJax) {
20 // MathJax loaded
20 // MathJax loaded
21 MathJax.Hub.Config({
21 MathJax.Hub.Config({
22 tex2jax: {
22 tex2jax: {
23 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
23 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
24 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
24 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
25 processEscapes: true,
25 processEscapes: true,
26 processEnvironments: true
26 processEnvironments: true
27 },
27 },
28 // Center justify equations in code and markdown cells. Elsewhere
28 // Center justify equations in code and markdown cells. Elsewhere
29 // we use CSS to left justify single line equations in code cells.
29 // we use CSS to left justify single line equations in code cells.
30 displayAlign: 'center',
30 displayAlign: 'center',
31 "HTML-CSS": {
31 "HTML-CSS": {
32 styles: {'.MathJax_Display': {"margin": 0}},
32 styles: {'.MathJax_Display': {"margin": 0}},
33 linebreaks: { automatic: true }
33 linebreaks: { automatic: true }
34 }
34 }
35 });
35 });
36 MathJax.Hub.Configured();
36 MathJax.Hub.Configured();
37 } else if (window.mathjax_url !== "") {
37 } else if (window.mathjax_url !== "") {
38 // Don't have MathJax, but should. Show dialog.
38 // Don't have MathJax, but should. Show dialog.
39 var message = $('<div/>')
39 var message = $('<div/>')
40 .append(
40 .append(
41 $("<p/></p>").addClass('dialog').html(
41 $("<p/></p>").addClass('dialog').html(
42 "Math/LaTeX rendering will be disabled."
42 "Math/LaTeX rendering will be disabled."
43 )
43 )
44 ).append(
44 ).append(
45 $("<p></p>").addClass('dialog').html(
45 $("<p></p>").addClass('dialog').html(
46 "If you have administrative access to the notebook server and" +
46 "If you have administrative access to the notebook server and" +
47 " a working internet connection, you can install a local copy" +
47 " a working internet connection, you can install a local copy" +
48 " of MathJax for offline use with the following command on the server" +
48 " of MathJax for offline use with the following command on the server" +
49 " at a Python or IPython prompt:"
49 " at a Python or IPython prompt:"
50 )
50 )
51 ).append(
51 ).append(
52 $("<pre></pre>").addClass('dialog').html(
52 $("<pre></pre>").addClass('dialog').html(
53 ">>> from IPython.external import mathjax; mathjax.install_mathjax()"
53 ">>> from IPython.external import mathjax; mathjax.install_mathjax()"
54 )
54 )
55 ).append(
55 ).append(
56 $("<p></p>").addClass('dialog').html(
56 $("<p></p>").addClass('dialog').html(
57 "This will try to install MathJax into the IPython source directory."
57 "This will try to install MathJax into the IPython source directory."
58 )
58 )
59 ).append(
59 ).append(
60 $("<p></p>").addClass('dialog').html(
60 $("<p></p>").addClass('dialog').html(
61 "If IPython is installed to a location that requires" +
61 "If IPython is installed to a location that requires" +
62 " administrative privileges to write, you will need to make this call as" +
62 " administrative privileges to write, you will need to make this call as" +
63 " an administrator, via 'sudo'."
63 " an administrator, via 'sudo'."
64 )
64 )
65 ).append(
65 ).append(
66 $("<p></p>").addClass('dialog').html(
66 $("<p></p>").addClass('dialog').html(
67 "When you start the notebook server, you can instruct it to disable MathJax support altogether:"
67 "When you start the notebook server, you can instruct it to disable MathJax support altogether:"
68 )
68 )
69 ).append(
69 ).append(
70 $("<pre></pre>").addClass('dialog').html(
70 $("<pre></pre>").addClass('dialog').html(
71 "$ ipython notebook --no-mathjax"
71 "$ ipython notebook --no-mathjax"
72 )
72 )
73 ).append(
73 ).append(
74 $("<p></p>").addClass('dialog').html(
74 $("<p></p>").addClass('dialog').html(
75 "which will prevent this dialog from appearing."
75 "which will prevent this dialog from appearing."
76 )
76 )
77 );
77 );
78 IPython.dialog.modal({
78 IPython.dialog.modal({
79 title : "Failed to retrieve MathJax from '" + window.mathjax_url + "'",
79 title : "Failed to retrieve MathJax from '" + window.mathjax_url + "'",
80 body : message,
80 body : message,
81 buttons : {
81 buttons : {
82 OK : {class: "btn-danger"}
82 OK : {class: "btn-danger"}
83 }
83 }
84 });
84 });
85 }
85 }
86 };
86 };
87
87
88 // Some magic for deferring mathematical expressions to MathJax
88 // Some magic for deferring mathematical expressions to MathJax
89 // by hiding them from the Markdown parser.
89 // by hiding them from the Markdown parser.
90 // Some of the code here is adapted with permission from Davide Cervone
90 // Some of the code here is adapted with permission from Davide Cervone
91 // under the terms of the Apache2 license governing the MathJax project.
91 // under the terms of the Apache2 license governing the MathJax project.
92 // Other minor modifications are also due to StackExchange and are used with
92 // Other minor modifications are also due to StackExchange and are used with
93 // permission.
93 // permission.
94
94
95 var inline = "$"; // the inline math delimiter
95 var inline = "$"; // the inline math delimiter
96
96
97 // MATHSPLIT contains the pattern for math delimiters and special symbols
97 // MATHSPLIT contains the pattern for math delimiters and special symbols
98 // needed for searching for math in the text input.
98 // needed for searching for math in the text input.
99 var MATHSPLIT = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i;
99 var MATHSPLIT = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i;
100
100
101 // The math is in blocks i through j, so
101 // The math is in blocks i through j, so
102 // collect it into one block and clear the others.
102 // collect it into one block and clear the others.
103 // Replace &, <, and > by named entities.
103 // Replace &, <, and > by named entities.
104 // For IE, put <br> at the ends of comments since IE removes \n.
104 // For IE, put <br> at the ends of comments since IE removes \n.
105 // Clear the current math positions and store the index of the
105 // Clear the current math positions and store the index of the
106 // math, then push the math string onto the storage array.
106 // math, then push the math string onto the storage array.
107 // The preProcess function is called on all blocks if it has been passed in
107 // The preProcess function is called on all blocks if it has been passed in
108 var process_math = function (i, j, pre_process, math, blocks) {
108 var process_math = function (i, j, pre_process, math, blocks) {
109 var hub = MathJax.Hub;
110 var block = blocks.slice(i, j + 1).join("").replace(/&/g, "&amp;") // use HTML entity for &
109 var block = blocks.slice(i, j + 1).join("").replace(/&/g, "&amp;") // use HTML entity for &
111 .replace(/</g, "&lt;") // use HTML entity for <
110 .replace(/</g, "&lt;") // use HTML entity for <
112 .replace(/>/g, "&gt;") // use HTML entity for >
111 .replace(/>/g, "&gt;") // use HTML entity for >
113 ;
112 ;
114 if (hub.Browser.isMSIE) {
113 if (IPython.utils.browser === 'msie') {
115 block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n");
114 block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n");
116 }
115 }
117 while (j > i) {
116 while (j > i) {
118 blocks[j] = "";
117 blocks[j] = "";
119 j--;
118 j--;
120 }
119 }
121 blocks[i] = "@@" + math.length + "@@"; // replace the current block text with a unique tag to find later
120 blocks[i] = "@@" + math.length + "@@"; // replace the current block text with a unique tag to find later
122 if (pre_process){
121 if (pre_process){
123 block = pre_process(block);
122 block = pre_process(block);
124 }
123 }
125 math.push(block);
124 math.push(block);
126 return blocks;
125 return blocks;
127 };
126 };
128
127
129 // Break up the text into its component parts and search
128 // Break up the text into its component parts and search
130 // through them for math delimiters, braces, linebreaks, etc.
129 // through them for math delimiters, braces, linebreaks, etc.
131 // Math delimiters must match and braces must balance.
130 // Math delimiters must match and braces must balance.
132 // Don't allow math to pass through a double linebreak
131 // Don't allow math to pass through a double linebreak
133 // (which will be a paragraph).
132 // (which will be a paragraph).
134 //
133 //
135 var remove_math = function (text) {
134 var remove_math = function (text) {
136 if (!window.MathJax) {
137 return [text, null];
138 }
139
140 var math = []; // stores math strings for later
135 var math = []; // stores math strings for later
141 var start;
136 var start;
142 var end;
137 var end;
143 var last;
138 var last;
144 var braces;
139 var braces;
145
140
146 // Except for extreme edge cases, this should catch precisely those pieces of the markdown
141 // Except for extreme edge cases, this should catch precisely those pieces of the markdown
147 // source that will later be turned into code spans. While MathJax will not TeXify code spans,
142 // source that will later be turned into code spans. While MathJax will not TeXify code spans,
148 // we still have to consider them at this point; the following issue has happened several times:
143 // we still have to consider them at this point; the following issue has happened several times:
149 //
144 //
150 // `$foo` and `$bar` are varibales. --> <code>$foo ` and `$bar</code> are variables.
145 // `$foo` and `$bar` are varibales. --> <code>$foo ` and `$bar</code> are variables.
151
146
152 var hasCodeSpans = /`/.test(text),
147 var hasCodeSpans = /`/.test(text),
153 de_tilde;
148 de_tilde;
154 if (hasCodeSpans) {
149 if (hasCodeSpans) {
155 text = text.replace(/~/g, "~T").replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, function (wholematch) {
150 text = text.replace(/~/g, "~T").replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, function (wholematch) {
156 return wholematch.replace(/\$/g, "~D");
151 return wholematch.replace(/\$/g, "~D");
157 });
152 });
158 de_tilde = function (text) {
153 de_tilde = function (text) {
159 return text.replace(/~([TD])/g, function (wholematch, character) {
154 return text.replace(/~([TD])/g, function (wholematch, character) {
160 return { T: "~", D: "$" }[character];
155 return { T: "~", D: "$" }[character];
161 });
156 });
162 };
157 };
163 } else {
158 } else {
164 de_tilde = function (text) { return text; };
159 de_tilde = function (text) { return text; };
165 }
160 }
166
161
167 var blocks = IPython.utils.regex_split(text.replace(/\r\n?/g, "\n"),MATHSPLIT);
162 var blocks = IPython.utils.regex_split(text.replace(/\r\n?/g, "\n"),MATHSPLIT);
168
163
169 for (var i = 1, m = blocks.length; i < m; i += 2) {
164 for (var i = 1, m = blocks.length; i < m; i += 2) {
170 var block = blocks[i];
165 var block = blocks[i];
171 if (block.charAt(0) === "@") {
166 if (block.charAt(0) === "@") {
172 //
167 //
173 // Things that look like our math markers will get
168 // Things that look like our math markers will get
174 // stored and then retrieved along with the math.
169 // stored and then retrieved along with the math.
175 //
170 //
176 blocks[i] = "@@" + math.length + "@@";
171 blocks[i] = "@@" + math.length + "@@";
177 math.push(block);
172 math.push(block);
178 }
173 }
179 else if (start) {
174 else if (start) {
180 //
175 //
181 // If we are in math, look for the end delimiter,
176 // If we are in math, look for the end delimiter,
182 // but don't go past double line breaks, and
177 // but don't go past double line breaks, and
183 // and balance braces within the math.
178 // and balance braces within the math.
184 //
179 //
185 if (block === end) {
180 if (block === end) {
186 if (braces) {
181 if (braces) {
187 last = i;
182 last = i;
188 }
183 }
189 else {
184 else {
190 blocks = process_math(start, i, de_tilde, math, blocks);
185 blocks = process_math(start, i, de_tilde, math, blocks);
191 start = null;
186 start = null;
192 end = null;
187 end = null;
193 last = null;
188 last = null;
194 }
189 }
195 }
190 }
196 else if (block.match(/\n.*\n/)) {
191 else if (block.match(/\n.*\n/)) {
197 if (last) {
192 if (last) {
198 i = last;
193 i = last;
199 blocks = process_math(start, i, de_tilde, math, blocks);
194 blocks = process_math(start, i, de_tilde, math, blocks);
200 }
195 }
201 start = null;
196 start = null;
202 end = null;
197 end = null;
203 last = null;
198 last = null;
204 braces = 0;
199 braces = 0;
205 }
200 }
206 else if (block === "{") {
201 else if (block === "{") {
207 braces++;
202 braces++;
208 }
203 }
209 else if (block === "}" && braces) {
204 else if (block === "}" && braces) {
210 braces--;
205 braces--;
211 }
206 }
212 }
207 }
213 else {
208 else {
214 //
209 //
215 // Look for math start delimiters and when
210 // Look for math start delimiters and when
216 // found, set up the end delimiter.
211 // found, set up the end delimiter.
217 //
212 //
218 if (block === inline || block === "$$") {
213 if (block === inline || block === "$$") {
219 start = i;
214 start = i;
220 end = block;
215 end = block;
221 braces = 0;
216 braces = 0;
222 }
217 }
223 else if (block.substr(1, 5) === "begin") {
218 else if (block.substr(1, 5) === "begin") {
224 start = i;
219 start = i;
225 end = "\\end" + block.substr(6);
220 end = "\\end" + block.substr(6);
226 braces = 0;
221 braces = 0;
227 }
222 }
228 }
223 }
229 }
224 }
230 if (last) {
225 if (last) {
231 blocks = process_math(start, last, de_tilde, math, blocks);
226 blocks = process_math(start, last, de_tilde, math, blocks);
232 start = null;
227 start = null;
233 end = null;
228 end = null;
234 last = null;
229 last = null;
235 }
230 }
236 return [de_tilde(blocks.join("")), math];
231 return [de_tilde(blocks.join("")), math];
237 };
232 };
238
233
239 //
234 //
240 // Put back the math strings that were saved,
235 // Put back the math strings that were saved,
241 // and clear the math array (no need to keep it around).
236 // and clear the math array (no need to keep it around).
242 //
237 //
243 var replace_math = function (text, math) {
238 var replace_math = function (text, math) {
244 if (!window.MathJax) {
245 return text;
246 }
247 text = text.replace(/@@(\d+)@@/g, function (match, n) {
239 text = text.replace(/@@(\d+)@@/g, function (match, n) {
248 return math[n];
240 return math[n];
249 });
241 });
250 return text;
242 return text;
251 };
243 };
252
244
253 return {
245 return {
254 init : init,
246 init : init,
255 remove_math : remove_math,
247 remove_math : remove_math,
256 replace_math : replace_math
248 replace_math : replace_math
257 };
249 };
258
250
259 }(IPython));
251 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now