inkcite 1.12.1 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,81 @@
1
+ module Inkcite
2
+ module Renderer
3
+ class Style
4
+
5
+ def initialize name, ctx, styles={}
6
+
7
+ @name = name
8
+ @ctx = ctx
9
+ @styles = styles
10
+
11
+ end
12
+
13
+ def [] key
14
+ @styles[key]
15
+ end
16
+
17
+ def []= key, val
18
+ @styles[key] = val
19
+ end
20
+
21
+ def to_css allowed_prefixes=nil
22
+ "#{@name} { #{to_inline_css(allowed_prefixes)} }"
23
+ end
24
+
25
+ def to_inline_css allowed_prefixes=nil
26
+
27
+ # Inherit the list of allowed prefixes from the context if
28
+ # none were provided. Otherwise, make sure we're working
29
+ # with an array.
30
+ if allowed_prefixes.nil?
31
+ allowed_prefixes = @ctx.prefixes
32
+ else
33
+ allowed_prefixes = [*allowed_prefixes]
34
+ end
35
+
36
+ # This will hold a copy of the key and values including
37
+ # all keys with prefixes.
38
+ _styles = {}
39
+
40
+ # A reusable array indicating no prefixing is necessary.
41
+ no_prefixes = ['']
42
+
43
+ @styles.each_pair do |key, val|
44
+
45
+ # Determine which list of prefixes are needed based on the
46
+ # original key (e.g. :transform) - or use the list of
47
+ # non-modifying prefixes.
48
+ prefixes = if Inkcite::Renderer::Style.needs_prefixing?(key)
49
+ allowed_prefixes
50
+ else
51
+ no_prefixes
52
+ end
53
+
54
+ # Iterate through each prefix and create a hybrid key. Then
55
+ # add the styles to the temporary list.
56
+ prefixes.each do |prefix|
57
+ prefixed_key = "#{prefix}#{key}".to_sym
58
+ _styles[prefixed_key] = val
59
+ end
60
+
61
+ end
62
+
63
+ Renderer.render_styles(_styles)
64
+ end
65
+
66
+ def to_s
67
+ @name.blank? ? to_inline_css : to_css
68
+ end
69
+
70
+ def self.needs_prefixing? key
71
+ PREFIXABLE_KEYS.include?(key.to_sym)
72
+ end
73
+
74
+ private
75
+
76
+ # Array of CSS attributes that must be prefixed (e.g. transform and animation)
77
+ PREFIXABLE_KEYS = [:animation, :transform]
78
+
79
+ end
80
+ end
81
+ end
@@ -16,6 +16,7 @@ module Inkcite
16
16
  mix_background element, opt, ctx
17
17
  mix_border element, opt, ctx
18
18
  mix_dimensions element, opt, ctx
19
+ mix_margins element, opt, ctx
19
20
 
20
21
  end
21
22
 
@@ -51,24 +52,15 @@ module Inkcite
51
52
  # mobile version inherits from the desktop version.
52
53
  mobile_background = mix_background_shorthand(
53
54
  detect(opt[MOBILE_BACKGROUND_COLOR], opt[MOBILE_BGCOLOR], bgcolor),
54
- detect(opt[MOBILE_BACKGROUND_IMAGE], opt[MOBILE_BACKGROUND], bgimage),
55
+ detect(opt[MOBILE_BACKGROUND_IMAGE], opt[MOBILE_BACKGROUND], opt[MOBILE_SRC], bgimage),
55
56
  detect(opt[MOBILE_BACKGROUND_POSITION], bgposition),
56
57
  detect(opt[MOBILE_BACKGROUND_REPEAT], bgrepeat),
57
58
  detect(opt[MOBILE_BACKGROUND_SIZE], bgsize),
58
59
  ctx
59
60
  )
60
61
 
61
- unless mobile_background.blank? || mobile_background == desktop_background
62
-
63
- mobile_background << ' !important' unless desktop_background.blank?
64
-
65
- # Add the responsive rule that applies to this element.
66
- rule = Rule.new(element.tag, unique_klass(ctx), { :background => mobile_background })
67
-
68
- # Add the rule to the view and the element
69
- ctx.media_query << rule
70
- element.add_rule rule
71
-
62
+ if !mobile_background.blank? && mobile_background != desktop_background
63
+ element.mobile_style[:background] = mobile_background
72
64
  end
73
65
 
74
66
  end
@@ -27,10 +27,6 @@ module Inkcite
27
27
  # Retrieve the opts that were used to open this TD.
