diff --git a/package-lock.json b/package-lock.json index e7fe7eb8a..be62a55e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "d3": "^6.6.2", "gettext.js": "^2.0.3", "jquery": "^3.5.1", + "mathjax": "^4.1.3", "resumablejs": "^1.1.0" }, "devDependencies": { @@ -352,6 +353,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mathjax/mathjax-newcm-font": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@mathjax/mathjax-newcm-font/-/mathjax-newcm-font-4.1.3.tgz", + "integrity": "sha512-gzAB3dFHilHX1l5x2xUqRL+1jDQt3Fyza1DkEMVXWC4E8SvsGdlgEza47HYi2WhVcgfkvf4zgUGzuhbq3Pjlew==", + "license": "Apache-2.0" + }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -2585,6 +2592,15 @@ "node": ">=6" } }, + "node_modules/mathjax": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-4.1.3.tgz", + "integrity": "sha512-BN/8Pkgn7G1pIDYJqd9md+JHsE/jydSYbyOZnSdSA0WziuVO8mRxdYiWFumkVVly/8U+hm9DpIIoWuvySverzw==", + "license": "Apache-2.0", + "dependencies": { + "@mathjax/mathjax-newcm-font": "^4.1.3" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", diff --git a/package.json b/package.json index 90e552787..be55f27ff 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "d3": "^6.6.2", "gettext.js": "^2.0.3", "jquery": "^3.5.1", + "mathjax": "^4.1.3", "resumablejs": "^1.1.0" }, "browserslist": [ diff --git a/pinc/base.inc b/pinc/base.inc index c7fcf7622..649b043e4 100644 --- a/pinc/base.inc +++ b/pinc/base.inc @@ -26,9 +26,11 @@ if (!headers_sent()) { "default-src 'self'", // allow inline styles "style-src 'self' 'unsafe-inline'", - // allow inline scripts until we remove them, and cdn.jsdelivr.net - // for MathJAX - "script-src 'self' 'unsafe-inline' cdn.jsdelivr.net", + // allow inline scripts until we remove them + "script-src 'self' 'unsafe-inline'", + // MathJAX 4 dynamically loads fonts and a worker + "font-src 'self' data:", + "worker-src 'self' blob:", // allow images from anywhere (due to project comments) "img-src 'self' *", // Disallow other sites from embedding pages in frames/iframes; diff --git a/tools/proofers/previewControl.js b/tools/proofers/previewControl.js index 33e0f1e10..1dd408a0f 100644 --- a/tools/proofers/previewControl.js +++ b/tools/proofers/previewControl.js @@ -15,7 +15,7 @@ import { ajax } from "../../scripts/api.js"; import { makePreview, defaultStyles } from "../../scripts/analyse_format.js"; import { validateText } from "../../scripts/text_validator.js"; -window.addEventListener("DOMContentLoaded", () => { +window.addEventListener("DOMContentLoaded", async () => { "use strict"; var supp_set = ["charBeforeStart", "sideNoteBlank"]; // this is a wrapper round text_preview which enables the padding @@ -88,14 +88,14 @@ window.addEventListener("DOMContentLoaded", () => { previewColorStyle.innerHTML = styleString; } - function writePreviewText() { + async function writePreviewText() { // makePreview is defined in analyse_format.js preview = makePreview(txtarea.value, viewMode, wrapMode, previewStyles); prevWin.style.whiteSpace = preview.ok && wrapMode ? "normal" : "pre"; prevWin.innerHTML = preview.txtout; if (preview.ok && previewStyles.allowMathPreview) { try { - MathJax.typeset([prevWin]); + await MathJax.typesetPromise([prevWin]); } catch (exception) { alert("MathJax error: " + exception); } @@ -187,13 +187,14 @@ window.addEventListener("DOMContentLoaded", () => { window.MathJax = { loader: { load: ["input/tex", "output/svg", "[tex]/unicode"] }, tex: { packages: { "[+]": ["unicode"] } }, + output: { font: "mathjax-newcm", fontPath: "../../node_modules/@mathjax/mathjax-newcm-font" }, }; const mathJaxScriptElement = document.createElement("script"); mathJaxScriptElement.type = "text/javascript"; - mathJaxScriptElement.src = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"; + mathJaxScriptElement.src = "../../node_modules/mathjax/tex-svg.js"; const scriptLoadPromise = new Promise(function (resolve) { mathJaxScriptElement.onload = function () { - resolve(); + MathJax.startup.promise.then(resolve); }; document.body.appendChild(mathJaxScriptElement); }); @@ -205,7 +206,7 @@ window.addEventListener("DOMContentLoaded", () => { } initStyle(); - initView(); + await initView(); setupFont(); function colorChange(event) { @@ -404,8 +405,9 @@ window.addEventListener("DOMContentLoaded", () => { saveStyle(); // if loading MathJax, wait for it to finish initView().then(function () { - writePreviewText(); - hideConfig(); + writePreviewText().then(function () { + hideConfig(); + }); }); },