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