كان علينا تحميل المحتوى ديناميكيًا من منتدى Discourse الخاص بنا في labs.daemon.com.au إلى الموقع الإلكتروني العام لشركتنا في www.daemon.com.au/labs
يقوم الكود باسترجاع أحدث المحتوى في فئات محددة من Discourse، ثم يلفه حول تنسيق (markup) يعمل مع موقعنا الإلكتروني قبل حقنه في الصفحة. بعد ذلك، نضيف بعض التغييرات الإضافية لجعل الكود أكثر عمومية، بحيث يمكن إعادة استخدامه بسهولة على مواقع إلكترونية مختلفة لتحميل المحتوى من منتديات Discourse متنوعة.
يحتوي منتدى Discourse على العديد من نقاط النهاية (endpoints) للبيانات. على سبيل المثال، عند الانتقال إلى الأحدث، يتم تحميل نقطة النهاية latest.json التي تعيد البيانات المطلوبة لتلك الصفحة بالتحديد. وهذا يتيح لنا عرض محتوى Discourse على موقعنا الخاص.
قبل البدء
لتحميل المحتوى من Discourse عن بُعد، يجب جعل نقاط نهاية Discourse متاحة لموقعنا الإلكتروني. ويمكن تحقيق ذلك من خلال إعدادات “الإدارة” (Admin) في Discourse.
قم بتسجيل الدخول إلى Discourse باستخدام حساب يتمتع بصلاحيات المسؤول، ثم انتقل إلى علامة التبويب “الإعدادات” (Settings) في لوحة “الإدارة” (Admin):
ابحث عن “الأمان” (Security) في قائمة التنقل على اليسار، ثم حدد حقل “origins cors” على الجانب الأيمن. أضف عنوان URL للموقع الإلكتروني الذي سيعرض محتوى من Discourse في هذا الحقل (في حالتنا: http://www.daemon.com.au/)، ثم احفظ التغييرات:
نقاط النهاية (Endpoints)
بما أن Discourse يولد عددًا لا يحصى من نقاط النهاية للبيانات، فمن المهم العثور على النقطة الصحيحة اعتمادًا على نوع المحتوى المطلوب عرضه عن بُعد. بإضافة /l/latest.json في نهاية عنوان URL لصفحة فئة معينة، ستظهر نقطة النهاية التي تحتوي على أحدث المشاركات لتلك الفئة بالتحديد. على سبيل المثال، https://labs.daemon.com.au/c/design/l/latest.json هي نقطة النهاية الخاصة بـ https://labs.daemon.com.au/c/design.
HTML و JavaScript
بما أننا حصلنا الآن على نقطة النهاية التي نحتاجها، ننتقل الآن إلى تمكين موقعنا من قراءة هذه النقطة لاسترجاع المعلومات المفيدة وعرضها بشكل صحيح. في هذا المثال، نهدف إلى عرض أحدث 3 مشاركات منشورة بواسطة المستخدم رقم 1 أو 2 أو 3 من فئة “التصميم” داخل عنصر #div في موقعنا. بالإضافة إلى ذلك، لا نريد عرض مشاركة “حول فئة التصميم”.
ملاحظة: في مثالنا، نستخدم Bootstrap v4.0.0-beta.2 الافتراضي لتقديم بعض الأنماط الضرورية لأغراض العرض التجريبي فقط، واستخدامها اختياري تمامًا.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="ie=edge" http-equiv="x-ua-compatible">
<meta content="initial-scale=1.0, shrink-to-fit=no, width=device-width" name="viewport">
<title>Discourse embed</title>
<!-- Bootstrap CSS للأنماط الأساسية في العرض التجريبي -->
<link crossorigin="anonymous" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="card-deck" id="div"></div>
</div>
<!-- jQuery -->
<script crossorigin="anonymous" integrity="sha384-p7RDedFtQzvcp0/3247fDud39nqze/MUmahi6MOWjyr3WKWaMOyqhXuCT1sM9Q+l" src="https://code.jquery.com/jquery-3.2.1.js"></script>
<!-- JavaScript -->
<script>
(function ($) {
'use strict'
$(function () {
$.ajax('https://labs.daemon.com.au/c/design/l/latest.json').then(function (result) {
// تحليل البيانات لتوليد المحتوى من Discourse:
// * نقطة نهاية Discourse، أي `result`،
// * عدد المشاركات المراد عرضها على موقعك، مثل `3`،
// * مصفوفة اختيارية لـمعرفات المستخدمين (قائمة بيضاء)
// إذا كان الهدف هو عرض المشاركات المنشورة بواسطة مستخدمين معينين فقط على موقعك، مثل `[1, 2, 3]`.
console.log(result);
$('#div').discourse(result, 3, [1, 2, 3]);
});
$.fn.discourse = function (feed, numToShow, whitelist) {
var feedLength = feed.topic_list.topics.length;
// التأكد من وجود عدد كافٍ من المشاركات للعرض.
if (numToShow > feedLength) {
numToShow = feedLength;
}
for (var i = 0; i < numToShow; i++) {
var content = '';
// جميع عناوين URL في نقاط نهاية Discourse هي عناوين نسبية (مثل topic.image_url)،
// نحتاج إلى هذا لكي تشير الروابط المعروضة على موقعك إلى الأماكن الصحيحة.
// يرجى تعديل هذا إلى عنوان URL لمنتدى Discourse الخاص بك.
var discourseURL = 'http://labs.daemon.com.au/';
// متغيرات لبيانات مشاركة Discourse.
var post = feed.topic_list.topics[i],
postAuthor = post.posters[0].user_id,
postDate = new Date(post.created_at),
postLink = discourseURL + 't/' + post.slug + '/' + post.id,
postThumbnail = discourseURL + post.image_url;
// إذا كانت قائمة بيضاء موجودة، تحقق مما إذا كان مؤلف المشاركة مستخدمًا موثوقًا.
if (typeof whitelist !== 'undefined') {
var verifiedUser = false;
for (var n = 0; n < whitelist.length; n++) {
if (postAuthor === whitelist[n]) {
verifiedUser = true;
break;
}
}
// إذا لم يكن مؤلف المشاركة في القائمة البيضاء،
// توقف عن هذه الدورة واستمر في الدورة التالية في الحلقة.
if (!verifiedUser) {
// زيادة عدد المشاركات المراد عرضها إذا أمكن
// لتعويض المشاركة المحذوفة.
if (numToShow < feedLength) {
numToShow++;
}
continue;
}
}
// كتلة الكود التالية اختيارية.
// الغرض منها هو تجاهل مشاركة "حول فئة X"
// حيث قد لا يكون من المرغوب عرضها على موقعك.
if (post.title.substring(0, 10) === "About the " && post.title.substring(post.title.length - 9) === ' category') {
// زيادة عدد المشاركات المراد عرضها إذا أمكن
// لتعويض المشاركة المحذوفة.
if (numToShow < feedLength) {
numToShow++;
}
continue;
}
// إذا لم تكن هناك صورة مصغرة للمشاركة،
// استخدم صورة نائبة افتراضية كصورة مصغرة لموقعك.
// يرجى تعديل هذا لاستخدام صورة نائبة خاصة بموقعك.
if (post.image_url === null) {
postThumbnail = 'http://placehold.it/320x180';
}
// توليد HTML لموقعك.
قد تحتاج هذه часть من الكود إلى تعديل وفقًا لذلك
لتناسب تنسيق (markup) موقعك.
content += '<div class="card" style="max-width: 20rem;">';
content += '<img alt="' + post.fancy_title + '" class="card-img-top" src="' + postThumbnail + '">';
content += '<div class="card-body">';
content += '<h4 class="card-title">' + post.fancy_title + '</h4>';
content += '<p class="card-text"><small>' + postDate.getDate() + '/' + postDate.getMonth() + '/' + postDate.getFullYear() + '</small></p>';
// السطر التالي يفعل أكثر من مجرد عرض مقتطف كما هو،
// حيث يستبدل وسوم `<a>` في المقتطف بوسوم `<em>`
// حتى لا تظهر كروابط على موقعك.
// هذا اختياري، لكنه قد يكون ضروريًا في ظروف معينة.
content += '<p class="card-text">' + post.excerpt.replace(/<a/g, '<em').replace(/<\/a/g, '</em') + '</p>';
content += '<a href="' + postLink + '">اقرأ المزيد</a>';
content += '</div>';
content += '</div>';
$(this).append(content);
}
};
});
}(jQuery));
</script>
</body>
</html>
الشكل النهائي
كود JavaScript عام بدرجة كافية لإعادة استخدامه على مواقع إلكترونية مختلفة. ومع ذلك، قد ترغب في المرور خطوة بخطوة لتخصيصه حسب احتياجاتك. خاصة جزء تنسيق HTML، فمن المرجح جدًا أن يحتاج إلى تخصيص ليتناسب مع تنسيق موقعك.
استمتع!
h/t @sesemaya Embed latest topics from Discourse on your website - development - Daemon Labs


