Procházet zdrojové kódy

Use MathJax v3 on the editor page (#11330)

GitOrigin-RevId: 5e51404c54e49735988f399ea080b6cb4be726d3
Alf Eaton před 3 roky
rodič
revize
8b610d2d1c

+ 13 - 0
package-lock.json

@@ -22595,6 +22595,12 @@
       "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.9.tgz",
       "integrity": "sha512-NOGEDTIM9+MrsqnjPEjVGNx4q0GQxqm61yQwSK+/5S59i26wId5IC5gNu9/bu8+CCVl5p9G2IHcAl/wJa+5+BQ=="
     },
+    "node_modules/mathjax-3": {
+      "name": "mathjax",
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-3.2.2.tgz",
+      "integrity": "sha512-Bt+SSVU8eBG27zChVewOicYs7Xsdt40qm4+UpHyX7k0/O9NliPc+x77k1/FEsPsjKPZGJvtRZM1vO+geW0OhGw=="
+    },
     "node_modules/maxmind": {
       "version": "4.3.6",
       "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.6.tgz",
@@ -35778,6 +35784,7 @@
         "marked": "^4.1.0",
         "match-sorter": "^6.2.0",
         "mathjax": "^2.7.9",
+        "mathjax-3": "npm:mathjax@^3.2.2",
         "method-override": "^2.3.3",
         "minimist": "^1.2.7",
         "mmmagic": "^0.5.3",
@@ -46297,6 +46304,7 @@
         "marked": "^4.1.0",
         "match-sorter": "^6.2.0",
         "mathjax": "^2.7.9",
+        "mathjax-3": "npm:mathjax@^3.2.2",
         "mensch": "^0.3.4",
         "method-override": "^2.3.3",
         "mini-css-extract-plugin": "^2.6.0",
@@ -60482,6 +60490,11 @@
       "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.9.tgz",
       "integrity": "sha512-NOGEDTIM9+MrsqnjPEjVGNx4q0GQxqm61yQwSK+/5S59i26wId5IC5gNu9/bu8+CCVl5p9G2IHcAl/wJa+5+BQ=="
     },
