ShunS
(Shun Sakurai)
1
目录:
我创建了一个书签小工具,用于生成可折叠的目录(ToC),就像上面显示的那样。
希望它能帮助那些喜欢写长文的社区成员!
摘要
我有时会写很长的帖子/主题,需要一个目录来方便阅读。
我发现了一些现有的工具,例如 https://meta.discourse.org/t/discotoc-automatic-table-of-contents/111143,但我需要一个只为我自己使用的工具,不需要在整个社区安装。
发布结构化的帖子后,点击书签小工具,目录就会被复制到剪贴板。编辑帖子,然后将目录粘贴到顶部!
如何使用
安装
- 将页面保存为书签。
- 编辑名称,例如“
将论坛目录复制到剪贴板。”
- 编辑 URL 并粘贴以下代码。如果需要,请自定义代码——请参阅下面的两个“可选”项目。
javascript:(function() {
const copyForumTocToClipboard = function() {
const urlMatch = window.location.href.match(/\/t\/[^\/]*\/\d+\/?(\d*)/);
if (!urlMatch) return;
const postIndex = urlMatch ? urlMatch[1] : 1;
const anchors = document.querySelectorAll('#post_' + postIndex + ' div.cooked h6 a.anchor,h5 a.anchor,h4 a.anchor,h3 a.anchor,h2 a.anchor,h1 a.anchor');
if (!anchors) return;
let toc = '';
anchors.forEach(anchor => {
toc +=
' '.repeat((anchor.parentNode.nodeName[1] - 1) * 4) +
`<a href="${anchor.href}">${anchor.parentNode.textContent}</a><br>\n`;
});
if (!toc) return;
navigator.clipboard.writeText('<details open><summary>Table of contents: </summary><ul>\n' + toc + '</ul></details>');
};
copyForumTocToClipboard();
})();
代码功能
- 检查 URL 是否看起来像一个社区帖子:
https://{domain}/t/{title}/{topicID}(/{postIndex})。
- 检查帖子中是否包含
锚点(标题,如 <h1> 和 # )。
- 生成目录的 HTML 代码。
- 将代码复制到剪贴板。
生成目录
- 发布一个带有结构的帖子(HTML
<h1>, <h2>, … 和 Markdown # , ## , …)。Discourse 会为每个标题分配锚点。
- 确保你的帖子被选中,查看进度条(例如,
1/22)或 URL(例如,/1)。
- 点击书签栏中的书签小工具。
- 目录已复制到剪贴板。
使用目录
- 点击铅笔图标编辑帖子。
- 将代码粘贴到顶部。
- 检查目录项是否正确显示(已知问题:书签小工具会丢失一些表情符号)。
- (可选)更改/翻译“目录”。
- (可选)删除
open,如果你想让目录默认折叠。
- 点击“保存编辑”。如果你在发布帖子后几分钟内这样做,你的帖子将不会添加“已编辑”的铅笔图标。
技术说明(面向技术人员)
- 你也可以将 JavaScript 代码复制并粘贴到开发者控制台中。
- 我将代码包装在一个函数中,因为
return; 在函数外部不起作用。
'\u0026nbsp;'.repeat() 方法在预览主题时看起来有点乱,但在实际帖子中(与使用 <li></li> 相比)看起来效果最好(在我看来)。
- 当我测试
querySelectorAll 时,不知何故 h6 a.anchor,h5 a.anchor, ... 中的第一个项目没有找到。我把 h6 放在最前面,因为它可能是最不常用的。
- 如果 Discourse 更改其 UI/DOM,书签小工具可能会停止工作。如果你发现错误,请回复我。
截图
作为 meta.discourse.org 的新用户,我无法添加多张图片,所以我将所有截图合并在一张图片中:
18 个赞
哦,不错——这可以扩展为创建整个帖子的目录,包含所有回复吗?
3 个赞
Lhc_fl
(Linca)
3
帖子通常一次加载大约 20 条,我认为一次性创建所有帖子的目录会很困难。
4 个赞
mcwumbly
(Dave McClure)
4
太棒了!感谢分享,@ShunS!
我喜欢你为这个工具提出的问题框架,以及它如何满足那些本身没有权限更改现有网站内容的重要用户们的需求。
10 个赞
ShunS
(Shun Sakurai)
5
感谢您的回复 
正如 @Lhc_fl 所说,DOM 方法(HTML/JavaScript)可管理的条目数量有限。Discourse API 也许能帮助处理此类操作。
创建回复目录的另一个问题是,很难为每个回复定义标题。我们可以使用作者和日期等信息,但我不太确定这比现有的滚动进度条更有用。
谢谢 @mcwumbly!
6 个赞
Lilly
(Lillian Louis)
6
@ShunS 这太酷了,感谢分享。另外,欢迎来到 Meta

5 个赞
RBoy
(RBoy)
7
这太棒了,正是我想要的。它似乎解决了这个问题
为什么不将其提交给 Discourse,作为官方插件或功能包含进去?它可以包含在编辑器工具栏中,以便在帖子中自动插入目录。
6 个赞
RBoy
(RBoy)
8
我有一个建议,是否可以在目录(TOC)行的开头添加一个项目符号?在我的例子中,每个标题都是长行,所以项目符号有助于区分条目。
1 个赞
ShunS
(Shun Sakurai)
9
你好 @RBoy,感谢您的反馈和建议!
创建一个编辑器插件会很棒,但要阅读 Discourse 的源代码 来理解处理表情符号和定义标题/锚文本的逻辑,并创建一个插件存储库,这将需要大量工作。
像 Spoiler Alert 这样(看似)简单的插件,其存储库就很大,我没有足够的时间来完全投入开发。所以,我希望 Discourse 能优先处理类似 Automatic Table of Contents generation 的功能请求,并在此期间开发一个原生功能 
下面是带有项目符号的版本。<ul> 和 </ul> 之间的空格有点太大了,所以我更喜欢原始的非项目符号版本。
截图:
代码:
javascript:(function() {
const copyForumTocToClipboard = function() {
const urlMatch = window.location.href.match(/\/t\/[^\/]*\/\d+\/?(\d*)/);
if (!urlMatch) return;
const postIndex = 1;
const anchors = document.querySelectorAll('#post_' + postIndex + ' div.cooked h6 a.anchor,h5 a.anchor,h4 a.anchor,h3 a.anchor,h2 a.anchor,h1 a.anchor');
let toc = '';
let currentLevel = 1;
anchors.forEach(anchor => {
newLevel = anchor.parentNode.nodeName[1];
levelChange = newLevel - currentLevel;
toc +=
((levelChange >= 0) ? '<ul>'.repeat(levelChange) : '</ul>'.repeat(levelChange * -1)) +
`<li><a href="${anchor.href}">${anchor.parentNode.textContent}</a></li>`;
currentLevel = newLevel;
});
if (newLevel > 1) toc += '</ul>'.repeat(newLevel - 1);
toc = '<details open><summary>Table of contents: </summary><ul>\n' + toc + '</ul></details>';
navigator.clipboard.writeText(toc);
};
copyForumTocToClipboard();
})();
5 个赞
我们已经有一个目录插件,它不需要维护帖子正文中的目录。
如果安装了该插件,我绝对推荐它,因为它不会不同步。
不过,当 DiscoToC 不可用时,这个工具看起来很棒。干得好!
4 个赞
Lhc_fl
(Linca)
11
您可以使用主题组件来完成此操作。您可以查看 api 的 decorateCookedElement 方法,它应该很有用。
4 个赞
ShunS
(Shun Sakurai)
12
HI @supermathie,感谢您的回复。
当 DiscoToC 不可用时
是的,这就是区别。我创建了书签工具,因为我无法决定通常使用的论坛要安装哪个“主题组件”,而且只有少数人会写需要目录的长文本。
谢谢 @Lhc_fl,非常有帮助!
我在 GitHub 仓库中搜索并找到了该方法。我将考虑(仅在)我有足够的时间并且看到该功能有大量需求时进行开发。
但是,如果可以在社区中添加主题组件,那么正如 @supermathie 所说,已经有 DiscoTOC 了 
4 个赞
RBoy
(RBoy)
13
不幸的是,当标题超过几个词时,该插件完全无法使用,因为它会把事情搞得一团糟。如果标题是一两行长(例如 FAQ 页面),那么 Disco TOC 插件就会把页面搞得一团糟,这就是为什么我提出了这个关于内联 TOC(这个插件提供的)的请求,它非常适合这类页面
鉴于构建 Discourse 的团队中拥有如此多的天才/才华,将此功能作为 DiscoTOC 的替代方案应该不难,这样可以大大扩展其使用范围。