182 lines
6.3 KiB
CoffeeScript
182 lines
6.3 KiB
CoffeeScript
# Mostly adapted from math.stackexchange.com: http://cdn.sstatic.net/js/mathjax-editing-new.js
|
|
|
|
$ ->
|
|
|
|
class MathJaxProcessor
|
|
|
|
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
|
|
|
|
constructor: (inlineMark, displayMark) ->
|
|
@inlineMark = inlineMark || "$"
|
|
@displayMark = displayMark || "$$"
|
|
@math = null
|
|
@blocks = null
|
|
|
|
processMath: (start, last, preProcess) ->
|
|
block = @blocks.slice(start, last + 1).join("").replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
if MathJax.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) ->
|
|
|
|
text = text || ""
|
|
@math = []
|
|
start = end = last = null
|
|
braces = 0
|
|
|
|
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 == @displayMark
|
|
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(""))
|
|
|
|
@removeMathWrapper: (_this) ->
|
|
(text) -> _this.removeMath(text)
|
|
|
|
replaceMath: (text) ->
|
|
text = text.replace /@@(\d+)@@/g, ($0, $1) => @math[$1]
|
|
@math = null
|
|
text
|
|
|
|
@replaceMathWrapper: (_this) ->
|
|
(text) -> _this.replaceMath(text)
|
|
|
|
if Markdown?
|
|
|
|
Markdown.getMathCompatibleConverter = (postProcessor) ->
|
|
postProcessor ||= ((text) -> text)
|
|
converter = Markdown.getSanitizingConverter()
|
|
if MathJax?
|
|
processor = new MathJaxProcessor()
|
|
converter.hooks.chain "preConversion", MathJaxProcessor.removeMathWrapper(processor)
|
|
converter.hooks.chain "postConversion", (text) ->
|
|
postProcessor(MathJaxProcessor.replaceMathWrapper(processor)(text))
|
|
converter
|
|
|
|
Markdown.makeWmdEditor = (elem, appended_id, imageUploadUrl, postProcessor) ->
|
|
$elem = $(elem)
|
|
if not $elem.length
|
|
console.log "warning: elem for makeWmdEditor doesn't exist"
|
|
return
|
|
if not $elem.find(".wmd-panel").length
|
|
initialText = $elem.html()
|
|
$elem.empty()
|
|
_append = appended_id || ""
|
|
wmdInputId = "wmd-input#{_append}"
|
|
$wmdPreviewContainer = $("<div>").addClass("wmd-preview-container")
|
|
.append($("<div>").addClass("wmd-preview-label").text(gettext("Preview")))
|
|
.append($("<div>").attr("id", "wmd-preview#{_append}").addClass("wmd-panel wmd-preview"))
|
|
$wmdPanel = $("<div>").addClass("wmd-panel")
|
|
.append($("<div>").attr("id", "wmd-button-bar#{_append}"))
|
|
.append($("<label>").addClass("sr").attr("for", wmdInputId).text(gettext("Post body")))
|
|
.append($("<textarea>").addClass("wmd-input").attr("id", wmdInputId).html(initialText))
|
|
.append($wmdPreviewContainer)
|
|
$elem.append($wmdPanel)
|
|
|
|
converter = Markdown.getMathCompatibleConverter(postProcessor)
|
|
|
|
ajaxFileUpload = (imageUploadUrl, input, startUploadHandler) ->
|
|
$("#loading").ajaxStart(-> $(this).show()).ajaxComplete(-> $(this).hide())
|
|
$("#upload").ajaxStart(-> $(this).hide()).ajaxComplete(-> $(this).show())
|
|
$.ajaxFileUpload
|
|
url: imageUploadUrl
|
|
secureuri: false
|
|
fileElementId: 'file-upload'
|
|
dataType: 'json'
|
|
success: (data, status) ->
|
|
fileURL = data['result']['file_url']
|
|
error = data['result']['error']
|
|
if error != ''
|
|
alert error
|
|
if startUploadHandler
|
|
$('#file-upload').unbind('change').change(startUploadHandler)
|
|
console.log error
|
|
else
|
|
$(input).attr('value', fileURL)
|
|
error: (data, status, e) ->
|
|
alert(e)
|
|
if startUploadHandler
|
|
$('#file-upload').unbind('change').change(startUploadHandler)
|
|
|
|
imageUploadHandler = (elem, input) ->
|
|
ajaxFileUpload(imageUploadUrl, input, imageUploadHandler)
|
|
|
|
editor = new Markdown.Editor(
|
|
converter,
|
|
appended_id, # idPostfix
|
|
null, # help handler
|
|
imageUploadHandler
|
|
)
|
|
delayRenderer = new MathJaxDelayRenderer()
|
|
editor.hooks.chain "onPreviewPush", (text, previewSet) ->
|
|
delayRenderer.render
|
|
text: text
|
|
previewSetter: previewSet
|
|
editor.run()
|
|
editor
|