require 'cgi' require 'gitlab_emoji' require 'html/pipeline/filter' require 'action_controller' module HTML class Pipeline class Gitlab # HTML filter that replaces :emoji: with images. class GitlabEmojiFilter < Filter def call search_text_nodes(doc).each do |node| content = node.to_html next if !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 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) return text unless text.include?(':') text.gsub(emoji_pattern) do |match| name = $1 ":#{name}:" end end private def emoji_url(name) emoji_path = "emoji/#{emoji_filename(name)}" if context[:asset_host] # Asset host is specified. url_to_image(emoji_path) elsif context[:asset_root] # Gitlab url is specified File.join(context[:asset_root], url_to_image(emoji_path)) else # All other cases url_to_image(emoji_path) end end def url_to_image(image) ActionController::Base.helpers.url_to_image(image) 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 def self.emoji_names Emoji.names end def emoji_filename(name) # CGI.escape makes + into %20, skip that in this case if name == "+1" "+1.png" else "#{::CGI.escape(name)}.png" end end end end end end