cactus rack-emoji.rb

# Original Work Copyright (c) 2014 SATO Naoya
# Modified work Copyright (c) 2016 Zachary Capalbo
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

require 'gemojione'

module Rack
  class Emoji

    HTML_REGEXP = /(.*<body[^>]*>)(.*)(<\/body>.*)/m
    def initialize(app, options = {})
      @app = app
      @dir = options.fetch(:dir, "images/emoji")
      @height = options.fetch(:height, 20)
      @width = options.fetch(:width, 20)
      @style = options.fetch(:style, "vertical-align:middle;")
      @@gemoji ||= Gemojione::Index.new
      @@fa_awesome ||= ::File.read("bower_components/components-font-awesome/scss/_icons.scss").each_line.collect{|l| l.scan(/\{\$fa-css-prefix\}-([a-z\-]+):/)[0]}.reject{|n| n.nil?}.flatten
      @@zm ||= ::File.read("source/stylesheets/zachmoji.css.styl").each_line.collect{|l| l.scan(/zm-([a-z\-]+):/)[0]}.reject(&:nil?).flatten
    end

    def call(env)
      status, headers, response = @app.call(env)

      if headers["Content-Type"] && headers["Content-Type"].include?("text/html")
        new_response = emojify(response)
        return [status, headers, response] if new_response.nil?
        headers['Content-Type'] = "text/html; charset=utf-8"
        length = new_response.respond_to?(:bytesize) ? new_response.bytesize.to_s : new_response.size.to_s
        headers['Content-Length'] = length
        [status, headers, [new_response]]
      else
        [status, headers, response]
      end
    end

    def emojify(response)
      response_str = ""
      response.each { |s| response_str << s }
      _, header, body, footer = response_str.match(HTML_REGEXP).to_a

      return nil if body.nil?

      body = body.gsub(/:([a-z0-9\+\-_]+):/) do |match|
        if @@zm.include?($1)
          %Q{<i class="fa zachmoji zm-#{$1}"></i>}
        elsif @@fa_awesome.include?($1)
          %Q{<i class="fa fa-#{$1}"></i>}
        elsif g = @@gemoji.find_by_name($1)
          %Q{<img class="emoji" alt="#{$1}" src="https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/png/#{g['unicode'].downcase}.png" style="#{@style}"/>}
        else
          match
        end
      end

      header + body + footer
    end

  end
end