JQ331
2020 年6 月 22 日 21:05
1
在我的主题中,当加载主题详情页时,我需要获取该主题的 ID(如果可能,也获取名称,但 ID 就足够了)。
然后,我在主题中使用这些信息向 API 发起调用,以获取关于该主题的信息(例如调用类似 forum-name/t/topic-name/id.json 的端点)。
如何在主题详情页加载时获取主题的 ID?
显而易见的方法不够用
显而易见的解决方案是使用 window.location.href 或 window.location.pathname 从 URL 中获取信息。问题在于,主题详情页的 URL 可能呈现不同的形式。通常,它会是:
forum-name/t/topic-name/topic-id
如果 URL 始终是这种形式,那么使用 window.location.pathname 就能很好地工作——它会返回 “t/topic-name/topic-id”。
但是,有时主题详情页的 URL 还会附加主题的类别顺序,因此 URL 变为:forum-name/t/topic-name/topic-id/category-index
因此,仅使用 window.location.pathname 是不够的,因为我在程序上无法确定最后一个参数是 topic-id 还是 category-index。
也许可以通过正则表达式来解决这个问题,但这需要相当高超的正则表达式技巧。也可能可以通过 jQuery 查看页面上可能包含 ID 的元素来解决——但我尚未成功实现这一点。
maiki
(maiki)
2020 年6 月 23 日 01:39
2
这种情况何时/何地发生?我找不到相关信息。
无论如何,当此主题加载时,它包含一个 link 元素:
<link rel="canonical" href="https://meta.discourse.org/t/get-topic-id-when-the-topic-show-page-loads/155620" />
也许你可以从中获取它。
JQ331
2020 年6 月 23 日 02:11
3
在我的论坛上,当你点击一个话题时,这种情况实际上经常发生。如果你是从分类中点击话题,URL 的最后一部分将是该话题在分类中的编号。这也许是 Discourse 的某个设置?在 meta- 论坛上似乎没有这种现象,但我不认为在我的论坛上有什么特殊操作导致了这种情况。
不过,我不能总是依赖这种情况的发生,因为如果一个话题是分类中的第一个话题,它不会附加分类索引。所以据我所见,目前还没有一个好的方法可以判断它是否会出现在分类索引中。
从 div 中获取 ID 是可以的,但不幸的是,这比直接从 URL 或其他直接方式获取要慢得多。如果没有其他解决方案,你知道如何用 jQuery 获取该 Href 的值吗?
Bcat
(Bcat)
2020 年6 月 23 日 02:45
4
尝试
api.onPageChange((url, title) => {
var res = url.match(/\/t\/(.*?)\/(\w+)/);
if (res && res[2] > 0) {
console.log(res[2]);
}
});
Johani
(Joe)
2020 年6 月 23 日 02:56
5
你想实现什么目标?
这可能可行,但效率不高,因为你为每个用户(包括匿名用户)的每个主题页面视图都额外发起了一次 AJAX 请求。这将给服务器带来大量不必要的负载。
其实不然。主题的 URL 格式如下:
your.site.com/t/topic_title/topic_id/linked_post_number(可选)
在默认的 Discourse 安装中,URL 中不包含分类顺序。
如果你能描述一下你想解决的具体问题,而不是描述你为此提出的解决方案,我们可以更好地帮助你。
JQ331
2020 年6 月 23 日 12:49
6
这行得通!非常感谢。我理解,这里的 match 方法是通过 URL 来提取内容的,我猜是提取第三个“/”之后的内容,因为 ID 总是出现在 URL 的第三个“/”之后,URL 的形式是“/t/name/id/otherstuff”。能否简单解释一下你的正则表达式是如何实现这一点的?这对我的正则表达式学习之旅会非常有帮助。
感谢提供信息。看来是“linked_post_number”有时会显示出来,导致我的 API 调用出错。你在这里说它是“可选的”——有没有办法确保它永远不会显示?
Johani:
你试图实现什么目标?
当用户访问主题展示页面时,我希望:
以编程方式获取与该主题关联的所有标签。请注意,某些标签对用户是隐藏的。
在主题页面上添加一个按钮,点击时添加某个隐藏标签(如果该隐藏标签尚不存在),再次点击时移除该隐藏标签(如果该隐藏标签已存在)。
使用管理 API 和 JavaScript/jQuery 实现这一切都很直接(假设我能获取正确的主题 URL 用于 API 调用)。
我认为实现此类功能的另一种方法是创建一个插件,深入涉及 1. Ember、2. Rails 以及 3. Discourse 代码库。我已经查阅了关于如何做到这一点的关键 Discourse 帖子和文档,但进展缓慢,因为你确实需要理解这三个部分。因此,目前我专注于 API 方法。
如果有其他方法可以实现这一目标并降低服务器负载,我很乐意听取建议。
fzngagan
(Faizaan Gagan)
2020 年6 月 23 日 15:12
7
如果这是一个单步解决方案,我当然可以帮你解决代码问题,但这里涉及多个步骤。如果你需要关于完成工作或学习自己编写主题组件的咨询帮助,请在市场板块发帖,我会主动联系你。
JQ331
2020 年6 月 23 日 15:14
8
谢谢,但获得任何步骤的指导都是有帮助的。例如,除了使用 API 之外,我如何知道与某个主题关联的所有标签?
fzngagan
(Faizaan Gagan)
2020 年6 月 23 日 15:20
9
当您加载主题页面时,完整的主题对象会在客户端加载。现在,如果您想使用它,需要在模板中添加自己的代码来使用该数据,或者reopen类以利用已加载的数据(即基本上创建您自己的计算属性并在模板中使用它们)。客户端已加载了您所需的大部分数据(可能比您需要的还多),无需额外的 API 调用。您还需要plugin-outlet以便在现有模板上放置自己的标记。
现在,如果您能浏览代码库/元数据以了解上述术语,会有所帮助。如果您遇到任何困难,我会在时间允许的范围内尽力提供帮助。祝好。
JQ331
2020 年6 月 23 日 15:45
10
谢谢。你提到的某些基础内容我比较熟悉,但有一个点让我卡住了(我敢打赌很多人也会在这里卡住):
在主题展示页面(topic show page)上,它会加载模板 /templates/components/topic-category.hbs。正是这个模板显示了分类以及主题标题下方的标签。
在 topic-category 中,它列出了 topic.tags。因此,这是我要实现功能所需的关键信息。
我卡住的地方是:如何将这些 topic.tags 信息传递给我的 JavaScript?
例如,如果我只想将 topic.tags 的内容输出到控制台(console.log),该怎么做?
我知道如何覆盖模板。例如,在一个主题中,我可以在 discourse/templates/components/topic-category.hbs 放置一个文件,并在那里重新打印模板,添加我对视图想要进行的修改。(我使用的是 这里 描述的独立文件结构)。
在我的主题中,我也知道如何将 JavaScript 放在 theme/initializers/initializer-file.js.es6。
并且我可以通过一些 jQuery 让两者进行交互。例如,我可以在模板中将 topic.tags 放入一个 div 中,然后在初始化器中使用 jQuery 获取该 div 的内容来访问它。
但这种方法有些绕。我该如何直接获取 topic.tags 信息,以便对其进行解析和操作?
fzngagan
(Faizaan Gagan)
2020 年6 月 23 日 16:25
11
我会先 console.log 整个 topic 对象,然后找出所需的键。对于 jQuery 交互,它们应该在组件内部进行,并且也应该如此。didInsertElement 是这里很有用的组件钩子。
听你的描述,似乎你需要一个计算属性,它依赖于 topic.tags,并在相关的控制器或组件中返回你对它的操作结果。它可以直接在模板中使用。另外,不要放弃这方面的学习。这需要时间,但回报绝对超乎你的想象。
JQ331
2020 年6 月 23 日 16:47
12
您说的“在组件内部”是什么意思——我应该把 jQuery 代码放在哪个文件中?(在我的主题中,我可以在 theme/initializers/initializer-file.js.es6 文件中使用 jQuery,但这似乎并不算是“在组件内部”)
didInsertElement 代码应该放在哪个文件中?
此时,您应该仔细查看 Ember 指南。组件是一个功能包,您可以部署它并将其附加到其他元素上。
JQ331
2020 年6 月 23 日 16:58
14
谢谢大家,这些信息都很有帮助。我正在查阅指南和一般文档。如果能知道 (i) jQuery 代码和 (ii) didInsertElement 代码应该放在哪个文件中,那将非常有帮助。这类具体的信息将对进一步的审查工作起到很大的指导作用。
fzngagan
(Faizaan Gagan)
2020 年6 月 23 日 17:07
15
组件指的是 Ember 组件。
JQ331:
看起来并不“在”组件内部)
你可以 reopen 各种 Ember 类,并将你的代码注入其中。你可以查找实现此功能的插件或主题,以获得更清晰的理解。
Bcat
(Bcat)
2020 年6 月 24 日 07:11
16
@JQ331 正如您可能知道的,我在 Google 上找到了正则表达式并在此处进行了尝试!您可以输入不同的变体以获得最佳结果。
Regular expression tester with syntax highlighting, explanation, cheat sheet for PHP/PCRE, Python, GO, JavaScript, Java, C#/.NET, Rust.
JQ331:
当用户访问主题展示页面时,我希望:
以编程方式获取与该主题关联的所有标签。请注意,某些标签对用户是隐藏的。
在主题页面上添加一个按钮,点击时若该隐藏标签尚未存在,则将其添加到主题中;若已存在,则将其移除。
在我看来,这属于插件开发的范畴。
如果标签对普通用户是隐藏的,那么额外的调用有何帮助?序列化器在任何情况下都应向普通用户隐藏这些标签。如果不是这样,那么你就暴露了一个内容安全漏洞。
如果你要费这么大劲来绕过仅前端修改的局限性,我建议你还是下定决心,考虑将其构建为一个插件。这样你就可以一次性完成序列化,而无需采用这种通过额外调用实现的杂乱设置。
JQ331
2020 年6 月 24 日 12:58
18
这很有道理。我想进一步了解如何使用序列化器——虽然序列化器是 Discourse 插件中最重要的步骤之一,但我尚未找到提供基本使用示例的文档。您知道相关的文档吗?
当您提到序列化器应该隐藏这些标签时,能否提供一些伪代码,让我更好地理解您的意思?(不要求完全可运行,我只是想理清这个概念。)
在这里:
这就像爵士乐……最佳实践通常已经存在于现有的开源插件生态中,就像所有的唱片一样。不要指望有一份完美的指南来教你如何做所有事情,很多时候你必须进入节奏(咳咳),向既有成果学习。
在 #plugin 中找一个功能上相似或包含你想要的部分内容的插件,检查其代码,看看它是如何实现这些功能的。Discourse 源代码 也同样适用,你可以将其作为终极“最佳实践”的来源,特别是关于 Discourse 的最佳实践。
在本地克隆一个现有插件,尝试修改一些内容,进行实验。
序列化器只是过滤从控制器/模型发送的内容,它们也可以进行一些基本的操作。
这是源文件中的一个示例:discourse/app/serializers/concerns/topic_tags_mixin.rb at 888e68a1637ca784a7bf51a6bbb524dcf7413b13 · discourse/discourse · GitHub
def tags
# 调用 `pluck` 方法并与 `includes` 一起使用会导致 N+1 查询
tags = topic.tags.map(&:name)
if scope.is_staff?
tags
else
tags - scope.hidden_tag_names
end
end
您可以看到,这里从非工作人员中排除了隐藏标签。