premailer 1.24.0 → 1.25.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/premailer +1 -1
- data/lib/premailer/adapter/nokogiri.rb +6 -4
- data/lib/premailer/adapter/nokogiri_fast.rb +8 -6
- data/lib/premailer/adapter/nokogumbo.rb +6 -4
- data/lib/premailer/adapter/rgb_to_hex.rb +1 -0
- data/lib/premailer/adapter.rb +4 -3
- data/lib/premailer/cached_rule_set.rb +1 -0
- data/lib/premailer/executor.rb +5 -4
- data/lib/premailer/html_to_plain_text.rb +3 -2
- data/lib/premailer/premailer.rb +19 -19
- data/lib/premailer/version.rb +2 -1
- data/lib/premailer.rb +1 -0
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d8f189b10e7c9868d3abeae3d057e0b0681bb7798c0fbd7e8fe3aa8bb922aad
|
4
|
+
data.tar.gz: e0dbb8d0d65aeb0ec7e463983148b1c54f77fa005fd73766a749ee147a12d240
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 650e617eefd069d1733092612fa4eb434b539564f61f81fcbda4c7a06121fc3d8a71ee440ce5dfee3e0f97f88282e4dcd1da6c33bddcd4008d05f0ebb4aa82a6
|
7
|
+
data.tar.gz: c537248adafbc5f6ed58f8825055fe557098c1bea88240c4ec08d5d248268fb3f45db365cf08912a693dd963abe0825f942f5b5937553ceeacd54a51f1f44f21
|
data/bin/premailer
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'nokogiri'
|
2
3
|
|
3
4
|
class Premailer
|
4
5
|
module Adapter
|
5
6
|
# Nokogiri adapter
|
6
7
|
module Nokogiri
|
8
|
+
WIDTH_AND_HIGHT = ['width', 'height'].freeze
|
7
9
|
|
8
10
|
include AdapterHelper::RgbToHex
|
9
11
|
# Merge CSS into the HTML document.
|
@@ -30,7 +32,7 @@ class Premailer
|
|
30
32
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
|
31
33
|
else
|
32
34
|
begin
|
33
|
-
if
|
35
|
+
if Premailer::RE_RESET_SELECTORS.match?(selector)
|
34
36
|
# this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
|
35
37
|
# however, this doesn't mean for testing pur
|
36
38
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
|
@@ -90,7 +92,7 @@ class Premailer
|
|
90
92
|
new_val.gsub!(/;$|\s*!important/, '').strip!
|
91
93
|
|
92
94
|
# For width and height tags, remove px units
|
93
|
-
new_val.gsub!(/(\d+)px/, '\1') if
|
95
|
+
new_val.gsub!(/(\d+)px/, '\1') if WIDTH_AND_HIGHT.include?(html_attr)
|
94
96
|
|
95
97
|
# For color-related tags, convert RGB to hex if specified by options
|
96
98
|
new_val = ensure_hex(new_val) if css_attr.end_with?('color') && @options[:rgb_to_hex_attributes]
|
@@ -99,7 +101,7 @@ class Premailer
|
|
99
101
|
end
|
100
102
|
|
101
103
|
unless @options[:preserve_style_attribute]
|
102
|
-
merged.instance_variable_get(
|
104
|
+
merged.instance_variable_get(:@declarations).tap do |declarations|
|
103
105
|
declarations.delete(css_attr)
|
104
106
|
end
|
105
107
|
end
|
@@ -250,7 +252,7 @@ class Premailer
|
|
250
252
|
# Fix for removing any CDATA tags from both style and script tags inserted per
|
251
253
|
# https://github.com/sparklemotion/nokogiri/issues/311 and
|
252
254
|
# https://github.com/premailer/premailer/issues/199
|
253
|
-
|
255
|
+
['style', 'script'].each do |tag|
|
254
256
|
doc.search(tag).children.each do |child|
|
255
257
|
child.swap(child.text()) if child.cdata?
|
256
258
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'nokogiri'
|
2
3
|
|
3
4
|
class Premailer
|
4
5
|
module Adapter
|
5
6
|
# NokogiriFast adapter
|
6
7
|
module NokogiriFast
|
8
|
+
WIDTH_AND_HEIGHT = ['width', 'height'].freeze
|
7
9
|
|
8
10
|
include AdapterHelper::RgbToHex
|
9
11
|
# Merge CSS into the HTML document.
|
@@ -36,7 +38,7 @@ class Premailer
|
|
36
38
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
|
37
39
|
else
|
38
40
|
begin
|
39
|
-
if
|
41
|
+
if Premailer::RE_RESET_SELECTORS.match?(selector)
|
40
42
|
# this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
|
41
43
|
# however, this doesn't mean for testing pur
|
42
44
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
|
@@ -96,7 +98,7 @@ class Premailer
|
|
96
98
|
new_val.gsub!(/;$|\s*!important/, '').strip!
|
97
99
|
|
98
100
|
# For width and height tags, remove px units
|
99
|
-
new_val.gsub!(/(\d+)px/, '\1') if
|
101
|
+
new_val.gsub!(/(\d+)px/, '\1') if WIDTH_AND_HEIGHT.include?(html_attr)
|
100
102
|
|
101
103
|
# For color-related tags, convert RGB to hex if specified by options
|
102
104
|
new_val = ensure_hex(new_val) if css_attr.end_with?('color') && @options[:rgb_to_hex_attributes]
|
@@ -105,7 +107,7 @@ class Premailer
|
|
105
107
|
end
|
106
108
|
|
107
109
|
unless @options[:preserve_style_attribute]
|
108
|
-
merged.instance_variable_get(
|
110
|
+
merged.instance_variable_get(:@declarations).tap do |declarations|
|
109
111
|
declarations.delete(css_attr)
|
110
112
|
end
|
111
113
|
end
|
@@ -255,7 +257,7 @@ class Premailer
|
|
255
257
|
# Fix for removing any CDATA tags from both style and script tags inserted per
|
256
258
|
# https://github.com/sparklemotion/nokogiri/issues/311 and
|
257
259
|
# https://github.com/premailer/premailer/issues/199
|
258
|
-
|
260
|
+
['style', 'script'].each do |tag|
|
259
261
|
doc.search(tag).children.each do |child|
|
260
262
|
child.swap(child.text()) if child.cdata?
|
261
263
|
end
|
@@ -314,7 +316,7 @@ class Premailer
|
|
314
316
|
index.default = Set.new
|
315
317
|
descendants.default = Set.new
|
316
318
|
|
317
|
-
|
319
|
+
[index, Set.new(all_nodes), descendants]
|
318
320
|
end
|
319
321
|
|
320
322
|
# @param doc The top level document
|
@@ -354,7 +356,7 @@ class Premailer
|
|
354
356
|
# It will return nil when such a selector is passed, so you can take
|
355
357
|
# action on the falsity of the return value.
|
356
358
|
def match_selector(index, all_nodes, descendants, selector)
|
357
|
-
if /[^-a-zA-Z0-9_\s.#]/.match(selector) then
|
359
|
+
if /[^-a-zA-Z0-9_\s.#]/.match?(selector) then
|
358
360
|
return nil
|
359
361
|
end
|
360
362
|
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
class Premailer
|
2
3
|
module Adapter
|
3
4
|
# Nokogiri adapter
|
4
5
|
module Nokogumbo
|
6
|
+
WIDTH_AND_HEIGHT = ['width', 'height'].freeze
|
5
7
|
|
6
8
|
include AdapterHelper::RgbToHex
|
7
9
|
# Merge CSS into the HTML document.
|
@@ -28,7 +30,7 @@ class Premailer
|
|
28
30
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
|
29
31
|
else
|
30
32
|
begin
|
31
|
-
if
|
33
|
+
if Premailer::RE_RESET_SELECTORS.match?(selector)
|
32
34
|
# this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
|
33
35
|
# however, this doesn't mean for testing pur
|
34
36
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
|
@@ -90,7 +92,7 @@ class Premailer
|
|
90
92
|
new_val.gsub!(/;$|\s*!important/, '').strip!
|
91
93
|
|
92
94
|
# For width and height tags, remove px units
|
93
|
-
new_val.gsub!(/(\d+)px/, '\1') if
|
95
|
+
new_val.gsub!(/(\d+)px/, '\1') if WIDTH_AND_HEIGHT.include?(html_attr)
|
94
96
|
|
95
97
|
# For color-related tags, convert RGB to hex if specified by options
|
96
98
|
new_val = ensure_hex(new_val) if css_attr.end_with?('color') && @options[:rgb_to_hex_attributes]
|
@@ -99,7 +101,7 @@ class Premailer
|
|
99
101
|
end
|
100
102
|
|
101
103
|
unless @options[:preserve_style_attribute]
|
102
|
-
merged.instance_variable_get(
|
104
|
+
merged.instance_variable_get(:@declarations).tap do |declarations|
|
103
105
|
declarations.delete(css_attr)
|
104
106
|
end
|
105
107
|
end
|
@@ -248,7 +250,7 @@ class Premailer
|
|
248
250
|
# Fix for removing any CDATA tags from both style and script tags inserted per
|
249
251
|
# https://github.com/sparklemotion/nokogiri/issues/311 and
|
250
252
|
# https://github.com/premailer/premailer/issues/199
|
251
|
-
|
253
|
+
['style', 'script'].each do |tag|
|
252
254
|
doc.search(tag).children.each do |child|
|
253
255
|
child.swap(child.text()) if child.cdata?
|
254
256
|
end
|
data/lib/premailer/adapter.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
class Premailer
|
2
3
|
# Manages the adapter classes. Currently supports:
|
3
4
|
#
|
@@ -14,7 +15,7 @@ class Premailer
|
|
14
15
|
REQUIREMENT_MAP = [
|
15
16
|
["nokogiri", :nokogiri],
|
16
17
|
["nokogiri", :nokogiri_fast],
|
17
|
-
["nokogumbo", :nokogumbo]
|
18
|
+
["nokogumbo", :nokogumbo]
|
18
19
|
]
|
19
20
|
|
20
21
|
# Returns the adapter to use.
|
@@ -42,7 +43,7 @@ class Premailer
|
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
|
-
raise
|
46
|
+
raise "No suitable adapter for Premailer was found, please install nokogiri or nokogumbo"
|
46
47
|
end
|
47
48
|
|
48
49
|
# Sets the adapter to use.
|
@@ -56,7 +57,7 @@ class Premailer
|
|
56
57
|
def self.find(adapter)
|
57
58
|
return adapter if adapter.is_a?(Module)
|
58
59
|
|
59
|
-
Premailer::Adapter.const_get("#{adapter.to_s.split('_').map{|s| s.capitalize}.join
|
60
|
+
Premailer::Adapter.const_get("#{adapter.to_s.split('_').map{|s| s.capitalize}.join}")
|
60
61
|
rescue NameError
|
61
62
|
raise ArgumentError, "Invalid adapter: #{adapter}"
|
62
63
|
end
|
data/lib/premailer/executor.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'optparse'
|
2
3
|
require 'premailer'
|
3
4
|
|
@@ -8,12 +9,12 @@ options = {
|
|
8
9
|
:remove_classes => false,
|
9
10
|
:verbose => false,
|
10
11
|
:line_length => 65,
|
11
|
-
:adapter => :nokogiri
|
12
|
+
:adapter => :nokogiri
|
12
13
|
}
|
13
14
|
|
14
15
|
mode = :html
|
15
16
|
|
16
|
-
|
17
|
+
parser = OptionParser.new do |opts|
|
17
18
|
opts.banner = "Improve the rendering of HTML emails by making CSS inline among other things. Takes a path to a local file, a URL or a pipe as input.\n\n"
|
18
19
|
opts.define_head "Usage: premailer <optional uri|optional path> [options]"
|
19
20
|
opts.separator ""
|
@@ -79,7 +80,7 @@ opts = OptionParser.new do |opts|
|
|
79
80
|
exit
|
80
81
|
end
|
81
82
|
end
|
82
|
-
|
83
|
+
parser.parse!
|
83
84
|
|
84
85
|
$stderr.puts "Processing in #{mode} mode with options #{options.inspect}" if options[:verbose]
|
85
86
|
|
@@ -98,7 +99,7 @@ end
|
|
98
99
|
if input
|
99
100
|
premailer = Premailer.new(input, options)
|
100
101
|
else
|
101
|
-
puts
|
102
|
+
puts parser
|
102
103
|
exit 1
|
103
104
|
end
|
104
105
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
require 'htmlentities'
|
3
4
|
|
4
5
|
# Support functions for Premailer
|
@@ -13,7 +14,7 @@ module HtmlToPlainText
|
|
13
14
|
#
|
14
15
|
# TODO: add support for DL, OL
|
15
16
|
# TODO: this is not safe and needs a real html parser to work
|
16
|
-
def convert_to_text(html, line_length = 65,
|
17
|
+
def convert_to_text(html, line_length = 65, _from_charset = 'UTF-8')
|
17
18
|
txt = +html
|
18
19
|
|
19
20
|
# strip text ignored html. Useful for removing
|
@@ -50,7 +51,7 @@ module HtmlToPlainText
|
|
50
51
|
|
51
52
|
if text.empty?
|
52
53
|
''
|
53
|
-
elsif href.nil? || text.strip.
|
54
|
+
elsif href.nil? || text.strip.casecmp(href.strip) == 0
|
54
55
|
text.strip
|
55
56
|
else
|
56
57
|
text.strip + ' ( ' + href.strip + ' )'
|
data/lib/premailer/premailer.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# Premailer processes HTML and CSS to improve e-mail deliverability.
|
2
3
|
#
|
3
4
|
# Premailer's main function is to render all CSS as inline <tt>style</tt>
|
@@ -141,7 +142,7 @@ class Premailer
|
|
141
142
|
include Warnings
|
142
143
|
|
143
144
|
# Waning level names
|
144
|
-
WARN_LABEL =
|
145
|
+
WARN_LABEL = ['NONE', 'SAFE', 'POOR', 'RISKY']
|
145
146
|
|
146
147
|
# Create a new Premailer object.
|
147
148
|
#
|
@@ -212,8 +213,7 @@ class Premailer
|
|
212
213
|
:create_shorthands => true,
|
213
214
|
:html_fragment => false,
|
214
215
|
:adapter => Adapter.use,
|
215
|
-
:drop_unmergeable_css_rules => false
|
216
|
-
}.merge(options)
|
216
|
+
:drop_unmergeable_css_rules => false}.merge(options)
|
217
217
|
|
218
218
|
@html_file = html
|
219
219
|
@is_local_file = @options[:with_html_string] || Premailer.local_data?(html)
|
@@ -265,10 +265,10 @@ class Premailer
|
|
265
265
|
protected
|
266
266
|
def load_css_from_local_file!(path)
|
267
267
|
css_block = +''
|
268
|
-
path.
|
268
|
+
path.delete_prefix!('file:')
|
269
269
|
begin
|
270
270
|
File.open(path, "r") do |file|
|
271
|
-
while line = file.gets
|
271
|
+
while (line = file.gets)
|
272
272
|
css_block << line
|
273
273
|
end
|
274
274
|
end
|
@@ -355,12 +355,12 @@ public
|
|
355
355
|
media_types.split(/[\s]+|,/).any? { |media_type| media_type.strip =~ /screen|handheld|all/i }
|
356
356
|
end
|
357
357
|
|
358
|
-
def append_query_string(doc,
|
359
|
-
return doc if
|
358
|
+
def append_query_string(doc, queries)
|
359
|
+
return doc if queries.nil?
|
360
360
|
|
361
|
-
|
362
|
-
|
363
|
-
return doc if
|
361
|
+
queries = +queries
|
362
|
+
queries.to_s.gsub!(/^[\?]*/, '').strip!
|
363
|
+
return doc if queries.empty?
|
364
364
|
|
365
365
|
begin
|
366
366
|
current_host = @base_url.host
|
@@ -368,18 +368,18 @@ public
|
|
368
368
|
current_host = nil
|
369
369
|
end
|
370
370
|
|
371
|
-
$stderr.puts "Attempting to append_query_string: #{
|
371
|
+
$stderr.puts "Attempting to append_query_string: #{queries}" if @options[:verbose]
|
372
372
|
|
373
|
-
doc.search('a').each do|el|
|
373
|
+
doc.search('a').each do |el|
|
374
374
|
href = el.attributes['href'].to_s.strip
|
375
375
|
next if href.nil? or href.empty?
|
376
376
|
|
377
|
-
next if
|
377
|
+
next if /[\#\{\[\<\%]/.match?(href[0,1]) # don't bother with anchors or special-looking links
|
378
378
|
|
379
379
|
begin
|
380
380
|
href = Addressable::URI.parse(href)
|
381
381
|
|
382
|
-
if current_host and href.host
|
382
|
+
if current_host and !href.host.nil? and href.host != current_host
|
383
383
|
$stderr.puts "Skipping append_query_string for: #{href.to_s} because host is no good" if @options[:verbose]
|
384
384
|
next
|
385
385
|
end
|
@@ -391,9 +391,9 @@ public
|
|
391
391
|
|
392
392
|
if href.query and not href.query.empty?
|
393
393
|
amp = @options[:unescaped_ampersand] ? '&' : '&'
|
394
|
-
href.query = href.query + amp +
|
394
|
+
href.query = href.query + amp + queries
|
395
395
|
else
|
396
|
-
href.query =
|
396
|
+
href.query = queries
|
397
397
|
end
|
398
398
|
|
399
399
|
el['href'] = href.to_s
|
@@ -436,11 +436,11 @@ public
|
|
436
436
|
tags.each do |tag|
|
437
437
|
# skip links that look like they have merge tags
|
438
438
|
# and mailto, ftp, etc...
|
439
|
-
if
|
439
|
+
if /^([\%\<\{\#\[]|data:|tel:|file:|sms:|callto:|facetime:|mailto:|ftp:|gopher:|cid:)/i.match?(tag.attributes[attribute].to_s)
|
440
440
|
next
|
441
441
|
end
|
442
442
|
|
443
|
-
if tag.attributes[attribute].to_s
|
443
|
+
if /^http/i.match?(tag.attributes[attribute].to_s)
|
444
444
|
begin
|
445
445
|
merged = Addressable::URI.parse(tag.attributes[attribute])
|
446
446
|
rescue; next; end
|
@@ -477,7 +477,7 @@ public
|
|
477
477
|
path = +path
|
478
478
|
path.strip!
|
479
479
|
resolved = nil
|
480
|
-
if
|
480
|
+
if /\A(?:(https?|ftp|file):)\/\//i.match?(path)
|
481
481
|
resolved = path
|
482
482
|
Premailer.canonicalize(resolved)
|
483
483
|
elsif base_path.kind_of?(Addressable::URI)
|
data/lib/premailer/version.rb
CHANGED
data/lib/premailer.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.25.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: 2024-08-
|
11
|
+
date: 2024-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: css_parser
|
@@ -129,7 +129,7 @@ dependencies:
|
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0'
|
131
131
|
- !ruby/object:Gem::Dependency
|
132
|
-
name:
|
132
|
+
name: webmock
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
134
134
|
requirements:
|
135
135
|
- - ">="
|
@@ -143,7 +143,7 @@ dependencies:
|
|
143
143
|
- !ruby/object:Gem::Version
|
144
144
|
version: '0'
|
145
145
|
- !ruby/object:Gem::Dependency
|
146
|
-
name:
|
146
|
+
name: bump
|
147
147
|
requirement: !ruby/object:Gem::Requirement
|
148
148
|
requirements:
|
149
149
|
- - ">="
|
@@ -157,7 +157,21 @@ dependencies:
|
|
157
157
|
- !ruby/object:Gem::Version
|
158
158
|
version: '0'
|
159
159
|
- !ruby/object:Gem::Dependency
|
160
|
-
name:
|
160
|
+
name: rubocop
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - "~>"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 1.62.1
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 1.62.1
|
173
|
+
- !ruby/object:Gem::Dependency
|
174
|
+
name: rubocop-performance
|
161
175
|
requirement: !ruby/object:Gem::Requirement
|
162
176
|
requirements:
|
163
177
|
- - ">="
|