Class: DiscourseEmojis::Utils

Inherits:
Object
  • Object
show all
Defined in:
lib/discourse_emojis/utils.rb

Class Method Summary collapse

Class Method Details

.can_be_toned?(emoji) ⇒ Boolean

Returns:

  • (Boolean)


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/discourse_emojis/utils.rb', line 9

def self.can_be_toned?(emoji)
  # these are only supported on a few platforms
  not_widely_supported = %w[👨️‍👦️ 👨️‍👧️ 👩️‍👦️ 👩️‍👧️ 👪️ 🧑️‍🧒️].to_set

  # Draft only. If approved by Unicode in late 2025,
  # this emoji is likely to arrive on most platforms in 2026.
  only_draft = %w[👯️ 👯️‍♂️ 👯️‍♀️ 🤼️ 🤼️‍♂️ 🤼️‍♀️].to_set

  emoji = emoji.gsub(/[#{SKIN_TONE_RANGE}]/, "")

  emoji_base_modifier_regex = /\p{Emoji_Modifier_Base}/
  modifiable_components = emoji.scan(emoji_base_modifier_regex).length

  if modifiable_components > 2 || not_widely_supported.include?(emoji) ||
       only_draft.include?(emoji)
    return false
  end

  emoji.chars.any? { |code_point| code_point.match?(emoji_base_modifier_regex) }
end

.force_emoji_presentation(emoji) ⇒ Object

The various emoji sets we use have different ways of representing skin tones in text most of the times the filenames don’t include the ZWJ sequences for example this method will try to normalize the emoji to a common representation



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/discourse_emojis/utils.rb', line 33

def self.force_emoji_presentation(emoji)
  emoji
    .scan(/\X/) # Splits into grapheme clusters
    .map do |cluster|
      components = cluster.split("\u{200D}") # Handle ZWJ sequences

      components.map! do |part|
        # Keycap (0️⃣, 1️⃣, etc.): Ensure FE0F is placed before U+20E3
        if part.match?(/^[0-9#*]#{KEYCAP_COMBINING}$/) &&
             !part.include?(EMOJI_PRESENTATION_SELECTOR)
          part.insert(1, EMOJI_PRESENTATION_SELECTOR) # Insert FE0F after digit/hash/star
        elsif part.codepoints.size == 1 && part.match?(/\p{Emoji}/) &&
              !part.include?(EMOJI_PRESENTATION_SELECTOR)
          part + EMOJI_PRESENTATION_SELECTOR
        elsif part == "\u{2642}" || part == "\u{2640}" # Ensure gender symbols get FE0F
          part + EMOJI_PRESENTATION_SELECTOR
        else
          part
        end
      end

      components.join("\u{200D}") # Reassemble ZWJ sequences
    end
    .join
end