لن أبالغ في هذا الأمر، لكنني كنت أستخدم Nokogiri لشيء آخر في عطلة نهاية الأسبوع. إنه نوع من الإدمان. اعتقدت أنني سألقي نظرة على كود التضمين بينما لا يزال Nokogiri في ذهني.
اهتمامي بهذا هو أنني أود أن أرى Discourse يُستخدم على نطاق أوسع من قبل مواقع الأخبار والمدونات. إذا حدث ذلك، يمكنني أن أتخيل أصحاب المواقع الجدد يصابون بالإحباط من وظيفة التضمين الحالية. إليك فكرة لتحسينها:
أضف سمتين جديدتين اختياريتين إلى نموذج EmbeddableHost:
target_selector: المحدد الخارجي لـ CSS الذي يحتوي على المحتوى المراد تضمينه
exclude_selectors: قائمة بمحددات CSS التي يجب استبعادها من المحتوى المحدد بواسطة target_selector.
يجب إضافة زر “تكوين” إلى كل صف مضيف مضمن في صفحة المسؤول / التضمين. يؤدي النقر فوق هذا الزر إلى فتح صفحة مشابهة لصفحة ملخص معاينة رسائل البريد الإلكتروني.
ستحتوي صفحة تكوين المضيف على نموذج به حقول لإدخال إعدادات target_selector و exclude_selectors للمضيف، وحقل عنوان URL يسمح باختبار القيم المقدمة مقابل صفحة ويب معينة. سيقوم الاختبار بشكل أساسي بتشغيل TopicEmbed.parse_html باستخدام قيم target_selector و exclude_selectors المقدمة، ثم عرض النتائج.
من السهل اختبار التغييرات في كود parse_html. إليك نهج محتمل. لاحظ أن هذا الكود هو مجرد إثبات للمفهوم:
تم تحريره في topic_embed.rb (discourse/app/models/topic_embed.rb at main · discourse/discourse · GitHub)
###########################################################################
# من الناحية المثالية، سيتم العثور على `target_selector` و `exclude_selectors` من سجل `EmbeddableHost` الخاص بالمجال
# تم استخدام هذه الإعدادات المحددة للاختبار مقابل boingboing.net
target_selector = 'article'
exclude_selectors = ['.article-header, .share-comments-container', '.boing-single-post-rev-content', '.next-post-list-container', '.boing-end-of-article-container-on-single-post-pages']
if defined?(target_selector) && target_selector.present?
read_doc = article_content(html, target_selector, exclude_selectors)
else
# الرجوع إلى Readability إذا لم يتم تعيين `target_selector` للمضيف
read_doc = Readability::Document.new(html, opts)
end
###########################################################################
للاختبار دون إنشاء فئة جديدة، إليك طريقة article_content أساسية تمت إضافتها إلى فئة TopicEmbed:
def self.article_content(html, target_selector, exclude_selectors = [])
doc = Nokogiri::HTML(html)
# إزالة التعليقات وعلامات النص البرمجي
doc.xpath('//comment()').each { |i| i.remove }
doc.css("script, style").each { |i| i.remove }
# الحصول على مجموعة العقد لـ target_selector
# ربما الرجوع إلى Readability هنا إذا كانت المجموعة المرجعة فارغة
selected_nodes = doc.css(target_selector)
# استبعاد العقد
unless exclude_selectors.empty?
selected_nodes.css(*exclude_selectors).each do |node|
node.remove
end
end
# التعامل مع أحجام الصور، قد تحتاج إلى تحسين
selected_nodes.css('img').each do |img|
img.remove_attribute('width')
img.remove_attribute('height')
end
# فقط من أجل المتعة، السماح بإطارات iframe إذا كان مصدرها مسموحًا به
# استخدم `[data-sanitized="true"]` لمنع إزالة إطارات iframe في خطوة remove_empty_nodes
allowed_iframe_sources = SiteSetting.allowed_iframes.split('|')
selected_nodes.css('iframe').each do |iframe|
allowed = allowed_iframe_sources.any? do |allowed_source|
iframe['src'].start_with?(allowed_source)
end
if allowed
iframe['data-sanitized'] = 'true'
iframe['width'] = '690'
iframe['height'] = '388'
else
iframe.remove
end
end
# إزالة عقد 'p' و 'div' الفارغة
selected_nodes.css('p', 'div').each do |node|
node.remove if node.content.strip.empty? && !node.at_css('iframe[data-sanitized="true"]')
end
# تحويل العقد إلى سلسلة وإرجاع كائن يحتوي على طريقة `content`
content = selected_nodes.to_s
OpenStruct.new(content: content)
end
أنا متأكد تمامًا من أن الأمر سيستغرق القليل من التعديل على نطاقات متعددة للحصول عليه بشكل صحيح. النتائج التي كنت أحصل عليها لـ BBS جيدة حتى الآن.
الهدف هو التوصل إلى شيء يمكن لأصحاب المواقع فهمه وتكوينه بسهولة بأنفسهم. مع هذا النهج، كلما كان target_selector أكثر تحديدًا، كان من الأسهل تكوين exclude_selectors. على سبيل المثال، بالنسبة لموقع WordPress، إذا تم تحديد .entry-content كـ target_selector، فلن تكون هناك حاجة إلى مزيد من التكوين. إذا أراد أصحاب المواقع الحصول على أكثر من محتوى HTML الأساسي .entry-content، فيمكنهم معرفة كيفية القيام بذلك في صفحة تكوين المضيف.
القضية الحقيقية الوحيدة التي يمكنني رؤيتها هي للمضيفين الذين لديهم HTML غير متناسق للغاية. يمكن التعامل مع هذه الحالة عن طريق الاحتفاظ بـ Ruby Readability كحل بديل.