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 可以追加递增的索引(例如 examples、examples-2 等)——这很可能应该作为默认行为——但更好的解决方案是上面讨论的问题,即让作者自行决定如何描述其内容。例如 <h5 id="topic-one-examples">示例</h5> 等。