premailer 1.9.2 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://travis-ci.org/premailer/premailer.png?branch=master)](https://travis-ci.org/premailer/premailer)
|
1
|
+
# Premailer README [![Build Status](https://travis-ci.org/premailer/premailer.png?branch=master)](https://travis-ci.org/premailer/premailer) [![Gem Version](https://badge.fury.io/rb/premailer.svg)](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
|
-
|