لقد أنشأت سمة أكثر تفصيلاً لـ user-card-contents، وأضفت بعض حقول المستخدم المخصصة. أود جعل البطاقة ثابتة مع زر إغلاق، بطريقة مشابهة لمكون “إنشاء موضوع جديد”.
هل صحيح أنني سأحتاج إلى استبدال ملف user-card-contents.js لمنع استدعاء إغلاق العنصر؟ وهل سأتمكن من تضمين هذا داخل السمة؟
الإجابة المختصرة هي نعم. إذا كانت التغييرات تؤثر فقط على الواجهة الأمامية، فيمكن تنفيذها ضمن سمة أو مكون.
هل يمكنك التوضيح أكثر بما تقصده بـ “ثابت” (sticky)؟ إذا كنت تقصد أنك تريد منه التمرير مع المحتوى مع البقاء في نفس الموقع، فسيكون ذلك تغييرًا في CSS. أيضًا، هل يُقصد تضمين التغيير على كل من سطح المكتب والجوال؟
هل يمكنك وصف الاستدعاء المحدد الذي تشير إليه؟ (مثل عند النقر أو عند التمرير، إلخ)
سيحتاج قالب زر الإغلاق إلى إضافته إلى قالب Handlebars لبطاقة المستخدم. أما المنطق اللازم للتعامل مع الإجراء عند النقر على الزر فيجب إضافته إلى ملف المكون .js.
قد لا يكون الاستبدال الكامل ضروريًا، فهناك بعض الخطافات (hooks) التي يمكنك استخدامها لاستبدال طرق محددة في فئة معينة. يمكنني مشاركة المزيد حول ذلك إذا وصفت ما تريد فعله بمزيد من التفصيل.
ما أطمح إليه هو منع معالج الأحداث clickOutsideEventName في mixin card-contents-base.js من إغلاق البطاقة على سطح المكتب. بدلاً من ذلك، أود إجبار المستخدمين على النقر على زر لإغلاقها. سأحتاج على الأرجح إلى فعل شيء مختلف للجوال.
نجحت في جعل قالب الـ Handlebars يعمل، والآن على حل مشكلة ملف الـ .js
ربما كنت تعرف معظم هذا بالفعل لأنك عملت بالفعل على سمة (Theme) الخاصة بك، لكنني سأحاول أن أجعلها أكثر تفصيلاً قليلاً للجمهور الأوسع.
أول شيء سأفعله هو البحث إما محليًا أو على Github. على Github، ستحصل على شيء مثل هذا. في معظم الحالات، ستحتوي مصطلح البحث على أكثر من نتيجة واحدة، وسيكون عليك إما أن تكون أكثر تحديدًا أو مسح النتائج يدويًا للعثور على شيء قريب مما تريد.
هذا الملف هو Mixin. لماذا أذكر هذا؟ لأنك بحاجة إلى أن تكون على علم بأن Mixins يمكن مشاركتها في عدد من الأماكن المختلفة. في هذه الحالة، يتم استخدامها لكل من بطاقات المستخدمين وبطاقات المجموعات. لذا، فإن التغييرات التي تجريها هنا ستؤثر على كليهما.
إذا بحثت في الملف، ستجد أن clickOutsideEventName يتم تعريفه أولاً هنا
يضمن Ember أنه بحلول الوقت الذي يتم فيه استدعاء didInsertElement():
تم إنشاء عنصر المكون وإدراجه في DOM.
يمكن الوصول إلى عنصر المكون عبر خاصية this.element الخاصة بالمكون.
لماذا نحتاج إلى هذا؟ لأننا نحتاج إلى معالج mousedown مختلف لبطاقات المستخدمين وبطاقات المجموعات. إذا عدنا قليلاً، ستلاحظ الآن أن معرف العنصر يتم استخدامه في clickOutsideEventName
والذي، كما ناقشنا أعلاه، يتم تمريره بعد ذلك كخاصية.
الآن، دعنا ننتقل إلى كيف يرتبط كل هذا بما تفعله.
أنت تحاول منع إغلاق البطاقات عندما ينقر المستخدم خارجها. لذا، دعنا نحاول معرفة طريقة للقيام بذلك. إذا كنت تتذكر، ناقشنا كيف يتم استهلاك clickOutsideEventName في النهاية هنا
باختصار، هذا يضيف معالج mousedown لعنصر HTML عند إدراج بطاقة (في أول عرض للصفحة). ثم نتحقق من هدف حدث mousedown. إذا كان الهدف في مكان ما داخل البطاقة، نتوقف. إذا كان خارج البطاقة، نغلقها عن طريق استدعاء this._close()
وهذا ما ستحتاج إلى استدعاؤه عند إضافة زر الإغلاق الخاص بك - لكننا سنعود إلى ذلك لاحقًا.
الآن، الهدف هو إزالة معالج mousedown هذا إذا كنت تريد أن لا يؤدي النقر خارج البطاقة إلى إغلاقها. إذن كيف نفعل ذلك؟ حسنًا، سنحتاج إلى تعديل didInsertElement() وإليك كيفية القيام بذلك.
تتمتع سمات Discourse بالوصول إلى واجهة برمجة التطبيقات الإضافية، والتي تحتوي على العديد من الطرق التي يمكنك استخدامها. هناك المزيد من التفاصيل حول الأكثر استخدامًا هنا
إذا كنت تتذكر، فإن الملف الذي نعمل عليه هو Mixin. Mixin هو فئة Ember. لذا، فإن الطريقة التي سنستخدمها هي modifyClass
لماذا حدث ذلك؟ حسنًا، اتضح أن طريقة modifyClass لا تدعم حاليًا تعديل Mixins (بقدر ما اختبرت) سأقوم بتدوين ملاحظة لمعرفة سبب ذلك والتحقق مما إذا كان بإمكاننا إصلاح ذلك. ولكن في الوقت الحالي، دعنا نعود إلى ما تريد فعله.
حسنًا، لا يمكننا تعديل Mixins، لذا أعتقد أننا عالقون، أليس كذلك؟ لا. دعنا نحفر أعمق قليلاً.
كما ذكرت من قبل، يتم استخدام هذا Mixin بواسطة كل من المستخدم user-card-contents و group-card-contents مكونات Ember (مرة أخرى، لأن Mixins مصممة لجعل الكود قابلاً لإعادة الاستخدام)
إذا قرأت بعناية، ستلاحظ أننا نستورد أولاً Mixin الذي ناقشناه هنا
ثم نقوم بإنشاء مكون Ember جديد ونمرر Mixin إليه.
ماذا يعني ذلك؟ يعني أن didInsertElement() لـ user-card-contents مُورث فعليًا من Mixin. يمكن قول الشيء نفسه عن group-card-contents.
أين يتركنا ذلك؟ حسنًا، هناك أخبار جيدة وأخبار سيئة. الأخبار الجيدة هي أنه إذا كنت تريد إجراء تغييرات على user-card-contents دون التأثير على group-card-contents، فيمكنك ذلك! الأخبار السيئة هي أنه إذا كنت تريد أن تنطبق تغييراتك على كليهما، فستحتاج إلى تكرار بعض الكود.
دعنا نعود إلى modifyClass ونحاول مرة أخرى مع user-card-contents. لذا شيء مثل هذا:
تم تسجيل التغيير ويمكننا رؤيته في وحدة التحكم، لكننا لم نصل بعد.
لذا، الآن بعد أن أصبح بإمكاننا تعديل didInsertElement()، دعنا نحاول العودة إلى ما تحاول فعله. إذا كنت تتذكر، يتم تعريف معالج mousedown في didInsertElement هنا
ستنتهي بشيء مكسور. لماذا حدث ذلك؟ لأن هذا ليس تعديلًا للطريقة. هذا تجاوز كامل لطريقة didInsertElement() الأساسية لذلك المكون. لذا، لا يتم تطبيق أي من الكود الأساسي فعليًا إذا قمت بذلك.
كيف نصلح هذا؟ حسنًا، اتضح أن Ember لديها شيء يسمى this._super(...arguments)
ماذا يفعل ذلك؟ يسمح لك بإضافة أو إضافة كود في إضافة إلى ما تحتويه طريقة الفئة بالفعل. على سبيل المثال، إذا قمت بذلك
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// الكود الذي تريد إضافته
$("html").off(clickOutsideEventName);
// الكود من الأساس
this._super(...arguments);
}
});
فإن الكود الذي تريد إضافته سيتم تشغيله قبل أي شيء آخر هنا
هذه طريقة رائعة للحفاظ على سمعتك مرنة تجاه التغييرات في الأساس لأن كل شيء في الأساس يتم تشغيله أولاً، ثم يتم تشغيل كودك بعد ذلك. لذا، دعنا نجرب هذا مرة أخرى ونرى ما يحدث.
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// الكود من الأساس
this._super(...arguments);
// الكود الذي تريد إضافته
$("html").off(clickOutsideEventName);
}
});
لماذا يحدث هذا؟ ذلك بسبب سياق كود مختلف. في ملف مكون Ember، يتم تعريف clickOutsideEventName بالفعل بحلول الوقت الذي يتم فيه استهلاكه. سمة (Theme) الخاصة بك في ملف مختلف، لذا clickOutsideEventName غير معرف هناك.
كيف نصلح ذلك؟ هل تتذكر هذا؟
clickOutsideEventName هي خاصية للمكون، لذا إذا استخدمت this.clickOutsideEventName فيجب أن يعمل. دعنا نجرب ذلك.
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// الكود من الأساس
this._super(...arguments);
// الكود الذي تريد إضافته
$("html").off(this.clickOutsideEventName);
},
});
وفي الواقع يعمل
تفتح بطاقات المستخدمين الآن دون أي أخطاء والنقر في أي مكان خارجها لا يفعل شيئًا.
يمكنك فعل نفس الشيء تمامًا لبطاقات المجموعات مثل هذا
api.modifyClass('component:group-card-contents', {
didInsertElement() {
// الكود من الأساس
this._super(...arguments);
// الكود الذي تريد إضافته
$("html").off(this.clickOutsideEventName);
},
});
الشيء الوحيد المتبقي هو ربط زر الإغلاق هذا بطريقة _close() التي ناقشناها سابقًا وهناك ثلاث خطوات لذلك.
إضافة إجراء closeCard (يمكنك تسميته بما تريد)
إضافة زر إلى قالب بطاقة المستخدم
استدعاء ذلك الإجراء عند النقر على الزر.
سألتزم ببطاقات المستخدمين للتبسيط. لذا، نضيف هذا (إلى جانب ما ناقشناه بالفعل)
وبالطبع يمكنك فعل شيء مماثل لبطاقات المجموعات كما ذكرت أعلاه.
سأترك بطاقة المجموعة والتنفيذ للجوال كتمرين لك لأنك ستستخدم فعليًا نفس المفاهيم التي ناقشناها أعلاه إذا كنت تريد إجراء تغييرات على تلك ولكن يرجى إعلامي إذا واجهت أي مشاكل.