Non mi lascerò trasportare troppo, ma nel fine settimana stavo usando Nokogiri per qualcos’altro. È piuttosto avvincente. Ho pensato di dare un’occhiata al codice di embedding mentre Nokogiri era ancora fresco nella mia mente.
Il mio interesse in questo è che vorrei vedere Discourse utilizzato più ampiamente dai siti di notizie e di blogging. Se ciò dovesse accadere, posso immaginare che i nuovi proprietari di siti si frustrassero con l’attuale funzionalità di embedding. Ecco un’idea per migliorarla:
Aggiungere due nuovi attributi opzionali al modello EmbeddableHost:
target_selector: il selettore CSS esterno che contiene il contenuto da incorporare
exclude_selectors: un elenco di selettori CSS da escludere dal contenuto selezionato da target_selector.
Un pulsante “Configura” dovrebbe essere aggiunto a ogni riga di Embeddable Host nella pagina Admin / Embedding. Cliccando su quel pulsante si apre una pagina simile alla pagina Email / Riepilogo anteprima.
La pagina Configura Host avrebbe un modulo con campi per inserire le impostazioni target_selector ed exclude_selectors dell’host e un campo URL che consentirebbe di testare i valori forniti su una pagina Web specifica. Il test essenzialmente eseguirebbe TopicEmbed.parse_html con i valori target_selector ed exclude_selectors forniti, quindi visualizzerebbe i risultati.
Le modifiche al codice parse_html sono facili da testare. Ecco un possibile approccio. Nota che questo codice è solo una prova di concetto:
modificato in topic_embed.rb (discourse/app/models/topic_embed.rb at main · discourse/discourse · GitHub)
###########################################################################
# `target_selector` e `exclude_selectors` dovrebbero idealmente essere trovati dal record `EmbeddableHost` del dominio
# queste impostazioni particolari sono state utilizzate per testare contro 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
# fallback a Readability se `target_selector` non è impostato per l'host
read_doc = Readability::Document.new(html, opts)
end
###########################################################################
Per testare senza creare una nuova classe, ecco un metodo article_content di base aggiunto alla classe TopicEmbed:
def self.article_content(html, target_selector, exclude_selectors = [])
doc = Nokogiri::HTML(html)
# rimuove commenti e tag script
doc.xpath('//comment()').each { |i| i.remove }
doc.css("script, style").each { |i| i.remove }
# ottiene il NodeSet per il target_selector
# forse fallback a Readability qui se il set restituito è vuoto
selected_nodes = doc.css(target_selector)
# esclude i nodi
unless exclude_selectors.empty?
selected_nodes.css(*exclude_selectors).each do |node|
node.remove
end
end
# gestisce le dimensioni delle immagini, potrebbe necessitare di miglioramenti
selected_nodes.css('img').each do |img|
img.remove_attribute('width')
img.remove_attribute('height')
end
# solo per divertimento, consente gli iframe se la loro origine è consentita
# usa `[data-sanitized="true"]` per evitare che gli iframe vengano rimossi nel passaggio 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
# rimuove nodi 'p' e 'div' vuoti
selected_nodes.css('p', 'div').each do |node|
node.remove if node.content.strip.empty? && !node.at_css('iframe[data-sanitized="true"]')
end
# converte i nodi in una stringa e restituisce un oggetto con un metodo `content`
content = selected_nodes.to_s
OpenStruct.new(content: content)
end
Sono abbastanza sicuro che basterebbe un po’ di aggiustamenti su più domini per ottenere il risultato giusto. I risultati che ho ottenuto finora per BBS sono buoni.
L’obiettivo è creare qualcosa che i proprietari di siti possano facilmente capire e configurare da soli. Con questo approccio, più specifico è il target_selector, più facile sarà configurare gli exclude_selectors. Ad esempio, per un sito WordPress, se .entry-content fosse selezionato come target_selector, non sarebbe necessaria alcuna configurazione aggiuntiva. Se i proprietari di siti volessero ottenere più dell’HTML di base .entry-content, potrebbero capire come farlo nella pagina Configura Host.
L’unico vero problema che vedo è per gli host con HTML molto incoerente. Quel caso potrebbe essere gestito mantenendo Ruby Readability come fallback.