| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 | const mjax = require('mathjax')/* global WIKI */// ------------------------------------// Markdown - MathJax Renderer// ------------------------------------const extensions = [  'bbox',  'boldsymbol',  'braket',  'color',  'extpfeil',  'mhchem',  'newcommand',  'unicode',  'verb']module.exports = {  async init (mdinst, conf) {    const MathJax = await mjax.init({      loader: {        require: require,        paths: { mathjax: 'mathjax/es5' },        load: [          'input/tex',          'output/svg',          ...extensions.map(e => `[tex]/${e}`)        ]      },      tex: {        packages: {'[+]': extensions}      }    })    if (conf.useInline) {      mdinst.inline.ruler.after('escape', 'mathjax_inline', mathjaxInline)      mdinst.renderer.rules.mathjax_inline = (tokens, idx) => {        try {          const result = MathJax.tex2svg(tokens[idx].content, {            display: false          })          return MathJax.startup.adaptor.innerHTML(result)        } catch (err) {          WIKI.logger.warn(err)          return tokens[idx].content        }      }    }    if (conf.useBlocks) {      mdinst.block.ruler.after('blockquote', 'mathjax_block', mathjaxBlock, {        alt: [ 'paragraph', 'reference', 'blockquote', 'list' ]      })      mdinst.renderer.rules.mathjax_block = (tokens, idx) => {        try {          const result = MathJax.tex2svg(tokens[idx].content, {            display: true          })          return `<p>` + MathJax.startup.adaptor.innerHTML(result) + `</p>`        } catch (err) {          WIKI.logger.warn(err)          return tokens[idx].content        }      }    }  }}// Test if potential opening or closing delimieter// Assumes that there is a "$" at state.src[pos]function isValidDelim (state, pos) {  let prevChar  let nextChar  let max = state.posMax  let canOpen = true  let canClose = true  prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1  nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1  // Check non-whitespace conditions for opening and closing, and  // check that closing delimeter isn't followed by a number  if (prevChar === 0x20/* " " */ || prevChar === 0x09/* \t */ ||  (nextChar >= 0x30/* "0" */ && nextChar <= 0x39/* "9" */)) {    canClose = false  }  if (nextChar === 0x20/* " " */ || nextChar === 0x09/* \t */) {    canOpen = false  }  return {    canOpen: canOpen,    canClose: canClose  }}function mathjaxInline (state, silent) {  let start, match, token, res, pos  if (state.src[state.pos] !== '$') { return false }  res = isValidDelim(state, state.pos)  if (!res.canOpen) {    if (!silent) { state.pending += '$' }    state.pos += 1    return true  }  // First check for and bypass all properly escaped delimieters  // This loop will assume that the first leading backtick can not  // be the first character in state.src, which is known since  // we have found an opening delimieter already.  start = state.pos + 1  match = start  while ((match = state.src.indexOf('$', match)) !== -1) {    // Found potential $, look for escapes, pos will point to    // first non escape when complete    pos = match - 1    while (state.src[pos] === '\\') { pos -= 1 }    // Even number of escapes, potential closing delimiter found    if (((match - pos) % 2) === 1) { break }    match += 1  }  // No closing delimter found.  Consume $ and continue.  if (match === -1) {    if (!silent) { state.pending += '$' }    state.pos = start    return true  }  // Check if we have empty content, ie: $$.  Do not parse.  if (match - start === 0) {    if (!silent) { state.pending += '$$' }    state.pos = start + 1    return true  }  // Check for valid closing delimiter  res = isValidDelim(state, match)  if (!res.canClose) {    if (!silent) { state.pending += '$' }    state.pos = start    return true  }  if (!silent) {    token = state.push('mathjax_inline', 'math', 0)    token.markup = '$'    token.content = state.src.slice(start, match)  }  state.pos = match + 1  return true}function mathjaxBlock (state, start, end, silent) {  let firstLine; let lastLine; let next; let lastPos; let found = false; let token  let pos = state.bMarks[start] + state.tShift[start]  let max = state.eMarks[start]  if (pos + 2 > max) { return false }  if (state.src.slice(pos, pos + 2) !== '$$') { return false }  pos += 2  firstLine = state.src.slice(pos, max)  if (silent) { return true }  if (firstLine.trim().slice(-2) === '$$') {    // Single line expression    firstLine = firstLine.trim().slice(0, -2)    found = true  }  for (next = start; !found;) {    next++    if (next >= end) { break }    pos = state.bMarks[next] + state.tShift[next]    max = state.eMarks[next]    if (pos < max && state.tShift[next] < state.blkIndent) {      // non-empty line with negative indent should stop the list:      break    }    if (state.src.slice(pos, max).trim().slice(-2) === '$$') {      lastPos = state.src.slice(0, max).lastIndexOf('$$')      lastLine = state.src.slice(pos, lastPos)      found = true    }  }  state.line = next + 1  token = state.push('mathjax_block', 'math', 0)  token.block = true  token.content = (firstLine && firstLine.trim() ? firstLine + '\n' : '') +  state.getLines(start + 1, next, state.tShift[start], true) +  (lastLine && lastLine.trim() ? lastLine : '')  token.map = [ start, state.line ]  token.markup = '$$'  return true}
 |