استخدام موصلات Plugin Outlet من سمة أو إضافة

يتضمن Discourse مئات منافذ الإضافات (Plugin Outlets) التي يمكن استخدامها لحقن محتوى جديد أو استبدال المحتوى الحالي في واجهة مستخدم Discourse. يتم توفير “مُعاملات المنافذ” (Outlet arguments) لتمكين تخصيص المحتوى بناءً على السياق.

اختيار منفذ

للعثور على اسم منفذ إضافة، ابحث في نواة Discourse عن “<PluginOutlet”، أو استخدم مكون السمة مواقع منافذ الإضافات. (مثل: 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]] الخاص بالـ Proxy.

في مثال 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 لدينا، قد نرغب في عرض المستخدم بشكل مختلف بناءً على إعداد الموقع “أولوية اسم المستخدم في واجهة المستخدم”. قد يبدو ملف .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 في سياق تتبع تلقائي (autotracking) لـ Glimmer. أي تغييرات مستقبلية في أي خصائص مرجعية (مثل outletArgs) ستؤدي إلى إعادة تقييم الدالة.

إدخال منافذ جديدة

إذا كنت بحاجة إلى منفذ غير موجود بعد، فلا تتردد في تقديم طلب سحب (pull request)، أو فتح موضوع في Development.


يتم التحكم في إصدار هذا المستند - اقترح التغييرات على GitHub.

39 إعجابًا
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
Developing Discourse Plugins - Part 2 - Connect to a plugin outlet
Native theme support
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
Add link to external SSO profile to profile page
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
How to add a custom button in user profile card?
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

هذا تم إهماله الآن، صحيح؟
إشعار الإهمال: تم إهمال تعريف فئات الموصلات عبر registerConnectorClass. انظر https://meta.discourse.org/t/32727 لأنماط أحدث. [معرف الإهمال: discourse.register-connector-class-legacy]

صحيح؛ يمكنك استخدام api.renderInOutlet بدلاً من ذلك. :slight_smile:

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

إعجاب واحد (1)

أعتقد أن الأمر أكثر تعقيدًا من ذلك بقليل :sweat_smile:
https://github.com/Firepup6500/discourse-custom-profile-link/blob/master/common/head_tag.html

لا تقلق؛ سأرى ما يمكنني فعله لمساعدتك لاحقًا (أحتاج إلى النوم الآن). :smile:

إعجاب واحد (1)

شكرا! (أعتذر عن كون الكود فوضويا، أردت فقط أن يعمل عندما لمسته آخر مرة :sweat_smile:)

إعجاب واحد (1)

أنا غارق قليلاً هنا، لقد تلقيت إشعارًا للمكون الذي أستخدمه في ملف HEAD الخاص بالقالب الخاص بي. لست متأكدًا من كيفية إعادة الكتابة باستخدام api.renderInOutlet.

  const ajax = require('discourse/lib/ajax').ajax;
  const Topic = require('discourse/models/topic').default;
  // نحن نستخدم ajax ونموذج Topic من Discourse

  api.registerConnectorClass('above-main-container', 'featured-topics', {
    // above-main-container هو منفذ المكون الإضافي،
    // featured-topics هو اسم المكون المخصص الخاص بك

    setupComponent(args, component) {

   // بقية الكود يتبع

أعتقد أنني حاولت استبدال api.registerConnectorClass بـ api.renderInOutlet لكنه تعطل. أنا لست خبيرًا حقًا في ترميز القوالب هنا. شكرًا على أي مساعدة.

يمكنك رؤية مثال هنا:

StatBanner هو فئة أصلية معرفة في دليل components:

في حالتك، سيكون ذلك api.renderInOutlet("above-main-container", YourClass)

لا أعتقد أنه يمكنك القيام بذلك في ملف HEAD. يجب عليك تقسيم الكود الخاص بك إلى ملفات متعددة.

أشجعك على استخدام Discourse Theme CLI لأنه سيكون من الأسهل بكثير تطوير مكون سمة!

هل مكون السمة الخاص بك عام؟

3 إعجابات

هل هناك طريقة للحصول على المنفذ الحالي في ملف .js الخاص بي؟

لا أعتقد أن هذا ممكن.

كان من الممكن فحص parentView في المكونات الكلاسيكية.

لكن تم إيقاف هذه الخاصية.

إعجاب واحد (1)

ماذا تقصد بـ “الحصول على المنفذ الحالي”؟ هل تريد اسم المنفذ؟ أم شيئًا آخر؟

لقد وجدت حلاً لمشكلتي (هنا)، وكان شيئًا كهذا:

  • إنشاء ملفات .hbs و .js لثلاث منافذ مختلفة.
  • في كل ملف JS، تحقق مما إذا كان المنفذ الذي يستخدمه هو القيمة المعينة للإعداد banner_location.
  • إذا كان كذلك، اعرض اللافتة. إذا لم يكن كذلك، أخفِ اللافتة.
إعجاب واحد (1)

رائع! يبدو أنك استقريت على استخدام api.renderInOutlet، مع قيمة ديناميكية لاسم المنفذ :chefs_kiss:

إعجاب واحد (1)