diff options
author | Claire <claire.github-309c@sitedethib.com> | 2022-11-09 15:38:46 +0100 |
---|---|---|
committer | Claire <claire.github-309c@sitedethib.com> | 2022-11-14 11:09:11 +0100 |
commit | 0ce2b4d358e791cc1710ecb50764a18458652d77 (patch) | |
tree | a43dcf557c51d6132d7103bb712f0982c9d244da | |
parent | 6f26dcae4d89fa6a303f8fbdd5c4efc5e8da7361 (diff) |
Fix emoji substitution not applying only to text nodes in backend code
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
-rw-r--r-- | app/lib/formatter.rb | 65 |
1 files changed, 31 insertions, 34 deletions
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index 1610f368925..d2caf042abb 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -8,6 +8,8 @@ class Formatter include ActionView::Helpers::TextHelper + DISALLOWED_BOUNDING_REGEX = /[[:alnum:]:]/.freeze + def format(status, **options) if status.reblog? prepend_reblog = status.reblog.account.acct @@ -140,54 +142,49 @@ class Formatter 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 |