Discourseには数百のPlugin Outletが含まれており、これらを使用してDiscourseのUIに新しいコンテンツを注入したり、既存のコンテンツを置き換えたりできます。コンテンツをコンテキストに基づいてカスタマイズできるように、「Outlet引数」が利用可能になっています。
Outletの選択
Plugin Outletの名前を見つけるには、Discourseのコアで"<PluginOutlet"を検索するか、plugin outlet locationsテーマコンポーネントを使用してください。(例:topic-above-posts)。
ラッパーOutlet
コア内の一部のOutletは<PluginOutlet @name="foo" />のように見えます。これらは新しいコンテンツの注入を可能にします。他のOutletは、次のように既存のコア実装を「ラップ(囲む)」します。
<PluginOutlet @name="foo">
core implementation
</PluginOutlet>
```\n
この種の「ラッパー」Outletに対するコネクタを定義すると、コア実装が置き換えられます。ラッパーPlugin Outletに対してコネクタを提供できるのは、アクティブなテーマ/プラグイン1つのみです。
ラッパーPlugin Outletでは、`{{yield}}`キーワードを使用して、元のコア実装をレンダリングできます。これは、コア実装を特定の条件下でのみ置き換えたい場合や、何かでラップしたい場合に役立ちます。
# コネクタの定義
Outletを選んだら、コネクタの名前を決定します。これは、特定のコミュニティにインストールされているすべてのテーマ/プラグインの中で一意である必要があります。例:`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ガイド](https://guides.emberjs.com/release/components/)を確認してください。
我々の仮想的な「brand official topics」コネクタの場合、ファイルは次のようになるかもしれません。
```gjs
<template>
<div class="alert alert-info">
This topic was created by a member of the
<a href="https://discourse.org/team">Discourse Team</a>
</div>
</template>
Outlet引数の使用
Plugin Outletは、@outletArgsを通じて、周囲のコンテキストに関する情報を提供します。各Outletに渡される引数は異なります。引数を表示する簡単な方法は、テンプレートにこれを追加することです:
{{log @outletArgs}}
これにより、引数がブラウザの開発者コンソールにログ出力されます。Proxyオブジェクトとして表示されます - 引数のリストを調べるには、プロキシの[[Target]]を展開してください。
我々のtopic-above-postsの例では、レンダリングされたトピックは@outletArgs.modelの下で利用可能です。したがって、チームメンバーのユーザー名を次のように追加できます:
<template>
<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>
</template>
より複雑なロジックの追加
場合によっては、単純なテンプレートでは不十分です。コネクタにJavaScriptロジックを追加するには、.gjsファイルをクラスベースのコンポーネントのエクスポートにアップグレードします。これは他のコンポーネント定義と同様に機能し、サービスの注入を含めることができます。
我々のtopic-above-postsの例では、「prioritize username in 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 topic was created by
{{this.displayName}}
(a member of the
<a href="https://discourse.org/team">Discourse Team</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";
}
// ... (any other logic)
<template>
{{! ... }}
</template>
}
これにより、トピックの最初の投稿がチームメンバーによって作成された場合のみ、コネクタがレンダリングされるようになります。
shouldRenderはGlimmerのオートトラッキングコンテキストで評価されます。参照されているプロパティ(例:outletArgs)への将来の変更は、関数が再評価される原因となります。
新しいOutletの導入
まだ存在しないOutletが必要な場合は、プルリクエストを作成するか、#devでトピックを開いてください。
このドキュメントはバージョン管理されています - 変更の提案はGitHub上で行ってください。