require 'cgi' require 'gitlab_emoji' require 'html/pipeline/filter' module HTML class Pipeline class GitLab # 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 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 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) return text unless text.include?(':') 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 private def emoji_url(name) File.join(asset_root, 'emoji', emoji_filename(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 def self.emoji_names Emoji.names end def emoji_filename(name) "#{::CGI.escape(name)}.png" end end end end end