أتساءل عما إذا كان بإمكاننا استخدام عوامل التصفية لعرض فئة باستخدام عرض المستندات و A-Z (أبجديًا).
لدينا مسرد يجب أن يعرض عرض الموضوع مرتبًا ![]()
حاليًا، عرض التصفية منفصل عن المستندات:
لقد انتهيت في النهاية إلى استخدام مكوّن مظهر مخصص لذلك:
// يتطلب الترتيب من أ إلى ز الفئة بأكملها: لا يمكن للنواة ترتيب قائمة المواضيع حسب العنوان
// (لا يحتوي TopicQuery::SORTABLE_MAPPING على "title")، لذا نستنفد القائمة المصنّفة
// قبل الترتيب. محدد السقف — فئات المستندات صغيرة الحجم؛ أي شيء أكبر يعتمد على
// ترتيب ما تم تحميله، مما يحافظ عليه محدثًا بواسطة MutationObserver أدناه.
// ponytail: احذف هذه الحلقة بأكملها إذا كانت النواة ستوفر يومًا ما ترتيبًا للعناوين على مستوى الخادم.
const MAX_DOC_PAGES = 12; // حوالي 360 موضوعًا بواقع 30 لكل صفحة
let docLoadRun = 0;
async function loadAllDocTopics(api) {
const run = ++docLoadRun;
// `controller:discovery/topics` أصبح غير مدعوم في Discourse الحالي
// (معرف الإلغاء: discourse.discovery-topics-controller). يستخدم Discovery الآن
// متحكمًا مخصصًا لكل مرشح؛ ففئات المستندات هي دائمًا قائمة أحدث المواضيع،
// لذا نبحث عن ذلك المتحكم مباشرة. الفشل هنا يعني فقط أننا سنرتب الصفحة الأولى،
// لذا كل خطوة اختيارية (optional-chained).
const list = api.container.lookup("controller:discovery/latest")?.model;
if (!list?.loadMore) {
return;
}
for (let page = 0; page < MAX_DOC_PAGES; page++) {
if (!list.more_topics_url) {
return;
}
const before = list.topics?.length ?? 0;
await list.loadMore();
// تم التنقل بعيدًا أثناء التحميل، أو توقفت القائمة عن النمو — في كلتا الحالتين، توقف.
if (run !== docLoadRun || (list.topics?.length ?? 0) === before) {
return;
}
}
}
// يرتب قائمة مواضيع المستندات من أ إلى ز، مع مطابقة لغة الصفحة الخاصة بـ <html lang>.
let docSortObservers = new Map();
function docSortLocale() {
const lang = document.documentElement.lang;
if (!lang) {
return undefined;
}
try {
Intl.getCanonicalLocales(lang); // يرمي RangeError في حالة وسم غير صحيح
return lang;
} catch {
return undefined; // يعود إلى لغة المتصفح الافتراضية
}
}
function sortDocTopicList(body, locale) {
const rows = [...body.querySelectorAll(":scope > .topic-list-item")];
if (rows.length < 2) {
return;
}
const sorted = [...rows].sort((a, b) => {
const titleA = a.querySelector(".title")?.textContent.trim() ?? "";
const titleB = b.querySelector(".title")?.textContent.trim() ?? "";
return titleA.localeCompare(titleB, locale);
});
if (sorted.every((row, i) => rows[i] === row)) {
return; // مرتب بالفعل — يوقف المراقب من تغذية نفسه
}
// إدراج قبل أي عنصر يتبع الصفوف، مع إبقاء عنصر "تحميل المزيد" (sentinel) في النهاية.
const anchor = rows[rows.length - 1].nextSibling;
// تثبيت الصف المرئي الأول حتى لا تقفز التمريرة عند الإدراج أعلاه.
const pinned = rows.find((row) => row.getBoundingClientRect().bottom > 0);
const pinnedTop = pinned?.getBoundingClientRect().top;
// إيقاف مؤقت للمراقب حتى لا تعيد حركاتنا الدخول إلى هذه الدالة.
const observer = docSortObservers.get(body);
observer?.disconnect();
sorted.forEach((row) => body.insertBefore(row, anchor));
observer?.observe(body, { childList: true });
if (pinned) {
window.scrollBy(0, pinned.getBoundingClientRect().top - pinnedTop);
}
}
function sortDocCategoryTopicLists() {
docSortObservers.forEach((observer) => observer.disconnect());
docSortObservers = new Map();
const locale = docSortLocale();
// ليس حاوية flex/grid، لذا يجب أن ينقل إعادة الترتيب عقد DOM — يتم تجاهل `order` في CSS.
document.querySelectorAll(".topic-list.doc-simple-mode .topic-list-body").forEach((body) => {
// try/finally لضمان ظهور القائمة دائمًا حتى لو ألقى الترتيب خطأً.
try {
sortDocTopicList(body, locale);
} finally {
body.classList.add("docs-sorted");
}
// الترتيب مرة واحدة فقط عندما يهدأ التحميل — إعادة الترتيب أثناء التحميل أوقفت المحمّل.
let settleTimer = null;
const observer = new MutationObserver(() => {
window.clearTimeout(settleTimer);
settleTimer = window.setTimeout(() => {
sortDocTopicList(body, locale);
}, 400);
});
observer.observe(body, { childList: true });
docSortObservers.set(body, observer);
});
}
أعتقد أن الكود يمكن تحسينه على الأرجح، وأرحب بقبول الاقتراحات و/أو طلبات الدمج (PRs).
حسناً - للأسف تظهر لي رسالة خطأ 404 عند اتباع الرابط في منشورك: https://github.com/somos-criptonautas/discourse-horizon-mod-nautas/blob/main/javascripts/api-initializers/init.gjs
آه، أعتذر عن ذلك. لقد حدّثت الرابط، وهو داخلي وما زلت أعمل عليه، لذا يرجى اعتباره تجريبياً.
أنا مستعد لاستقبال أي ملاحظات أو اقتراحات أو أخطاء قد تلاحظونها عند مراجعة الكود أو تجربته! أعلم أنها ليست الحل الأكثر أناقة، لكنها تناسب حالتنا الخاصة.