diff --git a/package-lock.json b/package-lock.json index ae5ac43110..db537dca1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30914,13 +30914,6 @@ "dev": true }, "node_modules/mathjax": { - "version": "2.7.9", - "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.9.tgz", - "integrity": "sha512-NOGEDTIM9+MrsqnjPEjVGNx4q0GQxqm61yQwSK+/5S59i26wId5IC5gNu9/bu8+CCVl5p9G2IHcAl/wJa+5+BQ==", - "dev": true - }, - "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==", @@ -46261,8 +46254,7 @@ "less": "^3.13.1", "less-loader": "^11.1.3", "match-sorter": "^6.2.0", - "mathjax": "^2.7.9", - "mathjax-3": "npm:mathjax@^3.2.2", + "mathjax": "^3.2.2", "mensch": "^0.3.4", "mini-css-extract-plugin": "^2.7.6", "mocha": "^10.2.0", @@ -55142,8 +55134,7 @@ "mailchimp-api-v3": "^1.12.0", "marked": "^4.1.0", "match-sorter": "^6.2.0", - "mathjax": "^2.7.9", - "mathjax-3": "npm:mathjax@^3.2.2", + "mathjax": "^3.2.2", "mensch": "^0.3.4", "method-override": "^2.3.3", "mini-css-extract-plugin": "^2.7.6", @@ -74114,13 +74105,7 @@ "dev": true }, "mathjax": { - "version": "2.7.9", - "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.9.tgz", - "integrity": "sha512-NOGEDTIM9+MrsqnjPEjVGNx4q0GQxqm61yQwSK+/5S59i26wId5IC5gNu9/bu8+CCVl5p9G2IHcAl/wJa+5+BQ==", - "dev": true - }, - "mathjax-3": { - "version": "npm:mathjax@3.2.2", + "version": "3.2.2", "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-3.2.2.tgz", "integrity": "sha512-Bt+SSVU8eBG27zChVewOicYs7Xsdt40qm4+UpHyX7k0/O9NliPc+x77k1/FEsPsjKPZGJvtRZM1vO+geW0OhGw==", "dev": true diff --git a/services/web/app/src/infrastructure/ExpressLocals.js b/services/web/app/src/infrastructure/ExpressLocals.js index 82bb64944e..d5c23547e6 100644 --- a/services/web/app/src/infrastructure/ExpressLocals.js +++ b/services/web/app/src/infrastructure/ExpressLocals.js @@ -1,7 +1,6 @@ const logger = require('@overleaf/logger') const Metrics = require('@overleaf/metrics') const Settings = require('@overleaf/settings') -const querystring = require('querystring') const _ = require('lodash') const { URL } = require('url') const Path = require('path') @@ -186,14 +185,7 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) { return chunks.map(chunk => staticFilesBase + chunk) } - res.locals.mathJaxPath = `/js/libs/mathjax/MathJax.js?${querystring.stringify( - { - config: 'TeX-AMS_HTML,Safe', - v: PackageVersions.version.mathjax, - } - )}` - - res.locals.mathJax3Path = `/js/libs/mathjax-3-${PackageVersions.version['mathjax-3']}/es5/tex-svg-full.js` + res.locals.mathJaxPath = `/js/libs/mathjax-${PackageVersions.version.mathjax}/es5/tex-svg-full.js` res.locals.lib = PackageVersions.lib diff --git a/services/web/app/src/infrastructure/PackageVersions.js b/services/web/app/src/infrastructure/PackageVersions.js index 06d4e7dfc3..bdf2ab54ec 100644 --- a/services/web/app/src/infrastructure/PackageVersions.js +++ b/services/web/app/src/infrastructure/PackageVersions.js @@ -1,7 +1,5 @@ const version = { - // Upgrade instructions: https://github.com/overleaf/write_latex/wiki/Upgrading-Ace - mathjax: '2.7.9', - 'mathjax-3': '3.2.2', + mathjax: '3.2.2', } module.exports = { diff --git a/services/web/app/views/layout-base.pug b/services/web/app/views/layout-base.pug index 87ec7affc6..7111251681 100644 --- a/services/web/app/views/layout-base.pug +++ b/services/web/app/views/layout-base.pug @@ -37,6 +37,7 @@ html( //- Configure dynamically loaded assets (via webpack) to be downloaded from CDN //- See: https://webpack.js.org/guides/public-path/#on-the-fly meta(name="ol-baseAssetPath" content=buildBaseAssetPath()) + meta(name="ol-mathJaxPath" content=mathJaxPath) meta(name="ol-usersEmail" content=getUserEmail()) meta(name="ol-ab" data-type="json" content={}) diff --git a/services/web/app/views/project/editor/meta.pug b/services/web/app/views/project/editor/meta.pug index 3ca59df463..77e8ad42aa 100644 --- a/services/web/app/views/project/editor/meta.pug +++ b/services/web/app/views/project/editor/meta.pug @@ -33,7 +33,6 @@ meta(name="ol-showTemplatesServerPro", data-type="boolean" content=showTemplates meta(name="ol-showPersonalAccessToken", data-type="boolean" content=showPersonalAccessToken) meta(name="ol-optionalPersonalAccessToken", data-type="boolean" content=optionalPersonalAccessToken) meta(name="ol-hasTrackChangesFeature", data-type="boolean" content=hasTrackChangesFeature) -meta(name="ol-mathJax3Path" content=mathJax3Path) meta(name="ol-inactiveTutorials", data-type="json" content=user.inactiveTutorials) meta(name="ol-projectTags" data-type="json" content=projectTags) meta(name="ol-idePageReact", data-type="boolean" content=idePageReact) diff --git a/services/web/cypress/support/shared/commands/mathjax.ts b/services/web/cypress/support/shared/commands/mathjax.ts index 73ed175318..ed4cb0213c 100644 --- a/services/web/cypress/support/shared/commands/mathjax.ts +++ b/services/web/cypress/support/shared/commands/mathjax.ts @@ -24,9 +24,9 @@ window.MathJax = { export const interceptMathJax = () => { // NOTE: this is just a URL to be intercepted with the stub, not the real (versioned) MathJax URL - const url = '/js/libs/mathjax-3/es5/tex-svg-full.js' + const url = '/js/libs/mathjax/es5/tex-svg-full.js' cy.window().then(win => { - win.metaAttributesCache.set('ol-mathJax3Path', url) + win.metaAttributesCache.set('ol-mathJaxPath', url) }) cy.intercept('GET', url, MATHJAX_STUB).as('mathjax-load-request') } diff --git a/services/web/frontend/js/base.js b/services/web/frontend/js/base.js index 5efb29fc29..c72058819a 100644 --- a/services/web/frontend/js/base.js +++ b/services/web/frontend/js/base.js @@ -22,7 +22,6 @@ import './modules/errorCatcher' import './modules/localStorage' import './modules/sessionStorage' import getMeta from './utils/meta' -import { configureMathJax } from './features/mathjax/configure' const App = angular .module('OverleafApp', [ @@ -40,8 +39,6 @@ const App = angular function ($qProvider, uiSelectConfig) { $qProvider.errorOnUnhandledRejections(false) uiSelectConfig.spinnerClass = 'fa fa-refresh ui-select-spin' - - configureMathJax() }, ]) diff --git a/services/web/frontend/js/directives/mathjax.js b/services/web/frontend/js/directives/mathjax.js deleted file mode 100644 index f391045b68..0000000000 --- a/services/web/frontend/js/directives/mathjax.js +++ /dev/null @@ -1,15 +0,0 @@ -/* global MathJax */ - -import App from '../base' - -export default App.directive('mathjax', function () { - return { - link(scope, element, attrs) { - if (!(MathJax && MathJax.Hub)) return - - setTimeout(() => { - MathJax.Hub.Queue(['Typeset', MathJax.Hub, element.get(0)]) - }, 0) - }, - } -}) diff --git a/services/web/frontend/js/features/chat/components/message-content.tsx b/services/web/frontend/js/features/chat/components/message-content.tsx index 3f64a0d07e..2459297a1b 100644 --- a/services/web/frontend/js/features/chat/components/message-content.tsx +++ b/services/web/frontend/js/features/chat/components/message-content.tsx @@ -1,8 +1,6 @@ import { useRef, useEffect, type FC } from 'react' -// @ts-ignore import Linkify from 'react-linkify' import useIsMounted from '../../../shared/hooks/use-is-mounted' -import { configureMathJax } from '../../mathjax/configure' import { loadMathJax } from '../../mathjax/load-mathjax' import { debugConsole } from '@/utils/debugging' @@ -18,18 +16,6 @@ const MessageContent: FC<{ content: string }> = ({ content }) => { a.setAttribute('rel', 'noreferrer noopener') } - // MathJax v2 typesetting - if (window.MathJax?.Hub) { - const { Hub } = window.MathJax - - const timeout = setTimeout(() => { - configureMathJax() - Hub.Queue(['Typeset', Hub, root.current]) - }, 0) - - return () => clearTimeout(timeout) - } - // MathJax v3 typesetting loadMathJax() .then(MathJax => { diff --git a/services/web/frontend/js/features/mathjax/configure.js b/services/web/frontend/js/features/mathjax/configure.js deleted file mode 100644 index 1cd476d294..0000000000 --- a/services/web/frontend/js/features/mathjax/configure.js +++ /dev/null @@ -1,49 +0,0 @@ -/* global MathJax */ - -import { mathJaxLoaded } from './util' -import getMeta from '../../utils/meta' - -let configured = false - -export function configureMathJax() { - if (configured) return - if (getMeta('ol-mathJax3Path')) return - if (!mathJaxLoaded()) return - - const inlineMath = [['\\(', '\\)']] - - if (!getMeta('ol-no-single-dollar')) { - inlineMath.push(['$', '$']) - } - - MathJax.Hub.Config({ - messageStyle: 'none', - imageFont: null, - // Fast preview, introduced in 2.5, is unhelpful due to extra codemirror refresh - // and disabling it avoids issues with math processing errors - // github.com/overleaf/write_latex/pull/1375 - 'fast-preview': { disabled: true }, - 'HTML-CSS': { - availableFonts: ['TeX'], - // MathJax's automatic font scaling does not work well when we render math - // that isn't yet on the page, so we disable it and set a global font - // scale factor - scale: 110, - matchFontHeight: false, - }, - TeX: { - equationNumbers: { autoNumber: 'AMS' }, - useLabelIDs: false, - }, - skipStartupTypeset: true, - tex2jax: { - processEscapes: true, - inlineMath, - displayMath: [ - ['$$', '$$'], - ['\\[', '\\]'], - ], - }, - }) - configured = true -} diff --git a/services/web/frontend/js/features/mathjax/index.js b/services/web/frontend/js/features/mathjax/index.js deleted file mode 100644 index fbf8734cd2..0000000000 --- a/services/web/frontend/js/features/mathjax/index.js +++ /dev/null @@ -1,14 +0,0 @@ -/* global MathJax */ -import { configureMathJax } from './configure' -import { mathJaxLoaded } from './util' - -function render(el) { - if (!mathJaxLoaded()) return - configureMathJax() - - setTimeout(() => { - MathJax.Hub.Queue(['Typeset', MathJax.Hub, el]) - }, 0) -} - -document.querySelectorAll('[data-ol-mathjax]').forEach(render) diff --git a/services/web/frontend/js/features/mathjax/index.ts b/services/web/frontend/js/features/mathjax/index.ts new file mode 100644 index 0000000000..c860596974 --- /dev/null +++ b/services/web/frontend/js/features/mathjax/index.ts @@ -0,0 +1,17 @@ +import { loadMathJax } from '@/features/mathjax/load-mathjax' +import { debugConsole } from '@/utils/debugging' +import getMeta from '@/utils/meta' + +window.addEventListener('DOMContentLoaded', function () { + const elements = document.querySelectorAll('[data-ol-mathjax]') + if (elements.length > 0) { + loadMathJax({ + enableMenu: true, + numbering: 'ams', + singleDollar: !getMeta('ol-no-single-dollar'), + useLabelIds: true, + }) + .then(MathJax => MathJax.typesetPromise([...elements])) + .catch(debugConsole.error) + } +}) diff --git a/services/web/frontend/js/features/mathjax/load-mathjax.ts b/services/web/frontend/js/features/mathjax/load-mathjax.ts index d9e9da5f01..0055f1ce73 100644 --- a/services/web/frontend/js/features/mathjax/load-mathjax.ts +++ b/services/web/frontend/js/features/mathjax/load-mathjax.ts @@ -2,9 +2,26 @@ import getMeta from '../../utils/meta' let mathJaxPromise: Promise -export const loadMathJax = async () => { +export const loadMathJax = async (options?: { + enableMenu?: boolean + numbering?: string + singleDollar?: boolean + useLabelIds?: boolean +}) => { if (!mathJaxPromise) { mathJaxPromise = new Promise((resolve, reject) => { + options = { + enableMenu: false, + singleDollar: true, + useLabelIds: false, + ...options, + } + + const inlineMath = [['\\(', '\\)']] + if (options.singleDollar) { + inlineMath.push(['$', '$']) + } + // https://docs.mathjax.org/en/v3.2-latest/upgrading/v2.html window.MathJax = { // https://docs.mathjax.org/en/latest/options/input/tex.html#the-configuration-block @@ -14,10 +31,7 @@ export const loadMathJax = async () => { // https://github.com/mathjax/MathJax/issues/1219#issuecomment-341059843 bm: ['\\boldsymbol{#1}', 1], }, - inlineMath: [ - ['\\(', '\\)'], - ['$', '$'], - ], + inlineMath, displayMath: [ ['\\[', '\\]'], ['$$', '$$'], @@ -30,6 +44,8 @@ export const loadMathJax = async () => { }, processEscapes: true, processEnvironments: true, + useLabelIds: options.useLabelIds, + tags: options.numbering, }, loader: { load: [ @@ -37,15 +53,22 @@ export const loadMathJax = async () => { ], }, options: { - enableMenu: false, // https://docs.mathjax.org/en/latest/options/menu.html + enableMenu: options.enableMenu, // https://docs.mathjax.org/en/latest/options/menu.html }, startup: { typeset: false, + pageReady() { + // disable the "Math Renderer" option in the context menu, + // as only SVG is available + window.MathJax.startup.document.menu.menu + .findID('Renderer') + .disable() + }, }, } const script = document.createElement('script') - const path = getMeta('ol-mathJax3Path') + const path = getMeta('ol-mathJaxPath') if (!path) { reject(new Error('No MathJax path found')) return diff --git a/services/web/frontend/js/features/mathjax/util.js b/services/web/frontend/js/features/mathjax/util.js deleted file mode 100644 index e3f98495bc..0000000000 --- a/services/web/frontend/js/features/mathjax/util.js +++ /dev/null @@ -1,5 +0,0 @@ -/* global MathJax */ - -export function mathJaxLoaded() { - return !!(typeof MathJax !== 'undefined' && MathJax && MathJax.Hub) -} diff --git a/services/web/frontend/js/marketing.js b/services/web/frontend/js/marketing.js index c79a6aece6..90fe6e5cd8 100644 --- a/services/web/frontend/js/marketing.js +++ b/services/web/frontend/js/marketing.js @@ -12,6 +12,7 @@ import './features/fallback-image' import './features/multi-submit' import './features/cookie-banner' import './features/autoplay-video' +import './features/mathjax' $('[data-ol-lang-selector-tooltip]').tooltip({ trigger: 'hover' }) $('[data-toggle="tooltip"]').tooltip() diff --git a/services/web/frontend/stories/chat.stories.jsx b/services/web/frontend/stories/chat.stories.jsx index 82dc4f4322..2f319a9457 100644 --- a/services/web/frontend/stories/chat.stories.jsx +++ b/services/web/frontend/stories/chat.stories.jsx @@ -1,4 +1,3 @@ -import { useEffect } from 'react' import ChatPane from '../js/features/chat/components/chat-pane' import useFetchMock from './hooks/use-fetch-mock' import { generateMessages } from './fixtures/chat-messages' @@ -47,23 +46,5 @@ export default { args: { resetUnreadMessages: () => {}, }, - decorators: [ - ScopeDecorator, - Story => { - useEffect(() => { - window.MathJax = { - Hub: { - Queue: () => {}, - config: { tex2jax: { inlineMath: [['$', '$']] } }, - }, - } - - return () => { - delete window.MathJax - } - }, []) - - return - }, - ], + decorators: [ScopeDecorator], } diff --git a/services/web/frontend/stories/source-editor/source-editor.stories.tsx b/services/web/frontend/stories/source-editor/source-editor.stories.tsx index e8dec5d9d3..eab278be77 100644 --- a/services/web/frontend/stories/source-editor/source-editor.stories.tsx +++ b/services/web/frontend/stories/source-editor/source-editor.stories.tsx @@ -142,7 +142,7 @@ export const Visual = (args: any, { globals: { theme } }: any) => { }) useMeta({ 'ol-showSymbolPalette': true, - 'ol-mathJax3Path': 'https://unpkg.com/mathjax@3.2.2/es5/tex-svg-full.js', + 'ol-mathJaxPath': 'https://unpkg.com/mathjax@3.2.2/es5/tex-svg-full.js', 'ol-inactiveTutorials': ['table-generator-promotion'], 'ol-project_id': '63e21c07946dd8c76505f85a', }) diff --git a/services/web/package.json b/services/web/package.json index d0a929fff3..5260277a2f 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -303,8 +303,7 @@ "less": "^3.13.1", "less-loader": "^11.1.3", "match-sorter": "^6.2.0", - "mathjax": "^2.7.9", - "mathjax-3": "npm:mathjax@^3.2.2", + "mathjax": "^3.2.2", "mensch": "^0.3.4", "mini-css-extract-plugin": "^2.7.6", "mocha": "^10.2.0", diff --git a/services/web/webpack.config.js b/services/web/webpack.config.js index de2b5345da..42ef1f26a9 100644 --- a/services/web/webpack.config.js +++ b/services/web/webpack.config.js @@ -64,7 +64,6 @@ function getModuleDirectory(moduleName) { } const mathjaxDir = getModuleDirectory('mathjax') -const mathjax3Dir = getModuleDirectory('mathjax-3') const pdfjsVersions = ['pdfjs-dist213', 'pdfjs-dist401'] @@ -77,13 +76,6 @@ if (MATHJAX_VERSION !== PackageVersions.version.mathjax) { ) } -const MATHJAX_3_VERSION = require('mathjax-3/package.json').version -if (MATHJAX_3_VERSION !== PackageVersions.version['mathjax-3']) { - throw new Error( - '"mathjax-3" version de-synced, update services/web/app/src/infrastructure/PackageVersions.js' - ) -} - module.exports = { // Defines the "entry point(s)" for the application - i.e. the file which // bootstraps the application @@ -277,57 +269,38 @@ module.exports = { // 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/mathjax-3-${PackageVersions.version['mathjax-3']}/es5`, + to: `js/libs/mathjax-${PackageVersions.version.mathjax}/es5`, toType: 'dir', - context: mathjax3Dir, + context: mathjaxDir, }, { from: 'es5/input/tex/extensions/**/*.js', - to: `js/libs/mathjax-3-${PackageVersions.version['mathjax-3']}`, + to: `js/libs/mathjax-${PackageVersions.version.mathjax}`, toType: 'dir', - context: mathjax3Dir, + context: mathjaxDir, }, { from: 'es5/ui/**/*', - to: `js/libs/mathjax-3-${PackageVersions.version['mathjax-3']}`, + to: `js/libs/mathjax-${PackageVersions.version.mathjax}`, toType: 'dir', - context: mathjax3Dir, - }, - { from: 'MathJax.js', to: 'js/libs/mathjax', context: mathjaxDir }, - { from: 'config/**/*', to: 'js/libs/mathjax', context: mathjaxDir }, - { - from: 'extensions/**/*', - globOptions: { - // https://github.com/mathjax/MathJax/issues/2403 - ignore: ['**/mathmaps/*.js'], - }, - to: 'js/libs/mathjax', context: mathjaxDir, }, { - from: 'localization/en/**/*', - to: 'js/libs/mathjax', + from: 'es5/a11y/**/*', + to: `js/libs/mathjax-${PackageVersions.version.mathjax}`, + toType: 'dir', context: mathjaxDir, }, { - from: 'jax/output/HTML-CSS/fonts/TeX/**/*', - to: 'js/libs/mathjax', + from: 'es5/input/mml.js', + to: `js/libs/mathjax-${PackageVersions.version.mathjax}/es5/input`, + toType: 'dir', context: mathjaxDir, }, { - from: 'jax/output/HTML-CSS/**/*.js', - to: 'js/libs/mathjax', - context: mathjaxDir, - }, - { - from: 'jax/element/**/*', - to: 'js/libs/mathjax', - context: mathjaxDir, - }, - { from: 'jax/input/**/*', to: 'js/libs/mathjax', context: mathjaxDir }, - { - from: 'fonts/HTML-CSS/TeX/woff/*', - to: 'js/libs/mathjax', + from: 'es5/sre/**/*', + to: `js/libs/mathjax-${PackageVersions.version.mathjax}`, + toType: 'dir', context: mathjaxDir, }, ...pdfjsVersions.flatMap(version => {