28
28
  open_opt = tag_stack.pop
29
29
 
30
- # If the opening tag initiated an automatic outlook background
31
- # then we need to inject the close tag here.
32
- html << "{/outlook-bg}\n" if outlook_bg?(open_opt)
33
-
34
30
  # Normal HTML produced by the Helper to close the cell.
35
31
  html << '</td>'
36
32
 
@@ -76,6 +72,12 @@ module Inkcite
76
72
 
77
73
  mobile = opt[:mobile]
78
74
 
75
+ # If the table defines mobile-padding, then apply the correct mobile
76
+ # style to this td - and its !important if there is padding on
77
+ # the td already.
78
+ mobile_padding = table_opt[MOBILE_PADDING] || opt[MOBILE_PADDING]
79
+ td.mobile_style[:padding] = px(mobile_padding) unless mobile_padding.blank? || mobile == HIDE
80
+
79
81
  # Need to handle Fluid-Drop HTML injection here before the rest of the
80
82
  # TD is formalized. Fluid-Drop removes the width attribute of the cell
81
83
  # as it is wrapped in a 100%-width table.
@@ -170,21 +172,6 @@ module Inkcite
170
172
 
171
173
  html << td.to_s
172
174
 
173
- # For convenience and to keep code DRY, support the outlook-bg boolean
174
- # attribute which causes an {outlook-bg} Helper to be injected automatically
175
- # inside of the {td}.
176
- if outlook_bg?(opt)
177
-
178
- html << "\n"
179
- html << Element.new('outlook-bg', {
180
- :bgcolor => detect_bgcolor(opt),
181
- :width => opt[:width],
182
- :height => opt[:height],
183
- :src => opt[:background]
184
- }).to_helper
185
-
186
- end
187
-
188
175
  end
189
176
 
190
177
  html
@@ -192,11 +179,6 @@ module Inkcite
192
179
 
193
180
  private
194
181
 
195
- # Returns true if the conditions are met that enable the
196
- # automatic {outlook-bg} helper integration.
197
- def outlook_bg? opt
198
- opt && opt[OUTLOOK_BG] && !opt[:background].blank?
199
- end
200
182
 
201
183
  CLOSE_TD = '/td'
202
184
  LEFT = 'left'
@@ -94,7 +94,19 @@ module Inkcite
94
94
  :width => '100%', :background => first_frame, BACKGROUND_SIZE => 'cover',
95
95
  Table::TR_TRANSITION => %q("all .5s cubic-bezier(0.075, 0.82, 0.165, 1)")
96
96
  })
97
- table[:animation] = %Q("#{animation_name} #{duration}s ease infinite") if has_animation
97
+
98
+ # Will hold the Animation if animation is enabled for this
99
+ # video-preview.
100
+ animation = nil
101
+
102
+ if has_animation
103
+ animation = Animation.new(animation_name, ctx)
104
+ animation.timing_function = Animation::EASE
105
+ animation.duration = duration
106
+
107
+ table[:animation] = quote(animation)
108
+ end
109
+
98
110
  html << table.to_helper
99
111
 
100
112
  # Transparent spacer for preserving aspect ratio.
@@ -218,26 +230,24 @@ module Inkcite
218
230
  # end of the animation.
219
231
  percent = 0.0
220
232
 
221
- keyframes = Animation::Keyframes.new(animation_name, ctx)
222
-
223
233
  # Iterate through each frame and add two keyframes, the first
224
234
  # being the time at which the frame appears plus another frame
225
235
  # after the duration it should be on screen.
226
236
  frames.each do |f|
227
237
  this_frame_url = "url(#{f})"
228
238
 
229
- keyframes.add_keyframe(percent, { BACKGROUND_IMAGE => this_frame_url })
239
+ animation.add_keyframe(percent, { BACKGROUND_IMAGE => this_frame_url })
230
240
  percent += percent_per_frame
231
- keyframes.add_keyframe(percent, { BACKGROUND_IMAGE => this_frame_url })
241
+ animation.add_keyframe(percent, { BACKGROUND_IMAGE => this_frame_url })
232
242
  percent += percent_per_transition
233
243
 
234
244
  end
235
245
 
236
246
  # Transition back to the first frame.
237
- keyframes.add_keyframe(100, { BACKGROUND_IMAGE => "url(#{first_frame})" })
247
+ animation.add_keyframe(100, { BACKGROUND_IMAGE => "url(#{first_frame})" })
238
248
 
239
249
  # Add the keyframes to the styles array.
