Skip to content

Commit

Permalink
Fix emoji substitution not applying only to text nodes in backend code
Browse files Browse the repository at this point in the history
Signed-off-by: Claire <[email protected]>
  • Loading branch information
ClearlyClaire authored and atsu1125 committed Nov 14, 2022
1 parent 491ac8b commit e19f1d9
Showing 1 changed file with 31 additions and 34 deletions.
65 changes: 31 additions & 34 deletions app/lib/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class Formatter

include ActionView::Helpers::TextHelper

DISALLOWED_BOUNDING_REGEX = /[[:alnum:]:]/.freeze

def format(status, **options)
if status.respond_to?(:reblog?) && status.reblog?
prepend_reblog = status.reblog.account.acct
Expand Down Expand Up @@ -208,54 +210,49 @@ def encode_custom_emojis(html, emojis, animate = false)

emoji_map = emojis.each_with_object({}) { |e, h| h[e.shortcode] = [full_asset_url(e.image.url), full_asset_url(e.image.url(:static))] }

i = -1
tag_open_index = nil
inside_shortname = false
shortname_start_index = -1
invisible_depth = 0
tree = Nokogiri::HTML.fragment(html)
tree.xpath('./text()|.//text()[not(ancestor[@class="invisible"])]').to_a.each do |node|
i = -1
inside_shortname = false
shortname_start_index = -1
last_index = 0
text = node.content
result = Nokogiri::XML::NodeSet.new(tree.document)

while i + 1 < text.size
i += 1

while i + 1 < html.size
i += 1
if inside_shortname && text[i] == ':'
inside_shortname = false
shortcode = text[shortname_start_index + 1..i - 1]
char_after = text[i + 1]

if invisible_depth.zero? && inside_shortname && html[i] == ':'
shortcode = html[shortname_start_index + 1..i - 1]
emoji = emoji_map[shortcode]
next unless (char_after.nil? || !DISALLOWED_BOUNDING_REGEX.match?(char_after)) && (emoji = emoji_map[shortcode])

if emoji
original_url, static_url = emoji
replacement = begin

result << Nokogiri::XML::Text.new(text[last_index..shortname_start_index - 1], tree.document) if shortname_start_index.positive?

result << Nokogiri::HTML.fragment(
if animate
image_tag(original_url, draggable: false, class: 'emojione', alt: ":#{shortcode}:", title: ":#{shortcode}:")
else
image_tag(original_url, draggable: false, class: 'emojione custom-emoji', alt: ":#{shortcode}:", title: ":#{shortcode}:", data: { original: original_url, static: static_url })
end
end
before_html = shortname_start_index.positive? ? html[0..shortname_start_index - 1] : ''
html = before_html + replacement + html[i + 1..-1]
i += replacement.size - (shortcode.size + 2) - 1
else
i -= 1
end
)

inside_shortname = false
elsif tag_open_index && html[i] == '>'
tag = html[tag_open_index..i]
tag_open_index = nil
if invisible_depth.positive?
invisible_depth += count_tag_nesting(tag)
elsif tag == '<span class="invisible">'
invisible_depth = 1
last_index = i + 1
elsif text[i] == ':' && (i.zero? || !DISALLOWED_BOUNDING_REGEX.match?(text[i - 1]))
inside_shortname = true
shortname_start_index = i
end
elsif html[i] == '<'
tag_open_index = i
inside_shortname = false
elsif !tag_open_index && html[i] == ':'
inside_shortname = true
shortname_start_index = i
end

result << Nokogiri::XML::Text.new(text[last_index..-1], tree.document)
node.replace(result)
end

html
tree.to_html
end
# rubocop:enable Metrics/BlockNesting

Expand Down

0 comments on commit e19f1d9

Please sign in to comment.