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:
parent
e669cf3648
commit
9d50790530
|
@ -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
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -34,6 +34,18 @@ RSpec.describe ExcerptParser do
|
|||
expect(ExcerptParser.get_excerpt(html, 2, {})).to match_html('<details class="disabled"><summary>fo…</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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue