FIX: Allow svg in oneboxer in certain cases (#19253)

When doing local oneboxes we sometimes want to allow
SVGs in the final preview HTML. The main case currently
is for the new cooked hashtags, which include an SVG
icon.

SVGs will be included in local oneboxes via `ExcerptParser` _only_
if they have the d-icon class, and if the caller for `post.excerpt`
specifies the `keep_svg: true` option.
This commit is contained in:
Martin Brennan 2022-11-30 12:42:15 +10:00 committed by GitHub
parent e669cf3648
commit 9d50790530
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 2 deletions

View File

@ -19,6 +19,7 @@ class ExcerptParser < Nokogiri::XML::SAX::Document
@keep_onebox_source = options[:keep_onebox_source] == true
@keep_onebox_body = options[:keep_onebox_body] == true
@keep_quotes = options[:keep_quotes] == true
@keep_svg = options[:keep_svg] == true
@remap_emoji = options[:remap_emoji] == true
@start_excerpt = false
@in_details_depth = 0
@ -133,6 +134,17 @@ class ExcerptParser < Nokogiri::XML::SAX::Document
@in_summary = true
end
when "svg"
attributes = Hash[*attributes.flatten]
if attributes["class"].include?("d-icon") && @keep_svg
include_tag(name, attributes)
@in_svg = true
end
when "use"
if @in_svg && @keep_svg
include_tag(name, attributes)
end
end
end
@ -178,6 +190,11 @@ class ExcerptParser < Nokogiri::XML::SAX::Document
@in_summary = false if @in_details_depth == 1
when "div", "span"
throw :done if @start_excerpt
when "svg"
characters("</svg>", truncate: false, count_it: false, encode: false)
@in_svg = false
when "use"
characters("</use>", truncate: false, count_it: false, encode: false)
end
end

View File

@ -322,7 +322,7 @@ module Oneboxer
return if !post || post.hidden || !allowed_post_types.include?(post.post_type)
if post_number > 1 && opts[:topic_id] == topic.id
excerpt = post.excerpt(SiteSetting.post_onebox_maxlength)
excerpt = post.excerpt(SiteSetting.post_onebox_maxlength, keep_svg: true)
excerpt.gsub!(/[\r\n]+/, " ")
excerpt.gsub!("[/quote]", "[quote]") # don't break my quote
@ -337,7 +337,7 @@ module Oneboxer
original_url: url,
title: PrettyText.unescape_emoji(CGI::escapeHTML(topic.title)),
category_html: CategoryBadge.html_for(topic.category),
quote: PrettyText.unescape_emoji(post.excerpt(SiteSetting.post_onebox_maxlength)),
quote: PrettyText.unescape_emoji(post.excerpt(SiteSetting.post_onebox_maxlength, keep_svg: true)),
}
template = template("discourse_topic_onebox")

View File

@ -34,6 +34,18 @@ RSpec.describe ExcerptParser do
expect(ExcerptParser.get_excerpt(html, 2, {})).to match_html('<details class="disabled"><summary>fo&hellip;</summary></details>')
end
it "allows <svg> with <use> inside for icons when keep_svg is true" do
html = '<svg class="fa d-icon d-icon-folder svg-icon svg-node"><use href="#folder"></use></svg>'
expect(ExcerptParser.get_excerpt(html, 100, { keep_svg: true })).to match_html('<svg class="fa d-icon d-icon-folder svg-icon svg-node"><use href="#folder"></use></svg>')
expect(ExcerptParser.get_excerpt(html, 100, {})).to match_html('')
html = '<svg class="blah"><use href="#folder"></use></svg>'
expect(ExcerptParser.get_excerpt(html, 100, { keep_svg: true })).to match_html('')
html = '<use href="#user"></use><svg class="fa d-icon d-icon-folder svg-icon svg-node"><use href="#folder"></use></svg>'
expect(ExcerptParser.get_excerpt(html, 100, { keep_svg: true })).to match_html('<svg class="fa d-icon d-icon-folder svg-icon svg-node"><use href="#folder"></use></svg>')
end
describe "keep_onebox_body parameter" do
it "keeps the body content for external oneboxes" do
html = <<~HTML.strip

View File

@ -146,6 +146,16 @@ RSpec.describe Oneboxer do
expect(preview("/u/#{user.username}")).to include("Thunderland")
end
it "includes hashtag HTML and icons" do
SiteSetting.enable_experimental_hashtag_autocomplete = true
category = Fabricate(:category, slug: "random")
Fabricate(:tag, name: "bug")
public_post = Fabricate(:post, raw: "This post has some hashtags, #random and #bug")
expect(preview(public_post.url).chomp).to include(<<~HTML.chomp)
<a class="hashtag-cooked" href="#{category.url}" data-type="category" data-slug="random"><svg class="fa d-icon d-icon-folder svg-icon svg-node"><use href="#folder"></use></svg>#{category.name}</a> and <a class="hashtag-cooked" href="/tag/bug" data-type="tag" data-slug="bug"><svg class="fa d-icon d-icon-tag svg-icon svg-node"><use href="#tag"></use></svg>bug</a>
HTML
end
end
describe ".onebox_raw" do