在主题或插件中使用插件输出连接器

Discourse 包含数百个插件出口(Plugin Outlets),可用于向 Discourse UI 注入新内容或替换现有内容。“出口参数”(Outlet arguments)的提供使得可以根据上下文对内容进行自定义。

选择出口

要查找插件出口的名称,请在 Discourse 核心代码中搜索 “<PluginOutlet”,或者使用 plugin outlet locations 主题组件。(例如 topic-above-posts)。

包装器出口

核心代码中的一些出口看起来像 <PluginOutlet @name="foo" />。这些允许你注入新内容。其他出口则会像这样“包装”一个现有的核心实现:

<PluginOutlet @name="foo">
  核心实现
</PluginOutlet>

为这种“包装器”出口定义连接器(connector)将会替换核心实现。只有一个活跃的主题/插件可以为一个包装器插件出口提供连接器。

对于包装器插件出口,你可以使用 {{yield}} 关键字来渲染原始的核心实现。如果你只想在特定条件下替换核心实现,或者希望将其包裹在其他内容中,这会很有用。

定义连接器

一旦你选择了出口,请为你的连接器决定一个名称。该名称需要在给定社区安装的所有主题/插件中保持唯一。例如 brand-official-topics

在你的主题/插件中,按照以下格式定义一个新的 .gjs 连接器路径:

:art: {theme}/javascripts/discourse/connectors/{outlet-name}/{connector-name}.gjs

:electric_plug: {plugin}/assets/javascripts/discourse/connectors/{outlet-name}/{connector-name}.gjs

这些文件的内容将作为 Ember 组件进行渲染。有关 Ember 和 .gjs 格式的一般信息,请查阅 Ember 指南

对于我们要假设的“品牌官方话题”连接器,该文件可能如下所示:

<template>
  <div class="alert alert-info">
    此话题由
    <a href="https://discourse.org/team">Discourse 团队</a>
    的成员创建
  </div>
</template>

使用出口参数

插件出口通过 @outletArgs 提供关于周围上下文的信息。传递给每个出口的参数各不相同。查看参数的一种简单方法是将以下内容添加到你的模板中:

{{log @outletArgs}}

这将把参数记录到浏览器的开发者控制台中。它们将显示为一个 Proxy 对象——要查看参数列表,请展开代理的 [[Target]]

在我们的 topic-above-posts 示例中,渲染的话题位于 @outletArgs.model 下。因此,我们可以像这样添加团队成员的用户名:

<template>
  <div class="alert alert-info">
    此话题由
    {{@outletArgs.model.details.created_by.username}}
    (
    <a href="https://discourse.org/team">Discourse 团队</a>的成员)创建
  </div>
</template>

添加更复杂的逻辑

有时,简单的模板是不够的。要向连接器添加 JavaScript 逻辑,请将你的 .gjs 文件升级为导出一个基于类的组件。这与任何其他组件定义的功能相同,并且可以包含服务注入。

在我们的 topic-above-posts 示例中,我们可能希望根据“在 UX 中优先显示用户名”站点设置来不同地渲染用户。.gjs 文件可能如下所示:

.../connectors/topic-above-posts/brand-official-topic.gjs:

import Component from "@glimmer/component";
import { service } from "@ember/service";

export default class BrandOfficialTopics extends Component {
  @service siteSettings;

  get displayName() {
    const user = this.args.outletArgs.model.details.created_by;
    if (this.siteSettings.prioritize_username_in_ux) {
      return user.username;
    } else {
      return user.name;
    }
  }

  <template>
    <div class="alert alert-info">
      此话题由
      {{this.displayName}}
      (
      <a href="https://discourse.org/team">Discourse 团队</a>的成员)创建
    </div>
  </template>
}

条件渲染

如果你只想在特定条件下渲染你的内容,通常只需使用 Handlebars {{#if}} 块包裹你的模板即可。如果这还不够,你可能想使用 shouldRender 钩子来控制是否渲染你的连接器模板。

首先,确保你拥有一个如上所述基于类的 .gjs 连接器。然后,添加一个 static shouldRender() 函数。扩展我们的示例:

import Component from "@glimmer/component";

export default class BrandOfficialTopics extends Component {
  static shouldRender(outletArgs, helper) {
    const firstPost = outletArgs.model.postStream.posts[0];
    return firstPost.primary_group_name === "team";
  }
  // ... (其他任何逻辑)

  <template>
    {{! ... }}
  </template>
}

现在,只有当话题的第一篇帖子是由团队成员创建时,连接器才会被渲染。

shouldRender 在 Glimmer 自动跟踪上下文中求值。对任何引用属性(例如 outletArgs)的未来更改都会导致该函数重新求值。

引入新出口

如果你需要一个尚不存在的出口,请随意提交拉取请求(pull request),或在 Development 中开启一个话题。


本文档受版本控制 - 在 github 上建议更改。

39 个赞
Using discourse's plugin outlets
Add HTML (Link) Next To Logo
What is the best way to integrate member applications?
Group Semantics
Can I put the search form at the top of our 404 page?
Native theme support
How to show user total post count beside name
Developing Discourse Plugins - Part 2 - Connect to a plugin outlet
Split up theme Javascript into multiple files
Feedback on "on-discourse" javascript for setting up custom JS for each page?
Topic-timeline api.decorateWidget call has stopped working
Developing Discourse Plugins - Part 2 - Connect to a plugin outlet
Developing Discourse Themes & Theme Components
How to add btn before "sign in"
Minimizing Maintenance on Theme Customizations
How to add custom fields to models
Tags at the top of the topic list in a Category
I want to insert images (banner) between the topic answers. How do I start?
How to add a link shortcut to the area under the title
Baidu Search
Add Banner/HTML (Widget) before reply button
Upcoming Header Changes - Preparing Themes and Plugins
Upgrading Discourse to Ember 4
Converting modals from legacy controllers to new DModal component API
Need help integrating code wrote on Edittext to the Discourse
Add link to external SSO profile to profile page
How to add a custom button in user profile card?
How to add a custom button in user profile card?
(not recommended) Overriding Discourse templates from a Theme or Plugin
How to override the site-header.hbs file from custom theme?
Upcoming topic-list changes - how to prepare themes and plugins
Working with .erb templates in a plugin
How to Integrate a Custom Plugin in discourse UI
Templating of my "component" broke. How do I fix it?
Templating of my "component" broke. How do I fix it?
Modernizing inline script tags for templates & JS API
Custom Components -- add button or text at any plugin outlet
(not recommended) Overriding Discourse templates from a Theme or Plugin
Adding "latest topics" header in the main interface
Display Tags inline with thread title, instead of being on the bottom line
Settings not appearing
Discourse view file update does not reflect in browser
Discourse view file update does not reflect in browser
Add likes and views to search display
Using template hbs to add HTML content to a plugin outlet
Adding a billing section in the member section
Adding a billing section in the member section
How to modify the header HTML, but still remaining the default founctions
Removing support for "template overrides" and mobile-specific templates
How can i add image in login and register box
Most “traditional” or classic forum Category listing
Customizing the topic list
Newbie help accessing code
How to add custom html next to logo using discourse plugin methods
Using the DModal API to render Modal windows (aka popups/dialogs) in Discourse
Air Theme
How to create a plugin with backend API calls to populate composer while drafting?
How to add a custom url text link on the login page
Add Text In Header Beside Logo