Skip to content

Commit

Permalink
Better CSS extraction
Browse files Browse the repository at this point in the history
- Move all methods in the subclassed Premailer to a separate module responsible
for loading CSS files.
- No longer force a specific adapter.
  • Loading branch information
fphilipe committed Sep 28, 2011
1 parent cd16520 commit f937173
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 57 deletions.
2 changes: 1 addition & 1 deletion lib/premailer-rails3.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require 'premailer'
require 'hpricot'
require 'premailer-rails3/css_helper'
require 'premailer-rails3/premailer'
require 'premailer-rails3/hook'

Expand Down
52 changes: 52 additions & 0 deletions lib/premailer-rails3/css_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
module PremailerRails
module CSSHelper
extend self

@@css_cache = {}

def css_for_doc(doc)
css = doc.search('link[@type="text/css"]').map { |link|
url = link.attributes['href']
load_css_at_path(url) unless url.blank?
}.reject(&:blank?).join("\n")
css = load_css_at_path(:default) if css.blank?
css
end

private

def load_css_at_path(path)
if path.is_a? String
# Remove everything after ? including ?
path = path[0..(path.index('?') - 1)] if path.include? '?'
# Remove the host
path = path.gsub(/^https?\:\/\/[^\/]*/, '') if path.index('http') == 0
end

# Don't cache in development.
if Rails.env.development? or not @@css_cache.include? path
@@css_cache[path] =
if defined? Hassle and Rails.configuration.middleware.include? Hassle
file = path == :default ? 'stylesheets/email.css' : path
File.read("#{Rails.root}/tmp/hassle/#{file}")
elsif Rails.configuration.try(:assets).try(:enabled)
file = if path == :default
'email.css'
else
path.sub("#{Rails.configuration.assets.prefix}/", '')
end
Rails.application.assets.find_asset(file).body
else
file = path == :default ? 'stylesheets/email.css' : path
File.read("#{Rails.root}/public/#{file}")
end
end

@@css_cache[path]
rescue => ex
# Print an error and store empty string as the CSS.
puts ex.message
@@css_cache[path] = ''
end
end
end
67 changes: 12 additions & 55 deletions lib/premailer-rails3/premailer.rb
Original file line number Diff line number Diff line change
@@ -1,64 +1,21 @@
module PremailerRails
class Premailer < ::Premailer
@@_css_cache = {}

def initialize(html)
load_html(html)
options = {
:with_html_string => true,
:adapter => :hpricot
}.merge css_options
super(html, options)
end

def load_html(string)
# @doc is also used by ::Premailer
@doc ||= Hpricot(string)
end

protected
# In order to pass the CSS as string to super it is necessary to access
# the parsed HTML beforehand. To do so, the adapter needs to be
# initialized. The ::Premailer::Adaptor handles the discovery of a
# suitable adaptor (Nokogiri or Hpricot). To make load_html work, an
# adaptor needs to be included and @options[:with_html_string] needs to be
# set. For further information, refer to ::Premailer#initialize.
@options = { :with_html_string => true }
::Premailer.send(:include, Adapter.find(Adapter.use))
doc = load_html(html)

def css_options
options = {
:css => linked_css_files
:with_html_string => true,
:css_string => CSSHelper.css_for_doc(doc)
}

if linked_css_files.empty?
options[:css_string] = default_css_file
end

options
end

def default_css_file
# Don't cache in development.
if Rails.env.development? or not @@_css_cache.include? :default
@@_css_cache[:default] =
if defined? Hassle and Rails.configuration.middleware.include? Hassle
File.read("#{Rails.root}/tmp/hassle/stylesheets/email.css")
elsif Rails.configuration.try(:assets).try(:enabled)
Rails.application.assets.find_asset('email.css').body
else
File.read("#{Rails.root}/public/stylesheets/email.css")
end
end
@@_css_cache[:default]
rescue => ex
puts ex.message
@@_css_cache[:default] = nil
end

# Scan the HTML mailer template for CSS files, specifically link tags with
# types of text/css (other ways of including CSS are not supported).
def linked_css_files
@_linked_css_files ||= @doc.search('link[@type="text/css"]').collect do |l|
href = l.attributes['href']
if href.include? '?'
href[0..(href.index('?') - 1)]
else
href
end
end
super(html, options)
end
end
end
1 change: 0 additions & 1 deletion premailer-rails3.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,4 @@ Gem::Specification.new do |s|
s.require_paths = ["lib"]

s.add_dependency("premailer", ["~> 1.7"])
s.add_dependency("hpricot", ["~> 0.8"])
end

0 comments on commit f937173

Please sign in to comment.