إذا كنت تطبق نافذة منبثقة (Modal) جديدة، فراجع الوثائق الرئيسية هنا. يصف هذا الموضوع كيفية ترحيل نافذة منبثقة قائمة على المتحكم (Controller) إلى واجهة برمجة التطبيقات (API) القائمة على المكونات الجديدة.
في الماضي، كان Discourse يستخدم واجهة برمجة تطبيقات قائمة على Ember-Controller لعرض النوافذ المنبثقة. لاستدعاء النافذة المنبثقة، كنت تمرر سلسلة تحتوي على اسم المتحكم إلى showModal(). تحت الغطاء، كان هذا يستخدم واجهة برمجة تطبيقات Route#renderTemplate الخاصة بـ Ember، وهي واجهة قديمة الإصدار في Ember 3.x وسيتم إزالتها في Ember 4.x.
للسماح لـ Discourse بالترقية إلى Ember 4.x وما بعده، قمنا بإدخال واجهة برمجة تطبيقات جديدة قائمة على المكونات للنوافذ المنبثقة. تتبنى هذه الواجهة الجديدة أنماط التصميم “الإعلانية” (declarative) لـ Ember، وتهدف إلى توفير دلالات DDAU (البيانات للأسفل، الإجراءات للأعلى) نظيفة.
الخطوة 1: نقل الملفات
انقل ملف JS الخاص بالمتحكم وملف القالب إلى الدليل /components/modal. يجعل هذا الأمرهما “مكونًا متجاورًا” (colocated component) يمكن استيراده تمامًا مثل أي وحدة JS أخرى.
الخطوة 2: تحديث ملف JS
ثم، قم بتحديث تعريف المكون في JS ليمتد من @ember/component بدلاً من @ember/controller [1]. قم بإزالة mixin ModalFunctionality وحدّث أي استخدامات لدوالها وفقًا للجدول أدناه:
| قبل | بعد |
|---|---|
flash() و clearFlash() |
قم بإنشاء خاصية flash في مكونك ومررها إلى الوسيطة @flash لـ <DModal>. بشكل افتراضي، سيتم تنسيق التنبيه باستخدام فئة alert التي هي نسخة من فئة ‘error’، ولكن يمكن تجاوز ذلك باستخدام الوسيطة @flashType. |
showModal() |
استورد دالة showModal من discourse/lib/show-modal |
إجراء closeModal |
استدعِ الوسيطة closeModal التي يتم تمريرها تلقائيًا إلى مكونك |
كانت متحكمات النوافذ المنبثقة ذات الطراز القديم تعيش “إلى الأبد”، مما يعني أنه كان علينا تنظيف الحالة يدويًا. مع واجهة برمجة التطبيقات الجديدة القائمة على المكونات، سيتم إنشاء المكون وتدميره عند إظهار/إخفاء النافذة المنبثقة. في العديد من الحالات، يعني ذلك أن دوال دورة الحياة القديمة لم تعد مطلوبة.
إذا كنت لا تزال بحاجة إلى بعض المنطق القائم على دورة الحياة، فاستخدم هذا الجدول:
| قبل | بعد |
|---|---|
onShow() |
استخدم دورة حياة مكون Ember القياسية (init() أو معدّل Ember) |
afterRender |
استخدم دورة حياة مكون Ember القياسية (init() أو معدّل Ember) |
beforeClose() |
قم بإنشاء غلاف حول الوسيطة @closeModal التي يتم تمريرها إلى مكونك. مرر مرجعًا إلى غلاف الإغلاق هذا إلى DModal مثل <DModal @closeModal={{this.myCloseModalWrapper}}> |
onClose() |
استخدم دورة حياة مكون Ember القياسية (willDestroy() أو معدّل Ember) |
الخطوة 3: تحديث القالب
استبدل الغلاف <DModalBody> بـ <DModal>. أضف بعض السمات الجديدة:
- مرّر الوسيطة الجديدة
@closeModal - أضف فئة صريحة. لمطابقة السلوك القديم، خذ اسم ملف المتحكم وأضف
-modal.
على سبيل المثال، إذا كان اسم متحكم النافذة المنبثقة لديك هو close-topic.js، فسيبدو استدعاء <DModal> الجديد شيئًا مثل هذا:
<DModal @closeModal={{@closeModal}} class="close-topic-modal">
إذا تضمن استدعاء DModalBody أي وسائط أخرى، فقم بتحديثها بناءً على الجدول أدناه:
| قبل | بعد |
|---|---|
@title="title_key" |
@title={{i18n "title_key"}} |
@rawTitle="translated title" |
@title="translated title" |
@subtitle="subtitle_key" |
@subtitle={{i18n "subtitle_key"}} |
@rawSubtitle="translated subtitle" |
@subtitle="translated subtitle" |
@class |
@bodyClass |
@modalClass |
استخدم صيغة الأقواس الزاوية مع سمة HTML عادية: <DModal class="blah"> |
@titleAriaElementId |
استخدم صيغة الأقواس الزاوية مع سمة HTML عادية: <DModal aria-labelledby="blah"> |
@dismissable, @submitOnEnter, @headerClass |
دون تغيير |
إذا كان هناك أي محتوى تذييل تم عرضه بعد مكون <DModalBody> القديم، فاستخدم كتلة الأسماء الجديدة :footer لإدخاله داخل <DModal>. عند استخدام أي كتل أسماء، يجب تغليف محتوى الجسم بـ :body و /:body. على سبيل المثال:
<DModal @closeModal={{@closeModal}}>
:body
مرحبًا بالعالم، هذا هو محتوى النافذة المنبثقة
/:body
:footer
هذا هو محتوى التذييل. سيتم إضافة غلاف `.modal-footer` تلقائيًا
/:footer
</DModal>
الخطوة 4: تحديث مواقع استدعاء showModal
في السابق، كانت النوافذ المنبثقة تُعرض باستخدام واجهة برمجة تطبيقات showModal، والتي كانت تأخذ سلسلة (اسم المتحكم) وعددًا من الخيارات. كانت تعيد مثيل المتحكم الذي يمكن التلاعب به:
import showModal from "discourse/lib/show-modal";
export default class extends Component {
showMyModal() {
const controller = showModal("my-modal", {
title: "My Modal Title",
modalClass: "my-modal-class",
model: { topic: this.topic },
});
controller.set("updateTopic", this.updateTopic);
});
}
لعرض النوافذ المنبثقة الجديدة القائمة على المكونات، يجب عليك حقن خدمة ‘modal’ (أو الوصول إليها باستخدام شيء مثل getOwner(this).lookup("service:modal")) واستدعاء الدالة show().
تأخذ show() مرجعًا إلى فئة المكون الجديدة كحجة أولى. الخيار الوحيد المدعوم لا يزال هو ‘model’، والذي يمكن استخدامه لتمرير جميع البيانات/الإجراءات المطلوبة لنافذتك المنبثقة.
لن يتم إرجاع أي مرجع إلى مثيل المكون. بدلاً من ذلك، تعيد show() وعدًا (promise) سيتم حله عند إغلاق النافذة المنبثقة. سيتم حل الوعد بأي بيانات تم تمريرها إلى @closeModal.
import MyModal from "discourse/components/my-modal";
import { service } from "@ember/service";
export default class extends Component {
@service modal;
showMyModal() {
this.modal.show(MyModal, {
model: { topic: this.topic, updateTopic: this.updateTopic },
});
});
}
بديلاً عن ذلك، قم بالترحيل إلى واجهة برمجة التطبيقات الإعلانية الموصوفة في وثائق DModal الرئيسية.
يمكن تكرار وظائف الخيارات القديمة على النحو التالي:
خيار showModal القديم |
الحل |
|---|---|
admin |
غير متاح للمكونات - قم بإزالته |
templateName |
غير متاح للمكونات - قم بإزالته |
title |
انقل إلى <DModal @title={{i18n "blah"}}> |
titleTranslated |
انقل إلى <DModal @title="blah">. يمكن حساب هذا بناءً على البيانات من model إذا لزم الأمر |
modalClass |
انقل إلى <DModal class="blah"> |
titleAriaElementId |
انقل إلى <DModal aria-labelledby="blah"> |
panels |
استخدم كتلة الأسماء :headerBelowTitle لتنفيذ علامات التبويب في مكونك (مثال) |
model |
دون تغيير |
الخطوة 5: الاختبارات
يجب أن تظل أي اختبارات كما هي إلى حد كبير. المشكلة الأكثر شيوعًا هي:
-
لم تعد النوافذ المنبثقة تحتوي على فئة افتراضية بناءً على اسمها. يجب تحديد الفئات صراحةً في القالب (انظر بداية الخطوة 3)
-
لم يعد غلاف
d-modalمستقرًا في DOM عند إغلاق النافذة المنبثقة. للتحقق من إغلاق جميع النوافذ المنبثقة، استخدم فحصًا مثلassert.dom('.d-modal').doesNotExist()
الربح!
يجب أن تعمل نافذتك المنبثقة الآن كما كانت من قبل. للاستفادة أكثر من الواجهة الجديدة، قد ترغب في النظر في [استبدال استدعاءات showModal باستراتيجية إعلانية]، وتحويل نافذتك المنبثقة لتكون مكون Glimmer.
أمثلة
إليك بعض commits الأمثلة التي توضح تحويل بعض نوافذ Discourse الأساسية إلى الواجهة الجديدة:
يتم التحكم في إصدار هذا المستند - اقترح تغييرات على github.
يُنصح باستخدام مكونات Ember الكلاسيكية في هذا الدليل لأنها توفر أسهل مسار ترحيل من متحكمات Ember. ولكن بالنسبة للنوافذ المنبثقة البسيطة، أو إذا كنت مستعدًا لقضاء بعض الوقت في إعادة الهيكلة، فإن مكونات Glimmer الحديثة هي الخيار الأفضل. ↩︎