From 1f9b90472d1561ae8cc6a1c3258ad57519eb12f3 Mon Sep 17 00:00:00 2001 From: mrducky Date: Sun, 26 Jul 2026 01:45:01 +0000 Subject: [PATCH 1/3] Update MathJax to version 4 for format preview. Adjust async behavior to await for MathJax. Update Content-Security-Policy to allow MathJax to dynamically load a worker and fonts. --- pinc/base.inc | 4 ++++ tools/proofers/previewControl.js | 15 ++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pinc/base.inc b/pinc/base.inc index c7fcf76227..9c8406f6cd 100644 --- a/pinc/base.inc +++ b/pinc/base.inc @@ -29,6 +29,10 @@ if (!headers_sent()) { // allow inline scripts until we remove them, and cdn.jsdelivr.net // for MathJAX "script-src 'self' 'unsafe-inline' cdn.jsdelivr.net", + // MathJAX 4 dynamically loads fonts and a worker + "font-src 'self' data:", + "worker-src 'self' blob:", + "connect-src 'self' cdn.jsdelivr.net", // 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 33e0f1e106..5f69c7960f 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); } @@ -190,7 +190,7 @@ window.addEventListener("DOMContentLoaded", () => { }; const mathJaxScriptElement = document.createElement("script"); mathJaxScriptElement.type = "text/javascript"; - mathJaxScriptElement.src = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"; + mathJaxScriptElement.src = "https://cdn.jsdelivr.net/npm/mathjax@4/tex-svg.js"; const scriptLoadPromise = new Promise(function (resolve) { mathJaxScriptElement.onload = function () { resolve(); @@ -205,7 +205,7 @@ window.addEventListener("DOMContentLoaded", () => { } initStyle(); - initView(); + await initView(); setupFont(); function colorChange(event) { @@ -404,8 +404,9 @@ window.addEventListener("DOMContentLoaded", () => { saveStyle(); // if loading MathJax, wait for it to finish initView().then(function () { - writePreviewText(); - hideConfig(); + writePreviewText().then(function () { + hideConfig(); + }); }); }, From d0dd568516cf131e44d444bb24e5ed036ed8312f Mon Sep 17 00:00:00 2001 From: mrducky Date: Sun, 26 Jul 2026 20:43:08 +0000 Subject: [PATCH 2/3] Serve mathjax4 ourself, rather than from a CDN. Simplify Content-Security-Policy to remove jsdelivr. Fix mathjax error when first enabling Preview Math. --- package-lock.json | 16 ++++++++++++++++ package.json | 1 + pinc/base.inc | 6 ++---- tools/proofers/previewControl.js | 5 +++-- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index e7fe7eb8a4..be62a55e90 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 90e552787b..be55f27ff9 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 9c8406f6cd..649b043e46 100644 --- a/pinc/base.inc +++ b/pinc/base.inc @@ -26,13 +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:", - "connect-src 'self' cdn.jsdelivr.net", // 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 5f69c7960f..6fe0009242 100644 --- a/tools/proofers/previewControl.js +++ b/tools/proofers/previewControl.js @@ -187,13 +187,14 @@ window.addEventListener("DOMContentLoaded", async () => { 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@4/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); }); From d1e91a7b286e0d644b7121d756ae566f4680832d Mon Sep 17 00:00:00 2001 From: mrducky Date: Sun, 26 Jul 2026 20:55:55 +0000 Subject: [PATCH 3/3] Fix previewControl.js formatting --- tools/proofers/previewControl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/proofers/previewControl.js b/tools/proofers/previewControl.js index 6fe0009242..1dd408a0fa 100644 --- a/tools/proofers/previewControl.js +++ b/tools/proofers/previewControl.js @@ -187,7 +187,7 @@ window.addEventListener("DOMContentLoaded", async () => { window.MathJax = { loader: { load: ["input/tex", "output/svg", "[tex]/unicode"] }, tex: { packages: { "[+]": ["unicode"] } }, - output: {font: "mathjax-newcm", fontPath: "../../node_modules/@mathjax/mathjax-newcm-font"}, + output: { font: "mathjax-newcm", fontPath: "../../node_modules/@mathjax/mathjax-newcm-font" }, }; const mathJaxScriptElement = document.createElement("script"); mathJaxScriptElement.type = "text/javascript";