require "cgi" begin require "gemoji" rescue LoadError => _ abort "Missing dependency 'gemoji' for EmojiFilter. See README.md for details." end module HTML class Pipeline # HTML filter that replaces :emoji: with images. # # Context: # :asset_root (required) - base url to link to emoji sprite # :asset_path (optional) - url path to link to emoji sprite. :file_name can be used as a placeholder for the sprite file name. If no asset_path is set "emoji/:file_name" is used. class EmojiFilter < Filter def call search_text_nodes(doc).each do |node| content = node.to_html next unless content.include?(':') next if has_ancestor?(node, %w(pre code)) html = emoji_image_filter(content) next if html == content node.replace(html) end doc end # Implementation of validate hook. # Errors should raise exceptions or use an existing validator. def validate needs :asset_root end # Replace :emoji: with corresponding images. # # text - String text to replace :emoji: in. # # Returns a String with :emoji: replaced with images. def emoji_image_filter(text) text.gsub(emoji_pattern) do |match| name = $1 ":#{name}:" end end # The base url to link emoji sprites # # Raises ArgumentError if context option has not been provided. # Returns the context's asset_root. def asset_root context[:asset_root] end # The url path to link emoji sprites # # :file_name can be used in the asset_path as a placeholder for the sprite file name. If no asset_path is set in the context "emoji/:file_name" is used. # Returns the context's asset_path or the default path if no context asset_path is given. def asset_path(name) if context[:asset_path] context[:asset_path].gsub(":file_name", emoji_filename(name)) else File.join("emoji", emoji_filename(name)) end end private def emoji_url(name) File.join(asset_root, asset_path(name)) end # Build a regexp that matches all valid :emoji: names. def self.emoji_pattern @emoji_pattern ||= /:(#{emoji_names.map { |name| Regexp.escape(name) }.join('|')}):/ end def emoji_pattern self.class.emoji_pattern end # Detect gemoji v2 which has a new API # https://github.com/jch/html-pipeline/pull/129 if Emoji.respond_to?(:all) def self.emoji_names Emoji.all.map(&:aliases).flatten.sort end def emoji_filename(name) Emoji.find_by_alias(name).image_filename end else def self.emoji_names Emoji.names end def emoji_filename(name) "#{::CGI.escape(name)}.png" end end end end end