إذا كنت تقوم بتنفيذ نافذة منبثقة (Modal) جديدة، فراجع الوثائق الرئيسية هنا. يصف هذا الموضوع كيفية هجرة نافذة منبثقة قائمة على المتحكم (Controller) إلى واجهة برمجة التطبيقات الجديدة القائمة على المكونات (Component-based API).
في الماضي، كان Discourse يستخدم واجهة برمجة تطبيقات قائمة على متحكمات Ember (Ember-Controller-based API) لعرض النوافذ المنبثقة. لاستدعاء النافذة المنبثقة، كنت تمرر نصاً يحتوي على اسم المتحكم إلى showModal(). تحت الغطاء، كان هذا يعتمد على واجهة Route#renderTemplate الخاصة بـ Ember، والتي تم إيقافها (deprecated) في 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]. احذف خليط ModalFunctionality (mixin) وحدّث أي استخدامات لدواله وفقاً للجداول أدناه:
| قبل | بعد |
|---|---|
flash() و clearFlash() |
أنشئ خاصية flash في مكوّنك ومررها إلى الحجة @flash في <DModal>. بشكل افتراضي، سيتم تنسيق التنبيه بفئة alert وهي نسخة من فئة ‘error’، ولكن يمكن تجاوز ذلك باستخدام الحجة @flashType. |
showModal() |
استورد دالة showModal من discourse/lib/show-modal |
إجراء closeModal |
استدعِ الحجة closeModal التي يتم تمريرها تلقائياً إلى مكوّنك |
كانت متحكمات النوافذ المنبثقة القديمة تعيش “إلى الأبد”، مما meant أنه كان علينا تنظيف الحالة يدوياً. مع واجهة برمجة التطبيقات الجديدة القائمة على المكونات، سيتم إنشاء المكوّن وتدميره عند إظهار/إخفاء النافذة المنبثقة. في كثير من الحالات، يعني ذلك أن خطافات دورة الحياة (lifecycle hooks) القديمة لم تعد مطلوبة.
إذا كنت لا تزال بحاجة إلى بعض المنطق المعتمد على دورة الحياة، استخدم هذا الجدول:
| قبل | بعد |
|---|---|
onShow() |
استخدم دورة حياة مكوّن Ember القياسية (init() أو معدّل Ember) |
afterRender |
استخدم دورة حياة مكوّن Ember القياسية (init() أو معدّل Ember) |
beforeClose() |
أنشئ غلافاً (wrapper) حول الحجة @closeModal التي يتم تمريرها إلى مكوّنك. مرر مرجعاً إلى غلاف الإغلاق الخاص بك إلى DModal مثل <DModal @closeModal={{this.myCloseModalWrapper}}> |
onClose() |
استخدم دورة حياة مكوّن Ember القياسية (willDestroy() أو معدّل Ember) |
الخطوة 3: تحديث القالب
استبدل الغلاف <DModalBody> بـ <DModal>. أضف بعض السمات الجديدة:
- مرر الحجة الجديدة
@closeModal - أضف فئة (class) صريحة. لمطابقة السلوك القديم، خذ اسم ملف المتحكم وأضف
-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 |
بدون تغيير |
إذا كان هناك أي محتوى تذييل (footer) يُعرض بعد مكوّن <DModalBody> القديم، فاستخدم الكتلة المسمية الجديدة <:footer> لإدخاله داخل <DModal>. عند استخدام أي كتل مسمية، يجب تغليف محتوى الجسم في <:body></:body>. على سبيل المثال:
<DModal @closeModal={{@closeModal}}>
<:body>
مرحباً عالماً، هذا هو محتوى النافذة المنبثقة
</:body>
<:footer>
هذا هو محتوى التذييل. سيتم إضافة غلاف `.modal-footer`
تلقائياً
</:footer>
</DModal>
الخطوة 4: تحديث مواضع استدعاء showModal
سابقاً، كانت النوافذ المنبثقة تُعرض باستخدام واجهة showModal، التي كانت تأخذ نصاً (اسم المتحكم) وعددًا من الخيارات (opts). كانت تعيد نسخة من المتحكم يمكن التحكم بها:
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) سيُحل (resolve) عند إغلاق النافذة المنبثقة. سيحل الوعد بأي بيانات تم تمريرها إلى @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 الكلاسيكية (Classic Ember Components) في هذا الدليل لأنها وفّرت أسهل مسار للهجرة من متحكمات Ember. لكن للنوافذ المنبثقة البسيطة، أو إذا كنت مستعداً لقضاء بعض الوقت في إعادة الهيكلة، فإن مكونات Glimmer الحديثة هي الخيار الأفضل. ↩︎