Discourse включает в себя сотни Plugin Outlets (точек расширения плагинов), которые можно использовать для вставки нового контента или замены существующего в интерфейсе Discourse. Для возможности настройки контента в зависимости от контекста предоставляются «аргументы outlet».
Выбор outlet
Чтобы найти название plugin outlet, выполните поиск по коду Discourse core по запросу “<PluginOutlet” или используйте тематический компонент plugin outlet locations. (например, topic-above-posts).
Wrapper outlets (обёрточные outlet)
Некоторые outlet в core выглядят как <PluginOutlet @name="foo" />. Они позволяют вставлять новый контент. Другие outlet «обёртывают» существующую реализацию core, например так:
<PluginOutlet @name="foo">
реализация core
</PluginOutlet>
Определение коннектора для такого «обёрточного» outlet заменит реализацию core. Только одна активная тема/плагин может предоставлять коннектор для обёрточного plugin outlet.
Для обёрточных plugin outlet вы можете отрисовать исходную реализацию core, используя ключевое слово {{yield}}. Это может быть полезно, если вы хотите заменить реализацию core только при определённых условиях, или если вы хотите обернуть её в что-то.
Определение коннектора
После выбора outlet придумайте название для вашего коннектора. Оно должно быть уникальным среди всех тем/плагинов, установленных в данном сообществе. Например, brand-official-topics.
В вашей теме/плагине определите новый .gjs коннектор с путём, оформленным следующим образом:
![]()
{theme}/javascripts/discourse/connectors/{outlet-name}/{connector-name}.gjs
![]()
{plugin}/assets/javascripts/discourse/connectors/{outlet-name}/{connector-name}.gjs
Содержимое этих файлов будет отрисовано как Ember-компонент. Для получения общей информации об Ember и формате .gjs ознакомьтесь с руководством по Ember.
Для нашего гипотетического коннектора «brand official topics» файл может выглядеть так:
<template>
<div class="alert alert-info">
Эта тема была создана участником
<a href="https://discourse.org/team">Discourse Team</a>
</div>
</template>
Использование аргументов outlet
Plugin Outlets предоставляют информацию об окружающем контексте через @outletArgs. Аргументы, передаваемые каждому outlet, различаются. Простой способ просмотра аргументов — добавить это в ваш шаблон:
{{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 Team</a>)
</div>
</template>
Добавление более сложной логики
Иногда простого шаблона недостаточно. Чтобы добавить JavaScript-логику в ваш коннектор, обновите ваш .gjs файл, чтобы он экспортировал класс-компонент. Это работает так же, как и любое другое определение компонента, и может включать инъекции сервисов.
В нашем примере topic-above-posts мы можем захотеть отрисовывать пользователя по-разному в зависимости от настроек сайта «prioritize username in ux» (приоритет имени пользователя в 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 Team</a>)
</div>
</template>
}
Условная отрисовка
Если вы хотите, чтобы ваш контент отрисовывался только при определённых условиях, часто достаточно обернуть ваш шаблон блоком handlebars {{#if}}. Если этого недостаточно, вы можете использовать хук shouldRender, чтобы контролировать, будет ли вообще отрисован шаблон вашего коннектора.
Сначала убедитесь, что у вас есть класс-коннектор .gjs, как описано выше. Затем добавьте статическую функцию 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 autotracking. Будущие изменения любых ссылочных свойств (например, outletArgs) приведут к повторному вычислению функции.
Добавление новых outlet
Если вам нужен outlet, который ещё не существует, пожалуйста, не стесняйтесь создать pull request или открыть тему в Development.
Этот документ управляется версиями — предложите изменения на github.