في سُمّتي (theme)، عندما يتم تحميل صفحة عرض الموضوع، أحتاج إلى الحصول على معرف (ID) ذلك الموضوع (والاسم أيضاً، إذا أمكن، لكن المعرف يكفي).
ثم أستخدم هذه المعلومات في سُمّتي لإجراء استدعاء API للحصول على معلومات حول الموضوع (باستخدام استدعاء لنقطة نهاية مثل forum-name/t/topic-name/id.json…)
كيف يمكنني الحصول على معرف الموضوع عند تحميل صفحة عرض الموضوع؟
الطرق الواضحة غير كافية
الحل الواضح هو استخدام window.location.href أو window.location.pathname لاستخراج المعلومات من الرابط. والمشكلة هي أن رابط صفحة عرض الموضوع يمكن أن يأخذ أشكالاً مختلفة. في كثير من الأحيان، يكون على النحو التالي: forum-name/t/topic-name/topic-id
لو كان هذا هو الشكل دائماً، لاستخدمت window.location.pathname بنجاح—مما يعطيني “t/topic-name/topic-id”.
لكن، أحياناً يضيف رابط صفحة عرض الموضوع ترتيب فئة الموضوع أيضاً، فيصبح الرابط: forum-name/t/topic-name/topic-id/category-index
لذا فإن استخدام window.location.pathname غير كافٍ، لأنني لا أعرف برمجياً ما إذا كان المعلمة الأخيرة هي معرف الموضوع أم فهرس الفئة.
قد يكون هناك حل باستخدام التعبير النمطي (regex)، لكن هذا يتطلب مهارة متقدمة في كتابة التعبيرات النمطية. وقد يكون هناك أيضاً حل باستخدام jQuery من خلال فحص العناصر في الصفحة التي قد تعطي المعرف—لكنني لم أستطع جعل ذلك يعمل بعد.
في منتداي، يحدث هذا في الواقع في معظم الأحيان عند النقر على موضوع. ستكون آخر جزء من عنوان URL هو رقم الموضوع داخل التصنيف الذي ينتمي إليه، إذا كنت قد نقرت على الموضوع من داخل ذلك التصنيف. ربما يكون هذا إعدادًا في نظام Discourse؟ لا يبدو أن هذا يحدث في موقع Meta، لكنني لا أعتقد أنني أفعل شيئًا خاصًا يتسبب في حدوث ذلك في منتداي.
ومع ذلك، لا يمكنني الاعتماد على حدوث هذا دائمًا، لأنه إذا كان الموضوع هو الأول في التصنيف، فلن يُضاف رقمه إلى فهرس التصنيف. لذا، قدر ما أستطيع رؤيته، لا توجد طريقة جيدة حاليًا لأتمكن من معرفة ما إذا كان سيظهر في فهرس التصنيف أم لا.
الحصول على المعرّف من عنصر div أمر مقبول، لكنه للأسف أبطأ إلى حد كبير من مجرد القدرة على الحصول عليه مباشرة من عنوان URL أو من خلال أي وسيلة مباشرة أخرى. في حال عدم وجود حل آخر، هل تعرف كود jQuery لاستخراج قيمة رابط href هذا؟
قد ينجح هذا الأمر، لكنه ليس فعالاً للغاية لأنك تقوم بإجراء استدعاء AJAX إضافي لكل عرض لصفحة الموضوع لكل مستخدم — بما في ذلك الزوار المجهولين. لذا فإن هذا سيؤدي إلى إنشاء حمل غير ضروري كبير على خادمك.
هذا يعمل! شكرًا جزيلًا لك. أفهم أنه باستخدام طريقة المطابقة (match method) هنا، فإنك تمر عبر الرابط للحصول، كما أفترض، على الحدوث الثالث لـ “/”، لأن المعرّف (id) سيحدث دائمًا بعد الشّرطة المائلة الثالثة في الرابط، والذي يعيد الشكل “/t/name/id/otherstuff”. هل يمكنك تقديم بعض المعلومات حول كيفية قيام تعبيرك النمطي (regex) بذلك؟ سيكون ذلك مفيدًا جدًا في رحلتي مع التعبيرات النمطية.
شكرًا لك على المعلومة. إذن، فإن “linked_post_number” هو ما يظهر أحيانًا ويسبب مشاكل في استدعاء واجهة برمجة التطبيقات (API call) الخاصة بي. تقول هنا إنه “اختياري”—هل هناك طريقة للتأكد من أنه لن يظهر أبدًا؟
عندما يزور المستخدم صفحة عرض الموضوع، أريد أن:
أعرف برمجياً جميع الوسوم المرتبطة بذلك الموضوع. لاحظ أن بعض الوسوم مخفية عن عرض المستخدم.
يكون هناك زر في صفحة الموضوع يضيف وسمًا مخفيًا معينًا إلى الموضوع عند النقر عليه (إذا لم يكن الوسم المخفي موجودًا بعد)، ويحذف الوسم المخفي عند النقر عليه (إذا كان الوسم المخفي موجودًا بالفعل).
كل هذا مباشر باستخدام واجهة برمجة التطبيقات للإدارة (Admin API) و JavaScript/jQuery (بافتراض أنني أستطيع الحصول على رابط الموضوع الصحيح لاستخدامه في استدعاءات واجهة برمجة التطبيقات).
أعتقد أن الطريقة الوحيدة الأخرى للقيام بهذا النوع من الأشياء هي إنشاء إضافة (plugin) حيث أغوص بعمق في: 1. إمبر (Ember)، 2. رايلز (Rails)، و3. قاعدة كود ديسكورد (Discourse). لقد راجعت المنشورات الرئيسية والوثائق الخاصة بديسكورد حول كيفية القيام بذلك، لكنني وجدت الأمر بطيئًا لأنك حقًا تحتاج إلى فهم هذه القطع الثلاث. لذا، فقد ركزت حتى الآن على نهج واجهة برمجة التطبيقات.
سأكون مهتمًا لسماع ما إذا كانت هناك طريقة أخرى للقيام بذلك تقلل من حمل الخادم.
كان بوسعي بالتأكيد مساعدتك في الكود لو كانت الحلّة خطوة واحدة، لكن هناك عدة خطوات متضمنة. إذا كنت بحاجة إلى مساعدة على شكل استشارة تتعلق بإنجاز العمل أو تعلم كتابة مكونات الثيم بنفسك، فالرجاء النشر في السوق وسأتواصل معك.
شكرًا لك، لكن من المفيد الحصول على أي توجيه في أي خطوة. على سبيل المثال، كيف يمكنني معرفة جميع الوسوم المرتبطة بموضوع ما، بخلاف استخدام واجهة برمجة التطبيقات (API)؟
يتم تحميل كائن موضوع كامل على جانب العميل عند فتح صفحة الموضوع. الآن، إذا كنت ترغب في استخدامه، ستحتاج إلى إضافة كودك الخاص إلى القالب لاستخدام هذه البيانات، أو إعادة فتح الفئات لاستغلال البيانات المحملة (أي إنشاء خصائص محسوبة خاصة بك واستخدامها في القالب). يحتوي على معظم البيانات التي تحتاجها (ربما أكثر مما تحتاجه فعليًا) محملة على جانب العميل دون الحاجة إلى مكالمات API إضافية. كما ستحتاج أيضًا إلى plugin-outlet لإدراج علامتك الخاصة في القوالب الموجودة.
سيكون من المفيد إذا استعرضت الكود الأساسي/البيانات الوصفية للمصطلحات التي استخدمتها أعلاه. سأكون سعيدًا للمساعدة هنا إذا علقت في أي نقطة، وذلك ضمن حدود وقتي المتاح. تحياتي.
شكرًا لك. أنا على دراية ببعض الأساسيات التي ذكرتها، لكن هناك نقطة واحدة تُعيقني (وأعتقد أن هذا النوع من الأمور يُعيق الكثير من الناس):
في صفحة عرض الموضوع، يتم تحميل القالب /templates/components/topic-category.hbs. وهذا القالب هو ما يعرض الفئة بالإضافة إلى الوسم أسفل عنوان الموضوع.
في ملف topic-category، يتم سرد topic.tags. لذا فإن هذه هي المعلومة الرئيسية التي أحتاجها لتبدأ الأمور.
إليك أين أعلق: كيف يمكنني الحصول على معلومات topic.tags هذه إلى جافا سكريبت؟
على سبيل المثال، إذا أردت فقط طباعة محتوى topic.tags في وحدة التحكم (console.log)، فكيف يمكنني فعل ذلك؟
أعرف كيفية تجاوز القوالب. على سبيل المثال، في سمة معينة، يمكنني وضع ملف في discourse/templates/components/topic-category.hbs، وإعادة طباعة القالب هناك، مع إضافة التغييرات التي أرغب في إجرائها على العرض. (أنا أستخدم هيكل الملفات المنفصل الموصوف هنا).
في سمتي، أعرف أيضًا كيفية وضع جافا سكريبت في theme/initializers/initializer-file.js.es6.
ويمكنني جعل الاثنين يتفاعلان باستخدام بعض مكتبة jQuery. على سبيل المثال، يمكنني وضع topic.tags داخل عنصر div في القالب، ثم الوصول إليه في الملف المبدئي باستخدام jQuery عن طريق الحصول على محتوى ذلك العنصر div.
لكن هذا طريق ملتوٍ. كيف يمكنني الحصول على معلومات topic.tags هذه مباشرةً حتى أتمكن من تحليلها والتلاعب بها؟
سأقوم بعرض كامل موضوع topic باستخدام console.log لتحديد المفتاح المطلوب. بالنسبة لتفاعلات jQuery، يجب أن تتم من داخل المكونات. didInsertElement هو خطاف المكون المفيد هنا.
من خلال ما يبدو، يبدو لي أنك تحتاج إلى خاصية محسوبة تعتمد على topic.tags وتعيد التلاعب بها في وحدة التحكم/المكون المعني. يمكن استخدامها مباشرة في القالب. أيضًا، لا تستسلم لهذه الأمور. سيستغرق الأمر وقتًا لكنه سيؤدي بالتأكيد إلى نتائج أفضل مما يمكنك طلبه.
ماذا تقصد بـ “داخل المكونات”—أي ملف أستخدم فيه كود jQuery؟ (في سُمّتي، يمكنني استخدام jQuery في ملف theme/intializers/intializer-file.js.es6، لكن هذا لا يبدو أنه “داخل” المكون)
شكرًا لكم يا رفاق، كل هذه المعلومات مفيدة. أنا أدرس الأدلة والوثائق العامة. سيكون من المفيد جدًا أيضًا معرفة اسم الملف الذي يجب أن أضع فيه (i) كود jQuery و (ii) كود didInsertElement. وجود هذه النوعية من المعلومات الملموسة سيساعد بشكل كبير في توجيه المراجعة اللاحقة.
إذا كانت الوسوم مخفية عن المستخدم العادي، فكيف يمكن أن تساعد مكالمة إضافية؟ يجب أن يقوم المُسلسل (serializer) في أي حال بإخفاء تلك الوسوم عن المستخدم العادي. إذا لم يفعل ذلك، فأنت تعرض ثغرة أمنية في المحتوى.
إذا كنت ستبذل كل هذا الجهد لتجاوز قيود التغييرات التي تقتصر على الواجهة الأمامية، فإنني أقترح أن تتحمل العناء وتنظر في بناء هذه الميزة ضمن إضافة، حيث يمكنك التسلسل في عملية واحدة بدلاً من وجود إعداد غير مرتب مع مكالمة إضافية.
هذا منطقي. أود أن أتعلم المزيد حول استخدام المُسلسل (serializer)؛ فبينما يُعد المُسلسل أحد أهم الخطوات في إضافة discourse، لم أجد بعد وثائق توضح أمثلة أساسية لاستخدامه. هل تعرف عن مثل هذه الوثائق؟
عندما تقول إن المُسلسل يجب أن يخفي هذه الوسوم، هل يمكنك تقديم بعض الكود الوهمي (pseudo-code) لتوضيح ما تقصده؟ (لا بأس إذا لم يعمل بشكل كامل، فأنا أحاول فقط استيعاب المفهوم)
هذا يشبه موسيقى الجاز تمامًا… أفضل الممارسات موجودة عادةً في مشهد الإضافات مفتوحة المصدر الحالي، تمامًا مثل جميع التسجيلات. لا تتوقع دليلًا مثاليًا حول كيفية القيام بكل شيء؛ ففي كثير من الأحيان، يجب أن تنغمس (أههه) في التعلم من الأعمال السابقة.
ابحث عن إضافة في #plugin تقوم بشيء مشابه وظيفيًا، أو عن عنصر مما تريد القيام به، ثم افحص الكود لترى كيف يحقق النتائج. وينطبق الشيء نفسه على كود مصدر Discourse، الذي يمكنك استخدامه كمصدر لأفضل الممارسات النهائية، خاصة فيما يتعلق بـ Discourse.
استنسخ إضافة موجودة محليًا وحاول تغيير بعض الأشياء، وجرب.
المُصنّفات (Serializers) تقوم فقط بتصفية ما يُرسل من المتحكمات/النماذج، ويمكنها أيضًا إجراء بعض التعديلات الأساسية.
def tags
# استدعاء الدالة `pluck` مع `includes` يتسبب في استعلامات N+1
tags = topic.tags.map(&:name)
if scope.is_staff?
tags
else
tags - scope.hidden_tag_names
end
end
يمكنك أن ترى هنا أنه يستبعد الوسوم المخفية عن غير الموظفين.