awesomemailer 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.2.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "awesomemailer"
8
- s.version = "0.1.4"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Flip Sasser"]
12
- s.date = "2013-04-12"
12
+ s.date = "2013-06-13"
13
13
  s.description = "\n AwesomeMailer embeds your e-mail CSS inline, allowing you to write e-mail templates without worrying too much about stylesheets\n "
14
14
  s.email = "flip@x451.com"
15
15
  s.extra_rdoc_files = [
@@ -17,11 +17,7 @@ Gem::Specification.new do |s|
17
17
  ]
18
18
  s.files = [
19
19
  "CHANGELOG",
20
- "Gemfile",
21
- "Gemfile.lock",
22
- "Guardfile",
23
20
  "README.md",
24
- "Rakefile",
25
21
  "VERSION",
26
22
  "awesomemailer.gemspec",
27
23
  "lib/awesome_mailer.rb",
@@ -12,7 +12,12 @@ module AwesomeMailer
12
12
  # Must be intended for digital screens!
13
13
  load_stylesheet(stylesheet) if stylesheet['media'] =~ /^(all|handheld|screen)$/
14
14
  end
15
- apply_css!(document)
15
+ inline_stylesheets = document.search('style')
16
+ inline_stylesheets.each do |styles|
17
+ css_parser.add_block!(styles.inner_html)
18
+ styles.remove
19
+ end
20
+ apply_css!
16
21
  end
17
22
 
18
23
  def to_html
@@ -20,41 +25,51 @@ module AwesomeMailer
20
25
  end
21
26
 
22
27
  private
23
- def append_styles_to_body!(document, selector, declarations)
24
- declarations = "#{declarations.join('; ')};"
25
- document.search(selector).each do |element|
26
- element['style'] = [element['style'], declarations].compact.join(';')
28
+ def apply_styles_to_body!(selector, properties)
29
+ rewrite_relative_urls(properties) if host
30
+ search_selector = selector =~ /^body/ ? selector : "body #{selector}"
31
+ document.search(search_selector).each do |element|
32
+ element['style'] = [element['style'], properties].flatten.compact.join('; ')
27
33
  end
28
34
  end
29
35
 
30
- def append_styles_to_head!(document, selector, declarations, media = nil)
31
- selector_and_declarations = "#{selector} { #{declarations.join('; ')}; }"
32
- if media != :all
33
- selector_and_declarations = "@media #{media} { #{selector_and_declarations} }"
34
- end
35
- header_stylesheet.inner_html += "#{selector_and_declarations}\n"
36
+ def apply_styles_to_head!(selector, properties, indent = 0)
37
+ rewrite_relative_urls(properties) if host
38
+ header_stylesheet.inner_html += "#{" " * indent}#{selector} { #{properties.join('; ')} }\n"
36
39
  end
37
40
 
38
- def apply_css!(document)
41
+ def apply_css!
42
+ css_parser.compact!
43
+ applied_rules = []
44
+
45
+ # Apply @media queries to the document head
39
46
  css_parser.rules_by_media_query.each do |media_query, rules|
47
+ next if media_query == :all
48
+ header_stylesheet.inner_html += "@media #{media_query} {\n"
40
49
  rules.each do |rule|
41
- rule.each_selector do |selector, declarations, specificity|
42
- # Rewrite relative URLs to match their parent CSS's URL path
43
- rewrite_relative_urls(declarations) if host
44
- declarations = declarations.split(';').map(&:strip)
45
- if media_query != :all || selector =~ /(^@|:|moz)/
46
- # Include difficult styles in the head
47
- append_styles_to_head!(document, selector, declarations, media_query)
48
- else
49
- # Strip vendor prefix styles and append them to the header
50
- vendor_specific_declarations = declarations.select {|declaration| declaration =~ /^-/ }
51
- if vendor_specific_declarations.any?
52
- declarations -= vendor_specific_declarations
53
- append_styles_to_head!(document, selector, vendor_specific_declarations, media_query)
54
- end
55
- # Include regular styles inline
56
- append_styles_to_body!(document, selector, declarations)
57
- end
50
+ rule.each_selector do |selector, properties, specificity|
51
+ properties = properties.split(';').map(&:strip)
52
+ apply_styles_to_head!(selector, properties, 2)
53
+ end
54
+ end
55
+ header_stylesheet.inner_html += "}\n"
56
+ applied_rules.push(*rules)
57
+ end
58
+
59
+ # Apply all other styles
60
+ css_parser.each_rule_set do |rule|
61
+ next if applied_rules.include? rule
62
+ rule.each_selector do |selector, properties, specificity|
63
+ properties = properties.split(';').map(&:strip)
64
+ if selector =~ /(^@|:(active|checked|disabled|enabled|focus|hover|lang|link|target|visited|:)|moz|webkit)/
65
+ # Special selectors get sent to the <head> tag
66
+ apply_styles_to_head!(selector, properties)
67
+ else
68
+ vendor_specific_properties = properties.select {|property| property =~ /^-/ }
69
+ # Special properties get sent to the <head> tag
70
+ apply_styles_to_head!(selector, vendor_specific_properties) unless vendor_specific_properties.empty?
71
+ # Everything else winds up inline on the body
72
+ apply_styles_to_body!(selector, properties - vendor_specific_properties)
58
73
  end
59
74
  end
60
75
  end
@@ -69,11 +84,12 @@ module AwesomeMailer
69
84
 
70
85
  def asset_pipeline_path
71
86
  return false unless sprockets?
72
- /^#{Regexp.escape(Rails.configuration.assets[:prefix])}\//
87
+ path = File.join('', Rails.configuration.assets[:prefix], '').gsub('//', '/')
88
+ /^#{Regexp.escape(path)}/
73
89
  end
74
90
 
75
91
  def css_parser
76
- @css_parser ||= CssParser::Parser.new
92
+ @css_parser ||= CssParser::Parser.new(absolute_paths: true)
77
93
  end
78
94
 
79
95
  def default_host
@@ -109,13 +125,15 @@ module AwesomeMailer
109
125
  when asset_pipeline_path
110
126
  if asset = read_asset_pipeline_asset(stylesheet_path)
111
127
  css_parser.add_block!(asset.to_s)
128
+ else
129
+ Rails.logger.error 'AwesomeMailer error. Could not find: ' + stylesheet_path if rails?
112
130
  end
113
131
  when /^\//
114
132
  local_path = rails? && Rails.root.join('public', stylesheet_path.gsub(/^\//, '')).to_s
115
- css_parser.load_file!(local_path) if local_path && File.file?(local_path)
133
+ css_parser.load_file!(local_path, nil, []) if local_path && File.file?(local_path)
116
134
  else
117
135
  dirname = File.dirname(stylesheet['href'])
118
- css_parser.load_uri!(stylesheet['href'], base_uri: dirname)
136
+ css_parser.load_uri!(stylesheet['href'], base_uri: dirname, media_types: [])
119
137
  end
120
138
  stylesheet.remove
121
139
  end
@@ -125,17 +143,19 @@ module AwesomeMailer
125
143
  end
126
144
 
127
145
  def read_asset_pipeline_asset(path)
128
- path = path.gsub(asset_pipeline_path, '')
146
+ path = path.gsub(asset_pipeline_path, '').gsub(/-[A-Fa-f0-9]{32}/, '')
129
147
  Rails.application.assets[path]
130
148
  end
131
149
 
132
- def rewrite_relative_urls(css_declarations)
133
- css_declarations.scan(/(url\s*\(?["']+(.[^'"]*)["']\))/i).each do |url_command, item|
134
- next if item =~ /^http(s){0,1}:\/\//
135
- item_url = host.dup
136
- item_url.path = File.join(item_url.path, item)
137
- new_url_command = url_command.gsub(item, item_url.to_s)
138
- css_declarations[url_command] = new_url_command
150
+ def rewrite_relative_urls(properties)
151
+ properties.each do |property|
152
+ property.scan(/(url\s*\(?["']+(.[^'"]*)["']\))/i).each do |url_command, item|
153
+ next if item =~ /^http(s){0,1}:\/\//
154
+ item_url = host.dup
155
+ item_url.path = File.join(item_url.path, item)
156
+ new_url_command = url_command.gsub(item, item_url.to_s)
157
+ property[url_command] = new_url_command
158
+ end
139
159
  end
140
160
  end
141
161
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: awesomemailer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-12 00:00:00.000000000 Z
12
+ date: 2013-06-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionmailer
@@ -84,11 +84,7 @@ extra_rdoc_files:
84
84
  - README.md
85
85
  files:
86
86
  - CHANGELOG
87
- - Gemfile
88
- - Gemfile.lock
89
- - Guardfile
90
87
  - README.md
91
- - Rakefile
92
88
  - VERSION
93
89
  - awesomemailer.gemspec
94
90
  - lib/awesome_mailer.rb
data/Gemfile DELETED
@@ -1,14 +0,0 @@
1
- source 'http://rubygems.org'
2
-
3
- gem 'actionmailer', '>= 3.2'
4
- gem 'addressable'
5
- gem 'css_parser', '>= 1.2.5'
6
- gem 'nokogiri', '>= 1.5.6'
7
-
8
- group :test do
9
- gem 'guard-rspec', require: false
10
- gem 'jeweler', require: false
11
- gem 'pry'
12
- gem 'rspec', require: false
13
- gem 'simplecov', require: false
14
- end
@@ -1,103 +0,0 @@
1
- GEM
2
- remote: http://rubygems.org/
3
- specs:
4
- actionmailer (3.2.8)
5
- actionpack (= 3.2.8)
6
- mail (~> 2.4.4)
7
- actionpack (3.2.8)
8
- activemodel (= 3.2.8)
9
- activesupport (= 3.2.8)
10
- builder (~> 3.0.0)
11
- erubis (~> 2.7.0)
12
- journey (~> 1.0.4)
13
- rack (~> 1.4.0)
14
- rack-cache (~> 1.2)
15
- rack-test (~> 0.6.1)
16
- sprockets (~> 2.1.3)
17
- activemodel (3.2.8)
18
- activesupport (= 3.2.8)
19
- builder (~> 3.0.0)
20
- activesupport (3.2.8)
21
- i18n (~> 0.6)
22
- multi_json (~> 1.0)
23
- addressable (2.3.2)
24
- builder (3.0.4)
25
- coderay (1.0.9)
26
- css_parser (1.2.6)
27
- addressable
28
- rdoc
29
- diff-lcs (1.1.3)
30
- erubis (2.7.0)
31
- git (1.2.5)
32
- guard (1.4.0)
33
- listen (>= 0.4.2)
34
- thor (>= 0.14.6)
35
- guard-rspec (1.2.1)
36
- guard (>= 1.1)
37
- hike (1.2.1)
38
- i18n (0.6.1)
39
- jeweler (1.8.4)
40
- bundler (~> 1.0)
41
- git (>= 1.2.5)
42
- rake
43
- rdoc
44
- journey (1.0.4)
45
- json (1.7.5)
46
- listen (0.5.2)
47
- mail (2.4.4)
48
- i18n (>= 0.4.0)
49
- mime-types (~> 1.16)
50
- treetop (~> 1.4.8)
51
- method_source (0.8.1)
52
- mime-types (1.19)
53
- multi_json (1.3.7)
54
- nokogiri (1.5.6)
55
- polyglot (0.3.3)
56
- pry (0.9.12)
57
- coderay (~> 1.0.5)
58
- method_source (~> 0.8)
59
- slop (~> 3.4)
60
- rack (1.4.1)
61
- rack-cache (1.2)
62
- rack (>= 0.4)
63
- rack-test (0.6.2)
64
- rack (>= 1.0)
65
- rake (0.9.2.2)
66
- rdoc (3.12)
67
- json (~> 1.4)
68
- rspec (2.11.0)
69
- rspec-core (~> 2.11.0)
70
- rspec-expectations (~> 2.11.0)
71
- rspec-mocks (~> 2.11.0)
72
- rspec-core (2.11.1)
73
- rspec-expectations (2.11.3)
74
- diff-lcs (~> 1.1.3)
75
- rspec-mocks (2.11.2)
76
- simplecov (0.7.1)
77
- multi_json (~> 1.0)
78
- simplecov-html (~> 0.7.1)
79
- simplecov-html (0.7.1)
80
- slop (3.4.4)
81
- sprockets (2.1.3)
82
- hike (~> 1.2)
83
- rack (~> 1.0)
84
- tilt (~> 1.1, != 1.3.0)
85
- thor (0.16.0)
86
- tilt (1.3.3)
87
- treetop (1.4.12)
88
- polyglot
89
- polyglot (>= 0.3.1)
90
-
91
- PLATFORMS
92
- ruby
93
-
94
- DEPENDENCIES
95
- actionmailer (>= 3.2)
96
- addressable
97
- css_parser (>= 1.2.5)
98
- guard-rspec
99
- jeweler
100
- nokogiri (>= 1.5.6)
101
- pry
102
- rspec
103
- simplecov
data/Guardfile DELETED
@@ -1,8 +0,0 @@
1
- # A sample Guardfile
2
- # More info at https://github.com/guard/guard#readme
3
-
4
- guard 'rspec', :version => 2 do
5
- watch(%r{^spec/.+_spec\.rb$})
6
- watch(%r{^lib/(.+)\.rb$}) { "spec" }
7
- watch('spec/spec_helper.rb') { "spec" }
8
- end
data/Rakefile DELETED
@@ -1,15 +0,0 @@
1
- begin
2
- require 'jeweler'
3
- Jeweler::Tasks.new do |gem|
4
- gem.name = "awesomemailer"
5
- gem.summary = "An ActionMailer extension that embeds CSS inline in e-mails"
6
- gem.description = %{
7
- AwesomeMailer embeds your e-mail CSS inline, allowing you to write e-mail templates without worrying too much about stylesheets
8
- }
9
- gem.email = "flip@x451.com"
10
- gem.homepage = "http://github.com/Plinq/awesome_mailer"
11
- gem.authors = ["Flip Sasser"]
12
- gem.files.exclude '.rspec', '.rvmrc', 'spec/**/*'
13
- end
14
- rescue LoadError
15
- end