+    "mathjax-3": {
+      "version": "npm:mathjax@3.2.2",
+      "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-3.2.2.tgz",
+      "integrity": "sha512-Bt+SSVU8eBG27zChVewOicYs7Xsdt40qm4+UpHyX7k0/O9NliPc+x77k1/FEsPsjKPZGJvtRZM1vO+geW0OhGw=="
+    },
     "maxmind": {
       "version": "4.3.6",
       "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.6.tgz",

+ 6 - 0
services/web/app/src/infrastructure/ExpressLocals.js

@@ -179,6 +179,12 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
       }
     )}`
 
+    res.locals.mathJax3Path = `/js/libs/mathjax3/es5/tex-svg-full.js?${querystring.stringify(
+      {
+        v: require('mathjax-3/package.json').version,
+      }
+    )}`
+
     res.locals.lib = PackageVersions.lib
 
     res.locals.moment = moment

+ 2 - 1
services/web/app/views/project/editor.pug

@@ -120,6 +120,7 @@ block foot-scripts
 	each file in (useOpenTelemetry ? entrypointScripts("tracing") : [])
 		script(type="text/javascript", nonce=scriptNonce, src=file)
 	script(type="text/javascript", nonce=scriptNonce, src=(wsUrl || '/socket.io') + '/socket.io.js')
-	script(type="text/javascript", nonce=scriptNonce, src=mathJaxPath)
+	if (richTextVariant !== 'cm6')
+		script(type="text/javascript", nonce=scriptNonce, src=mathJaxPath)
 	each file in entrypointScripts("ide")
 		script(type="text/javascript", nonce=scriptNonce, src=file)

+ 2 - 0
services/web/app/views/project/editor/meta.pug

@@ -37,6 +37,8 @@ meta(name="ol-useOpenTelemetry" data-type="boolean" content=useOpenTelemetry)
 meta(name="ol-showSupport", data-type="boolean" content=showSupport)
 meta(name="ol-showCM6SwitchAwaySurvey", data-type="boolean" content=showCM6SwitchAwaySurvey)
 meta(name="ol-richTextVariant" content=richTextVariant)
+if (richTextVariant === 'cm6')
+	meta(name="ol-mathJax3Path" content=mathJax3Path)
 
 - var fileActionI18n = ['edited', 'renamed', 'created', 'deleted'].reduce((acc, i) => {acc[i] = translate('file_action_' + i); return acc}, {})
 meta(name="ol-fileActionI18n" data-type="json" content=fileActionI18n)

+ 0 - 56
services/web/frontend/js/features/chat/components/message-content.js

@@ -1,56 +0,0 @@
-import { useRef, useEffect } from 'react'
-import PropTypes from 'prop-types'
-import Linkify from 'react-linkify'
-
-function MessageContent({ content }) {
-  const root = useRef(null)
-
-  useEffect(() => {
-    if (!(window.MathJax && window.MathJax.Hub)) {
-      return
-    }
-    const MJHub = window.MathJax.Hub
-    const inlineMathConfig =
-      (MJHub.config &&
-        MJHub.config.tex2jax &&
-        MJHub.config.tex2jax.inlineMath) ||
-      []
-    const alreadyConfigured = inlineMathConfig.some(
-      c => c[0] === '$' && c[1] === '$'
-    )
-    if (!alreadyConfigured) {
-      MJHub.Config({
-        tex2jax: {
-          inlineMath: inlineMathConfig.concat([['$', '$']]),
-        },
-      })
-    }
-  }, [])
-
-  useEffect(() => {
-    // adds attributes to all the links generated by <Linkify/>, required due to https://github.com/tasti/react-linkify/issues/99
-    for (const a of root.current.getElementsByTagName('a')) {
-      a.setAttribute('target', '_blank')
-      a.setAttribute('rel', 'noreferrer noopener')
-    }
-
-    // MathJax typesetting
-    const MJHub = window.MathJax.Hub
-    const timeoutHandler = setTimeout(() => {
-      MJHub.Queue(['Typeset', MJHub, root.current])
-    }, 0)
-    return () => clearTimeout(timeoutHandler)
-  }, [content])
-
-  return (
-    <p ref={root}>
-      <Linkify>{content}</Linkify>
-    </p>
-  )
-}
-
-MessageContent.propTypes = {
-  content: PropTypes.string.isRequired,
-}
-
-export default MessageContent

+ 57 - 0
services/web/frontend/js/features/chat/components/message-content.tsx

@@ -0,0 +1,57 @@
+import { useRef, useEffect, type FC } from 'react'
+// @ts-ignore
+import Linkify from 'react-linkify'
+import { loadMathJax } from '../../../../../modules/source-editor/frontend/js/utils/mathjax'
+import useIsMounted from '../../../shared/hooks/use-is-mounted'
+import { configureMathJax } from '../../mathjax/configure'
+
+const MessageContent: FC<{ content: string }> = ({ content }) => {
+  const root = useRef<HTMLDivElement | null>(null)
+  const mounted = useIsMounted()
+
+  useEffect(() => {
+    if (root.current) {
+      // adds attributes to all the links generated by <Linkify/>, required due to https://github.com/tasti/react-linkify/issues/99
+      for (const a of root.current.getElementsByTagName('a')) {
+        a.setAttribute('target', '_blank')
+        a.setAttribute('rel', 'noreferrer noopener')
+      }
+
+      // MathJax v2 typesetting
+      if (window.MathJax?.Hub) {
+        const timeout = setTimeout(() => {
+          configureMathJax()
+
+          window.MathJax.Hub.Queue([
+            'Typeset',
+            window.MathJax.Hub,
+            root.current,
+          ])
+        }, 0)
+
+        return () => clearTimeout(timeout)
+      }
+
+      // MathJax v3 typesetting
+      loadMathJax()
+        .then(MathJax => {
+          if (mounted.current) {
+            MathJax.typesetPromise([root.current]).catch((error: Error) => {
+              console.error(error)
+            })
+          }
+        })
+        .catch(error => {
+          console.error(error)
+        })
+    }
+  }, [content, mounted])
+
+  return (
+    <p ref={root}>
+      <Linkify>{content}</Linkify>
+    </p>
+  )
+}
+
+export default MessageContent

+ 1 - 0
services/web/frontend/js/features/mathjax/configure.js

@@ -7,6 +7,7 @@ let configured = false
 
 export function configureMathJax() {
   if (configured) return
+  if (getMeta('ol-mathJax3Path')) return
   if (!mathJaxLoaded()) return
 
   const inlineMath = [['\\(', '\\)']]

+ 1 - 0
services/web/package.json

@@ -180,6 +180,7 @@
     "marked": "^4.1.0",
     "match-sorter": "^6.2.0",
     "mathjax": "^2.7.9",
+    "mathjax-3": "npm:mathjax@^3.2.2",
     "method-override": "^2.3.3",
     "minimist": "^1.2.7",
     "mmmagic": "^0.5.3",

+ 1 - 3
services/web/types/window.ts

@@ -29,9 +29,7 @@ declare global {
     isRestrictedTokenMember: boolean
     _reportCM6Perf: () => void
     _reportAcePerf: () => void
-    MathJax: {
-      Hub: Record<string, any>
-    }
+    MathJax: Record<string, any>
     overallThemes: OverallThemeMeta[]
   }
 }

+ 17 - 0
services/web/webpack.config.js

@@ -58,6 +58,7 @@ function getModuleDirectory(moduleName) {
 }
 
 const mathjaxDir = getModuleDirectory('mathjax')
+const mathjax3Dir = getModuleDirectory('mathjax-3')
 const aceDir = getModuleDirectory('ace-builds')
 
 const pdfjsVersions = ['pdfjs-dist213', 'pdfjs-dist31']
@@ -257,6 +258,22 @@ module.exports = {
     // Copy the required files for loading MathJax from MathJax NPM package
     new CopyPlugin({
       patterns: [
+        // https://www.npmjs.com/package/mathjax#user-content-hosting-your-own-copy-of-the-mathjax-components
+        {
+          from: 'es5/tex-svg-full.js',
+          to: 'js/libs/mathjax3/es5',
+          context: mathjax3Dir,
+        },
+        {
+          from: 'es5/input/tex/extensions/**/*.js',
+          to: 'js/libs/mathjax3',
+          context: mathjax3Dir,
+        },
+        {
+          from: 'es5/ui/**/*',
+          to: 'js/libs/mathjax3',
+          context: mathjax3Dir,
+        },
         { from: 'MathJax.js', to: 'js/libs/mathjax', context: mathjaxDir },
         { from: 'config/**/*', to: 'js/libs/mathjax', context: mathjaxDir },
         {