You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
375 lines
13 KiB
375 lines
13 KiB
|
5 years ago
|
// Comes from: http://dev.stackoverflow.com/content/js/mathjax-editing.js (MIT-License)
|
||
|
|
// Version downloaded 2016-11-21
|
||
|
|
//
|
||
|
|
// Two things modified:
|
||
|
|
//
|
||
|
|
// - StackExchange.mathjaxEditing = (function () {
|
||
|
|
// + function mjpd() { this.mathjaxEditing = (function () {
|
||
|
|
// - converterObject.hooks.chain("preSafe", replaceMath);
|
||
|
|
// + converterObject.hooks.chain("postConversion", replaceMath);
|
||
|
|
// - return { prepareWmdForMathJax: prepareWmdForMathJax };})();
|
||
|
|
// + return { prepareWmdForMathJax: prepareWmdForMathJax } })(); }
|
||
|
|
|
||
|
|
|
||
|
|
"use strict";
|
||
|
|
|
||
|
|
function mjpd() {
|
||
|
|
this.mathjaxEditing = (function () {
|
||
|
|
var ready = false; // true after initial typeset is complete
|
||
|
|
var pending = null; // non-null when typesetting has been queued
|
||
|
|
var inline = "$"; // the inline math delimiter
|
||
|
|
var blocks, start, end, last, braces, indent; // used in searching for math
|
||
|
|
var math; // stores math until markdone is done
|
||
|
|
var HUB = MathJax.Hub, TEX, NOERRORS;
|
||
|
|
|
||
|
|
//
|
||
|
|
// Runs after initial typeset
|
||
|
|
//
|
||
|
|
HUB.Queue(function () {
|
||
|
|
TEX = MathJax.InputJax.TeX;
|
||
|
|
NOERRORS = TEX.config.noErrors;
|
||
|
|
ready = true;
|
||
|
|
HUB.processUpdateTime = 50; // reduce update time so that we can cancel easier
|
||
|
|
HUB.processSectionDelay = 0; // don't pause between input and output phases
|
||
|
|
MathJax.Extension["fast-preview"].Disable(); // disable fast-preview
|
||
|
|
HUB.Config({
|
||
|
|
// reduce chunk for more frequent updates
|
||
|
|
"HTML-CSS": {
|
||
|
|
EqnChunk: 10,
|
||
|
|
EqnChunkFactor: 1
|
||
|
|
},
|
||
|
|
CommonHTML: {
|
||
|
|
EqnChunk: 10,
|
||
|
|
EqnChunkFactor: 1
|
||
|
|
},
|
||
|
|
SVG: {
|
||
|
|
EqnChunk: 10,
|
||
|
|
EqnChunkFactor: 1
|
||
|
|
}
|
||
|
|
});
|
||
|
|
if (pending) return RestartMJ(pending, "Typeset");
|
||
|
|
});
|
||
|
|
|
||
|
|
//
|
||
|
|
// These get called before and after typsetting
|
||
|
|
//
|
||
|
|
function preTypeset() {
|
||
|
|
NOERRORS.disabled = true; // disable noErrors (error will be shown)
|
||
|
|
TEX.resetEquationNumbers(); // reset labels
|
||
|
|
}
|
||
|
|
function postTypeset() {
|
||
|
|
NOERRORS.disabled = false; // don't show errors when not editing
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// The pattern for math delimiters and special symbols
|
||
|
|
// needed for searching for math in the page.
|
||
|
|
//
|
||
|
|
var SPLIT = /(\$\$?|\\(?: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.
|
||
|
|
//
|
||
|
|
function processMath(i, j) {
|
||
|
|
var block = blocks.slice(i, j + 1).join("")
|
||
|
|
.replace(/&/g, "&") // use HTML entity for &
|
||
|
|
.replace(/</g, "<") // use HTML entity for <
|
||
|
|
.replace(/>/g, ">") // use HTML entity for >
|
||
|
|
;
|
||
|
|
if (indent) block = block.replace(/\n /g, "\n");
|
||
|
|
if (HUB.Browser.isMSIE) {
|
||
|
|
block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n");
|
||
|
|
}
|
||
|
|
while (j > i) blocks[j--] = "";
|
||
|
|
blocks[i] = "@@" + math.length + "@@";
|
||
|
|
math.push(block);
|
||
|
|
start = end = last = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
var capturingStringSplit;
|
||
|
|
if ("aba".split(/(b)/).length === 3) {
|
||
|
|
capturingStringSplit = function (str, regex) { return str.split(regex); };
|
||
|
|
}
|
||
|
|
else { // IE8
|
||
|
|
capturingStringSplit = function (str, regex) {
|
||
|
|
var result = [], match;
|
||
|
|
if (!regex.global) {
|
||
|
|
var source = regex.toString(),
|
||
|
|
flags = "";
|
||
|
|
source = source.replace(/^\/(.*)\/([im]*)$/, function (wholematch, re, fl) { flags = fl; return re; });
|
||
|
|
regex = new RegExp(source, flags + "g");
|
||
|
|
}
|
||
|
|
regex.lastIndex = 0;
|
||
|
|
var lastPos = 0;
|
||
|
|
while ((match = regex.exec(str))) {
|
||
|
|
result.push(str.substring(lastPos, match.index));
|
||
|
|
result.push.apply(result, match.slice(1));
|
||
|
|
lastPos = match.index + match[0].length;
|
||
|
|
}
|
||
|
|
result.push(str.substring(lastPos));
|
||
|
|
return result;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// 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).
|
||
|
|
// Handle backticks (don't do math inside them)
|
||
|
|
//
|
||
|
|
function removeMath(text) {
|
||
|
|
start = end = last = indent = null; // for tracking math delimiters
|
||
|
|
math = []; // stores math strings for latter
|
||
|
|
|
||
|
|
blocks = capturingStringSplit(text.replace(/\r\n?/g, "\n"), SPLIT);
|
||
|
|
|
||
|
|
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 or backticks,
|
||
|
|
// look for the end delimiter,
|
||
|
|
// but don't go past double line breaks,
|
||
|
|
// and balance braces within the math,
|
||
|
|
// but don't process math inside backticks.
|
||
|
|
//
|
||
|
|
if (block === end) {
|
||
|
|
if (braces > 0) {
|
||
|
|
last = i;
|
||
|
|
}
|
||
|
|
else if (braces === 0) {
|
||
|
|
processMath(start, i);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
start = end = last = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (block.match(/\n.*\n/) || i + 2 >= m) {
|
||
|
|
if (last) {
|
||
|
|
i = last;
|
||
|
|
if (braces >= 0) processMath(start, i);
|
||
|
|
}
|
||
|
|
start = end = last = null;
|
||
|
|
braces = 0;
|
||
|
|
}
|
||
|
|
else if (block === "{" && braces >= 0) {
|
||
|
|
braces++;
|
||
|
|
}
|
||
|
|
else if (block === "}" && braces > 0) {
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
else if (block.charAt(0) === "`") {
|
||
|
|
start = last = i;
|
||
|
|
end = block;
|
||
|
|
braces = -1; // no brace balancing
|
||
|
|
}
|
||
|
|
else if (block.charAt(0) === "\n") {
|
||
|
|
if (block.match(/ $/)) indent = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (last) processMath(start, last);
|
||
|
|
return 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;
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// This is run to restart MathJax after it has finished
|
||
|
|
// the previous run (that may have been canceled)
|
||
|
|
//
|
||
|
|
function RestartMJ(preview, method) {
|
||
|
|
pending = false;
|
||
|
|
HUB.cancelTypeset = false; // won't need to do this in the future
|
||
|
|
HUB.Queue(
|
||
|
|
preTypeset,
|
||
|
|
[method, HUB, preview],
|
||
|
|
postTypeset
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// When the preview changes, cancel MathJax and restart,
|
||
|
|
// if we haven't done that already.
|
||
|
|
//
|
||
|
|
function UpdateMJ(preview, method) {
|
||
|
|
if (!pending) {
|
||
|
|
pending = preview;
|
||
|
|
if (ready) {
|
||
|
|
HUB.Cancel();
|
||
|
|
HUB.Queue([RestartMJ, preview, method]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// Save the preview ID and the inline math delimiter.
|
||
|
|
// Create a converter for the editor and register a preConversion hook
|
||
|
|
// to handle escaping the math.
|
||
|
|
// Create a preview refresh hook to handle starting MathJax.
|
||
|
|
// Check if any errors are being displayed (in case there were
|
||
|
|
// errors in the initial display, which doesn't go through
|
||
|
|
// onPreviewRefresh), and reprocess if there are.
|
||
|
|
//
|
||
|
|
function prepareWmdForMathJax(editorObject, wmdId, delimiters) {
|
||
|
|
var preview = document.getElementById("wmd-preview" + wmdId);
|
||
|
|
inline = delimiters[0][0];
|
||
|
|
|
||
|
|
var converterObject = editorObject.getConverter();
|
||
|
|
converterObject.hooks.chain("preConversion", removeMath);
|
||
|
|
converterObject.hooks.chain("postConversion", replaceMath);
|
||
|
|
editorObject.hooks.chain("onPreviewRefresh", function () {
|
||
|
|
UpdateMJ(preview, "Typeset");
|
||
|
|
});
|
||
|
|
|
||
|
|
HUB.Queue(function () {
|
||
|
|
if (preview && preview.querySelector(".mjx-noError")) {
|
||
|
|
RestartMJ(preview, "Reprocess");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
prepareWmdForMathJax: prepareWmdForMathJax
|
||
|
|
}
|
||
|
|
})();
|
||
|
|
}
|
||
|
|
//
|
||
|
|
// Set up MathJax to allow canceling of typesetting, if it
|
||
|
|
// doesn't already have that.
|
||
|
|
//
|
||
|
|
(function () {
|
||
|
|
var HUB = MathJax.Hub;
|
||
|
|
|
||
|
|
if (!HUB.Cancel) {
|
||
|
|
|
||
|
|
HUB.cancelTypeset = false;
|
||
|
|
var CANCELMESSAGE = "MathJax Canceled";
|
||
|
|
|
||
|
|
HUB.Register.StartupHook("HTML-CSS Jax Config", function () {
|
||
|
|
var HTMLCSS = MathJax.OutputJax["HTML-CSS"],
|
||
|
|
TRANSLATE = HTMLCSS.Translate;
|
||
|
|
HTMLCSS.Augment({
|
||
|
|
Translate: function (script, state) {
|
||
|
|
if (HUB.cancelTypeset || state.cancelled) {
|
||
|
|
throw Error(CANCELMESSAGE)
|
||
|
|
}
|
||
|
|
return TRANSLATE.call(HTMLCSS, script, state);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
HUB.Register.StartupHook("SVG Jax Config", function () {
|
||
|
|
var SVG = MathJax.OutputJax["SVG"],
|
||
|
|
TRANSLATE = SVG.Translate;
|
||
|
|
SVG.Augment({
|
||
|
|
Translate: function (script, state) {
|
||
|
|
if (HUB.cancelTypeset || state.cancelled) {
|
||
|
|
throw Error(CANCELMESSAGE)
|
||
|
|
}
|
||
|
|
return TRANSLATE.call(SVG, script, state);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
HUB.Register.StartupHook("CommonHTML Jax Config", function () {
|
||
|
|
var CHTML = MathJax.OutputJax.CommonHTML,
|
||
|
|
TRANSLATE = CHTML.Translate;
|
||
|
|
CHTML.Augment({
|
||
|
|
Translate: function (script, state) {
|
||
|
|
if (HUB.cancelTypeset || state.cancelled) {
|
||
|
|
throw Error(CANCELMESSAGE);
|
||
|
|
}
|
||
|
|
return TRANSLATE.call(CHTML, script, state);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
HUB.Register.StartupHook("PreviewHTML Jax Config", function () {
|
||
|
|
var PHTML = MathJax.OutputJax.PreviewHTML,
|
||
|
|
TRANSLATE = PHTML.Translate;
|
||
|
|
PHTML.Augment({
|
||
|
|
Translate: function (script, state) {
|
||
|
|
if (HUB.cancelTypeset || state.cancelled) {
|
||
|
|
throw Error(CANCELMESSAGE);
|
||
|
|
}
|
||
|
|
return TRANSLATE.call(PHTML, script, state);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
HUB.Register.StartupHook("TeX Jax Config", function () {
|
||
|
|
var TEX = MathJax.InputJax.TeX,
|
||
|
|
TRANSLATE = TEX.Translate;
|
||
|
|
TEX.Augment({
|
||
|
|
Translate: function (script, state) {
|
||
|
|
if (HUB.cancelTypeset || state.cancelled) {
|
||
|
|
throw Error(CANCELMESSAGE)
|
||
|
|
}
|
||
|
|
return TRANSLATE.call(TEX, script, state);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
var PROCESSERROR = HUB.processError;
|
||
|
|
HUB.processError = function (error, state, type) {
|
||
|
|
if (error.message !== CANCELMESSAGE) {
|
||
|
|
return PROCESSERROR.call(HUB, error, state, type)
|
||
|
|
}
|
||
|
|
MathJax.Message.Clear(0, 0);
|
||
|
|
state.jaxIDs = [];
|
||
|
|
state.jax = {};
|
||
|
|
state.scripts = [];
|
||
|
|
state.i = state.j = 0;
|
||
|
|
state.cancelled = true;
|
||
|
|
return null;
|
||
|
|
};
|
||
|
|
|
||
|
|
HUB.Cancel = function () {
|
||
|
|
this.cancelTypeset = true;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
})();
|