load-mathjax.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import getMeta from '../../utils/meta'
  2. let mathJaxPromise: Promise<typeof window.MathJax>
  3. export const loadMathJax = async (options?: {
  4. enableMenu?: boolean
  5. numbering?: string
  6. singleDollar?: boolean
  7. useLabelIds?: boolean
  8. }) => {
  9. if (!mathJaxPromise) {
  10. mathJaxPromise = new Promise((resolve, reject) => {
  11. options = {
  12. enableMenu: false,
  13. singleDollar: true,
  14. useLabelIds: false,
  15. ...options,
  16. }
  17. const inlineMath = [['\\(', '\\)']]
  18. if (options.singleDollar) {
  19. inlineMath.push(['$', '$'])
  20. }
  21. // https://docs.mathjax.org/en/v3.2-latest/upgrading/v2.html
  22. window.MathJax = {
  23. // https://docs.mathjax.org/en/latest/options/input/tex.html#the-configuration-block
  24. tex: {
  25. macros: {
  26. // Implements support for the \bm command from the bm package. It bolds the argument in math mode.
  27. // https://github.com/mathjax/MathJax/issues/1219#issuecomment-341059843
  28. bm: ['\\boldsymbol{#1}', 1],
  29. // MathJax 3 renders \coloneq as :- whereas the mathtools package
  30. // renders it as :=. Here we override the \coloneq macro to produce
  31. // the := symbol.
  32. coloneq: '\\coloneqq',
  33. },
  34. inlineMath,
  35. displayMath: [
  36. ['\\[', '\\]'],
  37. ['$$', '$$'],
  38. ],
  39. packages: {
  40. '[-]': [
  41. 'html', // avoid creating HTML elements/attributes
  42. 'require', // prevent loading disabled packages
  43. ],
  44. },
  45. processEscapes: true,
  46. processEnvironments: true,
  47. useLabelIds: options.useLabelIds,
  48. tags: options.numbering,
  49. },
  50. loader: {
  51. load: [
  52. 'ui/safe', // https://docs.mathjax.org/en/latest/options/safe.html
  53. ],
  54. },
  55. options: {
  56. enableMenu: options.enableMenu, // https://docs.mathjax.org/en/latest/options/menu.html
  57. },
  58. startup: {
  59. typeset: false,
  60. pageReady() {
  61. // disable the "Math Renderer" option in the context menu,
  62. // as only SVG is available
  63. window.MathJax.startup.document.menu.menu
  64. .findID('Renderer')
  65. .disable()
  66. },
  67. ready() {
  68. window.MathJax.startup.defaultReady()
  69. // remove anything from the "font-family" attribute after a semicolon
  70. // so it's not added to the style attribute
  71. // https://github.com/mathjax/MathJax/issues/3129#issuecomment-1807225345
  72. const { safe } = window.MathJax.startup.document
  73. safe.filterAttributes.set('fontfamily', 'filterFontFamily')
  74. safe.filterMethods.filterFontFamily = (
  75. _safe: any,
  76. family: string
  77. ) => family.split(/;/)[0]
  78. },
  79. },
  80. }
  81. const script = document.createElement('script')
  82. const path = getMeta('ol-mathJaxPath')
  83. if (!path) {
  84. reject(new Error('No MathJax path found'))
  85. return
  86. }
  87. script.src = path
  88. script.addEventListener('load', async () => {
  89. await window.MathJax.startup.promise
  90. document.head.appendChild(window.MathJax.svgStylesheet())
  91. resolve(window.MathJax)
  92. })
  93. script.addEventListener('error', reject)
  94. document.head.append(script)
  95. })
  96. }
  97. return mathJaxPromise
  98. }