240
- styles << keyframes.to_s
250
+ styles << animation.to_keyframe_css
241
251
 
242
252
  end
243
253
 
@@ -1,3 +1,3 @@
1
1
  module Inkcite
2
- VERSION = "1.12.1"
2
+ VERSION = "1.13.0"
3
3
  end
@@ -335,6 +335,12 @@ module Inkcite
335
335
  tag_stack(tag).opts
336
336
  end
337
337
 
338
+ # Returns the array of browser prefixes that need to be included in
339
+ # CSS styles based on which version of the email this is.
340
+ def prefixes
341
+ [ '', '-webkit-' ]
342
+ end
343
+
338
344
  def preview?
339
345
  @environment == :preview
340
346
  end
@@ -432,9 +438,7 @@ module Inkcite
432
438
  # Add external styles
433
439
  html += external_styles
434
440
 
435
- html << '<style type="text/css">'
436
441
  html << inline_styles
437
- html << '</style>'
438
442
  html << '</head>'
439
443
 
440
444
  # Intentionally not setting the link colors because those should be entirely
@@ -710,7 +714,7 @@ module Inkcite
710
714
 
711
715
  def inline_google_fonts
712
716
 
713
- reset = ''
717
+ css = ''
714
718
 
715
719
  # Google Web Fonts support courtesy of
716
720
  # http://www.emaildesignreview.com/html-email-coding/web-fonts-in-email-1482/
@@ -729,7 +733,7 @@ module Inkcite
729
733
  # If you use @font-face in HTML email, Outlook 07/10/13 will default all
730
734
  # text back to Times New Roman.
731
735
  # http://www.emaildesignreview.com/html-email-coding/web-fonts-in-email-1482/
732
- reset << '@media screen {'
736
+ css << '@media screen {'
733
737
 
734
738
  # Iterate through the configured fonts. Check to see if we've already cached
735
739
  # Google's response. If not, retrieve it and add it to the
@@ -744,16 +748,16 @@ module Inkcite
744
748
  end
745
749
  end
746
750
 
747
- reset << font_cache[url]
751
+ css << font_cache[url]
748
752
  end
749
- reset << '}'
753
+ css << '}'
750
754
 
751
755
  # If the fontcache was updated, update it in our sekret file.
752
756
  File.write(font_cache_path, font_cache.to_yaml) if updated
753
757
 
754
758
  end
755
759
 
756
- reset
760
+ css
757
761
  end
758
762
 
759
763
 
@@ -779,7 +783,7 @@ module Inkcite
779
783
  code
780
784
  end
781
785
 
782
- def inline_styles
786
+ def inline_reset_styles
783
787
 
784
788
  reset = []
785
789
 
@@ -820,26 +824,57 @@ module Inkcite
820
824
  # Reset the font on every cell to the default family.
821
825
  reset << "td { font-family: #{self[Renderer::Base::FONT_FAMILY]}; }"
822
826
 
823
- # Obviously VML-specific CSS needed only if VML was used in the issue.
827
+ # VML-specific CSS needed only if VML was used in the email.
824
828
  if vml_used?
825
829
  reset << 'v\:* { behavior: url(#default#VML); display: inline-block; }'
826
830
  reset << 'o\:* { behavior: url(#default#VML); display: inline-block; }'
827
831
  end
828
832
 
829
- reset << inline_google_fonts
833
+ reset.join(NEW_LINE)
834
+ end
835
+
836
+ def inline_styles
837
+
838
+ # Separating <style> blocks to prevent Gmail from filtering
839
+ # the entire CSS section because of its strict parsing.
840
+ # https://emails.hteumeuleu.com/troubleshooting-gmails-responsive-design-support-ad124178bf81#.khhj4u4b5
841
+ style_blocks = []
842
+
843
+ # Add a section for the bootstrap/reset styles common to every email
844
+ # that address common rendering issues in many clients.
845
+ style_blocks << inline_reset_styles
846
+
847
+ # Web font styles need to be in their own block because
848
+ # they have multiple @ signs which Gmail doesn't like.
849
+ style_blocks << inline_google_fonts
830
850
 
831
851
  # Responsive styles.
832
- reset += @media_query.to_a unless @media_query.blank?
852
+ style_blocks << @media_query.to_css unless @media_query.blank?
833
853
 
834
- html = []
854
+ # Filter the URI-based styles and add the remaining styles as a
855
+ # separate block. Possibly need to consider making these style
856
+ # blocks separate in the future - e.g. special effects blocks
857
+ # should probably be separated since there is a high likelihood
858
+ # of @ within @
859
+ style_blocks << self.styles.select { |s| !s.is_a?(URI::HTTP) }.join(NEW_LINE)
835
860
 
