From 686736d3c2221b18b8c103b57e08964329c83c33 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Mon, 12 Aug 2024 09:31:09 +0200 Subject: [PATCH] FIX: adds katex support for chat (#88) Also drops jquery support and uses `decorateCookedElement` instead of `decorateCooked` for posts. --- .../initializers/discourse-math-katex.js | 96 +++++++++++-------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/assets/javascripts/initializers/discourse-math-katex.js b/assets/javascripts/initializers/discourse-math-katex.js index d3d5420..6d26ab7 100644 --- a/assets/javascripts/initializers/discourse-math-katex.js +++ b/assets/javascripts/initializers/discourse-math-katex.js @@ -1,72 +1,84 @@ -import $ from "jquery"; import loadScript from "discourse/lib/load-script"; import { withPluginApi } from "discourse/lib/plugin-api"; -function ensureKaTeX() { - return loadScript("/plugins/discourse-math/katex/katex.min.js").then(() => { - return loadScript("/plugins/discourse-math/katex/katex.min.css", { +async function ensureKaTeX() { + try { + await loadScript("/plugins/discourse-math/katex/katex.min.js"); + await loadScript("/plugins/discourse-math/katex/katex.min.css", { css: true, - }) - .then(() => { - return loadScript("/plugins/discourse-math/katex/mhchem.min.js"); - }) - .then(() => { - return loadScript("/plugins/discourse-math/katex/copy-tex.min.js"); - }); - }); + }); + await loadScript("/plugins/discourse-math/katex/mhchem.min.js"); + await loadScript("/plugins/discourse-math/katex/copy-tex.min.js"); + } catch (e) { + // eslint-disable-next-line no-console + console.error("Failed to load KaTeX dependencies.", e); + } } function decorate(elem, katexOpts) { - const $elem = $(elem); katexOpts["displayMode"] = elem.tagName === "DIV"; - if ($elem.data("applied-katex")) { + if (elem.dataset.appliedKatex) { return; } - $elem.data("applied-katex", true); - if ($elem.hasClass("math")) { - const tag = elem.tagName === "DIV" ? "div" : "span"; - const displayClass = tag === "div" ? "block-math" : "inline-math"; - const text = $elem.text(); - $elem.addClass(`math-container ${displayClass} katex-math`).text(""); - window.katex.render(text, elem, katexOpts); + elem.dataset.appliedKatex = true; + + if (!elem.classList.contains("math")) { + return; } + + const tag = elem.tagName === "DIV" ? "div" : "span"; + const displayClass = tag === "div" ? "block-math" : "inline-math"; + const text = elem.textContent; + elem.classList.add("math-container", displayClass, "katex-math"); + elem.textContent = ""; + window.katex.render(text, elem, katexOpts); } -function katex($elem) { - if (!$elem || !$elem.find) { +async function katex(elem) { + if (!elem) { return; } - const mathElems = $elem.find(".math"); - - if (mathElems.length > 0) { - ensureKaTeX().then(() => { - // enable persistent macros with are disabled by default: https://katex.org/docs/api.html#persistent-macros - // also enable equation labelling and referencing which are disabled by default - // both of these are enabled in mathjax by default, so now the katex implementation is (more) mathjax compatible - const katexOpts = { - trust: (context) => ["\\htmlId", "\\href"].includes(context.command), - macros: { - "\\eqref": "\\href{###1}{(\\text{#1})}", - "\\ref": "\\href{###1}{\\text{#1}}", - "\\label": "\\htmlId{#1}{}", - }, - displayMode: false, - }; - mathElems.each((idx, elem) => decorate(elem, katexOpts)); - }); + const mathElems = elem.querySelectorAll(".math"); + if (!mathElems.length > 0) { + return; } + + await ensureKaTeX(); + + // enable persistent macros with are disabled by default: https://katex.org/docs/api.html#persistent-macros + // also enable equation labelling and referencing which are disabled by default + // both of these are enabled in mathjax by default, so now the katex implementation is (more) mathjax compatible + const katexOpts = { + trust: (context) => ["\\htmlId", "\\href"].includes(context.command), + macros: { + "\\eqref": "\\href{###1}{(\\text{#1})}", + "\\ref": "\\href{###1}{\\text{#1}}", + "\\label": "\\htmlId{#1}{}", + }, + displayMode: false, + }; + mathElems.forEach((mathElem) => decorate(mathElem, katexOpts)); } function initializeMath(api) { - api.decorateCooked( + api.decorateCookedElement( function (elem) { katex(elem); }, { id: "katex" } ); + + if (api.decorateChatMessage) { + api.decorateChatMessage( + (element) => { + katex(element); + }, + { id: "katex-chat" } + ); + } } export default {