Discourse には数百のプラグインアウトレットが含まれており、これらを使用して新しいコンテンツを挿入したり、Discourse UI の既存のコンテンツを置き換えたりできます。コンテキストに基づいてコンテンツをカスタマイズできるように、「アウトレット引数」が利用可能になっています。
アウトレットの選択
プラグインアウトレットの名前を見つけるには、Discourse コア内で “<PluginOutlet” を検索するか、プラグインアウトレットの場所テーマコンポーネントを使用します。(例: topic-above-posts)。
ラッパーアウトレット
コア内のいくつかのアウトレットは <PluginOutlet @name="foo" /> のように見えます。これらは新しいコンテンツを挿入できるようにします。他のいくつかのアウトレットは、次のように既存のコア実装を「ラップ」します。
<PluginOutlet @name="foo">
core implementation
</PluginOutlet>
この種の「ラッパー」アウトレットのコネクタを定義すると、コア実装が置き換えられます。ラッパープラグインアウトレットに対してコネクタを提供するアクティブなテーマ/プラグインは 1 つだけです。
ラッパープラグインアウトレットの場合、{{yield}} キーワードを使用して元のコア実装をレンダリングできます。これは、特定の条件下でのみコア実装を置き換えたい場合や、何らかの要素でラップしたい場合に役立ちます。
テンプレートの定義
アウトレットを選択したら、コネクタの名前を決定します。これは、インストールされているすべてのテーマ/プラグイン全体で一意である必要があります。例: brand-official-topics
テーマ/プラグイン内で、次のような形式のパスを持つ新しいハンドルバーテンプレートを定義します。
![]()
{theme}/javascripts/discourse/connectors/{outlet-name}/{connector-name}.hbs
![]()
{plugin}/assets/javascripts/discourse/connectors/{outlet-name}/{connector-name}.hbs
これらのファイルの内容は Ember コンポーネントとしてレンダリングされます。Ember / Handlebars に関する一般的な情報については、Ember ガイドを参照してください。
架空の「ブランド公式トピック」コネクタの場合、テンプレートは次のようになります。
<div class="alert alert-info">
This topic was created by a member of the
<a href="https://discourse.org/team">Discourse Team</a>
</div>
一部のプラグインアウトレットは、コンテンツを HTML 要素で自動的にラップします。要素のタイプは、<PluginOutlet> の @connectorTagName によって定義されます。
アウトレット引数の使用
プラグインアウトレットは、@outletArgs 経由で周囲のコンテキストに関する情報を提供します。各アウトレットに渡される引数は異なります。引数を確認する簡単な方法は、テンプレートにこれを追加することです。
{{log @outletArgs}}
これにより、ブラウザの開発者コンソールに引数がログ出力されます。これらは Proxy オブジェクトとして表示されます。引数のリストを調べるには、プロキシの [[Target]] を展開します。
topic-above-posts の例では、レンダリングされているトピックは @outletArgs.model で利用可能です。したがって、チームメンバーのユーザー名を次のように追加できます。
<div class="alert alert-info">
This topic was created by
{{@outletArgs.model.details.created_by.username}}
(a member of the
<a href="https://discourse.org/team">Discourse Team</a>)
</div>
より複雑なロジックの追加
単純なハンドルバーテンプレートでは不十分な場合があります。コネクタに Javascript ロジックを追加するには、ハンドルバーテンプレートに隣接する Javascript ファイルを定義できます。このファイルはコンポーネント定義をエクスポートする必要があります。これは、サービスインジェクションを含む、他のコンポーネント定義とまったく同じように機能します。
このようにコンポーネントを定義すると、自動的な connectorTagName ラッパー要素が削除されるため、hbs ファイルで同じタイプの要素を再導入したい場合があります。
topic-above-posts の例では、「UX でユーザー名を優先する」サイト設定に基づいてユーザーを異なる方法でレンダリングしたい場合があります。そのコンポーネント定義は次のようになるかもしれません。
.../connectors/topic-above-posts/brand-official-topic.js:
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;
}
}
}
次に、新しいゲッターを参照するようにテンプレートを更新できます。
<div class="alert alert-info">
This topic was created by
{{this.displayName}}
(a member of the
<a href="https://discourse.org/team">Discourse Team</a>)
</div>
条件付きレンダリング
コンテンツを特定の条件下でのみレンダリングしたい場合は、テンプレートをハンドルバーの {{#if}} ブロックでラップするだけで十分なことがよくあります。それが不十分な場合は、コネクタテンプレートがレンダリングされるかどうかを制御するために shouldRender フックを使用したい場合があります。
まず、上記で説明したように .js コネクタ定義があることを確認します。次に、静的 static shouldRender() 関数を追加します。例を拡張します。
import Component from "@glimmer/component";
import { getOwner } from "discourse-common/lib/get-owner";
export default class BrandOfficialTopics extends Component {
static shouldRender(outletArgs, helper) {
const firstPost = outletArgs.model.postStream.posts[0];
return firstPost.primary_group_name === "team";
}
// ... (その他のロジック)
}
これで、トピックの最初の投稿がチームメンバーによって作成された場合にのみ、コネクタがレンダリングされます。
shouldRender は Glimmer の自動追跡コンテキストで評価されます。参照されたプロパティ(例: outletArgs)の将来の変更により、関数が再評価されます。
新しいアウトレットの導入
まだ存在しないアウトレットが必要な場合は、お気軽にプルリクエストを作成するか、Dev でトピックを開いてください。
このドキュメントはバージョン管理されています - 変更の提案は github で行えます。