836
- # Append the minified CSS
837
- html << Minifier.css(reset.join(NEW_LINE), self)
861
+ # Filter empty style blocks
862
+ style_blocks.select! { |s| !s.blank? }
838
863
 
839
- # Iterate through the list of files or in-line CSS and embed them into the HTML.
840
- self.styles.each do |css|
841
- next if css.is_a?(URI::HTTP)
842
- html << Minifier.css(from_uri(css), self)
864
+ # Minify each of the blocks
865
+ style_blocks.each { |s| Minifier.css(s, self) }
866
+
867
+ # Join all of the style blocks into a single block if this
868
+ # is not an email - otherwise, keep them separate.
869
+ style_blocks = [ style_blocks.join(NEW_LINE) ] unless email?
870
+
871
+ html = []
872
+
873
+ # Iterate through the style blocks and append them
874
+ style_blocks.each do |s|
875
+ html << '<style>'
876
+ html << s
877
+ html << '</style>'
843
878
  end
844
879
 
845
880
  html.join(NEW_LINE)
@@ -46,7 +46,7 @@ module Inkcite
46
46
  css = []
47
47
  css << "@media only screen and (max-width: #{Inkcite::Renderer::px(@max_width)}) {"
48
48
  css += active_styles.collect(&:to_css)
49
- css << "}"
49
+ css << '}'
50
50
 
51
51
  css
52
52
  end
@@ -7,31 +7,35 @@ describe Inkcite::Animation do
7
7
  end
8
8
 
9
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; ')
10
+ Inkcite::Renderer::Style.new(nil, @view, { :animation => 'video-frames 5s ease infinite' }).to_s.must_equal('-webkit-animation:video-frames 5s ease infinite;animation:video-frames 5s ease infinite')
11
+ end
12
+
13
+ it 'supports browser prefixing specific items only' do
14
+ Inkcite::Renderer::Style.new(nil, @view, { :left => '25%', :animation => 'video-frames 5s ease infinite' }).to_s.must_equal('-webkit-animation:video-frames 5s ease infinite;animation:video-frames 5s ease infinite;left:25%')
11
15
  end
12
16
 
13
17
  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 }')
18
+ Inkcite::Animation::Keyframe.new(5, @view, { :top => '-10px', :left => '22%' }).to_css('').must_equal('5% { left:22%;top:-10px }')
15
19
  end
16
20
 
17
21
  it 'can add style to an animation keyframe' do
18
- keyframe = Inkcite::Animation::Keyframe.new(25)
22
+ keyframe = Inkcite::Animation::Keyframe.new(25, @view)
19
23
  keyframe[:top] = '-15%'
20
24
  keyframe[:left] = '78px'
21
- keyframe.to_s.must_equal(' 25% { left:78px;top:-15% }')
25
+ keyframe.to_css('').must_equal('25% { left:78px;top:-15% }')
22
26
  end
23
27
 
24
28
  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) }')
29
+ keyframe = Inkcite::Animation::Keyframe.new(33, @view, { :transform => 'rotate(14deg)' })
30
+ keyframe.to_css('').must_equal('33% { transform:rotate(14deg) }')
31
+ keyframe.to_css('-webkit-').must_equal('33% { -webkit-transform:rotate(14deg) }')
28
32
  end
29
33
 
30
34
  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)
35
+ anim = Inkcite::Animation.new('snowflake7', @view)
36
+ anim.add_keyframe 5, { :top => '-10px', :left => '22%', :transform => 'rotate(14deg)' }
33
37
  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))
38
+ anim.to_keyframe_css.must_equal(%Q(@keyframes snowflake7 {\n5% { left:22%;top:-10px;transform:rotate(14deg) }\n25% { left:18%;top:100% }\n}\n@-webkit-keyframes snowflake7 {\n5% { -webkit-transform:rotate(14deg);left:22%;top:-10px }\n25% { left:18%;top:100% }\n}\n))
35
39
  end
36
40
 
37
41
 
