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