نعم، إضافة عنوان URL ستسبب التنقل لأنه لا توجد منطقية لاعتراض الحدث.
الرابط يستدعي إجراءً في Ember. جميع الإجراءات في Discourse قابلة للتوسيع. لذا، فهي تعمل كخطافات تخصيص بطريقة ما. إذن، كيف تعدّل إجراءً؟ حسنًا، دعنا نتحقق مما يفعله أولاً.
ابحث على GitHub أو محليًا عن اسم الإجراء. تُعرّف الإجراءات دائمًا في ملفات JS ويتم الإشارة إليها في Handlebars. نريد رؤية التعريف، لذا نضيق نطاق البحث إلى ملفات JS فقط.
Repository search results · GitHub
ستحصل على أربعة ملفات. أيها يجب أن تنظر إليه؟ تريد تخصيص قالب
discovery/topics.hbs
إذن،
discovery/topics.js
هو ما تريد النظر إليه.
هل أي من هذا الكود مفيد؟ لا، لكننا الآن نعرف مكان تعريف الإجراء. إذن، دعنا نعدله.
discovery/topics.js هو فئة Ember. يمكنك تعديل فئات Ember باستخدام طريقة في plugin-api تسمى… modifyClass ![]()
نحن نعرف بالفعل الفئة التي نريد تعديلها. إنها discovery/topics. نحتاج إلى معرفة نوع الفئة. لذا، دعنا نتحقق من دليل الملفات.
discourse/app/controllers/discovery/topics.js
إنه وحدة تحكم (controller).
نعلم أيضًا أننا نريد تعديل إجراء showInserted في تلك الفئة. لذا، نبدأ بهذا.
api.modifyClass("controller:discovery/topics", {
pluginId: 'sticky-new-topics-banner',
actions: {
showInserted() {
// لنقم ببعض العمل
}
}
});
يمكنك بعد ذلك إضافة أي كود تريده لتمرير النافذة عندما يضغط المستخدم على شريط “المواضيع الجديدة”. لقد اخترت شيئًا مثل هذا.
const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();
يمكنك قراءة المزيد حول scrollIntoView() هنا.
ثم تضيف ذلك إلى طريقة plugin-api كما يلي.
api.modifyClass("controller:discovery/topics", {
pluginId: 'sticky-new-topics-banner',
actions: {
showInserted() {
+ const listControls = document.querySelector(".list-controls");
+ listControls.scrollIntoView();
}
}
});
إذن، هل انتهينا؟ لا. هذا يكسر Discourse لأنك تتجاوز الإجراء بالكامل. عند النقر على الرابط، سيتم التمرير إلى عنصر list-controls، لكنه لن يحمل المواضيع الجديدة. لماذا؟ لأن الكود في النواة لم يعد يُطبَّق. أعني، هذا الشيء
إذن، كيف تصلح ذلك؟ بهذا السطر البسيط
this._super(...arguments);
لا تحتاج إلى نسخ أي كود من النواة إذا كنت تريد فقط إضافة إليه. قم بعملك، ثم أضف هذا السطر. كل ما يفعله هو التأكد من تطبيق الكود من النواة.
api.modifyClass("controller:discovery/topics", {
pluginId: 'sticky-new-topics-banner',
actions: {
showInserted() {
const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();
+
+ this._super(...arguments);
}
}
});
إذا جربت هذا، فسترى أن كل شيء يعمل بشكل رائع تقريبًا، باستثناء… أن الرأس يتداخل مع list-controls. لماذا؟ لأن الرأس مضبوط على sticky.
يمكنك إصلاح ذلك بعدة طرق في JS - احسب الارتفاع، احصل على الإزاحة، استورد مساعدًا من Discourse… إلخ. لن أدخل في التفاصيل.
الأسهل هو CSS باستخدام scroll-margin-top، ويمكنك قراءة المزيد عنها هنا.
إذن، نضيف هذا
.list-controls {
scroll-margin-top: calc(var(--header-offset) * 2);
}
باللغة الإنجليزية: عند النقر على الرابط، قم بالتمرير إلى أعلى list-controls - 2 × ارتفاع الرأس، حتى لا يتداخل ويترك مساحة صغيرة تحته.
إذن، دعنا نجمع كل هذا معًا.
علامة التبويب الرأس المشتركة
<script type="text/discourse-plugin" version="0.8">
api.modifyClass("controller:discovery/topics", {
pluginId: "sticky-new-topics-banner",
actions: {
showInserted() {
const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();
this._super(...arguments);
}
}
});
</script>
CSS المشترك
#list-area {
// للهاتف المحمول تخطيط مختلف
.alert-info,
.show-more.has-topics {
position: sticky;
// Safari يكون أحيانًا متطلبًا بدون البادئة
position: -webkit-sticky;
top: var(--header-offset);
// يجب أن يكون الشريط فوق المحتوى
z-index: z("header");
}
}
.list-controls {
scroll-margin-top: calc(var(--header-offset) * 2);
}