Ich werde mich damit nicht zu sehr beschäftigen, aber ich habe am Wochenende Nokogiri für etwas anderes verwendet. Es macht irgendwie süchtig. Ich dachte, ich schaue mir den Einbettungscode an, während Nokogiri mir noch frisch im Gedächtnis ist.
Mein Interesse daran ist, dass ich gerne sehen würde, wie Discourse von Nachrichten- und Blogging-Websites häufiger genutzt wird. Wenn das passieren würde, kann ich mir vorstellen, dass neue Websitebesitzer von der aktuellen Einbettungsfunktionalität frustriert werden. Hier ist eine Idee zur Verbesserung:
Fügen Sie dem EmbeddableHost-Modell zwei neue optionale Attribute hinzu:
target_selector: Der äußere CSS-Selektor, der den einzubettenden Inhalt enthält
exclude_selectors: Eine Liste von CSS-Selektoren, die aus dem durch target_selector ausgewählten Inhalt ausgeschlossen werden sollen.
Ein “Konfigurieren”-Button sollte zu jeder Zeile von Embeddable Host auf der Admin / Embedding-Seite hinzugefügt werden. Das Klicken auf diesen Button öffnet eine Seite, die der Seite E-Mails / Vorschau Zusammenfassung ähnelt.
Die Seite Host konfigurieren würde ein Formular mit Feldern für die Eingabe der target_selector- und exclude_selectors-Einstellungen des Hosts sowie ein URL-Feld enthalten, das es ermöglicht, die angegebenen Werte gegen eine bestimmte Webseite zu testen. Der Test würde im Wesentlichen nur TopicEmbed.parse_html mit den angegebenen target_selector- und exclude_selectors-Werten ausführen und dann die Ergebnisse anzeigen.
Änderungen am parse_html-Code sind leicht zu testen. Hier ist ein möglicher Ansatz. Beachten Sie, dass dieser Code nur ein Proof of Concept ist:
bearbeitet in topic_embed.rb (discourse/app/models/topic_embed.rb at main · discourse/discourse · GitHub)
###########################################################################
# `target_selector` und `exclude_selectors` würden idealerweise aus dem `EmbeddableHost`-Datensatz der Domain gefunden werden
# diese speziellen Einstellungen wurden zum Testen gegen boingboing.net verwendet
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 auf Readability, wenn `target_selector` für den Host nicht gesetzt ist
read_doc = Readability::Document.new(html, opts)
end
###########################################################################
Um ohne Erstellung einer neuen Klasse zu testen, hier eine einfache article_content-Methode, die der TopicEmbed-Klasse hinzugefügt wurde:
def self.article_content(html, target_selector, exclude_selectors = [])
doc = Nokogiri::HTML(html)
# Kommentare und Skript-Tags entfernen
doc.xpath('//comment()').each { |i| i.remove }
doc.css("script, style").each { |i| i.remove }
# NodeSet für den target_selector abrufen
# vielleicht hier auf Readability zurückgreifen, wenn das zurückgegebene Set leer ist
selected_nodes = doc.css(target_selector)
# Knoten ausschließen
unless exclude_selectors.empty?
selected_nodes.css(*exclude_selectors).each do |node|
node.remove
end
end
# Bildgrößen behandeln, muss möglicherweise verbessert werden
selected_nodes.css('img').each do |img|
img.remove_attribute('width')
img.remove_attribute('height')
end
# nur zum Spaß, iframes zulassen, wenn ihre Quelle erlaubt ist
# verwende `[data-sanitized="true"]`, um zu verhindern, dass iframes im remove_empty_nodes-Schritt entfernt werden
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
# leere 'p'- und 'div'-Knoten entfernen
selected_nodes.css('p', 'div').each do |node|
node.remove if node.content.strip.empty? && !node.at_css('iframe[data-sanitized="true"]')
end
# die Knoten in eine Zeichenkette umwandeln und ein Objekt mit einer `content`-Methode zurückgeben
content = selected_nodes.to_s
OpenStruct.new(content: content)
end
Ich bin ziemlich sicher, dass es nur ein wenig Bastelei an mehreren Domains erfordern würde, um es richtig zu machen. Die Ergebnisse, die ich bisher für BBS erzielt habe, sind gut.
Das Ziel ist es, etwas zu entwickeln, das Websitebesitzer leicht verstehen und selbst konfigurieren können. Mit diesem Ansatz gilt: Je spezifischer der target_selector ist, desto einfacher ist die Konfiguration der exclude_selectors. Zum Beispiel wäre für eine WordPress-Website, wenn .entry-content als target_selector ausgewählt würde, keine weitere Konfiguration erforderlich. Wenn Websitebesitzer mehr als nur das grundlegende .entry-content-HTML erhalten möchten, könnten sie auf der Seite Host konfigurieren herausfinden, wie das geht.
Das einzige wirkliche Problem, das ich sehe, sind Hosts mit sehr inkonsistentem HTML. Dieser Fall könnte durch die Beibehaltung von Ruby Readability als Fallback behandelt werden.