Math should be quotable

Discourse Math 在 2026 年 1 月进行了大量升级,采用了新的官方核心捆绑版本,默认使用 MathJax 4.1,并提供 KaTeX 作为替代方案。插件文档还指出,KaTeX 包含用于复制 LaTeX 源代码的 CopyTex 扩展。

是否值得添加一个小的 theme-component 补丁来改善对数学内容丰富的帖子的引用选择?

对于像 Physics with Ethan 这样的重度 MathJax 网站,最实用的想法是:

  1. 拦截选定的 HTML,然后再由 Discourse 将其转换回 Markdown,
  2. 查找数学包装元素,
  3. 将它们替换为其原始 TeX 源代码,用 $...$$$...$$ 包装,
  4. 然后让 Discourse 继续构建引用。

如果值得修改 Horizon(或默认)主题的 </head> 或 JS 区域,这是一个我将开始使用的潜在 theme-component 脚本。


<script type="text/discourse-plugin" version="1.0">
  apiInitializer("1.34.0", (api) => {
    function texFromMathElement(el) {
      // MathJax v3/v4 通常将源代码存储在注释子元素中。
      const annotation =
        el.querySelector('annotation[encoding="application/x-tex"]') ||
        el.querySelector('annotation');

      if (annotation?.textContent?.trim()) {
        const tex = annotation.textContent.trim();

        // 启发式:块级数学包装器通常是显示容器。
        const isBlock =
          el.tagName === "MJX-CONTAINER" &&
          (el.getAttribute("display") === "true" ||
            el.getAttribute("display") === "block");

        return isBlock ? `$$\n${tex}\n$$` : `$${tex}$`;
      }

      return null;
    }

    function patchMathInFragment(fragment) {
      const candidates = fragment.querySelectorAll(
        "mjx-container, .math, .katex, .MathJax"
      );

      candidates.forEach((node) => {
        const replacement = texFromMathElement(node);
        if (!replacement) {
          return;
        }

        const textNode = document.createTextNode(replacement);
        node.replaceWith(textNode);
      });

      return fragment;
    }

    api.modifyClass("component:quote-button", {
      pluginId: "ethan-math-quote-fix",

      _selectionChanged() {
        this._super(...arguments);

        try {
          const selection = window.getSelection();
          if (!selection || selection.rangeCount === 0) {
            return;
          }

          const range = selection.getRangeAt(0);
          const fragment = range.cloneContents();
          patchMathInFragment(fragment);

          const container = document.createElement("div");
          container.appendChild(fragment);

          // 替换 Discourse 稍后转换为引用 Markdown 的缓冲区。
          if (this.quoteState) {
            this.quoteState.buffer = container.innerHTML;
          }
        } catch (e) {
          // 保持静默失败,以便正常引用仍然有效。
          console.warn("Math quote patch failed:", e);
        }
      },
    });
  });
</script>

有几个重要的注意事项:

  • 这是一个实用的补丁,而不是我从 Meta 找到的已发布内容。底层策略是从引用路径穿过选定的 HTML 并到达 toMarkdown 推断出来的。
  • 当我使用 MathJax 提供程序时,它最有可能提供帮助,这是 Discourse Math 中的当前默认设置,也是我通常使用的选项。
  • 脚本可能需要小的选择器调整,这取决于我的渲染数学最终是 mjx-container.MathJax 还是其他包装器。我会在一个暂存站点上进行测试,该站点将是一个新的标准安装。
  • 对于所有边缘情况,尤其是在混合行内/块选择或嵌套引用内容的情况下,它不太可能完美。

由于 Discourse 现在官方支持带有 CopyTex 的 KaTeX,如果我的主要痛点是复制 LaTeX 源代码而不是渲染保真度,那么另一种方法是切换提供程序。这不会自动解决引用选择问题,但它确实意味着渲染的数学已经内置了更易于复制的路径。

对于我的重度 MathJax 网站 Physics with Ethan,我目前正在考虑:

  • 保持 MathJax,除非有人建议我改用 KaTeX?,
  • 也许从上面(使用暂存站点)向 Horizon 主题添加一个引用选择补丁。
  • 并将其视为本地化的质量改进,直到出现适当的上游解决方案。这个 2020 年的功能主题在 2026 年仍然开放,这表明上游可能仍然很慢。
2 个赞