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.

82 lines
2.0 KiB

  1. const mathjax = require('mathjax-node')
  2. const _ = require('lodash')
  3. // ------------------------------------
  4. // Mathjax
  5. // ------------------------------------
  6. /* global WIKI */
  7. const mathRegex = [
  8. {
  9. format: 'TeX',
  10. regex: /\\\[([\s\S]*?)\\\]/g
  11. },
  12. {
  13. format: 'inline-TeX',
  14. regex: /\\\((.*?)\\\)/g
  15. },
  16. {
  17. format: 'MathML',
  18. regex: /<math([\s\S]*?)<\/math>/g
  19. }
  20. ]
  21. module.exports = {
  22. init ($, config) {
  23. mathjax.config({
  24. MathJax: {
  25. jax: ['input/TeX', 'input/MathML', 'output/SVG'],
  26. extensions: ['tex2jax.js', 'mml2jax.js'],
  27. TeX: {
  28. extensions: ['AMSmath.js', 'AMSsymbols.js', 'noErrors.js', 'noUndefined.js']
  29. },
  30. SVG: {
  31. scale: 120,
  32. font: 'STIX-Web'
  33. }
  34. }
  35. })
  36. },
  37. async render (content) {
  38. let matchStack = []
  39. let replaceStack = []
  40. let currentMatch
  41. let mathjaxState = {}
  42. _.forEach(mathRegex, mode => {
  43. do {
  44. currentMatch = mode.regex.exec(content)
  45. if (currentMatch) {
  46. matchStack.push(currentMatch[0])
  47. replaceStack.push(
  48. new Promise((resolve, reject) => {
  49. mathjax.typeset({
  50. math: (mode.format === 'MathML') ? currentMatch[0] : currentMatch[1],
  51. format: mode.format,
  52. speakText: false,
  53. svg: true,
  54. state: mathjaxState,
  55. timeout: 30 * 1000
  56. }, result => {
  57. if (!result.errors) {
  58. resolve(result.svg)
  59. } else {
  60. resolve(currentMatch[0])
  61. WIKI.logger.warn(result.errors.join(', '))
  62. }
  63. })
  64. })
  65. )
  66. }
  67. } while (currentMatch)
  68. })
  69. return (matchStack.length > 0) ? Promise.all(replaceStack).then(results => {
  70. _.forEach(matchStack, (repMatch, idx) => {
  71. content = content.replace(repMatch, results[idx])
  72. })
  73. return content
  74. }) : Promise.resolve(content)
  75. }
  76. }