لاحظت أنه من غير الممكن فرز الفئة حسب الترتيب الأبجدي للعناوين بشكل افتراضي. ربما يُقال لي إنه يكفي استخدام عوامل التصفية لإجراء هذا الإعداد، لكن هذا يثير مشكلتين رئيسيتين:
هناك الكثير من الخطوات المطلوبة، مما قد يكون صعبًا على بعض المستخدمين.
نفقد الشكل البصري المعتاد للبلاطات (Tiles).
هل من الممكن إضافة إعداد لكل فئة لتحديد فرز المواضيع أبجديًا بشكل افتراضي؟ لا أعرف إن كان هذا مدرجًا في خطة الطريق.
أعيد التأكيد على أن هذا مجرد ملاحظة من تجربتي العملية، لكنني أرى أنه من المحزن التخلي عن خيار قياسي ومتوفر في Discourse.
إعجابَين (2)
chapoi
27 أغسطس 2026، 10:32ص
2
لكن لماذا تريد الترتيب الأبجدي؟ ما هو الاستخدام الذي تتخيله؟
gilles
27 أغسطس 2026، 10:35ص
3
في الحقيقة، لدي في الفئات بطاقات لألعاب الطاولة، وكنت أودّ أن يتم ترتيب المواضيع أبجديًا عند الدخول إلى هذه الفئات المحددة. لقد حاولتُ إجراء تعديل بسيط، لكنني لم أفلح في ذلك.
إعجابَين (2)
RGJ
(Richard - Communiteq)
27 أغسطس 2026، 10:51ص
4
يُعدّ هذا مفيدًا للدورات التدريبية وما شابه، حيث تكون عناوين المواضيع على شكل “الدرس 1”، “الدرس 2”، وما إلى ذلك.
علاوة على ذلك، من أكبر شكواي من إضافة تصنيفات المستندات أنها لا تزال تعرض قائمة بالمواضيع، خاصةً على الأجهزة المحمولة. إن إمكانية الفرز الأبجدي ستخفف على الأقل من بعض هذه المشكلة.
4 إعجابات
نقوم بإجبار العرض المحلي من أ إلى ي للحفاظ على نظافة المسرد. هناك حالات محددة يكون فيها ذلك ضروريًا حقًا.
Moin
27 أغسطس 2026، 11:35ص
6
gilles:
تفقد الترتيب المعتاد للبلوكات.
لست متأكدًا من أنني أفهم هذه النقطة. أي بلوكات هي التي تُفقد عند النظر إلى https://meta.discourse.org/filter?q=order%3Atitle-asc ؟
إعجاب واحد (1)
gilles
27 أغسطس 2026، 12:10م
7
ربما عبّرتُ عن نفسي بشكل غير واضح عبر البريد الإلكتروني كنتُ أظن أننا سنحتفظ بنفس المظهر البصري للبلوكات
الفئة بدون مرشّح
الفئة مع المرشّح
إعجاب واحد (1)
أؤكد أن هذا المرشّح غير مفيد لأولئك منا الذين يرغبون في الحفاظ على العرض الافتراضي كما هو، لا سيما إذا طُبِّق على فئات تعمل كوثائق فئات (المسرد، نظام إدارة المحتوى).
إنه نقطة بداية، لكنه لا يلبّي الحاجة البسيطة — ربما ليس من الناحية التقنية، لكن بالتأكيد من منظور مستخدمينا — لعرض المواضيع مرتبة أبجديًا.
أعتقد أن المرشّح يلبّي احتياجات أخرى بشكل شامل.
أشارك فقط حلاً كنت أستخدمه منذ أسابيع:
satonotdead:
في النهاية، استخدمت مكوّن مخصص للثيم لهذا الغرض:
// يحتاج الترتيب من أ إلى ز إلى الفئة كاملة: لا يمكن للنواة ترتيب قائمة المواضيع بالعنوان
// (لا يحتوي 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 الآن
// متحكمًا مخصصًا لكل فلتر؛ فئات المستندات هي دائمًا قائمة أحدث المواضيع،
// لذا نبحث عن ذلك المتحكم مباشرة. الفشل هنا يعني فقط أننا نرتب
// الصفحة الأولى، لذا كل خطوة اختيارية السلسلة.
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; // مرتب بالفعل — يوقف المراقب من تغذية نفسه
}
// يُدرج قبل ما يلي الصفوف، مع إبقاء أي علامة نهاية التحميل في النهاية.
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);
});
}
أعتقد أن الكود يمكن تحسينه على الأرجح، وأرحب بمقترحات و/أو طلبات الدمج.
إعجاب واحد (1)
gilles
14 سبتمبر 2026، 6:25ص
10
مبادرة رائعة، شكراً @satonotdead
إعجاب واحد (1)