TOC 组件和标题 ID

TOC 组件会根据标题文本生成标题元素的 id 属性。

例如,这是一个标题:

main outlet

间距来自应用于 #main-outlet 的样式,这是 Discourse 应用的一个元素,与本文无关。

如果我能指定一个替代的 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

请注意,它仍然使用了 main-outlet 而不是 alt-main-outlet

我想 Discourse 这样做是为了防止有人篡改页面元素。但有了 TOC 组件,绕过这一点其实很容易。

如果这个问题有解决方案,或者这是一个已经被广泛讨论而我遗漏的问题,那么对于接下来这些未经请求的意见,我表示歉意:)


附言:

就个人而言,我认为 Discourse 不应该移除元素的 id 属性。这是网页结构的基本组成部分,并通过 URL 片段用于页面导航。如果有人想在帖子中创建指向某个元素的链接,我认为这是他们作为作者的权利。

TOC 的存在使得 ID 篡改成为可能,这暗示了最初移除 ID 这一措施本身或许可以取消。

如果 Discourse 团队确实担心 ID 被劫持,那么所有 Discourse 的 ID 都应该加上前缀,例如 discourse-main-outlet,而 ID 移除规则应仅适用于这些带前缀的 ID。

我能理解由于现有代码的存在,这几乎是不可能的!

可以设想一个被排除在外的 ID 列表(例如 main-outlet 等),这些 ID 会被移除。这仍然无法解决 TOC 被用来绕过这一安全措施的问题,但至少能让作者创建有用的锚点。


再附言:

与此直接相关的是具有相同文本内容的标题问题。

主题一

示例

主题二

示例

使用 TOC 时,两个 示例 标题都会获得相同的 ID,这显然是有问题的。TOC 可以追加递增的索引(例如 examplesexamples-2 等)——这很可能应该作为默认行为——但更好的解决方案是上面讨论的问题,即让作者自行决定如何描述其内容。例如 <h5 id="topic-one-examples">示例</h5> 等。

@Johani 你觉得这个怎么样?

2 个赞

如果您需要添加标题,则必须在其前加上 heading-- 前缀。有关此的更多信息,请访问 Linking to a heading within a post or topic

未以此方式添加前缀的 ID 都会被移除,无论其 ID 值是什么。

目录(TOC)组件目前不支持(也从未支持过)具有重复文本的标题。该组件会根据标题文本生成 ID。因此,两个完全相同的标题文本会生成相同的 ID。

目前我们暂无计划修补此组件,因为自动生成 ID 已列入 Discourse 下一个版本 的功能清单中。我们计划通过在标题 ID 中添加其索引来解决重复标题的问题。

当我们在核心功能中实现此机制时,我认为为生成的标题添加前缀就足够了。

3 个赞

这说得通。感谢详细的解释!

3 个赞