数学は引用可能であるべき

科学ソフトウェア向けの Discourse フォーラムを利用しており、math プラグインを使用しています。残念ながら、数式は引用できません。

テキストを選択すると「引用」ボタンが表示されます:

これをクリックすると、以下のような結果になります:

[quote]
closeness centrality の定義:

ci=1N−1N∑j=11dij c_i = \frac{1}{N-1} \sum_{j=1}^N\frac{1}{d_{ij}}
[/quote]

引用部分を見ると、数式が読み取れない奇妙なテキスト形式で表示され、その後に実際の LaTeX ソースが続きますが、$ で囲まれていません。

現時点ではこの問題の修正はないと推測されます。将来的に改善されると良いのですが。

「いいね!」 8

これはまだ発生しており、インライン数式でも起こります。これは当インスタンスのメンバーによって報告されました:

「いいね!」 3

なお、この整理を行うべきだという点には完全に賛成ですが、非常に複雑に感じられます。

上級スキルをお持ちの方が挑戦される場合に備え、pr-welcome を付与しました。

「いいね!」 7

引用数式について調査しました(PRを作成するか、既存のPRに貢献することを検討しています)。

初期の考えと調査結果をここにまとめます。

  • 引用はすべて、これらの主要なコンポーネントを経由するようです。
  • buildQuote 関数
  • TopicController.selectedText
  • 引用に渡されるコンテンツは this.quoteState.buffer から取得されます。これは QuoteButton._selectionChanged で(おそらく他の場所でも)設定されます。
  • これは selectedText を呼び出します。
  • これは toMarkdown を呼び出します。
  • buildQuote 関数は投稿オブジェクトを受け取ります。これは投稿の完全なJSON記述だと思います。

したがって、私の最初の印象では、これらの点のいずれかが修正可能かもしれません。

  • toMarkdown はさまざまなHTMLタグに対して要素を照合します。MathJaxはカスタム要素を使用していると思いますが、検出可能だと思います(SVGレンダリングはそうではないかもしれません)。KaTeXもそうでしょうか?
  • selectedText はコードブロックやoneboxのような要素のマッチングを行います。MathJax/KaTeX要素を検出して変換できるかもしれません。(注:変換ロジックをメインのDiscourseコードベースではなく、discourse-mathプラグインに追加できるように、フックまたは同様のものを用意するのが良いでしょう。)
  • 他の点は、これら2つほど適していないようです。

アプローチと生の数式を取得する方法に関するその他の考え。

KaTeX / MathJax + SVG[^1] の動作によっては、数式の各インスタンスにはルートHTML要素があると思います(アクセシビリティなどのための非表示要素がいくつかあるため、複数になる可能性もあります)。したがって、数式が存在する場所がわかれば、投稿の生のコンテンツから $ で区切られたインスタンスを解析できるかもしれません(ただし、インタープリターはトリッキーです。コードベースにすでに存在するものはありますか?)。

[^1]:MathJax + SVGはサポートされていないと思いますが、したがって問題ではないかもしれません。

あるいは、MathJaxには少なくとも右クリック > texを表示するような機能があります(これは $ のペア間のリテラル文字列であるはずです)。それをどのようにフックできるかはわかりませんが、MathJax v2、v3、およびKaTeXでそれが可能な方法があれば、それを使用してフォーマットされた数式を選択して $ ... $ に置き換えることができるはずです(注:これはインライン数式の場合に機能します。他の種類の場合もカバーする必要があります。それらは $$ ... $$ または [/ ... /] デリミタを使用します。)

現在の問題点:

  • フックを実装する方法がわかりません。また、使用できるより良いものや、Discourseのコードベースでのより良い方法があるかどうかもわかりません。
  • MathJax/KaTeXに関するいくつかの不明点があり、調査が必要です。
  • HTML要素 - それらを確実に検出するにはどうすればよいですか?
  • 生のTeXコードをどのように取得しますか?

修正する場所/対象、その他の実装方法、またはその他のアイデアがあれば、投稿してください。

「いいね!」 6

Discourse Math は、2026年1月に新しい公式コアバンドルバージョンに大幅にアップグレードされ、デフォルトで MathJax 4.1、代替として KaTeX が使用されるようになりました。プラグインのドキュメントには、KaTeX には LaTeX ソースをコピーするための CopyTex 拡張機能が含まれているとも記載されています。

数式が多い投稿の引用選択を改善するための小さなテーマコンポーネントパッチを追加する価値はあるでしょうか?

Physics with Ethan のような MathJax を多用するサイトにとって、最も実用的なアイデアは次のとおりです。

  1. Discourse が選択した HTML を Markdown に戻す前にインターセプトする。
  2. 数式のラッパー要素を見つける。
  3. それらを $...$ または $$...$$ でラップされた元の TeX ソースに置き換える。
  4. その後、Discourse に引用の構築を続行させる。

以下は、Horizon (または Default) テーマの </head> または JS エリアを変更する価値がある場合に私が開始するであろう、考えられるテーマコンポーネントスクリプトです。


<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 に流れることから推測されたものです。
  • これは、Discourse Math で現在のデフォルトである MathJax プロバイダーを使用している場合に最も役立つ可能性が高く、私が通常使用するオプションです。
  • スクリプトは、レンダリングされた数式が mjx-container.MathJax、または別のラッパーとして最終的にどうなるかに応じて、小さなセレクターの調整が必要になる場合があります。新しい標準インストールであるステージングサイトでテストする必要があります。
  • 混合インライン/ブロック選択やネストされた引用されたコンテンツなど、すべてのエッジケースで完璧である可能性は低いです。

Discourse が CopyTex を備えた KaTeX を公式にサポートするようになったため、LaTeX ソースをコピーすることが主な問題点である場合は、プロバイダーを切り替えるという別の方法があります。これは引用選択を自動的に解決するわけではありませんが、レンダリングされた数式にはすでにコピーしやすいパスが組み込まれていることを意味します。

Physics with Ethan の場合、私のおすすめは次のとおりです。

  • 互換性とリッチなレンダリングを重視する場合は MathJax を維持する。
  • 上記のような小さな引用選択パッチを追加する。
  • Meta が適切なアップストリームソリューションを入手するまで、これをローカルの品質向上修正として扱う。2020年の機能トピックが2026年になっても開いていることは、アップストリームがここで遅れる可能性があることを示唆しています。

私の数式を多用するサイトである Physics with Ethan では、現在次のように考えています。

  • KaTeX に切り替えることができるという提案がない限り、MathJax を維持する。
  • 上記のパッチを使用して、Horizon テーマに引用選択パッチを追加する (ステージングサイトを使用)。
  • Meta が適切なアップストリームソリューションを入手するまで、これをローカルの品質向上修正として扱う。この2020年の機能トピックが2026年になっても開いていることは、アップストリームがここで遅れる可能性があることを示唆しています。
「いいね!」 3