From a7877483b00b87cb695f491925b1325404abce19 Mon Sep 17 00:00:00 2001 From: benweet Date: Tue, 29 Apr 2014 21:23:22 +0100 Subject: [PATCH] Fixes #391 --- .gitignore | 1 + public/res/editor.js | 3 +- public/res/extensions/mathJax.js | 422 +++++++++++++++++++------------ public/res/html/dialogAbout.html | 6 +- 4 files changed, 270 insertions(+), 162 deletions(-) diff --git a/.gitignore b/.gitignore index af94e349..1c02ab40 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ node_modules Thumbs.db .DS_Store +stackedit.iml public/res/bower-libs diff --git a/public/res/editor.js b/public/res/editor.js index 838387fc..64947526 100644 --- a/public/res/editor.js +++ b/public/res/editor.js @@ -534,8 +534,7 @@ define([ if(contentElt.lastChild === trailingLfNode && trailingLfNode.textContent.slice(-1) == '\n') { newTextContent = newTextContent.slice(0, -1); } - newTextContent = newTextContent.replace(/\r\n/g, '\n'); // DOS to Unix - newTextContent = newTextContent.replace(/\r/g, '\n'); // Mac to Unix + newTextContent = newTextContent.replace(/\r\n?/g, '\n'); // Mac/DOS to Unix if(fileChanged === false) { if(newTextContent == textContent) { diff --git a/public/res/extensions/mathJax.js b/public/res/extensions/mathJax.js index 9597f6a7..46e45587 100644 --- a/public/res/extensions/mathJax.js +++ b/public/res/extensions/mathJax.js @@ -1,169 +1,277 @@ /*defines MathJax */ define([ - "utils", - "classes/Extension", - "text!html/mathJaxSettingsBlock.html", - "mathjax" + "utils", + "classes/Extension", + "text!html/mathJaxSettingsBlock.html", + "mathjax" ], function(utils, Extension, mathJaxSettingsBlockHTML) { - + var mathJax = new Extension("mathJax", "MathJax", true); mathJax.settingsBlock = mathJaxSettingsBlockHTML; - mathJax.defaultConfig = { - tex: "{}", - tex2jax: '{ inlineMath: [["$","$"],["\\\\\\\\(","\\\\\\\\)"]], displayMath: [["$$","$$"],["\\\\[","\\\\]"]], processEscapes: true }' - }; + mathJax.defaultConfig = { + tex : "{}", + tex2jax: '{ inlineMath: [["$","$"],["\\\\\\\\(","\\\\\\\\)"]], displayMath: [["$$","$$"],["\\\\[","\\\\]"]], processEscapes: true }' + }; - mathJax.onLoadSettings = function() { - utils.setInputValue("#input-mathjax-config-tex", mathJax.config.tex); - utils.setInputValue("#input-mathjax-config-tex2jax", mathJax.config.tex2jax); - }; + mathJax.onLoadSettings = function() { + utils.setInputValue("#input-mathjax-config-tex", mathJax.config.tex); + utils.setInputValue("#input-mathjax-config-tex2jax", mathJax.config.tex2jax); + }; - mathJax.onSaveSettings = function(newConfig, event) { - newConfig.tex = utils.getInputJsValue("#input-mathjax-config-tex", event); - newConfig.tex2jax = utils.getInputJsValue("#input-mathjax-config-tex2jax", event); - }; - - /*jshint ignore:start */ - mathJax.onPagedownConfigure = function(editorObject) { - t = document.getElementById("preview-contents"); + mathJax.onSaveSettings = function(newConfig, event) { + newConfig.tex = utils.getInputJsValue("#input-mathjax-config-tex", event); + newConfig.tex2jax = utils.getInputJsValue("#input-mathjax-config-tex2jax", event); + }; - var converter = editorObject.getConverter(); - converter.hooks.chain("preConversion", p); - converter.hooks.chain("postConversion", d); - }; - - var afterRefreshCallback; - mathJax.onAsyncPreview = function(callback) { - afterRefreshCallback = callback; - j(); - }; - - // From math.stackexchange.com... + /*jshint ignore:start */ + mathJax.onPagedownConfigure = function(editorObject) { + preview = document.getElementById("preview-contents"); - function b(a, f, b) { - var c = k.slice(a, f + 1).join("").replace(/&/g, "&").replace(//g, ">"); - for (h.Browser.isMSIE && (c = c.replace(/(%[^\n]*)\n/g, "$1
\n")); f > a; ) - k[f] = "", f--; - k[a] = "@@" + m.length + "@@"; - b && (c = b(c)); - m.push(c); - i = o = l = null - } - function p(a) { - i = o = l = null; - m = []; - var f; - /`/.test(a) ? (a = a.replace(/~/g, "~T").replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, function(a) { - return a.replace(/\$/g, "~D") - }), f = function(a) { - return a.replace(/~([TD])/g, - function(a, c) { - return {T: "~",D: "$"}[c] - }) - }) : f = function(a) { - return a - }; - k = r(a.replace(/\r\n?/g, "\n"), u); - for (var a = 1, d = k.length; a < d; a += 2) { - var c = k[a]; - "@" === c.charAt(0) ? (k[a] = "@@" + m.length + "@@", m.push(c)) : i ? c === o ? n ? l = a : b(i, a, f) : c.match(/\n.*\n/) ? (l && (a = l, b(i, a, f)), i = o = l = null, n = 0) : "{" === c ? n++ : "}" === c && n && n-- : c === s || "$$" === c ? (i = a, o = c, n = 0) : "begin" === c.substr(1, 5) && (i = a, o = "\\end" + c.substr(6), n = 0) - } - l && b(i, l, f); - return f(k.join("")) - } - function d(a) { - a = a.replace(/@@(\d+)@@/g, function(a, b) { - return m[b] - }); - m = null; - return a - } - function e() { - q = !1; - h.cancelTypeset = !1; - h.Queue(["Typeset", h, t]) - h.Queue(afterRefreshCallback); //benweet - } - function j() { - !q && /*benweet (we need to call our afterRefreshCallback) g &&*/ (q = !0, h.Cancel(), h.Queue(e)) - } - var g = !1, q = !1, t = null, s = "$", k, i, o, l, n, m, h = MathJax.Hub; - h.Queue(function() { - g = !0; - h.processUpdateTime = 50; - h.Config({"HTML-CSS": {EqnChunk: 10,EqnChunkFactor: 1},SVG: {EqnChunk: 10,EqnChunkFactor: 1}}) - }); - /*benweet - Don't hash inline math $...$ (see https://github.com/benweet/stackedit/issues/136) - var u = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i, r; - */ - var u = /(\$\$|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i, r; - r = 3 === "aba".split(/(b)/).length ? function(a, f) { - return a.split(f) - } : function(a, f) { - var b = [], c; - if (!f.global) { - c = f.toString(); - var d = ""; - c = c.replace(/^\/(.*)\/([im]*)$/, function(a, c, b) { - d = b; - return c - }); - f = RegExp(c, d + "g") - } - for (var e = f.lastIndex = 0; c = f.exec(a); ) - b.push(a.substring(e, c.index)), b.push.apply(b, c.slice(1)), e = c.index + c[0].length; - b.push(a.substring(e)); - return b - }; - - (function() { - var b = MathJax.Hub; - if (!b.Cancel) { - b.cancelTypeset = !1; - b.Register.StartupHook("HTML-CSS Jax Config", function() { - var d = MathJax.OutputJax["HTML-CSS"], e = d.Translate; - d.Augment({Translate: function(j, g) { - if (b.cancelTypeset || g.cancelled) - throw Error("MathJax Canceled"); - return e.call(d, j, g) - }}) - }); - b.Register.StartupHook("SVG Jax Config", function() { - var d = MathJax.OutputJax.SVG, e = d.Translate; - d.Augment({Translate: function(j, g) { - if (b.cancelTypeset || g.cancelled) - throw Error("MathJax Canceled"); - return e.call(d, - j, g) - }}) - }); - b.Register.StartupHook("TeX Jax Config", function() { - var d = MathJax.InputJax.TeX, e = d.Translate; - d.Augment({Translate: function(j, g) { - if (b.cancelTypeset || g.cancelled) - throw Error("MathJax Canceled"); - return e.call(d, j, g) - }}) - }); - var p = b.processError; - b.processError = function(d, e, j) { - if ("MathJax Canceled" !== d.message) - return p.call(b, d, e, j); - MathJax.Message.Clear(0, 0); - e.jaxIDs = []; - e.jax = {}; - e.scripts = []; - e.i = e.j = 0; - e.cancelled = !0; - return null - }; - b.Cancel = function() { - this.cancelTypeset = !0 - } - } - })(); - /*jshint ignore:end */ + var converter = editorObject.getConverter(); + converter.hooks.chain("preConversion", removeMath); + converter.hooks.chain("postConversion", replaceMath); + }; + + var afterRefreshCallback; + mathJax.onAsyncPreview = function(callback) { + afterRefreshCallback = callback; + UpdateMJ(); + }; + + // From math.stackexchange.com... + + // + // 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
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, unescape) { + var block = blocks.slice(i, j + 1).join("") + .replace(/&/g, "&") + .replace(//g, ">"); + for(HUB.Browser.isMSIE && (block = block.replace(/(%[^\n]*)\n/g, "$1
\n")); j > i;) + blocks[j] = "", j--; + blocks[i] = "@@" + math.length + "@@"; + unescape && (block = unescape(block)); + math.push(block); + start = end = last = null; + } + + function removeMath(text) { + start = end = last = null; + math = []; + var unescape; + if(/`/.test(text)) { + text = text.replace(/~/g, "~T").replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, function(text) { + return text.replace(/\$/g, "~D") + }); + unescape = function(text) { + return text.replace(/~([TD])/g, + function(match, n) { + return {T: "~", D: "$"}[n] + }) + }; + } else { + unescape = function(text) { + return text + }; + } + blocks = split(text.replace(/\r\n?/g, "\n"), splitDelimiter); + 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(end == inline && block.charAt(0) == '\n') { + // This should fix #136 by ignoring inline maths that are actually multiline + start = end = last = null; + } else if(block === end) { + if(braces) { + last = i + } else { + processMath(start, i, unescape) + } + } else { + if(block.match(/\n.*\n/)) { + last && (i = last, processMath(start, i, unescape)), start = end = last = null, braces = 0 + } else { + if("{" === block) { + braces++ + } else { + "}" === block && braces && braces-- + } + } + } + } else { + if(block === inline || "$$" === block) { + start = i; + end = block; + braces = 0; + } else { + if("begin" === block.substr(1, 5)) { + start = i; + end = "\\end" + block.substr(6); + braces = 0; + } + } + } + + } + last && processMath(start, last, unescape); + return unescape(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() { + pending = false; + HUB.cancelTypeset = false; + HUB.Queue([ + "Typeset", + HUB, + preview + ]); + HUB.Queue(afterRefreshCallback); //benweet + } + + // + // When the preview changes, cancel MathJax and restart, + // if we haven't done that already. + // + function UpdateMJ() { + if(!pending /*benweet (we need to call our afterRefreshCallback) && ready */) { + pending = true; + HUB.Cancel(); + HUB.Queue(RestartMJ); + } + } + + var ready = false, pending = false, preview = null, inline = "$", blocks, start, end, last, braces, math, HUB = MathJax.Hub; + + // + // Runs after initial typeset + // + HUB.Queue(function() { + ready = true; + HUB.processUpdateTime = 50; + HUB.Config({"HTML-CSS": {EqnChunk: 10, EqnChunkFactor: 1}, SVG: {EqnChunk: 10, EqnChunkFactor: 1}}) + }); + + + /*benweet + Don't hash inline math $...$ (see https://github.com/benweet/stackedit/issues/136) + var u = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i, r; + */ + + + // + // The pattern for math delimiters and special symbols + // needed for searching for math in the page. + // + var splitDelimiter = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i; + var split; + + if(3 === "aba".split(/(b)/).length) { + split = function(text, delimiter) { + return text.split(delimiter) + }; + } else { + split = function(text, delimiter) { + var b = [], c; + if(!delimiter.global) { + c = delimiter.toString(); + var d = ""; + c = c.replace(/^\/(.*)\/([im]*)$/, function(a, c, b) { + d = b; + return c + }); + delimiter = RegExp(c, d + "g") + } + for(var e = delimiter.lastIndex = 0; c = delimiter.exec(text);) { + b.push(text.substring(e, c.index)); + b.push.apply(b, c.slice(1)); + e = c.index + c[0].length; + } + b.push(text.substring(e)); + return b + }; + } + + (function() { + var HUB = MathJax.Hub; + if(!HUB.Cancel) { + HUB.cancelTypeset = !1; + 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("MathJax Canceled"); + 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("MathJax Canceled"); + return TRANSLATE.call(SVG, + 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("MathJax Canceled"); + return TRANSLATE.call(TEX, script, state) + }}) + }); + var PROCESSERROR = HUB.processError; + HUB.processError = function(error, state, type) { + if("MathJax Canceled" !== error.message) + 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 + } + } + })(); + /*jshint ignore:end */ return mathJax; }); \ No newline at end of file diff --git a/public/res/html/dialogAbout.html b/public/res/html/dialogAbout.html index 65c9acb1..87b475d5 100644 --- a/public/res/html/dialogAbout.html +++ b/public/res/html/dialogAbout.html @@ -36,7 +36,7 @@ Benoit Schweblin
Pete Eigel (contributor)
wiibaa (contributor)
- Daniel Hug (contributor)
+ Daniel Hug (contributor)
@@ -60,8 +60,8 @@

- StackEdit <%= version %> – Privacy Policy
Copyright 2013 Benoit + StackEdit <%= version %> – Privacy Policy
Copyright 2013-2014 Benoit Schweblin
Licensed under an Apache License