Commit bb00444e by Rocky Duan

make mathjax working with the editor

parent 8eda490d
......@@ -54,7 +54,7 @@
idPostfix = idPostfix || "";
var hooks = this.hooks = new Markdown.HookCollection();
hooks.addNoop("onPreviewRefresh"); // called with no arguments after the preview has been refreshed
hooks.addNoop("onPreviewPush"); // called with no arguments after the preview has been refreshed
hooks.addNoop("postBlockquoteCreation"); // called with the user's selection *after* the blockquote was created; should return the actual to-be-inserted text
hooks.addFalse("insertImageDialog"); /* called with one parameter: a callback to be called with the URL of the image. If the application creates
* its own image insertion dialog, this hook should return true, and the callback should be called with the chosen
......@@ -72,7 +72,7 @@
panels = new PanelCollection(idPostfix);
var commandManager = new CommandManager(hooks);
var previewManager = new PreviewManager(markdownConverter, panels, function () { hooks.onPreviewRefresh(); });
var previewManager = new PreviewManager(markdownConverter, panels, function (text, previewSet) { hooks.onPreviewPush(text, previewSet); });
var undoManager, uiManager;
if (!/\?noundo/.test(doc.location.href)) {
......@@ -769,7 +769,7 @@
this.init();
};
function PreviewManager(converter, panels, previewRefreshCallback) {
function PreviewManager(converter, panels, previewPushCallback) {
var managerObj = this;
var timeout;
......@@ -928,8 +928,7 @@
var emptyTop = position.getTop(panels.input) - getDocScrollTop();
if (panels.preview) {
previewSet(text);
previewRefreshCallback();
previewPushCallback(text, previewSet);
}
setPanelScrollTops();
......@@ -2157,4 +2156,4 @@
}
})();
\ No newline at end of file
})();
/*!
* Cross-Browser Split 1.1.1
* Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
* Available under the MIT License
* ECMAScript compliant, uniform cross-browser split method
*/
/**
* Splits a string into an array of strings using a regex or string separator. Matches of the
* separator are not included in the result array. However, if `separator` is a regex that contains
* capturing groups, backreferences are spliced into the result each time `separator` is matched.
* Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably
* cross-browser.
* @param {String} str String to split.
* @param {RegExp|String} separator Regex or string to use for separating the string.
* @param {Number} [limit] Maximum number of items to include in the result array.
* @returns {Array} Array of substrings.
* @example
*
* // Basic use
* split('a b c d', ' ');
* // -> ['a', 'b', 'c', 'd']
*
* // With limit
* split('a b c d', ' ', 2);
* // -> ['a', 'b']
*
* // Backreferences in result array
* split('..word1 word2..', /([a-z]+)(\d+)/i);
* // -> ['..', 'word', '1', ' ', 'word', '2', '..']
*/
var _split; // instead of split for a less common name; avoid conflict
// Avoid running twice; that would break the `nativeSplit` reference
_split = _split || function (undef) {
var nativeSplit = String.prototype.split,
compliantExecNpcg = /()??/.exec("")[1] === undef, // NPCG: nonparticipating capturing group
self;
self = function (str, separator, limit) {
// If `separator` is not a regex, use `nativeSplit`
if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
return nativeSplit.call(str, separator, limit);
}
var output = [],
flags = (separator.ignoreCase ? "i" : "") +
(separator.multiline ? "m" : "") +
(separator.extended ? "x" : "") + // Proposed for ES6
(separator.sticky ? "y" : ""), // Firefox 3+
lastLastIndex = 0,
// Make `global` and avoid `lastIndex` issues by working with a copy
separator = new RegExp(separator.source, flags + "g"),
separator2, match, lastIndex, lastLength;
str += ""; // Type-convert
if (!compliantExecNpcg) {
// Doesn't need flags gy, but they don't hurt
separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
}
/* Values for `limit`, per the spec:
* If undefined: 4294967295 // Math.pow(2, 32) - 1
* If 0, Infinity, or NaN: 0
* If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
* If negative number: 4294967296 - Math.floor(Math.abs(limit))
* If other: Type-convert, then use the above rules
*/
limit = limit === undef ?
-1 >>> 0 : // Math.pow(2, 32) - 1
limit >>> 0; // ToUint32(limit)
while (match = separator.exec(str)) {
// `separator.lastIndex` is not reliable cross-browser
lastIndex = match.index + match[0].length;
if (lastIndex > lastLastIndex) {
output.push(str.slice(lastLastIndex, match.index));
// Fix browsers whose `exec` methods don't consistently return `undefined` for
// nonparticipating capturing groups
if (!compliantExecNpcg && match.length > 1) {
match[0].replace(separator2, function () {
for (var i = 1; i < arguments.length - 2; i++) {
if (arguments[i] === undef) {
match[i] = undef;
}
}
});
}
if (match.length > 1 && match.index < str.length) {
Array.prototype.push.apply(output, match.slice(1));
}
lastLength = match[0].length;
lastLastIndex = lastIndex;
if (output.length >= limit) {
break;
}
}
if (separator.lastIndex === match.index) {
separator.lastIndex++; // Avoid an infinite loop
}
}
if (lastLastIndex === str.length) {
if (lastLength || !separator.test("")) {
output.push("");
}
} else {
output.push(str.slice(lastLastIndex));
}
return output.length > limit ? output.slice(0, limit) : output;
};
// For convenience
String.prototype.split = function (separator, limit) {
return self(this, separator, limit);
};
return self;
}();
# Mostly adapted from math.stackexchange.com: http://cdn.sstatic.net/js/mathjax-editing-new.js
$ ->
if Markdown?
mathRenderer = new MathJaxDelayRenderer()
removeMath = (text) -> text
HUB = MathJax.Hub
class MathJaxProcessor
inlineMark = "$"
math = null
blocks = null
MATHSPLIT = /// (
\$\$? # normal inline or display delimiter
| \\(?:begin|end)\{[a-z]*\*?\} # \begin{} \end{} style
| \\[\\{}$]
| [{}]
| (?:\n\s*)+ # only treat as math when there's single new line
| @@\d+@@ # delimiter similar to the one used internally
) ///i
CODESPAN = ///
(^|[^\\]) # match beginning or any previous character other than escape delimiter ('/')
(`+) # code span starts
([^\n]*?[^`\n]) # code content
\2 # code span ends
(?!`)
///gm
###HUB.Queue ->
console.log "initializing"
renderReady = true
HUB.processUpdateTime = 50
HUB.Config
"HTML-CSS":
EqnChunk: 10
EqnChunkFactor: 1
SVG:
EqnChunk: 10
EqnChunkFactor: 1
###
@processMath: (start, last, preProcess) =>
block = blocks.slice(start, last + 1).join("").replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
if HUB.Browser.isMSIE
block = block.replace /(%[^\n]*)\n/g, "$1<br/>\n"
blocks[i] = "" for i in [start+1..last]
blocks[start] = "@@#{math.length}@@"
block = preProcess(block) if preProcess
math.push block
@removeMath: (text) =>
replaceMath = (text) -> text
math = []
start = end = last = null
braces = 0
updateMathJax = ->
console.log "updating"
#mathRenderer.render
# element: $("#wmd-preview")
MathJax.Hub.Queue(["Typeset", MathJax.Hub, "wmd-preview"])
hasCodeSpans = /`/.test text
if hasCodeSpans
text = text.replace(/~/g, "~T").replace CODESPAN, ($0) -> # replace dollar sign in code span temporarily
$0.replace /\$/g, "~D"
deTilde = (text) ->
text.replace /~([TD])/g, ($0, $1) ->
{T: "~", D: "$"}[$1]
else
deTilde = (text) -> text
blocks = _split(text.replace(/\r\n?/g, "\n"), MATHSPLIT)
for current in [1...blocks.length] by 2
block = blocks[current]
if block.charAt(0) == "@"
blocks[current] = "@@#{math.length}@@"
math.push block
else if start
if block == end
if braces
last = current
else
@processMath(start, current, deTilde)
start = end = last = null
else if block.match /\n.*\n/
if last
current = last
@processMath(start, current, deTilde)
start = end = last = null
braces = 0
else if block == "{"
++braces
else if block == "}" and braces
--braces
else
if block == inlineMark or block == "$$"
start = current
end = block
braces = 0
else if block.substr(1, 5) == "begin"
start = current
end = "\\end" + block.substr(6)
braces = 0
if last
@processMath(start, last, deTilde)
start = end = last = null
deTilde(blocks.join(""))
@replaceMath: (text) =>
text = text.replace /@@(\d+)@@/g, ($0, $1) => math[$1]
math = null
text
@updateMathJax: =>
HUB.Queue(["Typeset", HUB, "wmd-preview"])
###
if not HUB.Cancel? #and 1 == 2
HUB.cancelTypeset = false
CANCELMESSAGE = "MathJax Canceled"
HOOKS = [
{
name: "HTML-CSS Jax Config"
engine: -> window["MathJax"].OutputJax["HTML-CSS"]
},
{
name: "SVG Jax Config"
engine: -> window["MathJax"].OutputJax["SVG"]
},
{
name: "TeX Jax Config"
engine: -> window["MathJax"].InputJax.TeX
},
]
for hook in HOOKS
do (hook) ->
HUB.Register.StartupHook hook.name, ->
engine = hook.engine()
engine.Augment
Translate: (script, state) ->
console.log "translating"
if HUB.cancelTypeset or state.cancelled
throw Error(CANCELMESSAGE)
engine.Translate.call(engine, script, state)
prevProcessError = HUB.processError
HUB.processError = (error, state, type) ->
if error.message != CANCELMESSAGE
return prevProcessError.call(HUB, error, state, type)
else
console.log "handling message"
MathJax.Message.Clear(0, 0)
state.jaxIds = []
state.jax = {}
state.scripts = []
state.i = state.j = 0
state.cancelled = true
return null
HUB.Cancel = ->
this.cancelTypeset = true
###
if Markdown?
converter = Markdown.getSanitizingConverter()
editor = new Markdown.Editor(converter)
converter.hooks.chain "preConversion", removeMath
converter.hooks.chain "postConversion", replaceMath
editor.hooks.chain "onPreviewRefresh", updateMathJax
converter.hooks.chain "preConversion", MathJaxProcessor.removeMath
converter.hooks.chain "postConversion", MathJaxProcessor.replaceMath
delayRenderer = new MathJaxDelayRenderer()
editor.hooks.chain "onPreviewPush", (text, previewSet) ->
delayRenderer.render
text: text
previewSetter: previewSet
editor.run()
getTime = ->
new Date().getTime()
class @MathJaxDelayRenderer
maxDelay: 3000
mathjaxRunning: false
elapsedTime: 0
mathjaxDelay: 0
mathjaxTimeout: undefined
bufferId: "mathjax_delay_buffer"
constructor: (params) ->
params = params || {}
@maxDelay = params["maxDelay"] || @maxDelay
@bufferId = params["buffer"] || @bufferId
if not $("##{@bufferId}").length
$("<div>").attr("id", @bufferId).css("display", "none").appendTo($("body"))
# render: (params) ->
# params:
# elem: jquery element to be rendered
# text: text to be rendered & put into the element;
# if blank, then just render the current text in the element
# preprocessor: pre-process the text before rendering using MathJax
# if text is blank, it will pre-process the html in the element
# previewSetter: if provided, will pass text back to it instead of
# directly setting the element
render: (params) ->
elem = params["element"]
previewSetter = params["previewSetter"]
text = params["text"]
if not text?
text = $(elem).html()
preprocessor = params["preprocessor"]
buffer = $("##{@bufferId}")
if params["delay"] == false
if preprocessor?
text = preprocessor(text)
$(elem).html(text)
MathJax.Hub.Queue ["Typeset", MathJax.Hub, $(elem).attr("id")]
else
if @mathjaxTimeout
window.clearTimeout(@mathjaxTimeout)
@mathjaxTimeout = undefined
delay = Math.min @elapsedTime + @mathjaxDelay, @maxDelay
renderer = =>
if @mathjaxRunning
return
prevTime = getTime()
if preprocessor?
text = preprocessor(text)
buffer.html(text)
curTime = getTime()
@elapsedTime = curTime - prevTime
if MathJax
prevTime = getTime()
@mathjaxRunning = true
MathJax.Hub.Queue ["Typeset", MathJax.Hub, buffer.attr("id")], =>
@mathjaxRunning = false
curTime = getTime()
@mathjaxDelay = curTime - prevTime
if previewSetter
previewSetter($(buffer).html())
else
$(elem).html($(buffer).html())
else
@mathjaxDelay = 0
@mathjaxTimeout = window.setTimeout(renderer, delay)
......@@ -27,6 +27,7 @@
It can't be run through static.url because MathJax uses crazy url introspection to do lazy loading of
MathJax extension libraries -->
<script type="text/javascript" src="/static/js/vendor/mathjax-MathJax-c9db6ac/MathJax.js?config=TeX-MML-AM_HTMLorMML-full"></script>
<script type="text/javascript" src="${static.url('js/vendor/split.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/Markdown.Converter.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/Markdown.Sanitizer.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/Markdown.Editor.js')}"></script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment