inkcite 1.12.1 → 1.13.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.
@@ -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