inkcite 1.11.0 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -2
  3. data/assets/init/helpers.tsv +7 -0
  4. data/assets/social/facebook.png +0 -0
  5. data/assets/social/pintrest.png +0 -0
  6. data/assets/social/twitter.png +0 -0
  7. data/inkcite.gemspec +5 -4
  8. data/lib/inkcite.rb +17 -6
  9. data/lib/inkcite/animation.rb +135 -0
  10. data/lib/inkcite/cli/base.rb +5 -14
  11. data/lib/inkcite/cli/build.rb +3 -3
  12. data/lib/inkcite/cli/init.rb +3 -3
  13. data/lib/inkcite/cli/preview.rb +25 -1
  14. data/lib/inkcite/cli/server.rb +1 -1
  15. data/lib/inkcite/cli/validate.rb +2 -11
  16. data/lib/inkcite/email.rb +1 -1
  17. data/lib/inkcite/mailer.rb +5 -0
  18. data/lib/inkcite/minifier.rb +58 -11
  19. data/lib/inkcite/renderer.rb +10 -2
  20. data/lib/inkcite/renderer/base.rb +45 -3
  21. data/lib/inkcite/renderer/button.rb +16 -12
  22. data/lib/inkcite/renderer/container_base.rb +14 -4
  23. data/lib/inkcite/renderer/element.rb +13 -3
  24. data/lib/inkcite/renderer/image.rb +46 -19
  25. data/lib/inkcite/renderer/image_base.rb +3 -3
  26. data/lib/inkcite/renderer/in_browser.rb +1 -1
  27. data/lib/inkcite/renderer/link.rb +91 -59
  28. data/lib/inkcite/renderer/lorem.rb +9 -1
  29. data/lib/inkcite/renderer/mobile_image.rb +3 -11
  30. data/lib/inkcite/renderer/mobile_only.rb +48 -0
  31. data/lib/inkcite/renderer/outlook_background.rb +61 -13
  32. data/lib/inkcite/renderer/property.rb +1 -1
  33. data/lib/inkcite/renderer/responsive.rb +10 -8
  34. data/lib/inkcite/renderer/snow.rb +20 -10
  35. data/lib/inkcite/renderer/social.rb +128 -0
  36. data/lib/inkcite/renderer/table.rb +13 -1
  37. data/lib/inkcite/renderer/table_base.rb +3 -3
  38. data/lib/inkcite/renderer/td.rb +32 -7
  39. data/lib/inkcite/renderer/video_preview.rb +257 -0
  40. data/lib/inkcite/uploader.rb +3 -3
  41. data/lib/inkcite/util.rb +19 -5
  42. data/lib/inkcite/version.rb +1 -1
  43. data/lib/inkcite/view.rb +29 -18
  44. data/lib/inkcite/view/context.rb +30 -0
  45. data/test/animation_spec.rb +38 -0
  46. data/test/email_spec.rb +0 -4
  47. data/test/minifier_spec.rb +243 -4
  48. data/test/parser_spec.rb +0 -4
  49. data/test/project/helpers.tsv +3 -0
  50. data/test/renderer/button_spec.rb +15 -13
  51. data/test/renderer/div_spec.rb +13 -4
  52. data/test/renderer/element_spec.rb +1 -5
  53. data/test/renderer/footnote_spec.rb +0 -4
  54. data/test/renderer/image_spec.rb +27 -11
  55. data/test/renderer/link_spec.rb +14 -4
  56. data/test/renderer/lorem_spec.rb +0 -4
  57. data/test/renderer/mobile_image_spec.rb +3 -11
  58. data/test/renderer/mobile_only_spec.rb +21 -0
  59. data/test/renderer/mobile_style_spec.rb +1 -5
  60. data/test/renderer/outlook_background_spec.rb +61 -0
  61. data/test/renderer/redacted_spec.rb +0 -4
  62. data/test/renderer/social_spec.rb +53 -0
  63. data/test/renderer/span_spec.rb +0 -4
  64. data/test/renderer/table_spec.rb +8 -4
  65. data/test/renderer/td_spec.rb +0 -4
  66. data/test/renderer/video_preview_spec.rb +19 -0
  67. data/test/renderer_spec.rb +0 -4
  68. data/test/test_helper.rb +7 -0
  69. data/test/view_spec.rb +12 -4
  70. metadata +89 -56
@@ -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.exists?(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.exists?(local_images)
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.exists?(local)
45
+ return unless File.exist?(local)
46
46
 
47
47
  Dir.foreach(local) do |file|
48
48
  next if file.starts_with?('.')
@@ -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 { |color| color.hex }
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 { |color| color.hex }
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.exists?(path)
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.exists?(file) ? File.mtime(file).to_i : 0
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.exists?(path)
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,}/, ' ')
@@ -1,3 +1,3 @@
1
1
  module Inkcite
2
- VERSION = "1.11.0"
2
+ VERSION = "1.12.0"
3
3
  end
@@ -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 :line
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
- @line = 0
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.exists?(path)
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.line.to_i})"
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.exists?(footnotes_tsv_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.exists?(links_tsv_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
- html << '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
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? && is_enabled?(:vml)
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.exists?(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}#{Renderer::Base::ZERO_WIDTH_SPACE}")
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
- @line += 1
962
+ @line_number += 1
952
963
 
953
964
  begin
954
965
  line = Renderer.render(line, self)
@@ -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
@@ -1,7 +1,3 @@
1
- require 'minitest/spec'
2
- require 'minitest/autorun'
3
- require 'inkcite'
4
-
5
1
  describe Inkcite::Email do
6
2
 
7
3
  before do
@@ -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