premailer 1.8.4 → 1.8.6
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/.travis.yml +7 -0
- data/Gemfile +2 -0
- data/README.md +1 -1
- data/lib/premailer/adapter/nokogiri.rb +14 -11
- data/lib/premailer/html_to_plain_text.rb +5 -0
- data/lib/premailer/premailer.rb +11 -4
- data/lib/premailer/version.rb +1 -1
- data/test/helper.rb +6 -6
- data/test/test_html_to_plain_text.rb +24 -12
- data/test/test_links.rb +61 -51
- data/test/test_misc.rb +42 -42
- data/test/test_premailer.rb +32 -22
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7316d27a2fa70efed484e7c64733a351491f1cea
|
4
|
+
data.tar.gz: 6dd11b25df48ce0e73149ffdc25e6702de94ec21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d5aed590607bd5cdbe7b629424c2b18832e5ee36c5688627216ea660c493edfb92a6f5d2f77e5d78b2b5cb502d2fb7f592adf3e0d624d58ced7b57ac7f6acdb
|
7
|
+
data.tar.gz: 107fb306346e6e35b146b7e327b0e2cc8cca1ded78f75687ed5281e090f08d50e7a9625335fbaffe066496e0c72f121b3389779751933900b7aec356d8b86791
|
data/.travis.yml
CHANGED
@@ -6,10 +6,13 @@ rvm:
|
|
6
6
|
- 1.9.3
|
7
7
|
- 2.0.0
|
8
8
|
- 2.1.0
|
9
|
+
- 2.2.0
|
9
10
|
- ree
|
10
11
|
gemfile:
|
11
12
|
- Gemfile
|
12
13
|
- gemfiles/.ruby187.gemfile
|
14
|
+
before_install:
|
15
|
+
- gem install bundler
|
13
16
|
env:
|
14
17
|
global:
|
15
18
|
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
|
@@ -23,5 +26,9 @@ matrix:
|
|
23
26
|
gemfile: gemfiles/.ruby187.gemfile
|
24
27
|
- rvm: 2.0.0
|
25
28
|
gemfile: gemfiles/.ruby187.gemfile
|
29
|
+
- rvm: 2.1.0
|
30
|
+
gemfile: gemfiles/.ruby187.gemfile
|
31
|
+
- rvm: 2.2.0
|
32
|
+
gemfile: gemfiles/.ruby187.gemfile
|
26
33
|
- rvm: ree
|
27
34
|
gemfile: Gemfile
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -54,7 +54,7 @@ end
|
|
54
54
|
|
55
55
|
## Ruby Compatibility
|
56
56
|
|
57
|
-
Premailer is tested on Ruby 1.8.7, Ruby 1.9.2, Ruby 1.9.3, and Ruby 2.
|
57
|
+
Premailer is tested on Ruby 1.8.7, Ruby 1.9.2, Ruby 1.9.3, and Ruby 2.x.0 . It also works on REE. JRuby support is close; contributors are welcome. Checkout the latest build status on the [Travis CI dashboard](http://travis-ci.org/#!/premailer/premailer).
|
58
58
|
|
59
59
|
## Premailer-specific CSS
|
60
60
|
|
@@ -21,10 +21,10 @@ class Premailer
|
|
21
21
|
# Iterate through the rules and merge them into the HTML
|
22
22
|
@css_parser.each_selector(:all) do |selector, declaration, specificity, media_types|
|
23
23
|
# Save un-mergable rules separately
|
24
|
-
selector.gsub!(/:link([\s]*)+/i) {|m| $1 }
|
24
|
+
selector.gsub!(/:link([\s]*)+/i) { |m| $1 }
|
25
25
|
|
26
26
|
# Convert element names to lower case
|
27
|
-
selector.gsub!(/([\s]|^)([\w]+)/) {|m| $1.to_s + $2.to_s.downcase }
|
27
|
+
selector.gsub!(/([\s]|^)([\w]+)/) { |m| $1.to_s + $2.to_s.downcase }
|
28
28
|
|
29
29
|
if Premailer.is_media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
|
30
30
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
|
@@ -33,7 +33,7 @@ class Premailer
|
|
33
33
|
if selector =~ Premailer::RE_RESET_SELECTORS
|
34
34
|
# this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
|
35
35
|
# however, this doesn't mean for testing pur
|
36
|
-
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration))
|
36
|
+
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
|
37
37
|
end
|
38
38
|
|
39
39
|
# Change single ID CSS selectors into xpath so that we can match more
|
@@ -47,7 +47,7 @@ class Premailer
|
|
47
47
|
el['style'] = (el.attributes['style'].to_s ||= '') + ' ' + block
|
48
48
|
end
|
49
49
|
end
|
50
|
-
rescue
|
50
|
+
rescue ::Nokogiri::SyntaxError, RuntimeError, ArgumentError
|
51
51
|
$stderr.puts "CSS syntax error with selector: #{selector}" if @options[:verbose]
|
52
52
|
next
|
53
53
|
end
|
@@ -76,7 +76,7 @@ class Premailer
|
|
76
76
|
# Duplicate CSS attributes as HTML attributes
|
77
77
|
if Premailer::RELATED_ATTRIBUTES.has_key?(el.name)
|
78
78
|
Premailer::RELATED_ATTRIBUTES[el.name].each do |css_att, html_att|
|
79
|
-
el[html_att] = merged[css_att].gsub(/url\('(.*)'\)/,'\1').gsub(/;$|\s*!important/, '').strip if el[html_att].nil? and not merged[css_att].empty?
|
79
|
+
el[html_att] = merged[css_att].gsub(/url\(['|"](.*)['|"]\)/, '\1').gsub(/;$|\s*!important/, '').strip if el[html_att].nil? and not merged[css_att].empty?
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
@@ -84,7 +84,9 @@ class Premailer
|
|
84
84
|
merged.create_shorthand!
|
85
85
|
|
86
86
|
# write the inline STYLE attribute
|
87
|
-
|
87
|
+
attributes = Premailer.escape_string(merged.declarations_to_s).split(';').map(&:strip)
|
88
|
+
attributes = attributes.map { |attr| [attr.split(':').first, attr] }.sort_by { |pair| pair.first }.map { |pair| pair[1] }
|
89
|
+
el['style'] = attributes.join('; ')
|
88
90
|
end
|
89
91
|
|
90
92
|
doc = write_unmergable_css_rules(doc, @unmergable_rules)
|
@@ -144,7 +146,7 @@ class Premailer
|
|
144
146
|
|
145
147
|
unless styles.empty?
|
146
148
|
style_tag = "<style type=\"text/css\">\n#{styles}</style>"
|
147
|
-
|
149
|
+
unless (body = doc.search('body')).empty?
|
148
150
|
if doc.at_css('body').children && !doc.at_css('body').children.empty?
|
149
151
|
doc.at_css('body').children.before(::Nokogiri::XML.fragment(style_tag))
|
150
152
|
else
|
@@ -167,7 +169,8 @@ class Premailer
|
|
167
169
|
html_src = ''
|
168
170
|
begin
|
169
171
|
html_src = @doc.at("body").inner_html
|
170
|
-
rescue;
|
172
|
+
rescue;
|
173
|
+
end
|
171
174
|
|
172
175
|
html_src = @doc.to_html unless html_src and not html_src.empty?
|
173
176
|
convert_to_text(html_src, @options[:line_length], @html_encoding)
|
@@ -213,13 +216,13 @@ class Premailer
|
|
213
216
|
end
|
214
217
|
end
|
215
218
|
# Default encoding is ASCII-8BIT (binary) per http://groups.google.com/group/nokogiri-talk/msg/0b81ef0dc180dc74
|
216
|
-
# However, we really don't want to hardcode this. ASCII-
|
219
|
+
# However, we really don't want to hardcode this. ASCII-8BIT should be the default, but not the only option.
|
217
220
|
if thing.is_a?(String) and RUBY_VERSION =~ /1.9/
|
218
221
|
thing = thing.force_encoding(@options[:input_encoding]).encode!
|
219
|
-
doc = ::Nokogiri::HTML(thing, nil, @options[:input_encoding]) {|c| c.recover }
|
222
|
+
doc = ::Nokogiri::HTML(thing, nil, @options[:input_encoding]) { |c| c.recover }
|
220
223
|
else
|
221
224
|
default_encoding = RUBY_PLATFORM == 'java' ? nil : 'BINARY'
|
222
|
-
doc = ::Nokogiri::HTML(thing, nil, @options[:input_encoding] || default_encoding) {|c| c.recover }
|
225
|
+
doc = ::Nokogiri::HTML(thing, nil, @options[:input_encoding] || default_encoding) { |c| c.recover }
|
223
226
|
end
|
224
227
|
|
225
228
|
# Fix for removing any CDATA tags from both style and script tags inserted per
|
@@ -10,6 +10,11 @@ module HtmlToPlainText
|
|
10
10
|
def convert_to_text(html, line_length = 65, from_charset = 'UTF-8')
|
11
11
|
txt = html
|
12
12
|
|
13
|
+
# strip text ignored html. Useful for removing
|
14
|
+
# headers and footers that aren't needed in the
|
15
|
+
# text version
|
16
|
+
txt.gsub!(/<!-- start text\/html -->.*?<!-- end text\/html -->/m, '')
|
17
|
+
|
13
18
|
# replace images with their alt attributes
|
14
19
|
# for img tags with "" for attribute quotes
|
15
20
|
# with or without closing tag
|
data/lib/premailer/premailer.rb
CHANGED
@@ -74,12 +74,13 @@ class Premailer
|
|
74
74
|
'blockquote' => {'text-align' => 'align'},
|
75
75
|
'body' => {'background-color' => 'bgcolor'},
|
76
76
|
'table' => {
|
77
|
+
'-premailer-align' => 'align',
|
77
78
|
'background-color' => 'bgcolor',
|
78
79
|
'background-image' => 'background',
|
79
80
|
'-premailer-width' => 'width',
|
80
81
|
'-premailer-height' => 'height',
|
81
82
|
'-premailer-cellpadding' => 'cellpadding',
|
82
|
-
'-premailer-cellspacing' => 'cellspacing'
|
83
|
+
'-premailer-cellspacing' => 'cellspacing'
|
83
84
|
},
|
84
85
|
'tr' => {
|
85
86
|
'text-align' => 'align',
|
@@ -100,7 +101,11 @@ class Premailer
|
|
100
101
|
'-premailer-width' => 'width',
|
101
102
|
'-premailer-height' => 'height'
|
102
103
|
},
|
103
|
-
'img' => {
|
104
|
+
'img' => {
|
105
|
+
'float' => 'align',
|
106
|
+
'-premailer-width' => 'width',
|
107
|
+
'-premailer-height' => 'height'
|
108
|
+
}
|
104
109
|
}
|
105
110
|
|
106
111
|
# URI of the HTML file used
|
@@ -193,6 +198,7 @@ class Premailer
|
|
193
198
|
:output_encoding => nil,
|
194
199
|
:replace_html_entities => false,
|
195
200
|
:escape_url_attributes => true,
|
201
|
+
:unescaped_ampersand => false,
|
196
202
|
:adapter => Adapter.use,
|
197
203
|
}.merge(options)
|
198
204
|
|
@@ -289,7 +295,7 @@ protected
|
|
289
295
|
|
290
296
|
if tag.attributes['href'].to_s.include? @base_url.to_s and @html_file.kind_of?(String)
|
291
297
|
if @options[:with_html_string]
|
292
|
-
link_uri = tag.attributes['href'].to_s.sub(@base_url.to_s, '')
|
298
|
+
link_uri = tag.attributes['href'].to_s.sub(@base_url.to_s, '')
|
293
299
|
else
|
294
300
|
link_uri = File.join(File.dirname(@html_file), tag.attributes['href'].to_s.sub!(@base_url.to_s, ''))
|
295
301
|
# if the file does not exist locally, try to grab the remote reference
|
@@ -371,7 +377,8 @@ public
|
|
371
377
|
end
|
372
378
|
|
373
379
|
if href.query and not href.query.empty?
|
374
|
-
|
380
|
+
amp = @options[:unescaped_ampersand] ? '&' : '&'
|
381
|
+
href.query = href.query + amp + qs
|
375
382
|
else
|
376
383
|
href.query = qs
|
377
384
|
end
|
data/lib/premailer/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -11,9 +11,9 @@ class Premailer::TestCase < Test::Unit::TestCase
|
|
11
11
|
BASE_PATH = File.expand_path(File.dirname(__FILE__)) + '/files'
|
12
12
|
|
13
13
|
def setup
|
14
|
-
stub_request(:any, /premailer\.dev\/*/).to_return do |request|
|
14
|
+
stub_request(:any, /premailer\.dev\/*/).to_return do |request|
|
15
15
|
file_path = BASE_PATH + URI.parse(request.uri).path
|
16
|
-
if File.exists?(file_path)
|
16
|
+
if File.exists?(file_path)
|
17
17
|
{ :status => 200, :body => File.open(file_path) }
|
18
18
|
else
|
19
19
|
{ :status => 404, :body => "#{file_path} not found" }
|
@@ -22,17 +22,17 @@ class Premailer::TestCase < Test::Unit::TestCase
|
|
22
22
|
|
23
23
|
stub_request(:get, /my\.example\.com\:8080\/*/).to_return(:status => 200, :body => "", :headers => {})
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def default_test; end
|
27
|
-
|
28
|
-
protected
|
27
|
+
|
28
|
+
protected
|
29
29
|
def local_setup(f = 'base.html', opts = {})
|
30
30
|
base_file = BASE_PATH + '/' + f
|
31
31
|
premailer = Premailer.new(base_file, opts)
|
32
32
|
premailer.to_inline_css
|
33
33
|
@doc = premailer.processed_doc
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def remote_setup(f = 'base.html', opts = {})
|
37
37
|
@premailer = Premailer.new(BASE_URI + "#{f}", opts)
|
38
38
|
@premailer.to_inline_css
|
@@ -69,11 +69,23 @@ END_HTML
|
|
69
69
|
assert_plaintext "* item 1\n* item 2", "<li class='123'>item 1</li> <li>item 2</li>\n"
|
70
70
|
assert_plaintext "* item 1\n* item 2\n* item 3", "<li>item 1</li> \t\n <li>item 2</li> <li> item 3</li>\n"
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
def test_stripping_html
|
74
74
|
assert_plaintext 'test text', "<p class=\"123'45 , att\" att=tester>test <span class='te\"st'>text</span>\n"
|
75
75
|
end
|
76
76
|
|
77
|
+
def test_stripping_ignored_blocks
|
78
|
+
html = <<END_HTML
|
79
|
+
<p>test</p>
|
80
|
+
<!-- start text/html -->
|
81
|
+
<img src="logo.png" alt="logo">
|
82
|
+
<!-- end text/html -->
|
83
|
+
<p>text</p>
|
84
|
+
END_HTML
|
85
|
+
premailer = Premailer.new(html, :with_html_string => true)
|
86
|
+
assert_match /test\n\ntext/, premailer.to_plain_text
|
87
|
+
end
|
88
|
+
|
77
89
|
def test_paragraphs_and_breaks
|
78
90
|
assert_plaintext "Test text\n\nTest text", "<p>Test text</p><p>Test text</p>"
|
79
91
|
assert_plaintext "Test text\n\nTest text", "\n<p>Test text</p>\n\n\n\t<p>Test text</p>\n"
|
@@ -81,7 +93,7 @@ END_HTML
|
|
81
93
|
assert_plaintext "Test text\nTest text", "\n<p>Test text<br> \tTest text<br></p>\n"
|
82
94
|
assert_plaintext "Test text\n\nTest text", "Test text<br><BR />Test text"
|
83
95
|
end
|
84
|
-
|
96
|
+
|
85
97
|
def test_headings
|
86
98
|
assert_plaintext "****\nTest\n****", "<h1>Test</h1>"
|
87
99
|
assert_plaintext "****\nTest\n****", "\t<h1>\nTest</h1> "
|
@@ -90,7 +102,7 @@ END_HTML
|
|
90
102
|
assert_plaintext "----\nTest\n----", "<h2>Test</h2>"
|
91
103
|
assert_plaintext "Test\n----", "<h3> <span class='a'>Test </span></h3>"
|
92
104
|
end
|
93
|
-
|
105
|
+
|
94
106
|
def test_wrapping_lines
|
95
107
|
raw = ''
|
96
108
|
100.times { raw += 'test ' }
|
@@ -103,7 +115,7 @@ END_HTML
|
|
103
115
|
end
|
104
116
|
|
105
117
|
def test_img_alt_tags
|
106
|
-
# ensure html imag tags that aren't self-closed are parsed,
|
118
|
+
# ensure html imag tags that aren't self-closed are parsed,
|
107
119
|
# along with accepting both '' and "" as attribute quotes
|
108
120
|
|
109
121
|
# <img alt="" />
|
@@ -119,7 +131,7 @@ END_HTML
|
|
119
131
|
def test_links
|
120
132
|
# basic
|
121
133
|
assert_plaintext 'Link ( http://example.com/ )', '<a href="http://example.com/">Link</a>'
|
122
|
-
|
134
|
+
|
123
135
|
# nested html
|
124
136
|
assert_plaintext 'Link ( http://example.com/ )', '<a href="http://example.com/"><span class="a">Link</span></a>'
|
125
137
|
|
@@ -131,13 +143,13 @@ END_HTML
|
|
131
143
|
|
132
144
|
# complex link
|
133
145
|
assert_plaintext 'Link ( http://example.com:80/~user?aaa=bb&c=d,e,f#foo )', '<a href="http://example.com:80/~user?aaa=bb&c=d,e,f#foo">Link</a>'
|
134
|
-
|
146
|
+
|
135
147
|
# attributes
|
136
148
|
assert_plaintext 'Link ( http://example.com/ )', '<a title=\'title\' href="http://example.com/">Link</a>'
|
137
|
-
|
149
|
+
|
138
150
|
# spacing
|
139
151
|
assert_plaintext 'Link ( http://example.com/ )', '<a href=" http://example.com/ "> Link </a>'
|
140
|
-
|
152
|
+
|
141
153
|
# multiple
|
142
154
|
assert_plaintext 'Link A ( http://example.com/a/ ) Link B ( http://example.com/b/ )', '<a href="http://example.com/a/">Link A</a> <a href="http://example.com/b/">Link B</a>'
|
143
155
|
|
@@ -145,24 +157,24 @@ END_HTML
|
|
145
157
|
assert_plaintext 'Link ( %%LINK%% )', '<a href="%%LINK%%">Link</a>'
|
146
158
|
assert_plaintext 'Link ( [LINK] )', '<a href="[LINK]">Link</a>'
|
147
159
|
assert_plaintext 'Link ( {LINK} )', '<a href="{LINK}">Link</a>'
|
148
|
-
|
160
|
+
|
149
161
|
# unsubscribe
|
150
162
|
assert_plaintext 'Link ( [[!unsubscribe]] )', '<a href="[[!unsubscribe]]">Link</a>'
|
151
163
|
|
152
164
|
# empty link gets dropped, and shouldn't run forever
|
153
165
|
assert_plaintext(("This is some more text\n\n" * 14 + "This is some more text"), "<a href=\"test\"></a>#{"\n<p>This is some more text</p>" * 15}")
|
154
166
|
end
|
155
|
-
|
167
|
+
|
156
168
|
# see https://github.com/alexdunae/premailer/issues/72
|
157
169
|
def test_multiple_links_per_line
|
158
|
-
assert_plaintext 'This is link1 ( http://www.google.com ) and link2 ( http://www.google.com ) is next.',
|
170
|
+
assert_plaintext 'This is link1 ( http://www.google.com ) and link2 ( http://www.google.com ) is next.',
|
159
171
|
'<p>This is <a href="http://www.google.com" >link1</a> and <a href="http://www.google.com" >link2 </a> is next.</p>',
|
160
172
|
nil, 10000
|
161
173
|
end
|
162
174
|
|
163
175
|
# see https://github.com/alexdunae/premailer/issues/72
|
164
176
|
def test_links_within_headings
|
165
|
-
assert_plaintext "****************************\nTest ( http://example.com/ )\n****************************",
|
177
|
+
assert_plaintext "****************************\nTest ( http://example.com/ )\n****************************",
|
166
178
|
"<h1><a href='http://example.com/'>Test</a></h1>"
|
167
179
|
end
|
168
180
|
|
data/test/test_links.rb
CHANGED
@@ -12,36 +12,36 @@ class TestLinks < Premailer::TestCase
|
|
12
12
|
def test_appending_link_query_string
|
13
13
|
qs = 'utm_source=1234&tracking=good&doublescape'
|
14
14
|
opts = {:base_url => 'http://example.com/', :link_query_string => qs, :with_html_string => true, :adapter => :hpricot}
|
15
|
-
|
15
|
+
|
16
16
|
appendable = [
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
'/',
|
18
|
+
opts[:base_url],
|
19
|
+
'https://example.com/tester',
|
20
|
+
'images/',
|
21
|
+
"#{opts[:base_url]}test.html?cn=tf&c=20&ord=random",
|
22
|
+
'?query=string'
|
23
23
|
]
|
24
|
-
|
24
|
+
|
25
25
|
not_appendable = [
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
26
|
+
'%DONOTCONVERT%',
|
27
|
+
'{DONOTCONVERT}',
|
28
|
+
'[DONOTCONVERT]',
|
29
|
+
'<DONOTCONVERT>',
|
30
|
+
'{@msg-txturl}',
|
31
|
+
'[[!unsubscribe]]',
|
32
|
+
'#relative',
|
33
|
+
'tel:5555551212',
|
34
|
+
'http://example.net/',
|
35
|
+
'mailto:premailer@example.com',
|
36
|
+
'ftp://example.com',
|
37
|
+
'gopher://gopher.floodgap.com/1/fun/twitpher'
|
38
38
|
]
|
39
|
-
|
39
|
+
|
40
40
|
html = appendable.collect {|url| "<a href='#{url}'>Link</a>" }
|
41
41
|
|
42
42
|
premailer = Premailer.new(html.to_s, opts)
|
43
43
|
premailer.to_inline_css
|
44
|
-
|
44
|
+
|
45
45
|
premailer.processed_doc.search('a').each do |el|
|
46
46
|
href = el.attributes['href'].to_s
|
47
47
|
next if href.nil? or href.empty?
|
@@ -53,7 +53,7 @@ class TestLinks < Premailer::TestCase
|
|
53
53
|
|
54
54
|
premailer = Premailer.new(html.to_s, opts)
|
55
55
|
premailer.to_inline_css
|
56
|
-
|
56
|
+
|
57
57
|
premailer.processed_doc.search('a').each do |el|
|
58
58
|
href = el['href']
|
59
59
|
next if href.nil? or href.empty?
|
@@ -66,35 +66,45 @@ class TestLinks < Premailer::TestCase
|
|
66
66
|
|
67
67
|
premailer = Premailer.new("<a href='/test/?'>Link</a> <a href='/test/'>Link</a>", :link_query_string => qs, :with_html_string => true)
|
68
68
|
premailer.to_inline_css
|
69
|
-
|
69
|
+
|
70
70
|
premailer.processed_doc.search('a').each do |a|
|
71
71
|
assert_equal '/test/?utm_source=1234', a['href'].to_s
|
72
72
|
end
|
73
73
|
|
74
74
|
premailer = Premailer.new("<a href='/test/?123&456'>Link</a>", :link_query_string => qs, :with_html_string => true)
|
75
75
|
premailer.to_inline_css
|
76
|
-
|
76
|
+
|
77
77
|
assert_equal '/test/?123&456&utm_source=1234', premailer.processed_doc.at('a')['href']
|
78
78
|
end
|
79
79
|
|
80
|
+
def test_unescape_ampersand
|
81
|
+
qs = 'utm_source=1234'
|
82
|
+
|
83
|
+
premailer = Premailer.new("<a href='/test/?q=query'>Link</a>", :link_query_string => qs, :with_html_string => true, :unescaped_ampersand => true)
|
84
|
+
premailer.to_inline_css
|
85
|
+
|
86
|
+
premailer.processed_doc.search('a').each do |a|
|
87
|
+
assert_equal '/test/?q=query&utm_source=1234', a['href'].to_s
|
88
|
+
end
|
89
|
+
end
|
80
90
|
|
81
91
|
def test_preserving_links
|
82
92
|
html = "<a href='http://example.com/index.php?pram1=one&pram2=two'>Link</a>"
|
83
93
|
premailer = Premailer.new(html.to_s, :link_query_string => '', :with_html_string => true)
|
84
94
|
premailer.to_inline_css
|
85
|
-
|
95
|
+
|
86
96
|
assert_equal 'http://example.com/index.php?pram1=one&pram2=two', premailer.processed_doc.at('a')['href']
|
87
97
|
|
88
98
|
html = "<a href='http://example.com/index.php?pram1=one&pram2=two'>Link</a>"
|
89
99
|
premailer = Premailer.new(html.to_s, :link_query_string => 'qs', :with_html_string => true)
|
90
100
|
premailer.to_inline_css
|
91
|
-
|
101
|
+
|
92
102
|
assert_equal 'http://example.com/index.php?pram1=one&pram2=two&qs', premailer.processed_doc.at('a')['href']
|
93
103
|
|
94
104
|
end
|
95
105
|
|
96
106
|
def test_resolving_urls_from_string
|
97
|
-
['test.html', '/test.html', './test.html',
|
107
|
+
['test.html', '/test.html', './test.html',
|
98
108
|
'test/../test.html', 'test/../test/../test.html'].each do |q|
|
99
109
|
assert_equal 'http://example.com/test.html', Premailer.resolve_link(q, 'http://example.com/'), q
|
100
110
|
end
|
@@ -104,18 +114,18 @@ class TestLinks < Premailer::TestCase
|
|
104
114
|
|
105
115
|
def test_resolving_urls_from_uri
|
106
116
|
base_uri = URI.parse('http://example.com/')
|
107
|
-
['test.html', '/test.html', './test.html',
|
117
|
+
['test.html', '/test.html', './test.html',
|
108
118
|
'test/../test.html', 'test/../test/../test.html'].each do |q|
|
109
119
|
assert_equal 'http://example.com/test.html', Premailer.resolve_link(q, base_uri), q
|
110
120
|
end
|
111
121
|
|
112
122
|
base_uri = URI.parse('https://example.net:80/~basedir/')
|
113
123
|
assert_equal 'https://example.net:80/~basedir/test.html?var=1#anchor', Premailer.resolve_link('test/../test/../test.html?var=1#anchor', base_uri)
|
114
|
-
|
124
|
+
|
115
125
|
# base URI with a query string
|
116
126
|
base_uri = URI.parse('http://example.com/dir/index.cfm?newsletterID=16')
|
117
127
|
assert_equal 'http://example.com/dir/index.cfm?link=15', Premailer.resolve_link('?link=15', base_uri)
|
118
|
-
|
128
|
+
|
119
129
|
# URI preceded by a space
|
120
130
|
base_uri = URI.parse('http://example.com/')
|
121
131
|
assert_equal 'http://example.com/path', Premailer.resolve_link(' path', base_uri)
|
@@ -143,25 +153,25 @@ class TestLinks < Premailer::TestCase
|
|
143
153
|
doc = premailer.doc
|
144
154
|
|
145
155
|
# unchanged links
|
146
|
-
['#l02', '#l03', '#l05', '#l06', '#l07', '#l08',
|
156
|
+
['#l02', '#l03', '#l05', '#l06', '#l07', '#l08',
|
147
157
|
'#l09', '#l10', '#l11', '#l12', '#l13'].each do |link_id|
|
148
158
|
assert_equal doc.at(link_id).attributes['href'], pdoc.at(link_id).attributes['href'], link_id
|
149
159
|
end
|
150
|
-
|
160
|
+
|
151
161
|
assert_equal 'https://my.example.com:8080/', pdoc.at('#l01').attributes['href'].to_s
|
152
162
|
assert_equal 'https://my.example.com:8080/images/', pdoc.at('#l04').attributes['href'].to_s
|
153
163
|
end
|
154
164
|
|
155
165
|
def test_convertable_inline_links
|
156
166
|
convertable = [
|
157
|
-
|
158
|
-
|
159
|
-
|
167
|
+
'my/path/to',
|
168
|
+
'other/path',
|
169
|
+
'/'
|
160
170
|
]
|
161
171
|
|
162
172
|
html = convertable.collect {|url| "<a href='#{url}'>Link</a>" }
|
163
173
|
premailer = Premailer.new(html.to_s, :base_url => "http://example.com", :with_html_string => true)
|
164
|
-
|
174
|
+
|
165
175
|
premailer.processed_doc.search('a').each do |el|
|
166
176
|
href = el.attributes['href'].to_s
|
167
177
|
assert(href =~ /http:\/\/example.com/, "link #{href} is not absolute")
|
@@ -170,25 +180,25 @@ class TestLinks < Premailer::TestCase
|
|
170
180
|
|
171
181
|
def test_non_convertable_inline_links
|
172
182
|
not_convertable = [
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
183
|
+
'%DONOTCONVERT%',
|
184
|
+
'{DONOTCONVERT}',
|
185
|
+
'[DONOTCONVERT]',
|
186
|
+
'<DONOTCONVERT>',
|
187
|
+
'{@msg-txturl}',
|
188
|
+
'[[!unsubscribe]]',
|
189
|
+
'#relative',
|
190
|
+
'tel:5555551212',
|
191
|
+
'mailto:premailer@example.com',
|
192
|
+
'ftp://example.com',
|
193
|
+
'gopher://gopher.floodgap.com/1/fun/twitpher',
|
194
|
+
'cid:13443452066.10392logo.jpeg@inline_attachment'
|
185
195
|
]
|
186
|
-
|
196
|
+
|
187
197
|
html = not_convertable.collect {|url| "<a href='#{url}'>Link</a>" }
|
188
198
|
|
189
199
|
premailer = Premailer.new(html.to_s, :base_url => "example.com", :with_html_string => true)
|
190
200
|
premailer.to_inline_css
|
191
|
-
|
201
|
+
|
192
202
|
premailer.processed_doc.search('a').each do |el|
|
193
203
|
href = el.attributes['href'].to_s
|
194
204
|
assert not_convertable.include?(href), "link #{href} should not be converted: see #{not_convertable.inspect}"
|
data/test/test_misc.rb
CHANGED
@@ -28,10 +28,10 @@ class TestMisc < Premailer::TestCase
|
|
28
28
|
</html>
|
29
29
|
END_HTML
|
30
30
|
|
31
|
-
|
32
|
-
|
31
|
+
premailer = Premailer.new(html, :with_html_string => true)
|
32
|
+
premailer.to_inline_css
|
33
33
|
|
34
|
-
|
34
|
+
assert_match /color\: red/i, premailer.processed_doc.at('p')['style']
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_commented_out_styles_in_the_body
|
@@ -44,10 +44,10 @@ END_HTML
|
|
44
44
|
</html>
|
45
45
|
END_HTML
|
46
46
|
|
47
|
-
|
48
|
-
|
47
|
+
premailer = Premailer.new(html, :with_html_string => true)
|
48
|
+
premailer.to_inline_css
|
49
49
|
|
50
|
-
|
50
|
+
assert_match /color\: red/i, premailer.processed_doc.at('p')['style']
|
51
51
|
end
|
52
52
|
|
53
53
|
def test_not_applying_styles_to_the_head
|
@@ -64,14 +64,14 @@ END_HTML
|
|
64
64
|
END_HTML
|
65
65
|
|
66
66
|
[:nokogiri, :hpricot].each do |adapter|
|
67
|
-
|
68
|
-
|
67
|
+
premailer = Premailer.new(html, :with_html_string => true, :adapter => adapter)
|
68
|
+
premailer.to_inline_css
|
69
69
|
|
70
|
-
|
71
|
-
|
70
|
+
h = premailer.processed_doc.at('head')
|
71
|
+
assert_nil h['style']
|
72
72
|
|
73
|
-
|
74
|
-
|
73
|
+
t = premailer.processed_doc.at('title')
|
74
|
+
assert_nil t['style']
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
@@ -88,8 +88,8 @@ END_HTML
|
|
88
88
|
</html>
|
89
89
|
END_HTML
|
90
90
|
|
91
|
-
|
92
|
-
|
91
|
+
premailer = Premailer.new(html, :with_html_string => true)
|
92
|
+
premailer.to_inline_css
|
93
93
|
premailer.processed_doc.search('p').each do |el|
|
94
94
|
assert_match /red/i, el['style']
|
95
95
|
end
|
@@ -108,22 +108,22 @@ END_HTML
|
|
108
108
|
</html>
|
109
109
|
END_HTML
|
110
110
|
[:nokogiri, :hpricot].each do |adapter|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
111
|
+
premailer = Premailer.new(html, :with_html_string => true, :preserve_styles => true, :adapter => adapter)
|
112
|
+
premailer.to_inline_css
|
113
|
+
assert_equal 1, premailer.processed_doc.search('head link').length
|
114
|
+
assert_equal 1, premailer.processed_doc.search('head style').length
|
115
115
|
|
116
|
-
|
117
|
-
|
118
|
-
|
116
|
+
premailer = Premailer.new(html, :with_html_string => true, :preserve_styles => false, :adapter => adapter)
|
117
|
+
premailer.to_inline_css
|
118
|
+
assert_nil premailer.processed_doc.at('body link')
|
119
119
|
|
120
120
|
# should be preserved as unmergeable
|
121
121
|
|
122
|
-
|
122
|
+
assert_match /color: red/i, premailer.processed_doc.at('body style').inner_html
|
123
123
|
|
124
|
-
|
124
|
+
assert_match /a:hover/i, premailer.processed_doc.at('style').inner_html
|
125
125
|
|
126
|
-
|
126
|
+
end
|
127
127
|
end
|
128
128
|
|
129
129
|
def test_unmergable_rules
|
@@ -133,13 +133,13 @@ END_HTML
|
|
133
133
|
</body> </html>
|
134
134
|
END_HTML
|
135
135
|
|
136
|
-
|
137
|
-
|
136
|
+
premailer = Premailer.new(html, :with_html_string => true, :verbose => true)
|
137
|
+
premailer.to_inline_css
|
138
138
|
|
139
139
|
# blue should be inlined
|
140
|
-
|
140
|
+
assert_no_match /a\:hover[\s]*\{[\s]*color\:[\s]*blue[\s]*;[\s]*\}/i, premailer.processed_doc.at('body style').inner_html
|
141
141
|
# red should remain in <style> block
|
142
|
-
|
142
|
+
assert_match /a\:hover[\s]*\{[\s]*color\:[\s]*red;[\s]*\}/i, premailer.processed_doc.at('body style').inner_html
|
143
143
|
end
|
144
144
|
|
145
145
|
def test_unmergable_media_queries
|
@@ -188,11 +188,11 @@ END_HTML
|
|
188
188
|
</html>
|
189
189
|
END_HTML
|
190
190
|
|
191
|
-
|
191
|
+
premailer = Premailer.new(html, :with_html_string => true)
|
192
192
|
assert_nothing_raised do
|
193
|
-
|
194
|
-
|
195
|
-
|
193
|
+
premailer.to_inline_css
|
194
|
+
end
|
195
|
+
assert_match /a\:hover[\s]*\{[\s]*color\:[\s]*red;[\s]*\}/i, premailer.processed_doc.at('style').inner_html
|
196
196
|
end
|
197
197
|
|
198
198
|
# in response to https://github.com/alexdunae/premailer/issues#issue/7
|
@@ -206,11 +206,11 @@ END_HTML
|
|
206
206
|
</html>
|
207
207
|
END_HTML
|
208
208
|
|
209
|
-
|
209
|
+
premailer = Premailer.new(html, :with_html_string => true)
|
210
210
|
assert_nothing_raised do
|
211
|
-
|
212
|
-
|
213
|
-
|
211
|
+
premailer.to_inline_css
|
212
|
+
end
|
213
|
+
assert_match /color: red/, premailer.processed_doc.at('a').attributes['style'].to_s
|
214
214
|
end
|
215
215
|
|
216
216
|
# in response to https://github.com/alexdunae/premailer/issues#issue/7
|
@@ -234,10 +234,10 @@ END_HTML
|
|
234
234
|
</tr>
|
235
235
|
END_HTML
|
236
236
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
237
|
+
premailer = Premailer.new(html, :with_html_string => true)
|
238
|
+
premailer.to_inline_css
|
239
|
+
assert_match /font-size: xx-large/, premailer.processed_doc.search('.style3').first.attributes['style'].to_s
|
240
|
+
assert_match /background: #000080/, premailer.processed_doc.search('.style5').first.attributes['style'].to_s
|
241
241
|
end
|
242
242
|
|
243
243
|
# in response to https://github.com/alexdunae/premailer/issues/56
|
@@ -254,7 +254,7 @@ END_HTML
|
|
254
254
|
END_HTML
|
255
255
|
|
256
256
|
premailer = Premailer.new(html, :with_html_string => true, :adapter => :nokogiri)
|
257
|
-
|
257
|
+
premailer.to_inline_css
|
258
258
|
assert_equal 'color: green !important', premailer.processed_doc.search('p').first.attributes['style'].to_s
|
259
259
|
end
|
260
260
|
|
@@ -274,7 +274,7 @@ END_HTML
|
|
274
274
|
END_HTML
|
275
275
|
|
276
276
|
premailer = Premailer.new(html, :with_html_string => true)
|
277
|
-
|
277
|
+
premailer.to_inline_css
|
278
278
|
|
279
279
|
assert_match /margin: 0 auto/, premailer.processed_doc.search('#page').first.attributes['style'].to_s
|
280
280
|
assert_match /border-style: solid none solid solid;/, premailer.processed_doc.search('p').first.attributes['style'].to_s
|
data/test/test_premailer.rb
CHANGED
@@ -6,13 +6,13 @@ class TestPremailer < Premailer::TestCase
|
|
6
6
|
def test_special_characters_nokogiri
|
7
7
|
html = '<p>cédille cé & garçon garçon à à & ©</p>'
|
8
8
|
premailer = Premailer.new(html, :with_html_string => true, :adapter => :nokogiri)
|
9
|
-
|
9
|
+
premailer.to_inline_css
|
10
10
|
assert_equal 'cédille cé & garçon garçon à à & ©', premailer.processed_doc.at('p').inner_html
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_special_characters_nokogiri_remote
|
14
14
|
remote_setup('chars.html', :adapter => :nokogiri)
|
15
|
-
|
15
|
+
@premailer.to_inline_css
|
16
16
|
assert_equal 'cédille cé & garçon garçon à à & ©', @premailer.processed_doc.at('p').inner_html
|
17
17
|
end
|
18
18
|
|
@@ -29,7 +29,7 @@ class TestPremailer < Premailer::TestCase
|
|
29
29
|
def test_special_characters_hpricot
|
30
30
|
html = '<p>cédille cé & garçon garçon à à &</p>'
|
31
31
|
premailer = Premailer.new(html, :with_html_string => true, :adapter => :hpricot)
|
32
|
-
|
32
|
+
premailer.to_inline_css
|
33
33
|
assert_equal 'cédille cé & garçon garçon à à &', premailer.processed_doc.at('p').inner_html
|
34
34
|
end
|
35
35
|
|
@@ -73,10 +73,10 @@ END_HTML
|
|
73
73
|
qs = 'testing=123'
|
74
74
|
|
75
75
|
[:nokogiri, :hpricot].each do |adapter|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
76
|
+
premailer = Premailer.new(html, :with_html_string => true, :link_query_string => qs, :adapter => adapter)
|
77
|
+
premailer.to_inline_css
|
78
|
+
assert_no_match /testing=123/, premailer.processed_doc.search('a').first.attributes['href'].to_s
|
79
|
+
end
|
80
80
|
end
|
81
81
|
|
82
82
|
def test_escaping_strings
|
@@ -176,7 +176,7 @@ END_HTML
|
|
176
176
|
END_HTML
|
177
177
|
|
178
178
|
[:nokogiri, :hpricot].each do |adapter|
|
179
|
-
|
179
|
+
pm = Premailer.new(html, :with_html_string => true, :adapter => adapter, :escape_url_attributes => false)
|
180
180
|
pm.to_inline_css
|
181
181
|
doc = pm.processed_doc
|
182
182
|
assert_equal doc.at('#google')['href'], 'http://google.com'
|
@@ -194,14 +194,14 @@ END_HTML
|
|
194
194
|
END_HTML
|
195
195
|
|
196
196
|
[:nokogiri, :hpricot].each do |adapter|
|
197
|
-
|
197
|
+
pm = Premailer.new(html, :with_html_string => true, :remove_ids => true, :adapter => adapter)
|
198
198
|
pm.to_inline_css
|
199
199
|
doc = pm.processed_doc
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
200
|
+
assert_nil doc.at('#remove')
|
201
|
+
assert_nil doc.at('#keep')
|
202
|
+
hashed_id = doc.at('a')['href'][1..-1]
|
203
|
+
assert_not_nil doc.at("\##{hashed_id}")
|
204
|
+
end
|
205
205
|
end
|
206
206
|
|
207
207
|
def test_reset_contenteditable
|
@@ -213,12 +213,12 @@ END_HTML
|
|
213
213
|
</body> </html>
|
214
214
|
___
|
215
215
|
[:nokogiri, :hpricot].each do |adapter|
|
216
|
-
|
216
|
+
pm = Premailer.new(html, :with_html_string => true, :reset_contenteditable => true, :adapter => adapter)
|
217
217
|
pm.to_inline_css
|
218
218
|
doc = pm.processed_doc
|
219
|
-
|
220
|
-
|
221
|
-
|
219
|
+
assert_nil doc.at('#editable')['contenteditable'],
|
220
|
+
"#{adapter}: contenteditable attribute not removed"
|
221
|
+
end
|
222
222
|
end
|
223
223
|
|
224
224
|
def test_carriage_returns_as_entities
|
@@ -256,12 +256,12 @@ END_HTML
|
|
256
256
|
END_HTML
|
257
257
|
|
258
258
|
[:nokogiri, :hpricot].each do |adapter|
|
259
|
-
|
259
|
+
pm = Premailer.new(html, :with_html_string => true, :adapter => adapter)
|
260
260
|
pm.to_inline_css
|
261
261
|
doc = pm.processed_doc
|
262
|
-
|
263
|
-
|
264
|
-
|
262
|
+
assert_equal '500', doc.at('table')['width']
|
263
|
+
assert_equal '20', doc.at('td')['height']
|
264
|
+
end
|
265
265
|
end
|
266
266
|
|
267
267
|
def test_include_link_tags_option
|
@@ -334,4 +334,14 @@ END_HTML
|
|
334
334
|
end
|
335
335
|
end
|
336
336
|
|
337
|
+
def test_empty_html_nokogiri
|
338
|
+
html = ""
|
339
|
+
css = "a:hover {color:red;}"
|
340
|
+
|
341
|
+
assert_nothing_raised do
|
342
|
+
pm = Premailer.new(html, :with_html_string => true, :css_string => css, :adapter => :nokogiri)
|
343
|
+
pm.to_inline_css
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
337
347
|
end
|
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.8.
|
4
|
+
version: 1.8.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Dunae
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: css_parser
|
@@ -203,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
203
203
|
version: '0'
|
204
204
|
requirements: []
|
205
205
|
rubyforge_project:
|
206
|
-
rubygems_version: 2.4.
|
206
|
+
rubygems_version: 2.4.6
|
207
207
|
signing_key:
|
208
208
|
specification_version: 4
|
209
209
|
summary: Preflight for HTML e-mail.
|