mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 02:50:00 +08:00
DEV: Support more formats of inline images.
This commit is contained in:
parent
21876d46d6
commit
95db609586
|
@ -4,7 +4,7 @@ require_dependency "pretty_text"
|
|||
|
||||
class InlineUploads
|
||||
PLACEHOLDER = "__replace__"
|
||||
private_constant :PLACEHOLDER
|
||||
PATH_PLACEHOLDER = "__replace_path__"
|
||||
|
||||
UPLOAD_REGEXP_PATTERN = "/original/(\\dX/(?:[a-f0-9]/)*[a-f0-9]{40}[a-z0-9.]*)"
|
||||
private_constant :UPLOAD_REGEXP_PATTERN
|
||||
|
@ -17,8 +17,7 @@ class InlineUploads
|
|||
cooked_fragment.traverse do |node|
|
||||
if node.name == "img"
|
||||
# Do nothing
|
||||
elsif !(node.children.count == 1 && (node.children[0].name != "img" && node.children[0].children.blank?)) ||
|
||||
!node.ancestors.all? { |parent| !parent.attributes["class"]&.value&.include?("quote") }
|
||||
elsif !(node.children.count == 1 && (node.children[0].name != "img" && node.children[0].children.blank?))
|
||||
next
|
||||
end
|
||||
|
||||
|
@ -34,71 +33,24 @@ class InlineUploads
|
|||
|
||||
raw_matches = []
|
||||
|
||||
markdown.scan(/(\[img\]\s?(.+)\s?\[\/img\])/) do |match|
|
||||
raw_matches << [match[0], match[1], +"![](#{PLACEHOLDER})", $~.offset(0)[0]]
|
||||
match_bbcode_img(markdown) do |match, src, replacement, index|
|
||||
raw_matches << [match, src, replacement, index]
|
||||
end
|
||||
|
||||
markdown.scan(/(!?\[([^\[\]]+)\]\(([a-zA-z0-9\.\/:-]+)\))/) do |match|
|
||||
if matched_uploads(match[2]).present?
|
||||
raw_matches << [
|
||||
match[0],
|
||||
match[2],
|
||||
+"#{match[0].start_with?("!") ? "!" : ""}[#{match[1]}](#{PLACEHOLDER})",
|
||||
$~.offset(0)[0]
|
||||
]
|
||||
end
|
||||
match_md_inline_img(markdown) do |match, src, replacement, index|
|
||||
raw_matches << [match, src, replacement, index]
|
||||
end
|
||||
|
||||
markdown.scan(/(<(?!img)[^<>]+\/?>)?(\n*)(([ ]*)<img ([^<>]+)>([ ]*))(\n*)/) do |match|
|
||||
node = Nokogiri::HTML::fragment(match[2].strip).children[0]
|
||||
src = node.attributes["src"].value
|
||||
|
||||
if matched_uploads(src).present?
|
||||
text = node.attributes["alt"]&.value
|
||||
width = node.attributes["width"]&.value
|
||||
height = node.attributes["height"]&.value
|
||||
text = "#{text}|#{width}x#{height}" if width && height
|
||||
after_html_tag = match[0].present?
|
||||
|
||||
spaces_before =
|
||||
if after_html_tag && !match[0].end_with?("/>")
|
||||
(match[3].present? ? match[3] : " ")
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
replacement = +"#{spaces_before}![#{text}](#{PLACEHOLDER})"
|
||||
|
||||
if after_html_tag && (num_newlines = match[1].length) <= 1
|
||||
replacement.prepend("\n" * (num_newlines == 0 ? 2 : 1))
|
||||
end
|
||||
|
||||
if after_html_tag && !match[0].end_with?("/>") && (num_newlines = match[6].length) <= 1
|
||||
replacement += ("\n" * (num_newlines == 0 ? 2 : 1))
|
||||
end
|
||||
|
||||
match[2].strip! if !after_html_tag
|
||||
|
||||
raw_matches << [
|
||||
match[2],
|
||||
src,
|
||||
replacement,
|
||||
$~.offset(0)[0]
|
||||
]
|
||||
end
|
||||
match_md_reference(markdown) do |match, src, replacement, index|
|
||||
raw_matches << [match, src, replacement, index]
|
||||
end
|
||||
|
||||
markdown.scan(/((<a[^<]+>)([^<\a>]*?)<\/a>)/) do |match|
|
||||
node = Nokogiri::HTML::fragment(match[0]).children[0]
|
||||
href = node.attributes["href"]&.value
|
||||
match_img(markdown) do |match, src, replacement, index|
|
||||
raw_matches << [match, src, replacement, index]
|
||||
end
|
||||
|
||||
if href && matched_uploads(href).present?
|
||||
has_attachment = node.attributes["class"]&.value
|
||||
index = $~.offset(0)[0]
|
||||
text = match[2].strip.gsub("\n", "").gsub(/ +/, " ")
|
||||
text = "#{text}|attachment" if has_attachment
|
||||
raw_matches << [match[0], href, +"[#{text}](#{PLACEHOLDER})", index]
|
||||
end
|
||||
match_anchor(markdown) do |match, href, replacement, index|
|
||||
raw_matches << [match, href, replacement, index]
|
||||
end
|
||||
|
||||
db = RailsMultisite::ConnectionManagement.current_db
|
||||
|
@ -140,8 +92,9 @@ class InlineUploads
|
|||
upload = Upload.get_from_url(link)
|
||||
|
||||
if upload
|
||||
replacement = replace_with.sub!(PLACEHOLDER, upload.short_url)
|
||||
markdown.sub!(match, replacement)
|
||||
replace_with.sub!(PLACEHOLDER, upload.short_url)
|
||||
replace_with.sub!(PATH_PLACEHOLDER, upload.short_path)
|
||||
markdown.sub!(match, replace_with)
|
||||
else
|
||||
on_missing.call(link) if on_missing
|
||||
end
|
||||
|
@ -151,6 +104,91 @@ class InlineUploads
|
|||
markdown
|
||||
end
|
||||
|
||||
def self.match_md_inline_img(markdown, external_src: false)
|
||||
markdown.scan(/(!?\[([^\[\]]*)\]\(([a-zA-z0-9\.\/:-]+)([ ]*['"]{1}[^\)]*['"]{1}[ ]*)?\))/) do |match|
|
||||
if (matched_uploads(match[2]).present? || external_src) && block_given?
|
||||
yield(
|
||||
match[0],
|
||||
match[2],
|
||||
+"#{match[0].start_with?("!") ? "!" : ""}[#{match[1]}](#{PLACEHOLDER}#{match[3]})",
|
||||
$~.offset(0)[0]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.match_bbcode_img(markdown)
|
||||
markdown.scan(/(\[img\]\s?(.+)\s?\[\/img\])/) do |match|
|
||||
yield(match[0], match[1], +"![](#{PLACEHOLDER})", $~.offset(0)[0]) if block_given?
|
||||
end
|
||||
end
|
||||
|
||||
def self.match_md_reference(markdown)
|
||||
markdown.scan(/(\[([^\]]+)\]:([ ]+)(\S+))/) do |match|
|
||||
if match[3] && matched_uploads(match[3]) && block_given?
|
||||
yield(
|
||||
match[0],
|
||||
match[3],
|
||||
+"[#{match[1]}]:#{match[2]}#{Discourse.base_url}#{PATH_PLACEHOLDER}",
|
||||
$~.offset(0)[0]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.match_anchor(markdown, external_href: false)
|
||||
markdown.scan(/((<a[^<]+>)([^<\a>]*?)<\/a>)/) do |match|
|
||||
node = Nokogiri::HTML::fragment(match[0]).children[0]
|
||||
href = node.attributes["href"]&.value
|
||||
|
||||
if href && (matched_uploads(href).present? || external_href)
|
||||
has_attachment = node.attributes["class"]&.value
|
||||
index = $~.offset(0)[0]
|
||||
text = match[2].strip.gsub("\n", "").gsub(/ +/, " ")
|
||||
text = "#{text}|attachment" if has_attachment
|
||||
|
||||
yield(match[0], href, +"[#{text}](#{PLACEHOLDER})", index) if block_given?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.match_img(markdown, external_src: false)
|
||||
markdown.scan(/(<(?!img)[^<>]+\/?>)?(\n*)(([ ]*)<img ([^<>]+)>([ ]*))(\n*)/) do |match|
|
||||
node = Nokogiri::HTML::fragment(match[2].strip).children[0]
|
||||
src = node.attributes["src"].value
|
||||
|
||||
if matched_uploads(src).present? || external_src
|
||||
text = node.attributes["alt"]&.value
|
||||
width = node.attributes["width"]&.value
|
||||
height = node.attributes["height"]&.value
|
||||
title = node.attributes["title"]&.value
|
||||
text = "#{text}|#{width}x#{height}" if width && height
|
||||
after_html_tag = match[0].present?
|
||||
|
||||
spaces_before =
|
||||
if after_html_tag && !match[0].end_with?("/>")
|
||||
(match[3].present? ? match[3] : " ")
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
replacement = +"#{spaces_before}![#{text}](#{PLACEHOLDER}#{title.present? ? " \"#{title}\"" : ""})"
|
||||
|
||||
if after_html_tag && (num_newlines = match[1].length) <= 1
|
||||
replacement.prepend("\n" * (num_newlines == 0 ? 2 : 1))
|
||||
end
|
||||
|
||||
if after_html_tag && !match[0].end_with?("/>") && (num_newlines = match[6].length) <= 1
|
||||
replacement += ("\n" * (num_newlines == 0 ? 2 : 1))
|
||||
end
|
||||
|
||||
match[2].strip! if !after_html_tag
|
||||
|
||||
yield(match[2], src, replacement, $~.offset(0)[0]) if block_given?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.matched_uploads(node)
|
||||
matches = []
|
||||
|
||||
|
|
|
@ -64,10 +64,46 @@ RSpec.describe InlineUploads do
|
|||
some quote
|
||||
|
||||
#{Discourse.base_url}#{upload3.url}
|
||||
|
||||
![](#{upload.url})
|
||||
[/quote]
|
||||
MD
|
||||
|
||||
expect(InlineUploads.process(md)).to eq(md)
|
||||
expect(InlineUploads.process(md)).to eq(<<~MD)
|
||||
[quote="#{user.username}, post:#{post.post_number}, topic:#{post.topic.id}"]
|
||||
some quote
|
||||
|
||||
![](#{upload3.short_url})
|
||||
|
||||
![](#{upload.short_url})
|
||||
[/quote]
|
||||
MD
|
||||
end
|
||||
|
||||
it "should correct markdown linked images" do
|
||||
md = <<~MD
|
||||
[![](#{upload.url})](https://somelink.com)
|
||||
|
||||
[![some test](#{upload2.url})](https://somelink.com)
|
||||
MD
|
||||
|
||||
expect(InlineUploads.process(md)).to eq(<<~MD)
|
||||
[![](#{upload.short_url})](https://somelink.com)
|
||||
|
||||
[![some test](#{upload2.short_url})](https://somelink.com)
|
||||
MD
|
||||
end
|
||||
|
||||
it "should correct markdown images with title" do
|
||||
md = <<~MD
|
||||
![](#{upload.url} "some alt")
|
||||
![testing](#{upload2.url} 'some alt' )
|
||||
MD
|
||||
|
||||
expect(InlineUploads.process(md)).to eq(<<~MD)
|
||||
![](#{upload.short_url} "some alt")
|
||||
![testing](#{upload2.short_url} 'some alt' )
|
||||
MD
|
||||
end
|
||||
|
||||
it "should correct bbcode img URLs to the short version" do
|
||||
|
@ -86,6 +122,20 @@ RSpec.describe InlineUploads do
|
|||
MD
|
||||
end
|
||||
|
||||
it "should correct markdown references" do
|
||||
md = <<~MD
|
||||
This is a [some reference] somethign
|
||||
|
||||
[some reference]: #{Discourse.base_url}#{upload.url}
|
||||
MD
|
||||
|
||||
expect(InlineUploads.process(md)).to eq(<<~MD)
|
||||
This is a [some reference] somethign
|
||||
|
||||
[some reference]: #{Discourse.base_url}#{upload.short_path}
|
||||
MD
|
||||
end
|
||||
|
||||
it "should correct raw image URLs to the short version" do
|
||||
md = <<~MD
|
||||
#{Discourse.base_url}#{upload3.url} #{Discourse.base_url}#{upload3.url}
|
||||
|
@ -105,7 +155,7 @@ RSpec.describe InlineUploads do
|
|||
![image](#{upload2.url})
|
||||
![image|100x100](#{upload3.url})
|
||||
|
||||
<img src="#{Discourse.base_url}#{upload.url}" alt="some image" />
|
||||
<img src="#{Discourse.base_url}#{upload.url}" alt="some image" title="some title" />
|
||||
<img src="#{Discourse.base_url}#{upload2.url}" alt="some image"><img src="#{Discourse.base_url}#{upload3.url}" alt="some image">
|
||||
|
||||
#{Discourse.base_url}#{upload3.url} #{Discourse.base_url}#{upload3.url}
|
||||
|
@ -121,7 +171,7 @@ RSpec.describe InlineUploads do
|
|||
![image](#{upload2.short_url})
|
||||
![image|100x100](#{upload3.short_url})
|
||||
|
||||
![some image](#{upload.short_url})
|
||||
![some image](#{upload.short_url} "some title")
|
||||
![some image](#{upload2.short_url})![some image](#{upload3.short_url})
|
||||
|
||||
![](#{upload3.short_url}) ![](#{upload3.short_url})
|
||||
|
@ -392,6 +442,20 @@ RSpec.describe InlineUploads do
|
|||
MD
|
||||
end
|
||||
|
||||
it "should correct markdown references" do
|
||||
md = <<~MD
|
||||
This is a [some reference] somethign
|
||||
|
||||
[some reference]: https:#{upload.url}
|
||||
MD
|
||||
|
||||
expect(InlineUploads.process(md)).to eq(<<~MD)
|
||||
This is a [some reference] somethign
|
||||
|
||||
[some reference]: #{Discourse.base_url}#{upload.short_path}
|
||||
MD
|
||||
end
|
||||
|
||||
it "should correct image URLs in multisite" do
|
||||
begin
|
||||
Rails.configuration.multisite = true
|
||||
|
|
Loading…
Reference in New Issue
Block a user