inkcite 1.11.0 → 1.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +2 -2
- data/assets/init/helpers.tsv +7 -0
- data/assets/social/facebook.png +0 -0
- data/assets/social/pintrest.png +0 -0
- data/assets/social/twitter.png +0 -0
- data/inkcite.gemspec +5 -4
- data/lib/inkcite.rb +17 -6
- data/lib/inkcite/animation.rb +135 -0
- data/lib/inkcite/cli/base.rb +5 -14
- data/lib/inkcite/cli/build.rb +3 -3
- data/lib/inkcite/cli/init.rb +3 -3
- data/lib/inkcite/cli/preview.rb +25 -1
- data/lib/inkcite/cli/server.rb +1 -1
- data/lib/inkcite/cli/validate.rb +2 -11
- data/lib/inkcite/email.rb +1 -1
- data/lib/inkcite/mailer.rb +5 -0
- data/lib/inkcite/minifier.rb +58 -11
- data/lib/inkcite/renderer.rb +10 -2
- data/lib/inkcite/renderer/base.rb +45 -3
- data/lib/inkcite/renderer/button.rb +16 -12
- data/lib/inkcite/renderer/container_base.rb +14 -4
- data/lib/inkcite/renderer/element.rb +13 -3
- data/lib/inkcite/renderer/image.rb +46 -19
- data/lib/inkcite/renderer/image_base.rb +3 -3
- data/lib/inkcite/renderer/in_browser.rb +1 -1
- data/lib/inkcite/renderer/link.rb +91 -59
- data/lib/inkcite/renderer/lorem.rb +9 -1
- data/lib/inkcite/renderer/mobile_image.rb +3 -11
- data/lib/inkcite/renderer/mobile_only.rb +48 -0
- data/lib/inkcite/renderer/outlook_background.rb +61 -13
- data/lib/inkcite/renderer/property.rb +1 -1
- data/lib/inkcite/renderer/responsive.rb +10 -8
- data/lib/inkcite/renderer/snow.rb +20 -10
- data/lib/inkcite/renderer/social.rb +128 -0
- data/lib/inkcite/renderer/table.rb +13 -1
- data/lib/inkcite/renderer/table_base.rb +3 -3
- data/lib/inkcite/renderer/td.rb +32 -7
- data/lib/inkcite/renderer/video_preview.rb +257 -0
- data/lib/inkcite/uploader.rb +3 -3
- data/lib/inkcite/util.rb +19 -5
- data/lib/inkcite/version.rb +1 -1
- data/lib/inkcite/view.rb +29 -18
- data/lib/inkcite/view/context.rb +30 -0
- data/test/animation_spec.rb +38 -0
- data/test/email_spec.rb +0 -4
- data/test/minifier_spec.rb +243 -4
- data/test/parser_spec.rb +0 -4
- data/test/project/helpers.tsv +3 -0
- data/test/renderer/button_spec.rb +15 -13
- data/test/renderer/div_spec.rb +13 -4
- data/test/renderer/element_spec.rb +1 -5
- data/test/renderer/footnote_spec.rb +0 -4
- data/test/renderer/image_spec.rb +27 -11
- data/test/renderer/link_spec.rb +14 -4
- data/test/renderer/lorem_spec.rb +0 -4
- data/test/renderer/mobile_image_spec.rb +3 -11
- data/test/renderer/mobile_only_spec.rb +21 -0
- data/test/renderer/mobile_style_spec.rb +1 -5
- data/test/renderer/outlook_background_spec.rb +61 -0
- data/test/renderer/redacted_spec.rb +0 -4
- data/test/renderer/social_spec.rb +53 -0
- data/test/renderer/span_spec.rb +0 -4
- data/test/renderer/table_spec.rb +8 -4
- data/test/renderer/td_spec.rb +0 -4
- data/test/renderer/video_preview_spec.rb +19 -0
- data/test/renderer_spec.rb +0 -4
- data/test/test_helper.rb +7 -0
- data/test/view_spec.rb +12 -4
- metadata +89 -56
data/lib/inkcite/uploader.rb
CHANGED
@@ -10,11 +10,11 @@ module Inkcite
|
|
10
10
|
|
11
11
|
['source.html', 'source.txt', 'helpers.tsv'].each do |file|
|
12
12
|
file = email.project_file(file)
|
13
|
-
times << File.mtime(file).to_i if File.
|
13
|
+
times << File.mtime(file).to_i if File.exist?(file)
|
14
14
|
end
|
15
15
|
|
16
16
|
local_images = email.image_dir
|
17
|
-
if File.
|
17
|
+
if File.exist?(local_images)
|
18
18
|
Dir.foreach(local_images) do |file|
|
19
19
|
times << File.mtime(File.join(local_images, file)).to_i unless file.starts_with?('.')
|
20
20
|
end
|
@@ -42,7 +42,7 @@ module Inkcite
|
|
42
42
|
|
43
43
|
# Nothing to copy unless the local directory exists (e.g. some emails don't
|
44
44
|
# have an images directory.)
|
45
|
-
return unless File.
|
45
|
+
return unless File.exist?(local)
|
46
46
|
|
47
47
|
Dir.foreach(local) do |file|
|
48
48
|
next if file.starts_with?('.')
|
data/lib/inkcite/util.rb
CHANGED
@@ -25,7 +25,7 @@ module Inkcite
|
|
25
25
|
|
26
26
|
def self.darken color, amount=0.4
|
27
27
|
return BLACK if color.nil?
|
28
|
-
rgb = color.gsub('#', '').scan(/../).map { |
|
28
|
+
rgb = color.gsub('#', '').scan(/../).map { |c| c.hex }
|
29
29
|
rgb[0] = (rgb[0].to_i * amount).round
|
30
30
|
rgb[1] = (rgb[1].to_i * amount).round
|
31
31
|
rgb[2] = (rgb[2].to_i * amount).round
|
@@ -38,9 +38,23 @@ module Inkcite
|
|
38
38
|
opts.detect { |o| !o.blank? }
|
39
39
|
end
|
40
40
|
|
41
|
+
# Centralizing the URL/CGI encoding for all HREF processing because
|
42
|
+
# URI.escape/encode is obsolete.
|
43
|
+
def self.encode *arg
|
44
|
+
silence_warnings do
|
45
|
+
URI.escape(*arg)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.escape *arg
|
50
|
+
silence_warnings do
|
51
|
+
URI.escape(*arg)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
41
55
|
def self.lighten color, amount=0.6
|
42
56
|
return WHITE if color.nil?
|
43
|
-
rgb = color.gsub('#', '').scan(/../).map { |
|
57
|
+
rgb = color.gsub('#', '').scan(/../).map { |c| c.hex }
|
44
58
|
rgb[0] = [(rgb[0].to_i + 255 * amount).round, 255].min
|
45
59
|
rgb[1] = [(rgb[1].to_i + 255 * amount).round, 255].min
|
46
60
|
rgb[2] = [(rgb[2].to_i + 255 * amount).round, 255].min
|
@@ -53,7 +67,7 @@ module Inkcite
|
|
53
67
|
|
54
68
|
def self.each_line path, fail_if_not_exists, &block
|
55
69
|
|
56
|
-
if File.
|
70
|
+
if File.exist?(path)
|
57
71
|
File.open(path).each { |line| yield line.strip }
|
58
72
|
elsif fail_if_not_exists
|
59
73
|
raise "File not found: #{path}"
|
@@ -66,12 +80,12 @@ module Inkcite
|
|
66
80
|
end
|
67
81
|
|
68
82
|
def self.last_modified file
|
69
|
-
file && File.
|
83
|
+
file && File.exist?(file) ? File.mtime(file).to_i : 0
|
70
84
|
end
|
71
85
|
|
72
86
|
def self.read *argv
|
73
87
|
path = File.join(File.expand_path('../..', File.dirname(__FILE__)), argv)
|
74
|
-
if File.
|
88
|
+
if File.exist?(path)
|
75
89
|
line = File.open(path).read
|
76
90
|
line.gsub!(/[\r\f\n]+/, "\n")
|
77
91
|
line.gsub!(/ {2,}/, ' ')
|
data/lib/inkcite/version.rb
CHANGED
data/lib/inkcite/view.rb
CHANGED
@@ -24,7 +24,7 @@ module Inkcite
|
|
24
24
|
attr_reader :media_query
|
25
25
|
|
26
26
|
# Line number of the email file being processed
|
27
|
-
attr_accessor :
|
27
|
+
attr_accessor :line_number
|
28
28
|
|
29
29
|
# The configuration hash for the view
|
30
30
|
attr_accessor :config
|
@@ -35,7 +35,6 @@ module Inkcite
|
|
35
35
|
# Will be populated with the css and js compressor objects
|
36
36
|
# after first use. Ensures we can reset the compressors
|
37
37
|
# after a rendering is complete.
|
38
|
-
attr_accessor :css_compressor
|
39
38
|
attr_accessor :js_compressor
|
40
39
|
|
41
40
|
def initialize email, environment, format, version
|
@@ -60,6 +59,9 @@ module Inkcite
|
|
60
59
|
@config[:format] = format.to_s
|
61
60
|
@config[FILE_NAME] = file_name
|
62
61
|
|
62
|
+
# Expose the project's directory name as the project entry.
|
63
|
+
@config[:project] = File.basename(@email.path)
|
64
|
+
|
63
65
|
# The MediaQuery object manages the responsive styles that are applied to
|
64
66
|
# the email during rendering. Check to see if a breakwidth has been supplied
|
65
67
|
# in helpers.tsv so the designer can control the primary breakpoint.
|
@@ -77,11 +79,14 @@ module Inkcite
|
|
77
79
|
|
78
80
|
# Tracks the line number and is recorded when errors are encountered
|
79
81
|
# while rendering said line.
|
80
|
-
@
|
82
|
+
@line_number = 0
|
81
83
|
|
82
84
|
# True if VML is used during the preparation of this email.
|
83
85
|
@vml_used = false
|
84
86
|
|
87
|
+
# Initializing to prevent a ruby verbose warning.
|
88
|
+
@footnotes = nil
|
89
|
+
|
85
90
|
end
|
86
91
|
|
87
92
|
def [] key
|
@@ -110,7 +115,7 @@ module Inkcite
|
|
110
115
|
|
111
116
|
# This is the full path to the image on the dev's harddrive.
|
112
117
|
path = @email.image_path(src)
|
113
|
-
exists = File.
|
118
|
+
exists = File.exist?(path)
|
114
119
|
|
115
120
|
error('Missing image', { :src => src }) if !exists
|
116
121
|
|
@@ -121,6 +126,11 @@ module Inkcite
|
|
121
126
|
@format == :browser
|
122
127
|
end
|
123
128
|
|
129
|
+
# Arbitrary storage of data
|
130
|
+
def data
|
131
|
+
@data ||= {}
|
132
|
+
end
|
133
|
+
|
124
134
|
def default?
|
125
135
|
@version == :default
|
126
136
|
end
|
@@ -140,7 +150,7 @@ module Inkcite
|
|
140
150
|
# Records an error message on the currently processing line of the source.
|
141
151
|
def error message, obj=nil
|
142
152
|
|
143
|
-
message << " (line #{self.
|
153
|
+
message << " (line #{self.line_number.to_i})"
|
144
154
|
unless obj.blank?
|
145
155
|
message << ' ['
|
146
156
|
message << obj.collect { |k, v| "#{k}=#{v}" }.join(', ')
|
@@ -164,7 +174,7 @@ module Inkcite
|
|
164
174
|
|
165
175
|
# Preload the array of footnotes if they exist
|
166
176
|
footnotes_tsv_file = @email.project_file(FOOTNOTES_TSV_FILE)
|
167
|
-
if File.
|
177
|
+
if File.exist?(footnotes_tsv_file)
|
168
178
|
CSV.foreach(footnotes_tsv_file, { :col_sep => "\t" }) do |fn|
|
169
179
|
|
170
180
|
id = fn[0]
|
@@ -303,7 +313,7 @@ module Inkcite
|
|
303
313
|
def links_tsv
|
304
314
|
@links_tsv ||= begin
|
305
315
|
links_tsv_file = @email.project_file(LINKS_TSV_FILE)
|
306
|
-
if File.
|
316
|
+
if File.exist?(links_tsv_file)
|
307
317
|
Hash[CSV.read(links_tsv_file, { :col_sep => "\t" })]
|
308
318
|
else
|
309
319
|
{}
|
@@ -392,7 +402,10 @@ module Inkcite
|
|
392
402
|
|
393
403
|
# Prepare a copy of the HTML for saving as the file.
|
394
404
|
html = []
|
395
|
-
|
405
|
+
|
406
|
+
# Using HTML5 DOCTYPE
|
407
|
+
# https://emails.hteumeuleu.com/which-doctype-should-you-use-in-html-emails-cd323fdb793c#.cxet9febe
|
408
|
+
html << '<!DOCTYPE html>'
|
396
409
|
|
397
410
|
# Resolve the HTML declaration for this email based on whether or not VML was used.
|
398
411
|
html_declaration = '<html xmlns="http://www.w3.org/1999/xhtml"'
|
@@ -407,7 +420,7 @@ module Inkcite
|
|
407
420
|
|
408
421
|
# Enable responsive media queries on Windows phones courtesy of @jamesmacwhite
|
409
422
|
# https://blog.jmwhite.co.uk/2014/03/01/windows-phone-does-support-css3-media-queries-in-html-email/
|
410
|
-
html << '<!--[if !mso]
|
423
|
+
html << '<!--[if !mso]><!-- -->'
|
411
424
|
html << '<meta http-equiv="X-UA-Compatible" content="IE=edge" />'
|
412
425
|
html << '<!--<![endif]-->'
|
413
426
|
|
@@ -527,7 +540,7 @@ module Inkcite
|
|
527
540
|
# Returns true if vml is enabled in this context. This requires that the
|
528
541
|
# context is for an email and that the VML property is enabled.
|
529
542
|
def vml_enabled?
|
530
|
-
email? &&
|
543
|
+
email? && !is_disabled?(:vml)
|
531
544
|
end
|
532
545
|
|
533
546
|
# Signifies that VML was used during the rendering and that
|
@@ -727,8 +740,9 @@ module Inkcite
|
|
727
740
|
begin
|
728
741
|
font_cache[url] = open(url).read
|
729
742
|
updated = true
|
730
|
-
rescue
|
731
|
-
error 'Unable to load Google Web Font', { :url => url }
|
743
|
+
rescue Exception => error
|
744
|
+
error 'Unable to load Google Web Font', { :url => url, :error => error.inspect }
|
745
|
+
next
|
732
746
|
end
|
733
747
|
end
|
734
748
|
|
@@ -769,9 +783,6 @@ module Inkcite
|
|
769
783
|
|
770
784
|
def inline_styles
|
771
785
|
|
772
|
-
# This is the default font family for the email.
|
773
|
-
font_family = self[Renderer::Base::FONT_FAMILY]
|
774
|
-
|
775
786
|
reset = []
|
776
787
|
|
777
788
|
if email?
|
@@ -840,7 +851,7 @@ module Inkcite
|
|
840
851
|
|
841
852
|
path = @email.path
|
842
853
|
file = File.join(path, filename)
|
843
|
-
unless File.
|
854
|
+
unless File.exist?(file)
|
844
855
|
error("Unable to load helper file", :file => file) if abort_on_fail
|
845
856
|
return
|
846
857
|
end
|
@@ -932,7 +943,7 @@ module Inkcite
|
|
932
943
|
|
933
944
|
# Look for full month names (e.g. February) and add a zero-width space
|
934
945
|
# afterwards which prevents iOS from detecting said date.
|
935
|
-
raw.gsub!(/#{mon}/, "#{mon
|
946
|
+
raw.gsub!(/#{mon}/, "#{mon.dup.insert(1, Renderer::Base::ZERO_WIDTH_NON_BREAKING_SPACE)}")
|
936
947
|
|
937
948
|
end
|
938
949
|
|
@@ -948,7 +959,7 @@ module Inkcite
|
|
948
959
|
filtered.split("\n").each do |line|
|
949
960
|
|
950
961
|
# Increment the line number as we read the file.
|
951
|
-
@
|
962
|
+
@line_number += 1
|
952
963
|
|
953
964
|
begin
|
954
965
|
line = Renderer.render(line, self)
|
data/lib/inkcite/view/context.rb
CHANGED
@@ -11,6 +11,36 @@ module Inkcite
|
|
11
11
|
@view = view
|
12
12
|
end
|
13
13
|
|
14
|
+
# Defines a new helper via ERB, which allows designers to keep helper
|
15
|
+
# markup alongside the usage of it inside of partial. Helps keep
|
16
|
+
# code clean and prevents helper.tsv pollution for one-offs
|
17
|
+
def helper tag, open, close=nil
|
18
|
+
|
19
|
+
tag = tag.to_sym
|
20
|
+
|
21
|
+
# The config object holds the defined helpers
|
22
|
+
config = @view.config
|
23
|
+
|
24
|
+
# Warn the user if the helper is already defined.
|
25
|
+
view.error("Helper '#{tag}' already defined", :open => open, :close => close) unless config[tag].nil?
|
26
|
+
|
27
|
+
config[tag] = open.to_s
|
28
|
+
config[:"/#{tag}"] = close.to_s
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def once? key
|
33
|
+
|
34
|
+
# Initialize the 'once' data hash which maps
|
35
|
+
@view.data[:once] ||= {}
|
36
|
+
|
37
|
+
# True if this is the first time we've encountered this key.
|
38
|
+
first_time = @view.data[:once][key].nil?
|
39
|
+
@view.data[:once][key] = true if first_time
|
40
|
+
|
41
|
+
first_time
|
42
|
+
end
|
43
|
+
|
14
44
|
def method_missing(m, *args, &block)
|
15
45
|
if m[-1] == QUESTION_MARK
|
16
46
|
start_at = m[0] == UNDERSCORE ? 1 : 0
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
describe Inkcite::Animation do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@view = Inkcite::Email.new('test/project/').view(:development, :email)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'supports browser prefixing' do
|
10
|
+
Inkcite::Animation.with_browser_prefixes("animation: video-frames 5s ease infinite", @view, { :separator => '; ' }).must_equal('animation: video-frames 5s ease infinite; -webkit-animation: video-frames 5s ease infinite; ')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'can instantiate an animation keyframe' do
|
14
|
+
Inkcite::Animation::Keyframe.new(5, { :top => '-10px', :left => '22%' }).to_s.must_equal(' 5% { left:22%;top:-10px }')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can add style to an animation keyframe' do
|
18
|
+
keyframe = Inkcite::Animation::Keyframe.new(25)
|
19
|
+
keyframe[:top] = '-15%'
|
20
|
+
keyframe[:left] = '78px'
|
21
|
+
keyframe.to_s.must_equal(' 25% { left:78px;top:-15% }')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'can prefix a style on a keyframe' do
|
25
|
+
keyframe = Inkcite::Animation::Keyframe.new(33)
|
26
|
+
keyframe.add_with_prefixes :transform, 'rotate(14deg)', @view
|
27
|
+
keyframe.to_s.must_equal(' 33% { -webkit-transform:rotate(14deg);transform:rotate(14deg) }')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'can instantiate an animation and add keyframes' do
|
31
|
+
anim = Inkcite::Animation::Keyframes.new('snowflake7', @view)
|
32
|
+
anim << Inkcite::Animation::Keyframe.new(5, { :top => '-10px', :left => '22%' }).add_with_prefixes(:transform, 'rotate(14deg)', @view)
|
33
|
+
anim.add_keyframe 25, { :top => '100%', :left => '18%' }
|
34
|
+
anim.to_s.must_equal(%Q(@keyframes snowflake7 {\n 5% { -webkit-transform:rotate(14deg);left:22%;top:-10px;transform:rotate(14deg) }\n 25% { left:18%;top:100% }\n}\n@-webkit-keyframes snowflake7 {\n 5% { -webkit-transform:rotate(14deg);left:22%;top:-10px;transform:rotate(14deg) }\n 25% { left:18%;top:100% }\n}\n))
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
end
|
data/test/email_spec.rb
CHANGED
data/test/minifier_spec.rb
CHANGED
@@ -1,7 +1,3 @@
|
|
1
|
-
require 'minitest/spec'
|
2
|
-
require 'minitest/autorun'
|
3
|
-
require 'inkcite'
|
4
|
-
|
5
1
|
describe Inkcite::View do
|
6
2
|
|
7
3
|
before do
|
@@ -25,4 +21,247 @@ describe Inkcite::View do
|
|
25
21
|
Inkcite::Minifier.remove_comments(%Q(I am not <!-- This is a\n\nmulti-line HTML\ncomment -->commented out), @view).must_equal('I am not commented out')
|
26
22
|
end
|
27
23
|
|
24
|
+
it "compresses CSS whitespace" do
|
25
|
+
css = <<-EOF
|
26
|
+
table {
|
27
|
+
border-spacing: 0;
|
28
|
+
}
|
29
|
+
|
30
|
+
table, td {
|
31
|
+
border-collapse: collapse;
|
32
|
+
}
|
33
|
+
|
34
|
+
a[href^=tel] {
|
35
|
+
color: #336699;
|
36
|
+
text-decoration: none;
|
37
|
+
}
|
38
|
+
|
39
|
+
div[style*="margin:16px 0"] {
|
40
|
+
margin: 0 !important;
|
41
|
+
}
|
42
|
+
EOF
|
43
|
+
|
44
|
+
Inkcite::Minifier.css(css, @view).must_equal(%Q(table{border-spacing:0}table, td{border-collapse:collapse}a[href^=tel]{color:#336699;text-decoration:none}div[style*="margin:16px 0"]{margin:0 !important}))
|
45
|
+
end
|
46
|
+
|
47
|
+
it "does not interfere with CSS3 animation keyframe at 0%" do
|
48
|
+
css = <<-EOF
|
49
|
+
@-webkit-keyframes s1a2 {
|
50
|
+
0% {
|
51
|
+
top: -3%;
|
52
|
+
left: 68.75%
|
53
|
+
}
|
54
|
+
100% {
|
55
|
+
top: 100%;
|
56
|
+
left: 66%
|
57
|
+
}
|
58
|
+
}
|
59
|
+
EOF
|
60
|
+
Inkcite::Minifier.css(css, @view).must_equal('@-webkit-keyframes s1a2{0%{top:-3%;left:68.75%}100%{top:100%;left:66%}}')
|
61
|
+
end
|
62
|
+
|
63
|
+
it "does not interfere with CSS3 animation rotation in degrees" do
|
64
|
+
css = <<-EOF
|
65
|
+
@-webkit-keyframes snow1-anim8 {
|
66
|
+
0% { top: -3%; left: 57%; }
|
67
|
+
100% { top: 100%; left: 60%; transform: rotate(-93deg); -webkit-transform: rotate(-93deg); }
|
68
|
+
}
|
69
|
+
EOF
|
70
|
+
|
71
|
+
Inkcite::Minifier.css(css, @view).must_equal('@-webkit-keyframes snow1-anim8{0%{top:-3%;left:57%}100%{top:100%;left:60%;transform:rotate(-93deg);-webkit-transform:rotate(-93deg)}}')
|
72
|
+
end
|
73
|
+
|
74
|
+
it "wraps lines of CSS exceeding #{Inkcite::Minifier::MAXIMUM_LINE_LENGTH} characters" do
|
75
|
+
css = <<-EOF
|
76
|
+
.ExternalClass, .ReadMsgBody {
|
77
|
+
width: 100%;
|
78
|
+
}
|
79
|
+
|
80
|
+
.ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {
|
81
|
+
line-height: 100%;
|
82
|
+
}
|
83
|
+
|
84
|
+
#outlook a {
|
85
|
+
padding: 0;
|
86
|
+
}
|
87
|
+
|
88
|
+
.yshortcuts, .yshortcuts a, .yshortcuts a:link, .yshortcuts a:visited, .yshortcuts a:hover, .yshortcuts a span {
|
89
|
+
color: black;
|
90
|
+
text-decoration: none !important;
|
91
|
+
border-bottom: none !important;
|
92
|
+
background: none !important;
|
93
|
+
}
|
94
|
+
|
95
|
+
XHTML-STRIPONREPLY {
|
96
|
+
display: none;
|
97
|
+
}
|
98
|
+
|
99
|
+
table {
|
100
|
+
border-spacing: 0;
|
101
|
+
}
|
102
|
+
|
103
|
+
table, td {
|
104
|
+
border-collapse: collapse;
|
105
|
+
}
|
106
|
+
|
107
|
+
a[href^=tel] {
|
108
|
+
color: #336699;
|
109
|
+
text-decoration: none;
|
110
|
+
}
|
111
|
+
|
112
|
+
div[style*="margin: 16px 0"] {
|
113
|
+
margin: 0 !important;
|
114
|
+
}
|
115
|
+
|
116
|
+
td {
|
117
|
+
font-family: sans-serif;
|
118
|
+
}
|
119
|
+
|
120
|
+
@media only screen and (max-width: 480px) {
|
121
|
+
[class~="hide"] {
|
122
|
+
display: none !important;
|
123
|
+
}
|
124
|
+
|
125
|
+
td[class~="drop"] {
|
126
|
+
display: block;
|
127
|
+
width: 100% !important;
|
128
|
+
background-size: 100% auto !important;
|
129
|
+
-moz-box-sizing: border-box;
|
130
|
+
-webkit-box-sizing: border-box;
|
131
|
+
box-sizing: border-box;
|
132
|
+
}
|
133
|
+
|
134
|
+
img[class~="fill"] {
|
135
|
+
width: 100% !important;
|
136
|
+
height: auto !important;
|
137
|
+
}
|
138
|
+
|
139
|
+
table[class~="fill"], td[class~="fill"] {
|
140
|
+
width: 100% !important;
|
141
|
+
background-size: 100% auto !important;
|
142
|
+
}
|
143
|
+
|
144
|
+
span[class~="img"] {
|
145
|
+
display: block;
|
146
|
+
background-position: center;
|
147
|
+
background-size: cover;
|
148
|
+
}
|
149
|
+
|
150
|
+
a[class~="button"] {
|
151
|
+
border: 2px solid #336699;
|
152
|
+
border-radius: 5px;
|
153
|
+
color: #336699 !important;
|
154
|
+
display: block;
|
155
|
+
font-weight: bold;
|
156
|
+
margin-top: 5px;
|
157
|
+
padding: 9px;
|
158
|
+
text-align: center
|
159
|
+
}
|
160
|
+
|
161
|
+
img[class~="i01"] {
|
162
|
+
content: url("images-optim/xxxxxx-xxxxxxxx.jpg?1457623072") !important;
|
163
|
+
}
|
164
|
+
|
165
|
+
td[class~="m1"] {
|
166
|
+
font-size: 15px !important;
|
167
|
+
line-height: 20px !important
|
168
|
+
}
|
169
|
+
|
170
|
+
td[class~="m2"] {
|
171
|
+
text-align: center;
|
172
|
+
}
|
173
|
+
|
174
|
+
table[class~="m3"], td[class~="m3"] {
|
175
|
+
padding: 15px !important;
|
176
|
+
}
|
177
|
+
|
178
|
+
img[class~="i02"] {
|
179
|
+
content: url("images-optim/xxxxxx.jpg?1457623072") !important;
|
180
|
+
}
|
181
|
+
|
182
|
+
td[class~="m4"] {
|
183
|
+
height: 15px;
|
184
|
+
display: block;
|
185
|
+
width: 100%;
|
186
|
+
margin-top: 12px;
|
187
|
+
border-top: 1px dotted #cfcfcf;
|
188
|
+
}
|
189
|
+
|
190
|
+
img[class~="i03"] {
|
191
|
+
content: url("images-optim/xxxxxx.jpg?1457623072") !important;
|
192
|
+
}
|
193
|
+
|
194
|
+
img[class~="i04"] {
|
195
|
+
content: url("images-optim/xxxxxx.jpg?1457623072") !important;
|
196
|
+
}
|
197
|
+
|
198
|
+
table[class~="m5"] {
|
199
|
+
background: #5EAE3F url(images-optim/xxx-xx-x.jpg?1457623072) bottom left / 100% auto no-repeat !important
|
200
|
+
}
|
201
|
+
|
202
|
+
img[class~="i05"] {
|
203
|
+
content: url("images-optim/xxxxx.gif?1457623072") !important;
|
204
|
+
}
|
205
|
+
|
206
|
+
img[class~="i06"] {
|
207
|
+
content: url("images-optim/xxxxx.jpg?1457623072") !important;
|
208
|
+
}
|
209
|
+
|
210
|
+
td[class~="m6"] {
|
211
|
+
padding: 15px;
|
212
|
+
}
|
213
|
+
|
214
|
+
img[class~="i07"] {
|
215
|
+
content: url("images-optim/xxxxx.jpg?1457623072") !important;
|
216
|
+
}
|
217
|
+
|
218
|
+
img[class~="i08"] {
|
219
|
+
content: url("images-optim/xxxxx.jpg?1457623072") !important;
|
220
|
+
}
|
221
|
+
|
222
|
+
img[class~="i09"] {
|
223
|
+
content: url("images-optim/xxxxxx.jpg?1457623072") !important;
|
224
|
+
}
|
225
|
+
|
226
|
+
td[class~="m7"] {
|
227
|
+
height: 15px;
|
228
|
+
}
|
229
|
+
|
230
|
+
img[class~="i10"] {
|
231
|
+
content: url("images-optim/xxxxxx.jpg?1457623072") !important;
|
232
|
+
}
|
233
|
+
|
234
|
+
img[class~="i11"] {
|
235
|
+
content: url("images-optim/xxxxxx.jpg?1457623072") !important;
|
236
|
+
}
|
237
|
+
|
238
|
+
td[class~="m8"] {
|
239
|
+
background: url(images-optim/xxxxx-xx.gif?1457623072) center no-repeat
|
240
|
+
}
|
241
|
+
|
242
|
+
img[class~="i12"] {
|
243
|
+
content: url("images-optim/xxxxx.jpg?1457623072") !important;
|
244
|
+
}
|
245
|
+
|
246
|
+
img[class~="i13"] {
|
247
|
+
content: url("images-optim/xxxxx.jpg?1457623072") !important;
|
248
|
+
}
|
249
|
+
|
250
|
+
img[class~="i14"] {
|
251
|
+
content: url("images-optim/xxxxx.jpg?1457623072") !important;
|
252
|
+
}
|
253
|
+
|
254
|
+
span[class~="i15"] {
|
255
|
+
background-image: url("images-optim/xxx.gif?1457623072");
|
256
|
+
float: right;
|
257
|
+
height: 101px;
|
258
|
+
width: 139px
|
259
|
+
}
|
260
|
+
}
|
261
|
+
EOF
|
262
|
+
|
263
|
+
minified_css = Inkcite::Minifier.css(css, @view)
|
264
|
+
minified_css.split("\n").all? { |l| l.length <= Inkcite::Minifier::MAXIMUM_LINE_LENGTH }.must_equal(true)
|
265
|
+
end
|
266
|
+
|
28
267
|
end
|