premailer 1.26.0 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +69 -0
- data/lib/premailer/adapter/nokogiri.rb +25 -27
- data/lib/premailer/adapter/nokogiri_fast.rb +35 -39
- data/lib/premailer/adapter/nokogumbo.rb +27 -31
- data/lib/premailer/adapter/rgb_to_hex.rb +3 -3
- data/lib/premailer/adapter.rb +7 -11
- data/lib/premailer/executor.rb +8 -8
- data/lib/premailer/html_to_plain_text.rb +16 -14
- data/lib/premailer/premailer.rb +142 -110
- data/lib/premailer/version.rb +1 -1
- metadata +12 -147
data/lib/premailer/premailer.rb
CHANGED
|
@@ -39,9 +39,9 @@ class Premailer
|
|
|
39
39
|
CLIENT_SUPPORT_FILE = File.dirname(__FILE__) + '/../../misc/client_support.yaml'
|
|
40
40
|
|
|
41
41
|
# Unmergable selectors regexp.
|
|
42
|
-
RE_UNMERGABLE_SELECTORS = /(
|
|
42
|
+
RE_UNMERGABLE_SELECTORS = /(:(visited|active|hover|focus|after|before|selection|target|first-(line|letter))|^@)/i
|
|
43
43
|
# Reset selectors regexp.
|
|
44
|
-
RE_RESET_SELECTORS = /^(
|
|
44
|
+
RE_RESET_SELECTORS = /^(:\#outlook|body.*|\.ReadMsgBody|\.ExternalClass|img|\#backgroundTable)$/
|
|
45
45
|
|
|
46
46
|
# list of HTMLEntities to fix
|
|
47
47
|
# source: http://stackoverflow.com/questions/2812781/how-to-convert-webpage-apostrophe-8217-to-ascii-39-in-ruby-1-
|
|
@@ -57,23 +57,23 @@ class Premailer
|
|
|
57
57
|
"–" => '-',
|
|
58
58
|
"—" => '--',
|
|
59
59
|
"―" => '--'
|
|
60
|
-
}
|
|
60
|
+
}.freeze
|
|
61
61
|
|
|
62
62
|
# list of CSS attributes that can be rendered as HTML attributes
|
|
63
63
|
#
|
|
64
64
|
# @todo too much repetition
|
|
65
65
|
# @todo background=""
|
|
66
66
|
RELATED_ATTRIBUTES = {
|
|
67
|
-
'h1' => {'text-align' => 'align'},
|
|
68
|
-
'h2' => {'text-align' => 'align'},
|
|
69
|
-
'h3' => {'text-align' => 'align'},
|
|
70
|
-
'h4' => {'text-align' => 'align'},
|
|
71
|
-
'h5' => {'text-align' => 'align'},
|
|
72
|
-
'h6' => {'text-align' => 'align'},
|
|
73
|
-
'p' => {'text-align' => 'align'},
|
|
74
|
-
'div' => {'text-align' => 'align'},
|
|
75
|
-
'blockquote' => {'text-align' => 'align'},
|
|
76
|
-
'body' => {'background-color' => 'bgcolor'},
|
|
67
|
+
'h1' => { 'text-align' => 'align' },
|
|
68
|
+
'h2' => { 'text-align' => 'align' },
|
|
69
|
+
'h3' => { 'text-align' => 'align' },
|
|
70
|
+
'h4' => { 'text-align' => 'align' },
|
|
71
|
+
'h5' => { 'text-align' => 'align' },
|
|
72
|
+
'h6' => { 'text-align' => 'align' },
|
|
73
|
+
'p' => { 'text-align' => 'align' },
|
|
74
|
+
'div' => { 'text-align' => 'align' },
|
|
75
|
+
'blockquote' => { 'text-align' => 'align' },
|
|
76
|
+
'body' => { 'background-color' => 'bgcolor' },
|
|
77
77
|
'table' => {
|
|
78
78
|
'-premailer-align' => 'align',
|
|
79
79
|
'background-color' => 'bgcolor',
|
|
@@ -107,7 +107,7 @@ class Premailer
|
|
|
107
107
|
'-premailer-width' => 'width',
|
|
108
108
|
'-premailer-height' => 'height'
|
|
109
109
|
}
|
|
110
|
-
}
|
|
110
|
+
}.freeze
|
|
111
111
|
|
|
112
112
|
# URI of the HTML file used
|
|
113
113
|
attr_reader :html_file
|
|
@@ -142,7 +142,7 @@ class Premailer
|
|
|
142
142
|
include Warnings
|
|
143
143
|
|
|
144
144
|
# Waning level names
|
|
145
|
-
WARN_LABEL = ['NONE', 'SAFE', 'POOR', 'RISKY']
|
|
145
|
+
WARN_LABEL = ['NONE', 'SAFE', 'POOR', 'RISKY'].freeze
|
|
146
146
|
|
|
147
147
|
# Create a new Premailer object.
|
|
148
148
|
#
|
|
@@ -182,38 +182,40 @@ class Premailer
|
|
|
182
182
|
# @option options [Boolean] :html_fragment Handle HTML fragment without any HTML content wrappers. Default is false.
|
|
183
183
|
# @option options [Boolean] :drop_unmergeable_css_rules Do not include unmergeable css rules in a <tt><style><tt> tag. Default is false.
|
|
184
184
|
def initialize(html, options = {})
|
|
185
|
-
@options = {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
185
|
+
@options = {
|
|
186
|
+
:warn_level => Warnings::SAFE,
|
|
187
|
+
:line_length => 65,
|
|
188
|
+
:link_query_string => nil,
|
|
189
|
+
:base_url => nil,
|
|
190
|
+
:rgb_to_hex_attributes => true,
|
|
191
|
+
:remove_classes => false,
|
|
192
|
+
:remove_ids => false,
|
|
193
|
+
:remove_comments => false,
|
|
194
|
+
:remove_scripts => true,
|
|
195
|
+
:reset_contenteditable => true,
|
|
196
|
+
:css => [],
|
|
197
|
+
:css_to_attributes => true,
|
|
198
|
+
:preserve_style_attribute => false,
|
|
199
|
+
:with_html_string => false,
|
|
200
|
+
:css_string => nil,
|
|
201
|
+
:preserve_styles => false,
|
|
202
|
+
:preserve_reset => true,
|
|
203
|
+
:verbose => false,
|
|
204
|
+
:debug => false,
|
|
205
|
+
:io_exceptions => false,
|
|
206
|
+
:rule_set_exceptions => true,
|
|
207
|
+
:include_link_tags => true,
|
|
208
|
+
:include_style_tags => true,
|
|
209
|
+
:input_encoding => 'ASCII-8BIT',
|
|
210
|
+
:output_encoding => nil,
|
|
211
|
+
:replace_html_entities => false,
|
|
212
|
+
:escape_url_attributes => true,
|
|
213
|
+
:unescaped_ampersand => false,
|
|
214
|
+
:create_shorthands => true,
|
|
215
|
+
:html_fragment => false,
|
|
216
|
+
:adapter => Adapter.use,
|
|
217
|
+
:drop_unmergeable_css_rules => false
|
|
218
|
+
}.merge(options)
|
|
217
219
|
|
|
218
220
|
@html_file = html
|
|
219
221
|
@is_local_file = @options[:with_html_string] || Premailer.local_data?(html)
|
|
@@ -228,20 +230,22 @@ class Premailer
|
|
|
228
230
|
|
|
229
231
|
if @options[:base_url]
|
|
230
232
|
@base_url = Addressable::URI.parse(@options.delete(:base_url))
|
|
231
|
-
elsif
|
|
233
|
+
elsif !@is_local_file
|
|
232
234
|
@base_url = Addressable::URI.parse(@html_file)
|
|
233
235
|
end
|
|
234
236
|
|
|
235
|
-
@css_parser = CssParser::Parser.new(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
@css_parser = CssParser::Parser.new(
|
|
238
|
+
{
|
|
239
|
+
:absolute_paths => true,
|
|
240
|
+
:import => true,
|
|
241
|
+
:io_exceptions => @options[:io_exceptions],
|
|
242
|
+
:rule_set_exceptions => @options[:rule_set_exceptions]
|
|
243
|
+
}
|
|
244
|
+
)
|
|
241
245
|
|
|
242
246
|
@adapter_class = Adapter.find @options[:adapter]
|
|
243
247
|
|
|
244
|
-
|
|
248
|
+
extend(@adapter_class)
|
|
245
249
|
|
|
246
250
|
@doc = load_html(@html_file)
|
|
247
251
|
|
|
@@ -262,7 +266,8 @@ class Premailer
|
|
|
262
266
|
@css_warnings
|
|
263
267
|
end
|
|
264
268
|
|
|
265
|
-
protected
|
|
269
|
+
protected
|
|
270
|
+
|
|
266
271
|
def load_css_from_local_file!(path)
|
|
267
272
|
css_block = +''
|
|
268
273
|
path.delete_prefix!('file:')
|
|
@@ -274,13 +279,13 @@ protected
|
|
|
274
279
|
end
|
|
275
280
|
|
|
276
281
|
load_css_from_string(css_block)
|
|
277
|
-
rescue => e
|
|
282
|
+
rescue StandardError => e
|
|
278
283
|
raise e if @options[:io_exceptions]
|
|
279
284
|
end
|
|
280
285
|
end
|
|
281
286
|
|
|
282
287
|
def load_css_from_string(css_string)
|
|
283
|
-
@css_parser.add_block!(css_string, {:base_uri => @base_url, :base_dir => @base_dir, :only_media_types => [:screen, :handheld]})
|
|
288
|
+
@css_parser.add_block!(css_string, { :base_uri => @base_url, :base_dir => @base_dir, :only_media_types => [:screen, :handheld] })
|
|
284
289
|
end
|
|
285
290
|
|
|
286
291
|
# @private
|
|
@@ -296,20 +301,20 @@ protected
|
|
|
296
301
|
end
|
|
297
302
|
end
|
|
298
303
|
|
|
299
|
-
|
|
304
|
+
# Load CSS included in <tt>style</tt> and <tt>link</tt> tags from an HTML document.
|
|
300
305
|
def load_css_from_html! # :nodoc:
|
|
301
306
|
tags = @doc.search("link[@rel='stylesheet']:not([@data-premailer='ignore']), style:not([@data-premailer='ignore'])")
|
|
302
307
|
if tags
|
|
303
308
|
tags.each do |tag|
|
|
304
|
-
if tag.to_s.strip =~
|
|
309
|
+
if tag.to_s.strip =~ /^<link/i && tag.attributes['href'] && media_type_ok?(tag.attributes['media']) && @options[:include_link_tags]
|
|
305
310
|
# A user might want to <link /> to a local css file that is also mirrored on the site
|
|
306
311
|
# but the local one is different (e.g. newer) than the live file, premailer will now choose the local file
|
|
307
312
|
|
|
308
|
-
if tag.attributes['href'].to_s.include?
|
|
309
|
-
if @options[:with_html_string]
|
|
310
|
-
|
|
313
|
+
if tag.attributes['href'].to_s.include?(@base_url.to_s) && @html_file.is_a?(String)
|
|
314
|
+
link_uri = if @options[:with_html_string]
|
|
315
|
+
tag.attributes['href'].to_s.sub(@base_url.to_s, '')
|
|
311
316
|
else
|
|
312
|
-
|
|
317
|
+
File.join(File.dirname(@html_file), tag.attributes['href'].to_s.sub!(@base_url.to_s, ''))
|
|
313
318
|
end
|
|
314
319
|
# if the file does not exist locally, try to grab the remote reference
|
|
315
320
|
unless File.exist?(link_uri)
|
|
@@ -320,14 +325,14 @@ protected
|
|
|
320
325
|
end
|
|
321
326
|
|
|
322
327
|
if Premailer.local_data?(link_uri)
|
|
323
|
-
|
|
328
|
+
warn "Loading css from local file: " + link_uri if @options[:verbose]
|
|
324
329
|
load_css_from_local_file!(link_uri)
|
|
325
330
|
else
|
|
326
|
-
|
|
327
|
-
@css_parser.load_uri!(link_uri, {:only_media_types => [:screen, :handheld]})
|
|
331
|
+
warn "Loading css from uri: " + link_uri if @options[:verbose]
|
|
332
|
+
@css_parser.load_uri!(link_uri, { :only_media_types => [:screen, :handheld] })
|
|
328
333
|
end
|
|
329
334
|
|
|
330
|
-
elsif tag.to_s.strip =~
|
|
335
|
+
elsif tag.to_s.strip =~ /^<style/i && @options[:include_style_tags]
|
|
331
336
|
@css_parser.add_block!(tag.inner_html, :base_uri => @base_url, :base_dir => @base_dir, :only_media_types => [:screen, :handheld])
|
|
332
337
|
end
|
|
333
338
|
end
|
|
@@ -335,10 +340,28 @@ protected
|
|
|
335
340
|
end
|
|
336
341
|
end
|
|
337
342
|
|
|
343
|
+
# here be deprecated methods
|
|
344
|
+
public
|
|
338
345
|
|
|
346
|
+
# Free native Nokogiri/libxml2 memory held by this instance.
|
|
347
|
+
#
|
|
348
|
+
# After calling +to_inline_css+ or +to_plain_text+, the Premailer instance
|
|
349
|
+
# retains live Nokogiri documents that pin native libxml2 memory. Ruby's GC
|
|
350
|
+
# cannot see this native memory pressure, so in high-throughput scenarios
|
|
351
|
+
# (e.g. email rendering in Sidekiq workers) native memory can accumulate
|
|
352
|
+
# unboundedly. Call +cleanup!+ when you are done with the instance to
|
|
353
|
+
# release that memory immediately.
|
|
354
|
+
#
|
|
355
|
+
# After calling this method the instance is no longer usable.
|
|
356
|
+
def cleanup!
|
|
357
|
+
@processed_doc&.unlink
|
|
358
|
+
@doc&.unlink
|
|
359
|
+
@doc = nil
|
|
360
|
+
@processed_doc = nil
|
|
361
|
+
@css_parser = nil
|
|
362
|
+
@unmergable_rules = nil
|
|
363
|
+
end
|
|
339
364
|
|
|
340
|
-
# here be deprecated methods
|
|
341
|
-
public
|
|
342
365
|
# @private
|
|
343
366
|
# @deprecated
|
|
344
367
|
def local_uri?(uri) # :nodoc:
|
|
@@ -346,12 +369,12 @@ public
|
|
|
346
369
|
Premailer.local_data?(uri)
|
|
347
370
|
end
|
|
348
371
|
|
|
349
|
-
# here be instance methods
|
|
372
|
+
# here be instance methods
|
|
350
373
|
|
|
351
374
|
# @private
|
|
352
375
|
def media_type_ok?(media_types)
|
|
353
376
|
media_types = media_types.to_s
|
|
354
|
-
return true if media_types.nil?
|
|
377
|
+
return true if media_types.nil? || media_types.empty?
|
|
355
378
|
media_types.split(/[\s]+|,/).any? { |media_type| media_type.strip =~ /screen|handheld|all/i }
|
|
356
379
|
end
|
|
357
380
|
|
|
@@ -364,32 +387,32 @@ public
|
|
|
364
387
|
|
|
365
388
|
begin
|
|
366
389
|
current_host = @base_url.host
|
|
367
|
-
rescue
|
|
390
|
+
rescue StandardError
|
|
368
391
|
current_host = nil
|
|
369
392
|
end
|
|
370
393
|
|
|
371
|
-
|
|
394
|
+
warn "Attempting to append_query_string: #{queries}" if @options[:verbose]
|
|
372
395
|
|
|
373
396
|
doc.search('a').each do |el|
|
|
374
397
|
href = el.attributes['href'].to_s.strip
|
|
375
|
-
next if href.nil?
|
|
398
|
+
next if href.nil? || href.empty?
|
|
376
399
|
|
|
377
|
-
next if /[\#\{\[\<\%]/.match?(href[0,1]) # don't bother with anchors or special-looking links
|
|
400
|
+
next if /[\#\{\[\<\%]/.match?(href[0, 1]) # don't bother with anchors or special-looking links
|
|
378
401
|
|
|
379
402
|
begin
|
|
380
403
|
href = Addressable::URI.parse(href)
|
|
381
404
|
|
|
382
|
-
if current_host
|
|
383
|
-
|
|
405
|
+
if current_host && !href.host.nil? && (href.host != current_host)
|
|
406
|
+
warn "Skipping append_query_string for: #{href} because host is no good" if @options[:verbose]
|
|
384
407
|
next
|
|
385
408
|
end
|
|
386
409
|
|
|
387
|
-
if href.scheme
|
|
388
|
-
puts "Skipping append_query_string for: #{href
|
|
410
|
+
if href.scheme && (href.scheme != 'http') && (href.scheme != 'https')
|
|
411
|
+
puts "Skipping append_query_string for: #{href} because scheme is no good" if @options[:verbose]
|
|
389
412
|
next
|
|
390
413
|
end
|
|
391
414
|
|
|
392
|
-
if href.query
|
|
415
|
+
if href.query && !href.query.empty?
|
|
393
416
|
amp = @options[:unescaped_ampersand] ? '&' : '&'
|
|
394
417
|
href.query = href.query + amp + queries
|
|
395
418
|
else
|
|
@@ -398,19 +421,18 @@ public
|
|
|
398
421
|
|
|
399
422
|
el['href'] = href.to_s
|
|
400
423
|
rescue Addressable::URI::InvalidURIError => e
|
|
401
|
-
|
|
424
|
+
warn "Skipping append_query_string for: #{href} (#{e.message})" if @options[:verbose]
|
|
402
425
|
next
|
|
403
426
|
end
|
|
404
|
-
|
|
405
427
|
end
|
|
406
428
|
doc
|
|
407
429
|
end
|
|
408
430
|
|
|
409
431
|
# Check for an XHTML doctype
|
|
410
|
-
def
|
|
432
|
+
def xhtml?
|
|
411
433
|
intro = @doc.to_xhtml.strip.split("\n")[0..2].join(' ')
|
|
412
434
|
is_xhtml = !!(intro =~ /w3c\/\/[\s]*dtd[\s]+xhtml/i)
|
|
413
|
-
|
|
435
|
+
warn "Is XHTML? #{is_xhtml.inspect}\nChecked:\n#{intro}" if @options[:debug]
|
|
414
436
|
is_xhtml
|
|
415
437
|
end
|
|
416
438
|
|
|
@@ -423,9 +445,8 @@ public
|
|
|
423
445
|
#
|
|
424
446
|
# Returns a document.
|
|
425
447
|
def convert_inline_links(doc, base_uri) # :nodoc:
|
|
426
|
-
base_uri = Addressable::URI.parse(base_uri) unless base_uri.
|
|
448
|
+
base_uri = Addressable::URI.parse(base_uri) unless base_uri.is_a?(Addressable::URI)
|
|
427
449
|
|
|
428
|
-
append_qs = @options[:link_query_string] || ''
|
|
429
450
|
escape_attrs = @options[:escape_url_attributes]
|
|
430
451
|
|
|
431
452
|
['href', 'src', 'background'].each do |attribute|
|
|
@@ -443,23 +464,23 @@ public
|
|
|
443
464
|
if /^http/i.match?(tag.attributes[attribute].to_s)
|
|
444
465
|
begin
|
|
445
466
|
merged = Addressable::URI.parse(tag.attributes[attribute])
|
|
446
|
-
rescue; next; end
|
|
467
|
+
rescue StandardError; next; end
|
|
447
468
|
else
|
|
448
469
|
begin
|
|
449
470
|
merged = Premailer.resolve_link(tag.attributes[attribute].to_s, base_uri)
|
|
450
|
-
rescue
|
|
471
|
+
rescue StandardError
|
|
451
472
|
begin
|
|
452
473
|
next unless escape_attrs
|
|
453
474
|
merged = Premailer.resolve_link(Addressable::URI.escape(tag.attributes[attribute].to_s), base_uri)
|
|
454
|
-
rescue; end
|
|
475
|
+
rescue StandardError; end
|
|
455
476
|
end
|
|
456
477
|
end
|
|
457
478
|
|
|
458
479
|
# make sure 'merged' is a URI
|
|
459
|
-
merged = Addressable::URI.parse(merged.to_s) unless merged.
|
|
480
|
+
merged = Addressable::URI.parse(merged.to_s) unless merged.is_a?(Addressable::URI)
|
|
460
481
|
tag[attribute] = merged.to_s
|
|
461
|
-
end
|
|
462
|
-
end
|
|
482
|
+
end
|
|
483
|
+
end
|
|
463
484
|
|
|
464
485
|
doc.search("*[@style]").each do |el|
|
|
465
486
|
el['style'] = CssParser.convert_uris(el.attributes['style'].to_s, base_uri)
|
|
@@ -468,22 +489,21 @@ public
|
|
|
468
489
|
end
|
|
469
490
|
|
|
470
491
|
# @private
|
|
471
|
-
def self.
|
|
472
|
-
media_types
|
|
492
|
+
def self.media_query?(media_types)
|
|
493
|
+
media_types&.any? { |mt| mt.to_s.count('()') >= 2 }
|
|
473
494
|
end
|
|
474
495
|
|
|
475
496
|
# @private
|
|
476
497
|
def self.resolve_link(path, base_path) # :nodoc:
|
|
477
498
|
path = +path
|
|
478
499
|
path.strip!
|
|
479
|
-
resolved = nil
|
|
480
500
|
if /\A(?:(https?|ftp|file):)\/\//i.match?(path)
|
|
481
501
|
resolved = path
|
|
482
502
|
Premailer.canonicalize(resolved)
|
|
483
|
-
elsif base_path.
|
|
503
|
+
elsif base_path.is_a?(Addressable::URI)
|
|
484
504
|
resolved = base_path.join(path)
|
|
485
505
|
Premailer.canonicalize(resolved)
|
|
486
|
-
elsif base_path.
|
|
506
|
+
elsif base_path.is_a?(String) && base_path =~ (/\A(?:(?:https?|ftp|file):)\/\//i)
|
|
487
507
|
resolved = Addressable::URI.parse(base_path)
|
|
488
508
|
resolved = resolved.join(path)
|
|
489
509
|
Premailer.canonicalize(resolved)
|
|
@@ -496,13 +516,13 @@ public
|
|
|
496
516
|
#
|
|
497
517
|
# IO objects return true, as do strings that look like URLs.
|
|
498
518
|
def self.local_data?(data)
|
|
499
|
-
return false
|
|
519
|
+
return false if data.is_a?(String) && data =~ /\A(?:(https?|ftp):)\/\//i
|
|
500
520
|
true
|
|
501
521
|
end
|
|
502
522
|
|
|
503
523
|
# from http://www.ruby-forum.com/topic/140101
|
|
504
524
|
def self.canonicalize(uri) # :nodoc:
|
|
505
|
-
u = uri.
|
|
525
|
+
u = uri.is_a?(Addressable::URI) ? uri : Addressable::URI.parse(uri.to_s)
|
|
506
526
|
u.normalize!
|
|
507
527
|
u.to_s
|
|
508
528
|
end
|
|
@@ -517,7 +537,7 @@ public
|
|
|
517
537
|
|
|
518
538
|
# Get a list off CSS properties
|
|
519
539
|
@processed_doc.search("*[@style]").each do |el|
|
|
520
|
-
|
|
540
|
+
el.attributes['style'].to_s.gsub(/([\w\-]+)[\s]*:/i) do |_s|
|
|
521
541
|
properties.push($1)
|
|
522
542
|
end
|
|
523
543
|
end
|
|
@@ -526,30 +546,42 @@ public
|
|
|
526
546
|
|
|
527
547
|
property_support = @client_support['css_properties']
|
|
528
548
|
properties.each do |prop|
|
|
529
|
-
if property_support.include?(prop)
|
|
530
|
-
property_support[prop].include?('support')
|
|
531
|
-
property_support[prop]['support'] >= @options[:warn_level]
|
|
532
|
-
warnings.push(
|
|
549
|
+
if property_support.include?(prop) &&
|
|
550
|
+
property_support[prop].include?('support') &&
|
|
551
|
+
(property_support[prop]['support'] >= @options[:warn_level])
|
|
552
|
+
warnings.push(
|
|
553
|
+
{
|
|
554
|
+
:message => "#{prop} CSS property",
|
|
533
555
|
:level => WARN_LABEL[property_support[prop]['support']],
|
|
534
|
-
:clients => property_support[prop]['unsupported_in'].join(', ')
|
|
556
|
+
:clients => property_support[prop]['unsupported_in'].join(', ')
|
|
557
|
+
}
|
|
558
|
+
)
|
|
535
559
|
end
|
|
536
560
|
end
|
|
537
561
|
|
|
538
562
|
@client_support['attributes'].each do |attribute, data|
|
|
539
563
|
next unless data['support'] >= @options[:warn_level]
|
|
540
564
|
if @doc.search("*[@#{attribute}]").length > 0
|
|
541
|
-
warnings.push(
|
|
565
|
+
warnings.push(
|
|
566
|
+
{
|
|
567
|
+
:message => "#{attribute} HTML attribute",
|
|
542
568
|
:level => WARN_LABEL[data['support']],
|
|
543
|
-
:clients => data['unsupported_in'].join(', ')
|
|
569
|
+
:clients => data['unsupported_in'].join(', ')
|
|
570
|
+
}
|
|
571
|
+
)
|
|
544
572
|
end
|
|
545
573
|
end
|
|
546
574
|
|
|
547
575
|
@client_support['elements'].each do |element, data|
|
|
548
576
|
next unless data['support'] >= @options[:warn_level]
|
|
549
577
|
if @doc.search(element).length > 0
|
|
550
|
-
warnings.push(
|
|
578
|
+
warnings.push(
|
|
579
|
+
{
|
|
580
|
+
:message => "#{element} HTML element",
|
|
551
581
|
:level => WARN_LABEL[data['support']],
|
|
552
|
-
:clients => data['unsupported_in'].join(', ')
|
|
582
|
+
:clients => data['unsupported_in'].join(', ')
|
|
583
|
+
}
|
|
584
|
+
)
|
|
553
585
|
end
|
|
554
586
|
end
|
|
555
587
|
|
data/lib/premailer/version.rb
CHANGED