Verwendung von Plugin Outlet Connectors aus einem Theme oder Plugin

Discourse enthält Hunderte von Plugin-Outlets, die verwendet werden können, um neuen Inhalt in die Discourse-Benutzeroberfläche einzufügen oder vorhandenen Inhalt zu ersetzen. „Outlet-Argumente“ werden zur Verfügung gestellt, damit Inhalte basierend auf dem Kontext angepasst werden können.

Ein Outlet auswählen

Um den Namen eines Plugin-Outlets zu finden, durchsuchen Sie den Discourse-Kern nach „\u003cPluginOutlet“ oder verwenden Sie die Theme-Komponente Plugin Outlet Locations. (z. B. topic-above-posts).

Wrapper-Outlets

Einige Outlets im Kern sehen so aus: \u003cPluginOutlet @name=\"foo\" /\u003e. Diese ermöglichen es Ihnen, neuen Inhalt einzufügen. Andere Outlets „umschließen“ eine vorhandene Kernimplementierung wie folgt:

\u003cPluginOutlet @name=\"foo\"\u003e
  Kernimplementierung
\u003c/PluginOutlet\u003e

Die Definition eines Connectors für diese Art von „Wrapper“-Outlet ersetzt die Kernimplementierung. Nur ein aktives Theme/Plugin kann einen Connector für ein Wrapper-Plugin-Outlet bereitstellen.

Bei Wrapper-Plugin-Outlets können Sie die ursprüngliche Kernimplementierung mit dem Schlüsselwort {{yield}} rendern. Dies kann hilfreich sein, wenn Sie die Kernimplementierung nur unter bestimmten Bedingungen ersetzen möchten oder wenn Sie sie in etwas einbetten möchten.

Die Vorlage definieren

Sobald Sie ein Outlet ausgewählt haben, entscheiden Sie sich für einen Namen für Ihren Connector. Dieser muss eindeutig für alle auf einer bestimmten Community installierten Themes/Plugins sein. Z. B. brand-official-topics

Definieren Sie in Ihrem Theme/Plugin eine neue Handlebars-Vorlage mit einem Pfad, der wie folgt formatiert ist:

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

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

Der Inhalt dieser Dateien wird als Ember Component gerendert. Allgemeine Informationen zu Ember/Handlebars finden Sie in den Ember-Anleitungen.

Für unseren hypothetischen „brand official topics“-Connector könnte die Vorlage wie folgt aussehen:

\u003cdiv class=\"alert alert-info\"\u003e
  Dieses Thema wurde von einem Mitglied des
  \u003ca href=\"https://discourse.org/team\"\u003eDiscourse Teams\u003c/a\u003e
  erstellt
\u003c/div\u003e

Einige Plugin-Outlets umschließen Ihren Inhalt automatisch in einem HTML-Element. Der Elementtyp wird durch @connectorTagName auf dem \u003cPluginOutlet\u003e definiert.

Outlet-Argumente verwenden

Plugin-Outlets stellen Informationen über den umgebenden Kontext über @outletArgs bereit. Die an jedes Outlet übergebenen Argumente variieren. Eine einfache Möglichkeit, die Argumente anzuzeigen, besteht darin, dies zu Ihrer Vorlage hinzuzufügen:

{{log @outletArgs}}

Dies protokolliert die Argumente in der Entwicklerkonsole Ihres Browsers. Sie erscheinen als Proxy-Objekt – um die Liste der Argumente zu untersuchen, erweitern Sie das [[Target]] des Proxys.

In unserem topic-above-posts-Beispiel ist das gerenderte Thema unter @outletArgs.model verfügbar. Wir können also den Benutzernamen des Teammitglieds wie folgt hinzufügen:

\u003cdiv class=\"alert alert-info\"\u003e
  Dieses Thema wurde erstellt von
  {{@outletArgs.model.details.created_by.username}}
  (ein Mitglied des
  \u003ca href=\"https://discourse.org/team\"\u003eDiscourse Teams\u003c/a\u003e)
\u003c/div\u003e

Komplexere Logik hinzufügen

Manchmal reicht eine einfache Handlebars-Vorlage nicht aus. Um Ihrer Connector-Logik Javascript hinzuzufügen, können Sie eine Javascript-Datei neben Ihrer Handlebars-Vorlage definieren. Diese Datei sollte eine Komponenten-Definition exportieren. Dies funktioniert genauso wie jede andere Komponenten-Definition und kann Service-Injektionen enthalten.

Die Definition einer Komponente auf diese Weise entfernt das automatische connectorTagName-Wrapper-Element, sodass Sie möglicherweise ein Element desselben Typs in Ihrer hbs-Datei wieder einführen möchten.

In unserem topic-above-posts-Beispiel möchten wir den Benutzer möglicherweise anders rendern, basierend auf der Site-Einstellung „Benutzernamen in der UX priorisieren“. Eine Komponenten-Definition dafür könnte etwa so aussehen:

.../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;
    }
  }
}

Wir können dann die Vorlage aktualisieren, um auf den neuen Getter zu verweisen:

