Je ne m’emballerai pas trop avec ça, mais j’ai utilisé Nokogiri pour autre chose ce week-end. C’est plutôt addictif. J’ai pensé jeter un œil au code d’intégration pendant que Nokogiri était encore frais dans mon esprit.
Mon intérêt réside dans le fait que j’aimerais voir Discourse utilisé plus largement par les sites d’information et de blogging. Si cela devait se produire, je peux imaginer que les nouveaux propriétaires de sites soient frustrés par la fonctionnalité d’intégration actuelle. Voici une idée pour l’améliorer :
Ajoutez deux nouveaux attributs optionnels au modèle EmbeddableHost :
target_selector : le sélecteur CSS externe qui contient le contenu à intégrer.
exclude_selectors : une liste de sélecteurs CSS à exclure du contenu sélectionné par le target_selector.
Un bouton « Configurer » devrait être ajouté à chaque ligne d’Hôte Intégrable sur la page Admin / Intégration. Cliquer sur ce bouton ouvre une page similaire à la page E-mails / Aperçu du résumé.
La page de configuration de l’hôte aurait un formulaire avec des champs pour saisir les paramètres target_selector et exclude_selectors de l’hôte, et un champ d’URL qui permettrait de tester les valeurs fournies sur une page Web spécifique. Le test exécuterait essentiellement TopicEmbed.parse_html avec les valeurs target_selector et exclude_selectors fournies, puis afficherait les résultats.
Les modifications du code parse_html sont faciles à tester. Voici une approche possible. Notez que ce code n’est qu’une preuve de concept :
édité dans topic_embed.rb (discourse/app/models/topic_embed.rb at main · discourse/discourse · GitHub)
###########################################################################
# `target_selector` et `exclude_selectors` seraient idéalement trouvés dans l'enregistrement `EmbeddableHost` du domaine
# ces paramètres particuliers ont été utilisés pour tester 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
# retour à Readability si `target_selector` n'est pas défini pour l'hôte
read_doc = Readability::Document.new(html, opts)
end
###########################################################################
Pour tester sans créer de nouvelle classe, voici une méthode article_content de base ajoutée à la classe TopicEmbed :
def self.article_content(html, target_selector, exclude_selectors = [])
doc = Nokogiri::HTML(html)
# supprimer les commentaires et les balises script
doc.xpath('//comment()').each { |i| i.remove }
doc.css("script, style").each { |i| i.remove }
# obtenir le NodeSet pour le target_selector
# peut-être revenir à Readability ici si l'ensemble retourné est vide
selected_nodes = doc.css(target_selector)
# exclure les nœuds
unless exclude_selectors.empty?
selected_nodes.css(*exclude_selectors).each do |node|
node.remove
end
end
# gérer les tailles d'image, pourrait nécessiter des améliorations
selected_nodes.css('img').each do |img|
img.remove_attribute('width')
img.remove_attribute('height')
end
# juste pour le plaisir, autoriser les iframes si leur source est autorisée
# utiliser `[data-sanitized=\"true\"]` pour empêcher les iframes d'être supprimés lors de l'étape 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
# supprimer les nœuds 'p' et 'div' vides
selected_nodes.css('p', 'div').each do |node|
node.remove if node.content.strip.empty? && !node.at_css('iframe[data-sanitized="true"]')
end
# convertir les nœuds en une chaîne et retourner un objet avec une méthode `content`
content = selected_nodes.to_s
OpenStruct.new(content: content)
end
Je suis à peu près sûr qu’il suffirait d’un peu de bricolage sur plusieurs domaines pour y parvenir. Les résultats que j’obtiens pour BBS sont bons jusqu’à présent.
L’objectif est de proposer quelque chose que les propriétaires de sites peuvent facilement comprendre et configurer eux-mêmes. Avec cette approche, plus le target_selector est précis, plus il sera facile de configurer les exclude_selectors. Par exemple, pour un site WordPress, si .entry-content était sélectionné comme target_selector, aucune configuration supplémentaire ne serait nécessaire. Si les propriétaires de sites souhaitaient obtenir plus que le HTML de base .entry-content, ils pourraient trouver comment le faire sur la page Configurer l’hôte.
Le seul vrai problème que je vois concerne les hôtes avec un HTML très incohérent. Ce cas pourrait être traité en conservant Ruby Readability comme solution de repli.