// This is taken from Jupyter, which is BSD/Apache2 licensed... -- https://github.com/jupyter/notebook/blob/master/notebook/static/notebook/js/mathjaxutils.js12// Some magic for deferring mathematical expressions to MathJax3// by hiding them from the Markdown parser.4// Some of the code here is adapted with permission from Davide Cervone5// under the terms of the Apache2 license governing the MathJax project.6// Other minor modifications are also due to StackExchange and are used with7// permission.89// MATHSPLIT contains the pattern for math delimiters and special symbols10// needed for searching for math in the text input.11var MATHSPLIT = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[{}$]|[{}]|(?:\n\s*)+|@@\d+@@|\\\\(?:\(|\)|\[|\]))/i;1213regex_split = require('./regex-split').regex_split;1415// The math is in blocks i through j, so16// collect it into one block and clear the others.17// Replace &, <, and > by named entities.18// For IE, put <br> at the ends of comments since IE removes \n.19// Clear the current math positions and store the index of the20// math, then push the math string onto the storage array.21// The preProcess function is called on all blocks if it has been passed in22var process_math = function (i, j, pre_process, math, blocks) {23var block = blocks.slice(i, j + 1).join("").replace(/&/g, "&") // use HTML entity for &24.replace(/</g, "<") // use HTML entity for <25.replace(/>/g, ">") // use HTML entity for >26;27if (typeof($) !== "undefined" && $.browser.ie) {28block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n");29}30while (j > i) {31blocks[j] = "";32j--;33}34blocks[i] = "@@" + math.length + "@@"; // replace the current block text with a unique tag to find later35if (pre_process){36block = pre_process(block);37}38math.push(block);39return blocks;40};4142// Break up the text into its component parts and search43// through them for math delimiters, braces, linebreaks, etc.44// Math delimiters must match and braces must balance.45// Don't allow math to pass through a double linebreak46// (which will be a paragraph).47//48exports.remove_math = function (text) {49var math = []; // stores math strings for later50var start;51var end;52var last;53var braces;5455// Except for extreme edge cases, this should catch precisely those pieces of the markdown56// source that will later be turned into code spans. While MathJax will not TeXify code spans,57// we still have to consider them at this point; the following issue has happened several times:58//59// `$foo` and `$bar` are varibales. --> <code>$foo ` and `$bar</code> are variables.6061var hasCodeSpans = /`/.test(text),62de_tilde;63if (hasCodeSpans) {64text = text.replace(/~/g, "~T").replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, function (wholematch) {65return wholematch.replace(/\$/g, "~D");66});67de_tilde = function (text) {68return text.replace(/~([TD])/g, function (wholematch, character) {69return { T: "~", D: "$" }[character];70});71};72} else {73de_tilde = function (text) { return text; };74}7576var blocks = regex_split(text.replace(/\r\n?/g, "\n"),MATHSPLIT);7778for (var i = 1, m = blocks.length; i < m; i += 2) {79var block = blocks[i];80if (block.charAt(0) === "@") {81//82// Things that look like our math markers will get83// stored and then retrieved along with the math.84//85blocks[i] = "@@" + math.length + "@@";86math.push(block);87}88else if (start) {89//90// If we are in math, look for the end delimiter,91// but don't go past double line breaks, and92// and balance braces within the math.93//94if (block === end) {95if (braces) {96last = i;97}98else {99blocks = process_math(start, i, de_tilde, math, blocks);100start = null;101end = null;102last = null;103}104}105else if (block.match(/\n.*\n/)) {106if (last) {107i = last;108blocks = process_math(start, i, de_tilde, math, blocks);109}110start = null;111end = null;112last = null;113braces = 0;114}115else if (block === "{") {116braces++;117}118else if (block === "}" && braces) {119braces--;120}121}122else {123//124// Look for math start delimiters and when125// found, set up the end delimiter.126//127if (block === "$" || block === "$$") {128start = i;129end = block;130braces = 0;131}132else if (block === "\\\\\(" || block === "\\\\\[") {133start = i;134end = block.slice(-1) === "(" ? "\\\\\)" : "\\\\\]";135braces = 0;136}137else if (block.substr(1, 5) === "begin") {138start = i;139end = "\\end" + block.substr(6);140braces = 0;141}142}143}144if (last) {145blocks = process_math(start, last, de_tilde, math, blocks);146start = null;147end = null;148last = null;149}150return [de_tilde(blocks.join("")), math];151};152153//154// Put back the math strings that were saved,155// and clear the math array (no need to keep it around).156//157exports.replace_math = function (text, math) {158//159// Replaces a math placeholder with its corresponding group.160// The math delimiters "\\(", "\\[", "\\)" and "\\]" are replaced161// removing one backslash in order to be interpreted correctly by MathJax.162//163var math_group_process = function (match, n) {164var math_group = math[n];165166if (math_group.substr(0, 3) === "\\\\\(" && math_group.substr(math_group.length - 3) === "\\\\\)") {167math_group = "\\\(" + math_group.substring(3, math_group.length - 3) + "\\\)";168} else if (math_group.substr(0, 3) === "\\\\\[" && math_group.substr(math_group.length - 3) === "\\\\\]") {169math_group = "\\\[" + math_group.substring(3, math_group.length - 3) + "\\\]";170}171172return math_group;173};174175// Replace all the math group placeholders in the text176// with the saved strings.177text = text.replace(/@@(\d+)@@/g, math_group_process);178179return text;180};181182