TOC コンポーネントとヘッダー ID

TOC コンポーネントは、ヘッダーのテキストに基づいてヘッダー要素の id 属性を生成します。

例えば、以下のヘッダーがあります。

main outlet

この間隔は、Discourse アプリの要素である #main-outlet に適用されたスタイルに由来するもので、この投稿とは無関係です。

ヘッダーに別の id を指定できれば、これは致命的な問題ではありません。TOC コンポーネントはこの機能をサポートしています。

https://github.com/discourse/DiscoTOC/blob/master/common/header.html#L293

しかし残念ながら、Discourse は上記のコードが実行される前に投稿要素から id 属性を削除してしまうため、このロジックは機能しません。

以下は、<h4 id="alt-main-outlet">main outlet</h4> を使用したヘッダーの例です。

main outlet

ご覧の通り、これは alt-main-outlet ではなく、依然として main-outlet を使用しています。

Discourse がページ要素へのハッキングを想定してこのような処理を行っているのだと推測されますが、TOC コンポーネントを使えばこれを簡単に回避できます。

もしこの問題に対する解決策があるか、あるいは私が見過ごしている既によく議論されている問題であれば、以下に続く勝手な意見についてお詫び申し上げます :slight_smile:


追伸

個人的には、Discourse は要素の id 属性を削除すべきではないと考えています。これはウェブページの基本的な構造であり、URL フラグメントを用いたページナビゲーションで使用されます。投稿内の要素へのリンクを作成したいと考える作者には、その権利があるべきだと考えます。

TOC が ID のハッキングを可能にしているという事実は、そもそも ID を削除するという対策が不要である可能性を示唆しています。

もし Discourse チームが ID の乗っ取りを懸念しているなら、すべての Discourse ID にプレフィックス(例:discourse-main-outlet)を付け、ID の削除はそのプレフィックス付きの ID のみに適用すべきです。

既存のコードを考慮すると、これが不可能であることは理解できます。

除外する ID のセット(例:main-outlet など)を定義し、それらを削除するという案も考えられます。これでも TOC を使ってこの対策を回避できるという問題は残りますが、少なくとも作者が有用なアンカーを作成できるようにはなります。


追伸その 2

これに直接関連する問題として、同じテキスト内容を持つヘッダーの扱いがあります。

Topic One

Examples

Topic Two

Examples

TOC を使用すると、両方の Examples ヘッダーが同じ ID を持ってしまい、これは明らかに不具合です。TOC はインクリメントするインデックス(例:examplesexamples-2 など)を付与できるはずです(おそらくデフォルトでそうあるべきです)が、それでもより良いのは、上記の問題を解決し、作者がコンテンツの記述方法を決められるようにすることです。例えば、<h5 id="topic-one-examples">Examples</h5> のような形です。

@Johani これについてどう思いますか?

見出しを追加する必要がある場合は、heading-- でプレフィックスする必要があります。詳しくは、こちらをご覧ください:Linking to a heading within a post or topic

そのようにプレフィックスされていない ID は、ID の値に関係なくすべて削除されます。

現在、TOC コンポーネントでは重複するテキストを持つ見出しはサポートされていません(過去にもありませんでした)。このコンポーネントは、見出しのテキストに基づいて ID を生成するため、完全に同じテキストを持つ 2 つの見出しは同じ ID を取得してしまいます。

自動 ID 生成は 次の Discourse リリース の機能リストに含まれており、重複する見出しの問題については ID に見出しのインデックスを追加することで対応する予定であるため、現時点ではこのコンポーネントでこの問題を修正する予定はありません。

これをコアに実装する際、生成される見出しにプレフィックスを追加するだけで十分だと考えます。

なるほど、納得です。詳しいご説明をありがとうございます!