@@ -0,0 +1,59 @@
1
+ describe Inkcite::Renderer::Background do
2
+
3
+ before do
4
+ @view = Inkcite::Email.new('test/project/').view(:development, :email)
5
+ end
6
+
7
+ it 'warns when an image is missing' do
8
+ Inkcite::Renderer.render('{background src=missing.jpg}', @view)
9
+ @view.errors.must_include('Missing image (line 0) [src=missing.jpg]')
10
+ end
11
+
12
+ it 'warns when an outlook-specific image is missing' do
13
+ Inkcite::Renderer.render('{background outlook-src=also-missing.jpg}', @view)
14
+ @view.errors.must_include('Missing image (line 0) [src=also-missing.jpg]')
15
+ end
16
+
17
+ it 'defaults to filling the available horizontal space' do
18
+ Inkcite::Renderer.render('{background src=https://i.imgur.com/YJOX1PC.png}{/background}', @view).must_equal('<table border=0 cellpadding=0 cellspacing=0 style="background:url(https://i.imgur.com/YJOX1PC.png)" width=100%><tr><td><!--[if mso]><v:rect fill="t" stroke="f" style="mso-width-percent:1000" xmlns:v="urn:schemas-microsoft-com:vml"><v:fill src="https://i.imgur.com/YJOX1PC.png" type="tile" /><v:textbox inset="0,0,0,0" style="mso-fit-shape-to-text:True"><![endif]--><div></div><!--[if mso]></v:textbox></v:rect><![endif]--></td></tr></table>')
19
+ end
20
+
21
+ it 'supports 100% width' do
22
+ Inkcite::Renderer.render('{background src=https://i.imgur.com/YJOX1PC.png width=100%}{/background}', @view).must_equal('<table border=0 cellpadding=0 cellspacing=0 style="background:url(https://i.imgur.com/YJOX1PC.png)" width=100%><tr><td><!--[if mso]><v:rect fill="t" stroke="f" style="mso-width-percent:1000" xmlns:v="urn:schemas-microsoft-com:vml"><v:fill src="https://i.imgur.com/YJOX1PC.png" type="tile" /><v:textbox inset="0,0,0,0" style="mso-fit-shape-to-text:True"><![endif]--><div></div><!--[if mso]></v:textbox></v:rect><![endif]--></td></tr></table>')
23
+ end
24
+
25
+ it 'supports fill width' do
26
+ Inkcite::Renderer.render('{background src=https://i.imgur.com/YJOX1PC.png width=fill}{/background}', @view).must_equal('<table border=0 cellpadding=0 cellspacing=0 style="background:url(https://i.imgur.com/YJOX1PC.png)" width=100%><tr><td><!--[if mso]><v:rect fill="t" stroke="f" style="mso-width-percent:1000" xmlns:v="urn:schemas-microsoft-com:vml"><v:fill src="https://i.imgur.com/YJOX1PC.png" type="tile" /><v:textbox inset="0,0,0,0" style="mso-fit-shape-to-text:True"><![endif]--><div></div><!--[if mso]></v:textbox></v:rect><![endif]--></td></tr></table>')
27
+ end
28
+
29
+ it 'supports an optional width in pixels' do
30
+ Inkcite::Renderer.render('{background src=https://i.imgur.com/YJOX1PC.png width=120}{/background}', @view).must_equal('<table border=0 cellpadding=0 cellspacing=0 style="background:url(https://i.imgur.com/YJOX1PC.png)" width=120><tr><td><!--[if mso]><v:rect fill="t" stroke="f" style="width:120px" xmlns:v="urn:schemas-microsoft-com:vml"><v:fill src="https://i.imgur.com/YJOX1PC.png" type="tile" /><v:textbox inset="0,0,0,0" style="mso-fit-shape-to-text:True"><![endif]--><div></div><!--[if mso]></v:textbox></v:rect><![endif]--></td></tr></table>')
31
+ end
32
+
33
+ it 'supports an optional height in pixels' do
34
+ Inkcite::Renderer.render('{background src=https://i.imgur.com/YJOX1PC.png bgcolor=#7bceeb height=92 width=120}{/background}', @view).must_equal('<table bgcolor=#7bceeb border=0 cellpadding=0 cellspacing=0 height=92 style="background:#7bceeb url(https://i.imgur.com/YJOX1PC.png)" width=120><tr><td><!--[if mso]><v:rect fill="t" stroke="f" style="height:92px;width:120px" xmlns:v="urn:schemas-microsoft-com:vml"><v:fill color="#7bceeb" src="https://i.imgur.com/YJOX1PC.png" type="tile" /><v:textbox inset="0,0,0,0"><![endif]--><div></div><!--[if mso]></v:textbox></v:rect><![endif]--></td></tr></table>')
35
+ end
36
+
37
+ it 'supports an optional background color' do
38
+ Inkcite::Renderer.render('{background src=https://i.imgur.com/YJOX1PC.png bgcolor=#7bceeb width=120}{/background}', @view).must_equal('<table bgcolor=#7bceeb border=0 cellpadding=0 cellspacing=0 style="background:#7bceeb url(https://i.imgur.com/YJOX1PC.png)" width=120><tr><td><!--[if mso]><v:rect fill="t" stroke="f" style="width:120px" xmlns:v="urn:schemas-microsoft-com:vml"><v:fill color="#7bceeb" src="https://i.imgur.com/YJOX1PC.png" type="tile" /><v:textbox inset="0,0,0,0" style="mso-fit-shape-to-text:True"><![endif]--><div></div><!--[if mso]></v:textbox></v:rect><![endif]--></td></tr></table>')
39
+ end
40
+
41
+ it 'supports the font attribute' do
42
+ Inkcite::Renderer.render('{background src=https://i.imgur.com/YJOX1PC.png font=large align=center}{/background}', @view).must_equal('<table border=0 cellpadding=0 cellspacing=0 style="background:url(https://i.imgur.com/YJOX1PC.png)" width=100%><tr><td><!--[if mso]><v:rect fill="t" stroke="f" style="mso-width-percent:1000" xmlns:v="urn:schemas-microsoft-com:vml"><v:fill src="https://i.imgur.com/YJOX1PC.png" type="tile" /><v:textbox inset="0,0,0,0" style="mso-fit-shape-to-text:True"><![endif]--><div style="color:#ff0000;font-family:serif;font-size:24px;font-weight:bold;line-height:24px;text-align:center"></div><!--[if mso]></v:textbox></v:rect><![endif]--></td></tr></table>')
43
+ end
44
+
45
+ it 'supports font-related attributes' do
46
+ Inkcite::Renderer.render('{background src=https://i.imgur.com/YJOX1PC.png font-size=18 line-height=27}{/background}', @view).must_equal('<table border=0 cellpadding=0 cellspacing=0 style="background:url(https://i.imgur.com/YJOX1PC.png)" width=100%><tr><td><!--[if mso]><v:rect fill="t" stroke="f" style="mso-width-percent:1000" xmlns:v="urn:schemas-microsoft-com:vml"><v:fill src="https://i.imgur.com/YJOX1PC.png" type="tile" /><v:textbox inset="0,0,0,0" style="mso-fit-shape-to-text:True"><![endif]--><div style="font-size:18px;line-height:27px"></div><!--[if mso]></v:textbox></v:rect><![endif]--></td></tr></table>')
47
+ end
48
+
49
+ it 'supports a custom mobile background' do
50
+ Inkcite::Renderer.render('{background src=https://i.imgur.com/YJOX1PC.png mobile-src="https://i.imgur.com/YJOX1PC-mobile.png" mobile-background-position="top" mobile-background-size="cover"}{/background}', @view).must_equal('<table border=0 cellpadding=0 cellspacing=0 class="m1" style="background:url(https://i.imgur.com/YJOX1PC.png)" width=100%><tr><td><!--[if mso]><v:rect fill="t" stroke="f" style="mso-width-percent:1000" xmlns:v="urn:schemas-microsoft-com:vml"><v:fill src="https://i.imgur.com/YJOX1PC.png" type="tile" /><v:textbox inset="0,0,0,0" style="mso-fit-shape-to-text:True"><![endif]--><div></div><!--[if mso]></v:textbox></v:rect><![endif]--></td></tr></table>')
51
+ @view.media_query.find_by_klass('m1').declaration_string.must_equal('background:url(https://i.imgur.com/YJOX1PC-mobile.png) top / cover no-repeat !important')
52
+ end
53
+
54
+ it 'supports mobile padding' do
55
+ Inkcite::Renderer.render('{background src=background.jpg mobile-padding=15}{/background}', @view).must_equal('<table border=0 cellpadding=0 cellspacing=0 style="background:url(images/background.jpg)" width=100%><tr><td class="m1"><!--[if mso]><v:rect fill="t" stroke="f" style="mso-width-percent:1000" xmlns:v="urn:schemas-microsoft-com:vml"><v:fill src="images/background.jpg" type="tile" /><v:textbox inset="0,0,0,0" style="mso-fit-shape-to-text:True"><![endif]--><div></div><!--[if mso]></v:textbox></v:rect><![endif]--></td></tr></table>')
56
+ @view.media_query.find_by_klass('m1').declaration_string.must_equal('padding:15px')
57
+ end
58
+
59
+ end