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.

86 lines
2.1 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. key: 'common/mathjax',
  23. title: 'Mathjax',
  24. dependsOn: [],
  25. props: [],
  26. init (conf) {
  27. mathjax.config({
  28. MathJax: {
  29. jax: ['input/TeX', 'input/MathML', 'output/SVG'],
  30. extensions: ['tex2jax.js', 'mml2jax.js'],
  31. TeX: {
  32. extensions: ['AMSmath.js', 'AMSsymbols.js', 'noErrors.js', 'noUndefined.js']
  33. },
  34. SVG: {
  35. scale: 120,
  36. font: 'STIX-Web'
  37. }
  38. }
  39. })
  40. },
  41. async render (content) {
  42. let matchStack = []
  43. let replaceStack = []
  44. let currentMatch
  45. let mathjaxState = {}
  46. _.forEach(mathRegex, mode => {
  47. do {
  48. currentMatch = mode.regex.exec(content)
  49. if (currentMatch) {
  50. matchStack.push(currentMatch[0])
  51. replaceStack.push(
  52. new Promise((resolve, reject) => {
  53. mathjax.typeset({
  54. math: (mode.format === 'MathML') ? currentMatch[0] : currentMatch[1],
  55. format: mode.format,
  56. speakText: false,
  57. svg: true,
  58. state: mathjaxState,
  59. timeout: 30 * 1000
  60. }, result => {
  61. if (!result.errors) {
  62. resolve(result.svg)
  63. } else {
  64. resolve(currentMatch[0])
  65. WIKI.logger.warn(result.errors.join(', '))
  66. }
  67. })
  68. })
  69. )
  70. }
  71. } while (currentMatch)
  72. })
  73. return (matchStack.length > 0) ? Promise.all(replaceStack).then(results => {
  74. _.forEach(matchStack, (repMatch, idx) => {
  75. content = content.replace(repMatch, results[idx])
  76. })
  77. return content
  78. }) : Promise.resolve(content)
  79. }
  80. }