\u003cdiv class=\"alert alert-info\"\u003e
  Dieses Thema wurde erstellt von
  {{this.displayName}}
  (ein Mitglied des
  \u003ca href=\"https://discourse.org/team\"\u003eDiscourse Teams\u003c/a\u003e)
\u003c/div\u003e

Bedingtes Rendern

Wenn Sie möchten, dass Ihr Inhalt nur unter bestimmten Bedingungen gerendert wird, reicht es oft aus, Ihre Vorlage mit einem Handlebars {{#if}}-Block zu umschließen. Wenn das nicht ausreicht, möchten Sie möglicherweise den Hook shouldRender verwenden, um zu steuern, ob Ihre Connector-Vorlage überhaupt gerendert wird.

Stellen Sie zunächst sicher, dass Sie eine .js-Connector-Definition wie oben beschrieben haben. Fügen Sie dann eine statische Funktion shouldRender() hinzu. Erweiterung unseres Beispiels:

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";
  }
  // ... (jede andere Logik)
}

Nun wird der Connector nur gerendert, wenn der erste Beitrag des Themas von einem Teammitglied erstellt wurde.

shouldRender wird in einem Glimmer-Autotracking-Kontext ausgewertet. Zukünftige Änderungen an allen referenzierten Eigenschaften (z. B. outletArgs) führen dazu, dass die Funktion neu ausgewertet wird.

Neue Outlets einführen

Wenn Sie ein Outlet benötigen, das noch nicht existiert, können Sie gerne eine Pull-Anfrage stellen oder ein Thema in Dev eröffnen.


\u003csmall\u003eDieses Dokument wird versionskontrolliert – schlagen Sie Änderungen auf github vor.\u003c/small\u003e

39 „Gefällt mir“
Using discourse's plugin outlets
What is the best way to integrate member applications?
Add HTML (Link) Next To Logo
Group Semantics
Can I put the search form at the top of our 404 page?
How to show user total post count beside name
Native theme support
Developing Discourse Plugins - Part 2 - Connect to a plugin outlet
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
Settings not appearing
How to add a custom button in user profile card?
How to add a custom button in user profile card?
Customizing the topic list
(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
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
Display Tags inline with thread title, instead of being on the bottom line
Add link to external SSO profile to profile page
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
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
Split up theme Javascript into multiple files

Dies ist jetzt veraltet, richtig?
Deprecation notice: Defining connector classes via registerConnectorClass is deprecated. See https://meta.discourse.org/t/32727 for more modern patterns. [deprecation id: discourse.register-connector-class-legacy]

Das ist richtig; Sie können stattdessen api.renderInOutlet verwenden. :slight_smile:

https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L982-L1008

1 „Gefällt mir“

Ich glaube, es ist ein bisschen komplizierter als das :sweat_smile:
https://github.com/Firepup6500/discourse-custom-profile-link/blob/master/common/head_tag.html

Keine Sorge; ich werde sehen, was ich später für Sie tun kann (ich muss jetzt schlafen). :smile:

1 „Gefällt mir“

Danke! (Entschuldigung, dass der Code ein Chaos ist, ich wollte nur, dass er funktioniert, als ich ihn das letzte Mal angefasst habe :sweat_smile:)

1 „Gefällt mir“

Ich stecke hier etwas fest. Ich habe eine Benachrichtigung für meine Komponente erhalten, die in der HEAD-Datei meines Themes verwendet wird. Ich bin mir nicht sicher, wie ich sie mit api.renderInOutlet neu schreiben soll.

  const ajax = require('discourse/lib/ajax').ajax;
  const Topic = require('discourse/models/topic').default;
  // Wir verwenden ajax und das Topic-Modell von Discourse

  api.registerConnectorClass('above-main-container', 'featured-topics', {
    // above-main-container ist der Plugin-Outlet,
    // featured-topics ist der Name Ihrer benutzerdefinierten Komponente

    setupComponent(args, component) {

   // der Rest des Codes folgt

Ich glaube, ich habe versucht, api.registerConnectorClass durch api.renderInOutlet zu ersetzen, aber es hat nicht funktioniert. Ich bin hier kein Experte für Theme-Coding. Danke für jede Hilfe.

Sie können hier ein Beispiel sehen:

StatBanner ist eine native Klasse, die im Verzeichnis components definiert ist:

In Ihrem Fall wäre das api.renderInOutlet("above-main-container", YourClass)

Ich glaube nicht, dass Sie das in der HEAD-Datei tun können. Sie sollten Ihren Code in mehrere Dateien aufteilen.

Ich ermutige Sie, Discourse Theme CLI zu verwenden, da die Entwicklung einer Theme-Komponente damit viel einfacher ist!

Ist Ihre Theme-Komponente öffentlich?

3 „Gefällt mir“

Gibt es eine Möglichkeit, den aktuellen Auslass in meiner .js-Datei zu erhalten?

Ich glaube nicht, dass das möglich ist.

Früher war es möglich, parentView in Classic Components zu inspizieren.

Aber diese Eigenschaft wurde als veraltet markiert.

1 „Gefällt mir“

Was meinen Sie mit „den aktuellen Auslass erhalten“? Meinen Sie den Namen des Auslasses? Oder etwas anderes?

Ich habe eine Lösung für mein Problem gefunden (hier), aber sie sah ungefähr so aus:

  • Erstellen Sie .hbs- und .js-Dateien für 3 verschiedene Auslässe.
  • Überprüfen Sie in jeder JS-Datei, ob der verwendete Auslass dem Wert der Einstellung banner_location entspricht.
  • Wenn ja, zeigen Sie das Banner an. Wenn nicht, blenden Sie das Banner aus.
1 „Gefällt mir“

Cool! Es sieht so aus, als ob Sie sich für die Verwendung von api.renderInOutlet mit einem dynamischen Wert für den Outlet-Namen entschieden haben :chefs_kiss:

1 „Gefällt mir“