awesomemailer 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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