premailer 1.9.2 → 1.10.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.
- checksums.yaml +4 -4
- data/README.md +4 -5
- data/lib/premailer/adapter.rb +1 -5
- data/lib/premailer/adapter/nokogiri.rb +6 -12
- data/lib/premailer/adapter/nokogiri_fast.rb +7 -14
- data/lib/premailer/adapter/nokogumbo.rb +7 -14
- data/lib/premailer/executor.rb +17 -12
- data/lib/premailer/premailer.rb +5 -5
- data/lib/premailer/version.rb +1 -1
- metadata +14 -35
- data/lib/premailer/adapter/hpricot.rb +0 -220
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b62798f9ef3929357e4fe01538d05615f37b9b3
|
4
|
+
data.tar.gz: f0224b7a6a42b88ebea688cf9d55fe30504f9751
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96bfa7a6374f3cd91f6004a8a988d46e789bd2cce29e12f595fee64c0e86244236e77766b1380a347329dbd71866f487ca23f9aedab0d600b2cf1a54a1c3253f
|
7
|
+
data.tar.gz: 09148edbb09bee950ad6e5c7c97709587b862136a38b5f484ab8e5f039f92f137ce7b948303796480004b31018e0f4ebe488d68c4ae1767f0f61d141d11f8db7
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Premailer README [](https://travis-ci.org/premailer/premailer)
|
1
|
+
# Premailer README [](https://travis-ci.org/premailer/premailer) [](https://badge.fury.io/rb/premailer)
|
2
2
|
|
3
3
|
## What is this?
|
4
4
|
|
@@ -50,14 +50,13 @@ end
|
|
50
50
|
|
51
51
|
## Adapters
|
52
52
|
|
53
|
-
Premailer's default adapter is nokogiri if both nokogiri and
|
53
|
+
Premailer's default adapter is nokogiri if both nokogiri and nokogumbo are included in the Gemfile list. However, if you want to use a different adapter, you can choose to.
|
54
54
|
|
55
|
-
There are
|
55
|
+
There are three adapters in total (as of premailer 1.9.1)
|
56
56
|
|
57
57
|
1. nokogiri (default)
|
58
58
|
2. nokogiri_fast
|
59
59
|
3. nokogumbo
|
60
|
-
4. hpricot (deprecated and will be removed in future premailer releases)
|
61
60
|
|
62
61
|
`NokogiriFast` adapter improves the Algorithmic complexity of the running time by 20x with a slight compensation on memory. To switch to any of these adapters, add the following line. For example, if you want to include the `NokogiriFast` adapter,
|
63
62
|
|
@@ -113,5 +112,5 @@ and to [Campaign Monitor](https://www.campaignmonitor.com/) for supporting the w
|
|
113
112
|
|
114
113
|
The source code can be found on [GitHub](https://github.com/premailer/premailer).
|
115
114
|
|
116
|
-
Copyright by Alex Dunae (dunae.ca, e-mail 'code' at the same domain), 2007-2017. See [LICENSE.md](https://github.com/
|
115
|
+
Copyright by Alex Dunae (dunae.ca, e-mail 'code' at the same domain), 2007-2017. See [LICENSE.md](https://github.com/premailer/premailer/blob/master/LICENSE.md) for license details.
|
117
116
|
|
data/lib/premailer/adapter.rb
CHANGED
@@ -4,10 +4,8 @@ class Premailer
|
|
4
4
|
# * nokogiri
|
5
5
|
# * nokogiri_fast
|
6
6
|
# * nokogumbo
|
7
|
-
# * hpricot
|
8
7
|
module Adapter
|
9
8
|
|
10
|
-
autoload :Hpricot, 'premailer/adapter/hpricot'
|
11
9
|
autoload :Nokogiri, 'premailer/adapter/nokogiri'
|
12
10
|
autoload :NokogiriFast, 'premailer/adapter/nokogiri_fast'
|
13
11
|
autoload :Nokogumbo, 'premailer/adapter/nokogumbo'
|
@@ -17,7 +15,6 @@ class Premailer
|
|
17
15
|
["nokogiri", :nokogiri],
|
18
16
|
["nokogiri", :nokogiri_fast],
|
19
17
|
["nokogumbo", :nokogumbo],
|
20
|
-
["hpricot", :hpricot],
|
21
18
|
]
|
22
19
|
|
23
20
|
# Returns the adapter to use.
|
@@ -35,7 +32,6 @@ class Premailer
|
|
35
32
|
return :nokogiri if defined?(::Nokogiri)
|
36
33
|
return :nokogiri_fast if defined?(::NokogiriFast)
|
37
34
|
return :nokogumbo if defined?(::Nokogumbo)
|
38
|
-
return :hpricot if defined?(::Hpricot)
|
39
35
|
|
40
36
|
REQUIREMENT_MAP.each do |(library, adapter)|
|
41
37
|
begin
|
@@ -46,7 +42,7 @@ class Premailer
|
|
46
42
|
end
|
47
43
|
end
|
48
44
|
|
49
|
-
raise RuntimeError.new("No suitable adapter for Premailer was found, please install
|
45
|
+
raise RuntimeError.new("No suitable adapter for Premailer was found, please install nokogiri or nokogumbo")
|
50
46
|
end
|
51
47
|
|
52
48
|
# Sets the adapter to use.
|
@@ -144,25 +144,19 @@ class Premailer
|
|
144
144
|
end
|
145
145
|
|
146
146
|
# Create a <tt>style</tt> element with un-mergable rules (e.g. <tt>:hover</tt>)
|
147
|
-
# and write it into the <tt>
|
147
|
+
# and write it into the <tt>head</tt>.
|
148
148
|
#
|
149
149
|
# <tt>doc</tt> is an Nokogiri document and <tt>unmergable_css_rules</tt> is a Css::RuleSet.
|
150
150
|
#
|
151
151
|
# @return [::Nokogiri::XML] a document.
|
152
152
|
def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc:
|
153
153
|
styles = unmergable_rules.to_s
|
154
|
-
|
155
154
|
unless styles.empty?
|
156
|
-
style_tag = "
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
doc.at_css('body').add_child(::Nokogiri::XML.fragment(style_tag))
|
162
|
-
end
|
163
|
-
else
|
164
|
-
doc.inner_html = style_tag += doc.inner_html
|
165
|
-
end
|
155
|
+
style_tag = doc.create_element "style", "#{styles}"
|
156
|
+
head = doc.at_css('head')
|
157
|
+
head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element "head") if doc.root && doc.root.first_element_child
|
158
|
+
head ||= doc.add_child(doc.create_element "head")
|
159
|
+
head << style_tag
|
166
160
|
end
|
167
161
|
doc
|
168
162
|
end
|
@@ -146,26 +146,19 @@ class Premailer
|
|
146
146
|
end
|
147
147
|
|
148
148
|
# Create a <tt>style</tt> element with un-mergable rules (e.g. <tt>:hover</tt>)
|
149
|
-
# and write it into the <tt>
|
149
|
+
# and write it into the <tt>head</tt>.
|
150
150
|
#
|
151
151
|
# <tt>doc</tt> is an Nokogiri document and <tt>unmergable_css_rules</tt> is a Css::RuleSet.
|
152
152
|
#
|
153
153
|
# @return [::Nokogiri::XML] a document.
|
154
154
|
def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc:
|
155
155
|
styles = unmergable_rules.to_s
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
else
|
163
|
-
doc.at_css('body').add_child(::Nokogiri::XML.fragment(style_tag))
|
164
|
-
end
|
165
|
-
else
|
166
|
-
doc.inner_html = style_tag += doc.inner_html
|
167
|
-
end
|
168
|
-
end
|
156
|
+
return doc if styles.empty?
|
157
|
+
style_tag = doc.create_element "style", styles
|
158
|
+
head = doc.at_css('head')
|
159
|
+
head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element "head") if doc.root && doc.root.first_element_child
|
160
|
+
head ||= doc.add_child(doc.create_element "head")
|
161
|
+
head << style_tag
|
169
162
|
doc
|
170
163
|
end
|
171
164
|
|
@@ -143,26 +143,19 @@ class Premailer
|
|
143
143
|
end
|
144
144
|
|
145
145
|
# Create a <tt>style</tt> element with un-mergable rules (e.g. <tt>:hover</tt>)
|
146
|
-
# and write it into the <tt>
|
146
|
+
# and write it into the <tt>head</tt>.
|
147
147
|
#
|
148
148
|
# <tt>doc</tt> is an Nokogiri document and <tt>unmergable_css_rules</tt> is a Css::RuleSet.
|
149
149
|
#
|
150
150
|
# @return [::Nokogiri::XML] a document.
|
151
151
|
def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc:
|
152
152
|
styles = unmergable_rules.to_s
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
else
|
160
|
-
doc.at_css('body').add_child(::Nokogiri::XML.fragment(style_tag))
|
161
|
-
end
|
162
|
-
else
|
163
|
-
doc.inner_html = style_tag += doc.inner_html
|
164
|
-
end
|
165
|
-
end
|
153
|
+
return doc if styles.empty?
|
154
|
+
style_tag = doc.create_element "style", styles
|
155
|
+
head = doc.at_css('head')
|
156
|
+
head ||= doc.root.first_element_child.add_previous_sibling(doc.create_element "head") if doc.root && doc.root.first_element_child
|
157
|
+
head ||= doc.add_child(doc.create_element "head")
|
158
|
+
head << style_tag
|
166
159
|
doc
|
167
160
|
end
|
168
161
|
|
data/lib/premailer/executor.rb
CHANGED
@@ -3,11 +3,12 @@ require 'premailer'
|
|
3
3
|
|
4
4
|
# defaults
|
5
5
|
options = {
|
6
|
-
:base_url
|
6
|
+
:base_url => nil,
|
7
7
|
:link_query_string => nil,
|
8
|
-
:remove_classes
|
9
|
-
:verbose
|
10
|
-
:line_length
|
8
|
+
:remove_classes => false,
|
9
|
+
:verbose => false,
|
10
|
+
:line_length => 65,
|
11
|
+
:adapter => :nokogiri,
|
11
12
|
}
|
12
13
|
|
13
14
|
mode = :html
|
@@ -28,6 +29,10 @@ opts = OptionParser.new do |opts|
|
|
28
29
|
mode = v
|
29
30
|
end
|
30
31
|
|
32
|
+
opts.on("--adapter ADAPTER", [:nokogiri, :nokogiri_fast, :nokogumbo], "Adapter: nokogiri, nokogiri_fast or nokogumbo (default: #{options[:adapter]}") do |v|
|
33
|
+
options[:adapter] = v
|
34
|
+
end
|
35
|
+
|
31
36
|
opts.on("-b", "--base-url STRING", String, "Base URL, useful for local files") do |v|
|
32
37
|
options[:base_url] = v
|
33
38
|
end
|
@@ -40,12 +45,12 @@ opts = OptionParser.new do |opts|
|
|
40
45
|
options[:css] = v
|
41
46
|
end
|
42
47
|
|
43
|
-
opts.on("-r", "--remove-classes", "Remove HTML classes") do
|
44
|
-
options[:remove_classes] =
|
48
|
+
opts.on("-r", "--remove-classes", "Remove HTML classes") do
|
49
|
+
options[:remove_classes] = true
|
45
50
|
end
|
46
51
|
|
47
|
-
opts.on("-j", "--remove-scripts", "Remove <script> elements") do
|
48
|
-
options[:remove_scripts] =
|
52
|
+
opts.on("-j", "--remove-scripts", "Remove <script> elements") do
|
53
|
+
options[:remove_scripts] = true
|
49
54
|
end
|
50
55
|
|
51
56
|
opts.on("-l", "--line-length N", Integer, "Line length for plaintext (default: #{options[:line_length].to_s})") do |v|
|
@@ -56,12 +61,12 @@ opts = OptionParser.new do |opts|
|
|
56
61
|
options[:output_encoding] = "US-ASCII"
|
57
62
|
end
|
58
63
|
|
59
|
-
opts.on("-d", "--io-exceptions", "Abort on I/O errors") do
|
60
|
-
options[:io_exceptions] =
|
64
|
+
opts.on("-d", "--io-exceptions", "Abort on I/O errors") do
|
65
|
+
options[:io_exceptions] = true
|
61
66
|
end
|
62
67
|
|
63
|
-
opts.on("-v", "--verbose", "Print additional information at runtime") do
|
64
|
-
options[:verbose] =
|
68
|
+
opts.on("-v", "--verbose", "Print additional information at runtime") do
|
69
|
+
options[:verbose] = true
|
65
70
|
end
|
66
71
|
|
67
72
|
opts.on_tail("-?", "--help", "Show this message") do
|
data/lib/premailer/premailer.rb
CHANGED
@@ -121,10 +121,10 @@ class Premailer
|
|
121
121
|
# unmergeable CSS rules to be preserved in the head (CssParser)
|
122
122
|
attr_reader :unmergable_rules
|
123
123
|
|
124
|
-
# processed HTML document (
|
124
|
+
# processed HTML document (Nokogiri/Nokogumbo)
|
125
125
|
attr_reader :processed_doc
|
126
126
|
|
127
|
-
# source HTML document (
|
127
|
+
# source HTML document (Nokogiri/Nokogumbo)
|
128
128
|
attr_reader :doc
|
129
129
|
|
130
130
|
# Warning levels
|
@@ -174,7 +174,7 @@ class Premailer
|
|
174
174
|
# @option options [String] :input_encoding Manually specify the source documents encoding. This is a good idea. Default is ASCII-8BIT.
|
175
175
|
# @option options [Boolean] :replace_html_entities Convert HTML entities to actual characters. Default is false.
|
176
176
|
# @option options [Boolean] :escape_url_attributes URL Escapes href, src, and background attributes on elements. Default is true.
|
177
|
-
# @option options [Symbol] :adapter Which HTML parser to use,
|
177
|
+
# @option options [Symbol] :adapter Which HTML parser to use, <tt>:nokogiri</tt>, <tt>:nokogiri_fast</tt> or <tt>:nokogumbo</tt>. Default is <tt>:nokogiri</tt>.
|
178
178
|
# @option options [String] :output_encoding Output encoding option for Nokogiri adapter. Should be set to "US-ASCII" to output HTML entities instead of Unicode characters.
|
179
179
|
# @option options [Boolean] :create_shorthands Combine several properties into a shorthand one, e.g. font: style weight size. Default is true.
|
180
180
|
def initialize(html, options = {})
|
@@ -411,9 +411,9 @@ public
|
|
411
411
|
# Processes <tt>href</tt> <tt>src</tt> and <tt>background</tt> attributes
|
412
412
|
# as well as CSS <tt>url()</tt> declarations found in inline <tt>style</tt> attributes.
|
413
413
|
#
|
414
|
-
# <tt>doc</tt> is
|
414
|
+
# <tt>doc</tt> is a document and <tt>base_uri</tt> is either a string or a URI.
|
415
415
|
#
|
416
|
-
# Returns
|
416
|
+
# Returns a document.
|
417
417
|
def convert_inline_links(doc, base_uri) # :nodoc:
|
418
418
|
base_uri = URI.parse(base_uri) unless base_uri.kind_of?(URI)
|
419
419
|
|
data/lib/premailer/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: premailer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Dunae
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: css_parser
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.4.
|
19
|
+
version: 1.4.9
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.4.
|
26
|
+
version: 1.4.9
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: htmlentities
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -42,14 +42,14 @@ dependencies:
|
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
@@ -72,40 +72,20 @@ dependencies:
|
|
72
72
|
- - "!="
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: 0.9.0
|
75
|
-
- !ruby/object:Gem::Dependency
|
76
|
-
name: hpricot
|
77
|
-
requirement: !ruby/object:Gem::Requirement
|
78
|
-
requirements:
|
79
|
-
- - ">="
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version: 0.8.3
|
82
|
-
type: :development
|
83
|
-
prerelease: false
|
84
|
-
version_requirements: !ruby/object:Gem::Requirement
|
85
|
-
requirements:
|
86
|
-
- - ">="
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: 0.8.3
|
89
75
|
- !ruby/object:Gem::Dependency
|
90
76
|
name: nokogiri
|
91
77
|
requirement: !ruby/object:Gem::Requirement
|
92
78
|
requirements:
|
93
|
-
- - "
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
version: 1.4.4
|
96
|
-
- - "<="
|
79
|
+
- - "~>"
|
97
80
|
- !ruby/object:Gem::Version
|
98
|
-
version: 1.
|
81
|
+
version: '1.7'
|
99
82
|
type: :development
|
100
83
|
prerelease: false
|
101
84
|
version_requirements: !ruby/object:Gem::Requirement
|
102
85
|
requirements:
|
103
|
-
- - "
|
104
|
-
- !ruby/object:Gem::Version
|
105
|
-
version: 1.4.4
|
106
|
-
- - "<="
|
86
|
+
- - "~>"
|
107
87
|
- !ruby/object:Gem::Version
|
108
|
-
version: 1.
|
88
|
+
version: '1.7'
|
109
89
|
- !ruby/object:Gem::Dependency
|
110
90
|
name: yard
|
111
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,7 +172,7 @@ dependencies:
|
|
192
172
|
version: '0'
|
193
173
|
description: Improve the rendering of HTML emails by making CSS inline, converting
|
194
174
|
links and warning about unsupported code.
|
195
|
-
email:
|
175
|
+
email: akzhan.abdulin@gmail.com
|
196
176
|
executables:
|
197
177
|
- premailer
|
198
178
|
extensions: []
|
@@ -203,7 +183,6 @@ files:
|
|
203
183
|
- bin/premailer
|
204
184
|
- lib/premailer.rb
|
205
185
|
- lib/premailer/adapter.rb
|
206
|
-
- lib/premailer/adapter/hpricot.rb
|
207
186
|
- lib/premailer/adapter/nokogiri.rb
|
208
187
|
- lib/premailer/adapter/nokogiri_fast.rb
|
209
188
|
- lib/premailer/adapter/nokogumbo.rb
|
@@ -213,7 +192,7 @@ files:
|
|
213
192
|
- lib/premailer/premailer.rb
|
214
193
|
- lib/premailer/version.rb
|
215
194
|
- misc/client_support.yaml
|
216
|
-
homepage:
|
195
|
+
homepage: https://github.com/premailer/premailer
|
217
196
|
licenses: []
|
218
197
|
metadata:
|
219
198
|
yard.run: yri
|
@@ -225,7 +204,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
225
204
|
requirements:
|
226
205
|
- - ">="
|
227
206
|
- !ruby/object:Gem::Version
|
228
|
-
version: 2.
|
207
|
+
version: 2.1.0
|
229
208
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
230
209
|
requirements:
|
231
210
|
- - ">="
|
@@ -233,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
233
212
|
version: '0'
|
234
213
|
requirements: []
|
235
214
|
rubyforge_project:
|
236
|
-
rubygems_version: 2.
|
215
|
+
rubygems_version: 2.5.1
|
237
216
|
signing_key:
|
238
217
|
specification_version: 4
|
239
218
|
summary: Preflight for HTML e-mail.
|
@@ -1,220 +0,0 @@
|
|
1
|
-
require 'hpricot'
|
2
|
-
|
3
|
-
class Premailer
|
4
|
-
module Adapter
|
5
|
-
# Hpricot adapter
|
6
|
-
module Hpricot
|
7
|
-
include AdapterHelper::RgbToHex
|
8
|
-
|
9
|
-
def self.included(base)
|
10
|
-
warn <<eos
|
11
|
-
[DEPRECATED] Premailer's Hpricot adapter will be removed with the next major \
|
12
|
-
release. Change your :adapter option to :nokogiri or remove the `hpricot` gem \
|
13
|
-
from your application to silence this warning. (Called from #{caller[2]})
|
14
|
-
eos
|
15
|
-
end
|
16
|
-
|
17
|
-
# Merge CSS into the HTML document.
|
18
|
-
# @return [String] HTML.
|
19
|
-
def to_inline_css
|
20
|
-
doc = @processed_doc
|
21
|
-
@unmergable_rules = CssParser::Parser.new
|
22
|
-
|
23
|
-
# Give all styles already in style attributes a specificity of 1000
|
24
|
-
# per http://www.w3.org/TR/CSS21/cascade.html#specificity
|
25
|
-
doc.search("*[@style]").each do |el|
|
26
|
-
el['style'] = '[SPEC=1000[' + el.attributes['style'] + ']]'
|
27
|
-
end
|
28
|
-
|
29
|
-
# Iterate through the rules and merge them into the HTML
|
30
|
-
@css_parser.each_selector(:all) do |selector, declaration, specificity, media_types|
|
31
|
-
# Save un-mergable rules separately
|
32
|
-
selector.gsub!(/:link([\s]*)+/i) {|m| $1 }
|
33
|
-
|
34
|
-
# Convert element names to lower case
|
35
|
-
selector.gsub!(/([\s]|^)([\w]+)/) {|m| $1.to_s + $2.to_s.downcase }
|
36
|
-
|
37
|
-
if Premailer.is_media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
|
38
|
-
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
|
39
|
-
else
|
40
|
-
begin
|
41
|
-
if selector =~ Premailer::RE_RESET_SELECTORS
|
42
|
-
# this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
|
43
|
-
# however, this doesn't mean for testing pur
|
44
|
-
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
|
45
|
-
end
|
46
|
-
|
47
|
-
# Change single ID CSS selectors into xpath so that we can match more
|
48
|
-
# than one element. Added to work around dodgy generated code.
|
49
|
-
selector.gsub!(/\A\#([\w_\-]+)\Z/, '*[@id=\1]')
|
50
|
-
|
51
|
-
# convert attribute selectors to hpricot's format
|
52
|
-
selector.gsub!(/\[([\w]+)\]/, '[@\1]')
|
53
|
-
selector.gsub!(/\[([\w]+)([\=\~\^\$\*]+)([\w\s]+)\]/, '[@\1\2\'\3\']')
|
54
|
-
|
55
|
-
doc.search(selector).each do |el|
|
56
|
-
if el.elem? and (el.name != 'head' and el.parent.name != 'head')
|
57
|
-
# Add a style attribute or append to the existing one
|
58
|
-
block = "[SPEC=#{specificity}[#{declaration}]]"
|
59
|
-
el['style'] = (el.attributes['style'].to_s ||= '') + ' ' + block
|
60
|
-
end
|
61
|
-
end
|
62
|
-
rescue ::Hpricot::Error, RuntimeError, ArgumentError
|
63
|
-
$stderr.puts "CSS syntax error with selector: #{selector}" if @options[:verbose]
|
64
|
-
next
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Remove script tags
|
70
|
-
if @options[:remove_scripts]
|
71
|
-
doc.search("script").remove
|
72
|
-
end
|
73
|
-
|
74
|
-
# Read STYLE attributes and perform folding
|
75
|
-
doc.search("*[@style]").each do |el|
|
76
|
-
style = el.attributes['style'].to_s
|
77
|
-
|
78
|
-
declarations = []
|
79
|
-
|
80
|
-
style.scan(/\[SPEC\=([\d]+)\[(.[^\]\]]*)\]\]/).each do |declaration|
|
81
|
-
rs = CssParser::RuleSet.new(nil, declaration[1].to_s, declaration[0].to_i)
|
82
|
-
declarations << rs
|
83
|
-
end
|
84
|
-
# Perform style folding
|
85
|
-
merged = CssParser.merge(declarations)
|
86
|
-
merged.expand_shorthand!
|
87
|
-
merged.create_shorthand! if @options[:create_shorthands]
|
88
|
-
|
89
|
-
# Duplicate CSS attributes as HTML attributes
|
90
|
-
if Premailer::RELATED_ATTRIBUTES.has_key?(el.name) && @options[:css_to_attributes]
|
91
|
-
Premailer::RELATED_ATTRIBUTES[el.name].each do |css_att, html_att|
|
92
|
-
if el[html_att].nil? and not merged[css_att].empty?
|
93
|
-
new_html_att = merged[css_att].gsub(/url\(['|"](.*)['|"]\)/, '\1').gsub(/;$|\s*!important/, '').strip
|
94
|
-
el[html_att] = css_att.end_with?('color') && @options[:rgb_to_hex_attributes] ? ensure_hex(new_html_att) : new_html_att
|
95
|
-
end
|
96
|
-
merged.instance_variable_get("@declarations").tap do |declarations|
|
97
|
-
unless @options[:preserve_style_attribute]
|
98
|
-
declarations.delete(css_att)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
# write the inline STYLE attribute
|
105
|
-
el['style'] = Premailer.escape_string(merged.declarations_to_s)
|
106
|
-
end
|
107
|
-
|
108
|
-
doc = write_unmergable_css_rules(doc, @unmergable_rules)
|
109
|
-
|
110
|
-
if @options[:remove_classes] or @options[:remove_comments]
|
111
|
-
doc.search('*').each do |el|
|
112
|
-
if el.comment? and @options[:remove_comments]
|
113
|
-
lst = el.parent.children
|
114
|
-
el.parent = nil
|
115
|
-
lst.delete(el)
|
116
|
-
elsif el.elem?
|
117
|
-
el.remove_attribute('class') if @options[:remove_classes]
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
if @options[:reset_contenteditable]
|
123
|
-
doc.search('*[@contenteditable]').each do |el|
|
124
|
-
el.remove_attribute('contenteditable')
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
if @options[:remove_ids]
|
129
|
-
# find all anchor's targets and hash them
|
130
|
-
targets = []
|
131
|
-
doc.search("a[@href^='#']").each do |el|
|
132
|
-
target = el.get_attribute('href')[1..-1]
|
133
|
-
targets << target
|
134
|
-
el.set_attribute('href', "#" + Digest::MD5.hexdigest(target))
|
135
|
-
end
|
136
|
-
# hash ids that are links target, delete others
|
137
|
-
doc.search("*[@id]").each do |el|
|
138
|
-
id = el.get_attribute('id')
|
139
|
-
if targets.include?(id)
|
140
|
-
el.set_attribute('id', Digest::MD5.hexdigest(id))
|
141
|
-
else
|
142
|
-
el.remove_attribute('id')
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
@processed_doc = doc
|
148
|
-
|
149
|
-
@processed_doc.to_original_html
|
150
|
-
end
|
151
|
-
|
152
|
-
# Create a <tt>style</tt> element with un-mergable rules (e.g. <tt>:hover</tt>)
|
153
|
-
# and write it into the <tt>body</tt>.
|
154
|
-
#
|
155
|
-
# <tt>doc</tt> is an Hpricot document and <tt>unmergable_css_rules</tt> is a Css::RuleSet.
|
156
|
-
#
|
157
|
-
# @return [::Hpricot] a document.
|
158
|
-
def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc:
|
159
|
-
styles = unmergable_rules.to_s
|
160
|
-
|
161
|
-
unless styles.empty?
|
162
|
-
style_tag = "\n<style type=\"text/css\">\n#{styles}</style>\n"
|
163
|
-
if head = doc.search('head')
|
164
|
-
head.append(style_tag)
|
165
|
-
elsif body = doc.search('body')
|
166
|
-
body.append(style_tag)
|
167
|
-
else
|
168
|
-
doc.inner_html= doc.inner_html << style_tag
|
169
|
-
end
|
170
|
-
end
|
171
|
-
doc
|
172
|
-
end
|
173
|
-
|
174
|
-
|
175
|
-
# Converts the HTML document to a format suitable for plain-text e-mail.
|
176
|
-
#
|
177
|
-
# If present, uses the <body> element as its base; otherwise uses the whole document.
|
178
|
-
#
|
179
|
-
# @return [String] Plain text.
|
180
|
-
def to_plain_text
|
181
|
-
html_src = ''
|
182
|
-
begin
|
183
|
-
html_src = @doc.search("body").inner_html
|
184
|
-
rescue; end
|
185
|
-
|
186
|
-
html_src = @doc.to_html unless html_src and not html_src.empty?
|
187
|
-
convert_to_text(html_src, @options[:line_length], @html_encoding)
|
188
|
-
end
|
189
|
-
|
190
|
-
|
191
|
-
# Gets the original HTML as a string.
|
192
|
-
# @return [String] HTML.
|
193
|
-
def to_s
|
194
|
-
@doc.to_original_html
|
195
|
-
end
|
196
|
-
|
197
|
-
# Load the HTML file and convert it into an Hpricot document.
|
198
|
-
#
|
199
|
-
# @return [::Hpricot] a document.
|
200
|
-
def load_html(input) # :nodoc:
|
201
|
-
thing = nil
|
202
|
-
|
203
|
-
# TODO: duplicate options
|
204
|
-
if @options[:with_html_string] or @options[:inline] or input.respond_to?(:read)
|
205
|
-
thing = input
|
206
|
-
elsif @is_local_file
|
207
|
-
@base_dir = File.dirname(input)
|
208
|
-
thing = File.open(input, 'r')
|
209
|
-
else
|
210
|
-
thing = open(input)
|
211
|
-
end
|
212
|
-
|
213
|
-
# TODO: deal with Hpricot seg faults on empty input
|
214
|
-
thing ? Hpricot(thing) : nil
|
215
|
-
end
|
216
|
-
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|