inkcite 1.0.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 +7 -0
- data/LICENSE +20 -0
- data/README.md +110 -0
- data/Rakefile +8 -0
- data/assets/facebook-like.css +62 -0
- data/assets/facebook-like.js +59 -0
- data/assets/init/config.yml +97 -0
- data/assets/init/helpers.tsv +31 -0
- data/assets/init/source.html +60 -0
- data/assets/init/source.txt +6 -0
- data/bin/inkcite +6 -0
- data/inkcite.gemspec +42 -0
- data/lib/inkcite.rb +32 -0
- data/lib/inkcite/cli/base.rb +128 -0
- data/lib/inkcite/cli/build.rb +130 -0
- data/lib/inkcite/cli/init.rb +58 -0
- data/lib/inkcite/cli/preview.rb +30 -0
- data/lib/inkcite/cli/server.rb +123 -0
- data/lib/inkcite/cli/test.rb +61 -0
- data/lib/inkcite/email.rb +219 -0
- data/lib/inkcite/mailer.rb +140 -0
- data/lib/inkcite/minifier.rb +151 -0
- data/lib/inkcite/parser.rb +111 -0
- data/lib/inkcite/renderer.rb +177 -0
- data/lib/inkcite/renderer/base.rb +186 -0
- data/lib/inkcite/renderer/button.rb +168 -0
- data/lib/inkcite/renderer/div.rb +29 -0
- data/lib/inkcite/renderer/element.rb +82 -0
- data/lib/inkcite/renderer/footnote.rb +132 -0
- data/lib/inkcite/renderer/google_analytics.rb +35 -0
- data/lib/inkcite/renderer/image.rb +95 -0
- data/lib/inkcite/renderer/image_base.rb +82 -0
- data/lib/inkcite/renderer/in_browser.rb +38 -0
- data/lib/inkcite/renderer/like.rb +73 -0
- data/lib/inkcite/renderer/link.rb +243 -0
- data/lib/inkcite/renderer/litmus.rb +33 -0
- data/lib/inkcite/renderer/lorem.rb +39 -0
- data/lib/inkcite/renderer/mobile_image.rb +67 -0
- data/lib/inkcite/renderer/mobile_style.rb +40 -0
- data/lib/inkcite/renderer/mobile_toggle.rb +27 -0
- data/lib/inkcite/renderer/outlook_background.rb +48 -0
- data/lib/inkcite/renderer/partial.rb +31 -0
- data/lib/inkcite/renderer/preheader.rb +22 -0
- data/lib/inkcite/renderer/property.rb +39 -0
- data/lib/inkcite/renderer/responsive.rb +334 -0
- data/lib/inkcite/renderer/span.rb +21 -0
- data/lib/inkcite/renderer/table.rb +67 -0
- data/lib/inkcite/renderer/table_base.rb +149 -0
- data/lib/inkcite/renderer/td.rb +92 -0
- data/lib/inkcite/uploader.rb +173 -0
- data/lib/inkcite/util.rb +85 -0
- data/lib/inkcite/version.rb +3 -0
- data/lib/inkcite/view.rb +745 -0
- data/lib/inkcite/view/context.rb +38 -0
- data/lib/inkcite/view/media_query.rb +60 -0
- data/lib/inkcite/view/tag_stack.rb +38 -0
- data/test/email_spec.rb +16 -0
- data/test/parser_spec.rb +72 -0
- data/test/project/config.yml +98 -0
- data/test/project/helpers.tsv +56 -0
- data/test/project/images/inkcite.jpg +0 -0
- data/test/project/source.html +58 -0
- data/test/project/source.txt +6 -0
- data/test/renderer/button_spec.rb +45 -0
- data/test/renderer/div_spec.rb +101 -0
- data/test/renderer/element_spec.rb +31 -0
- data/test/renderer/footnote_spec.rb +57 -0
- data/test/renderer/image_spec.rb +82 -0
- data/test/renderer/link_spec.rb +84 -0
- data/test/renderer/mobile_image_spec.rb +27 -0
- data/test/renderer/mobile_style_spec.rb +37 -0
- data/test/renderer/td_spec.rb +126 -0
- data/test/renderer_spec.rb +28 -0
- data/test/view_spec.rb +15 -0
- metadata +333 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'inkcite'
|
4
|
+
|
5
|
+
describe Inkcite::Renderer::Button do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@view = Inkcite::Email.new('test/project/').view(:development, :email)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'inherits default settings from the context' do
|
12
|
+
Inkcite::Renderer.render('{button id="learn-more" href="http://inkceptional.com"}Learn More{/button}', @view).
|
13
|
+
must_equal("<a href=\"http://inkceptional.com\" style=\"text-decoration:none\" target=_blank><table align=center bgcolor=#0099cc border=0 cellpadding=8 cellspacing=0 class=\"fill\" style=\"border-radius:5px\" width=175><tr>\n<td align=center style=\"padding:8px;text-shadow:0 -1px 0 #003d52\"><a href=\"http://inkceptional.com\" style=\"color:#99ffff;text-decoration:none\" target=_blank>Learn More</a></td>\n</tr></table></a>")
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'can have a custom background color' do
|
17
|
+
Inkcite::Renderer.render('{button id="learn-more" href="http://inkceptional.com" bgcolor=#090}Learn More{/button}', @view).
|
18
|
+
must_equal("<a href=\"http://inkceptional.com\" style=\"text-decoration:none\" target=_blank><table align=center bgcolor=#009900 border=0 cellpadding=8 cellspacing=0 class=\"fill\" style=\"border-radius:5px\" width=175><tr>\n<td align=center style=\"padding:8px;text-shadow:0 -1px 0 #003d00\"><a href=\"http://inkceptional.com\" style=\"color:#99ff99;text-decoration:none\" target=_blank>Learn More</a></td>\n</tr></table></a>")
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'can have a custom bevel that is dynamically colored based on the background color' do
|
22
|
+
Inkcite::Renderer.render('{button id="learn-more" href="http://inkceptional.com" bevel=3}Learn More{/button}', @view).
|
23
|
+
must_equal("<a href=\"http://inkceptional.com\" style=\"text-decoration:none\" target=_blank><table align=center bgcolor=#0099cc border=0 cellpadding=8 cellspacing=0 class=\"fill\" style=\"border-bottom:3px solid #003d52;border-collapse:separate;border-radius:5px\" width=175><tr>\n<td align=center style=\"padding:8px;text-shadow:0 -1px 0 #003d52\"><a href=\"http://inkceptional.com\" style=\"color:#99ffff;text-decoration:none\" target=_blank>Learn More</a></td>\n</tr></table></a>")
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'can have a custom font size' do
|
27
|
+
Inkcite::Renderer.render('{button id="learn-more" href="http://inkceptional.com" font-size=27}Learn More{/button}', @view).
|
28
|
+
must_equal("<a href=\"http://inkceptional.com\" style=\"text-decoration:none\" target=_blank><table align=center bgcolor=#0099cc border=0 cellpadding=8 cellspacing=0 class=\"fill\" style=\"border-radius:5px\" width=175><tr>\n<td align=center style=\"font-size:27px;padding:8px;text-shadow:0 -1px 0 #003d52\"><a href=\"http://inkceptional.com\" style=\"color:#99ffff;text-decoration:none\" target=_blank>Learn More</a></td>\n</tr></table></a>")
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'has px line-height by default, if specified' do
|
32
|
+
Inkcite::Renderer.render('{button id="learn-more" href="http://inkceptional.com" font-size=27 line-height=56}Learn More{/button}', @view).
|
33
|
+
must_equal("<a href=\"http://inkceptional.com\" style=\"text-decoration:none\" target=_blank><table align=center bgcolor=#0099cc border=0 cellpadding=8 cellspacing=0 class=\"fill\" style=\"border-radius:5px\" width=175><tr>\n<td align=center style=\"font-size:27px;line-height:56px;padding:8px;text-shadow:0 -1px 0 #003d52\"><a href=\"http://inkceptional.com\" style=\"color:#99ffff;text-decoration:none\" target=_blank>Learn More</a></td>\n</tr></table></a>")
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'accepts line-height specified in em units' do
|
37
|
+
Inkcite::Renderer.render('{button id="learn-more" href="http://inkceptional.com" font-size=27 line-height=2em}Learn More{/button}', @view).
|
38
|
+
must_equal("<a href=\"http://inkceptional.com\" style=\"text-decoration:none\" target=_blank><table align=center bgcolor=#0099cc border=0 cellpadding=8 cellspacing=0 class=\"fill\" style=\"border-radius:5px\" width=175><tr>\n<td align=center style=\"font-size:27px;line-height:2em;padding:8px;text-shadow:0 -1px 0 #003d52\"><a href=\"http://inkceptional.com\" style=\"color:#99ffff;text-decoration:none\" target=_blank>Learn More</a></td>\n</tr></table></a>")
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'accepts normal line-height' do
|
42
|
+
Inkcite::Renderer.render('{button id="learn-more" href="http://inkceptional.com" font-size=27 line-height=normal}Learn More{/button}', @view).
|
43
|
+
must_equal("<a href=\"http://inkceptional.com\" style=\"text-decoration:none\" target=_blank><table align=center bgcolor=#0099cc border=0 cellpadding=8 cellspacing=0 class=\"fill\" style=\"border-radius:5px\" width=175><tr>\n<td align=center style=\"font-size:27px;line-height:normal;padding:8px;text-shadow:0 -1px 0 #003d52\"><a href=\"http://inkceptional.com\" style=\"color:#99ffff;text-decoration:none\" target=_blank>Learn More</a></td>\n</tr></table></a>")
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'inkcite'
|
4
|
+
|
5
|
+
describe Inkcite::Renderer::Div do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@view = Inkcite::Email.new('test/project/').view(:development, :email)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'can have empty parameters' do
|
12
|
+
Inkcite::Renderer.render('{div}{/div}', @view).must_equal('<div></div>')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'can have a custom font color' do
|
16
|
+
Inkcite::Renderer.render('{div color=#f90}{/div}', @view).must_equal('<div style="color:#ff9900"></div>')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'can have a custom font family' do
|
20
|
+
Inkcite::Renderer.render('{div font-family="Comic Sans"}{/div}', @view).must_equal('<div style="font-family:Comic Sans"></div>')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'can have a custom font size' do
|
24
|
+
Inkcite::Renderer.render('{div font-size=18}{/div}', @view).must_equal('<div style="font-size:18px"></div>')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'can have a custom font weight' do
|
28
|
+
Inkcite::Renderer.render('{div font-weight=bold}{/div}', @view).must_equal('<div style="font-weight:bold"></div>')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can have a custom line height' do
|
32
|
+
Inkcite::Renderer.render('{div line-height=15}{/div}', @view).must_equal('<div style="line-height:15px"></div>')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'can inherit a font from the context' do
|
36
|
+
Inkcite::Renderer.render('{div font=large}{/div}', @view).must_equal('<div style="color:#ff0000;font-family:serif;font-size:24px;font-weight:bold;line-height:24px"></div>')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'can override the font size of an inherited font' do
|
40
|
+
Inkcite::Renderer.render('{div font=large font-size=8}{/div}', @view).must_equal('<div style="color:#ff0000;font-family:serif;font-size:8px;font-weight:bold;line-height:24px"></div>')
|
41
|
+
Inkcite::Renderer.render('{div font=large font-size=none}{/div}', @view).must_equal('<div style="color:#ff0000;font-family:serif;font-weight:bold;line-height:24px"></div>')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'can override the color of an inherited font' do
|
45
|
+
Inkcite::Renderer.render('{div font=large color=#00f}{/div}', @view).must_equal('<div style="color:#0000ff;font-family:serif;font-size:24px;font-weight:bold;line-height:24px"></div>')
|
46
|
+
Inkcite::Renderer.render('{div font=large color=none}{/div}', @view).must_equal('<div style="font-family:serif;font-size:24px;font-weight:bold;line-height:24px"></div>')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'can override the font weight of an inherited font' do
|
50
|
+
Inkcite::Renderer.render('{div font=large font-weight=normal}{/div}', @view).must_equal('<div style="color:#ff0000;font-family:serif;font-size:24px;font-weight:normal;line-height:24px"></div>')
|
51
|
+
Inkcite::Renderer.render('{div font=large font-weight=none}{/div}', @view).must_equal('<div style="color:#ff0000;font-family:serif;font-size:24px;line-height:24px"></div>')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'can override the line height of an inherited font' do
|
55
|
+
Inkcite::Renderer.render('{div font=large line-height=12}{/div}', @view).must_equal('<div style="color:#ff0000;font-family:serif;font-size:24px;font-weight:bold;line-height:12px"></div>')
|
56
|
+
Inkcite::Renderer.render('{div font=large line-height=normal}{/div}', @view).must_equal('<div style="color:#ff0000;font-family:serif;font-size:24px;font-weight:bold;line-height:normal"></div>')
|
57
|
+
Inkcite::Renderer.render('{div font=large line-height=none}{/div}', @view).must_equal('<div style="color:#ff0000;font-family:serif;font-size:24px;font-weight:bold"></div>')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'can have a text shadow' do
|
61
|
+
Inkcite::Renderer.render('{div shadow=#99c}{/div}', @view).must_equal('<div style="text-shadow:0 1px 0 #9999cc"></div>')
|
62
|
+
Inkcite::Renderer.render('{div shadow=#9c9 shadow-blur=2}{/div}', @view).must_equal('<div style="text-shadow:0 1px 2px #99cc99"></div>')
|
63
|
+
Inkcite::Renderer.render('{div shadow=#c99 shadow-offset=-1}{/div}', @view).must_equal('<div style="text-shadow:0 -1px 0 #cc9999"></div>')
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'can have a background color' do
|
67
|
+
Inkcite::Renderer.render('{div bgcolor=#06c}{/div}', @view).must_equal('<div style="background-color:#0066cc"></div>')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'can be responsive' do
|
71
|
+
Inkcite::Renderer.render('{div mobile=hide}{/div}', @view).must_equal('<div class="hide"></div>')
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'can have height in pixels' do
|
75
|
+
Inkcite::Renderer.render('{div height=15}{/div}', @view).must_equal('<div style="height:15px"></div>')
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'can have custom letter spacing' do
|
79
|
+
Inkcite::Renderer.render('{div letter-spacing=3}{/div}', @view).must_equal('<div style="letter-spacing:3px"></div>')
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'can have a custom font size on mobile' do
|
83
|
+
Inkcite::Renderer.render('{div font-size=15 mobile-font-size=20}{/div}', @view).must_equal('<div class="m1" style="font-size:15px"></div>')
|
84
|
+
@view.media_query.find_by_klass('m1').declarations.must_match('font-size:20px !important')
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'can have a custom line height on mobile' do
|
88
|
+
Inkcite::Renderer.render('{div line-height=15 mobile-line-height=20}{/div}', @view).must_equal('<div class="m1" style="line-height:15px"></div>')
|
89
|
+
@view.media_query.find_by_klass('m1').to_css.must_equal('div[class~="m1"] { line-height:20px !important }')
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'can inherit a custom font size on mobile from the context' do
|
93
|
+
Inkcite::Renderer.render('{div font=responsive}{/div}', @view).must_equal('<div class="m1" style="font-size:20px"></div>')
|
94
|
+
@view.media_query.find_by_klass('m1').declarations.must_match('font-size:40px')
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'supports text alignment' do
|
98
|
+
Inkcite::Renderer.render('{div align=right}{/div}', @view).must_equal('<div style="text-align:right"></div>')
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'inkcite'
|
4
|
+
|
5
|
+
describe Inkcite::Renderer::Element do
|
6
|
+
|
7
|
+
it 'has configurable attributes' do
|
8
|
+
e = Inkcite::Renderer::Element.new('a', :href => '"http://inkceptional.com"', :target => '"_blank"').to_s.must_equal('<a href="http://inkceptional.com" target="_blank">')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'has configurable styles which are rendered alphabetically' do
|
12
|
+
e = Inkcite::Renderer::Element.new('div')
|
13
|
+
e.style[:padding] = '5px'
|
14
|
+
e.style[:border] = '1px solid #f00'
|
15
|
+
e.to_s.must_equal('<div style="border:1px solid #f00;padding:5px">')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'has a unique, alphabetized list of classes' do
|
19
|
+
e = Inkcite::Renderer::Element.new('div')
|
20
|
+
e.classes << 'm1'
|
21
|
+
e.classes << 'hide'
|
22
|
+
e.to_s.must_equal('<div class="hide m1">')
|
23
|
+
e.classes << 'm1' # Duplicate
|
24
|
+
e.to_s.must_equal('<div class="hide m1">')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'can self-close' do
|
28
|
+
Inkcite::Renderer::Element.new('br', :self_close => true).to_s.must_equal('<br />')
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'inkcite'
|
4
|
+
|
5
|
+
describe Inkcite::Renderer::Footnote do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@view = Inkcite::Email.new('test/project/').view(:development, :email)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'requires text' do
|
12
|
+
Inkcite::Renderer.render('({footnote symbol="†"})', @view)
|
13
|
+
@view.errors.must_include('Footnote requires text attribute (line 0) [id=, symbol=†]')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'can have a custom symbol' do
|
17
|
+
Inkcite::Renderer.render('({footnote symbol="†" text="See Blackmur, especially chapters 3 and 4, for an insightful analysis of this trend."})', @view).must_equal("(†)")
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'assigns a numeric symbol if unspecified' do
|
21
|
+
Inkcite::Renderer.render('({footnote text="EPA-estimated fuel economy."})', @view).must_equal("(1)")
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'assigns an auto-incrementing symbol if multiple footnotes are provided' do
|
25
|
+
Inkcite::Renderer.render('({footnote text="EPA-estimated fuel economy."})({footnote text="Actual mileage may vary."})', @view).must_equal("(1)(2)")
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can auto-increment with mixed symbols' do
|
29
|
+
Inkcite::Renderer.render('({footnote text="EPA-estimated fuel economy."})({footnote symbol="†" text="See Blackmur, especially chapters 3 and 4, for an insightful analysis of this trend."})({footnote text="Actual mileage may vary."})', @view).must_equal("(1)(†)(2)")
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'renders using the {footnotes} tag' do
|
33
|
+
Inkcite::Renderer.render('yadda yadda({footnote text="EPA-estimated fuel economy."})<br><br>{footnotes}', @view).must_equal("yadda yadda(1)<br><br><sup>1</sup> EPA-estimated fuel economy.<br><br>")
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'sorts symbols before numeric footnotes' do
|
37
|
+
Inkcite::Renderer.render('({footnote text="EPA-estimated fuel economy."})({footnote symbol="†" text="See Blackmur, especially chapters 3 and 4, for an insightful analysis of this trend."})({footnote text="Actual mileage may vary."})<br><br>{footnotes}', @view).must_equal("(1)(†)(2)<br><br><sup>†</sup> See Blackmur, especially chapters 3 and 4, for an insightful analysis of this trend.<br><br><sup>1</sup> EPA-estimated fuel economy.<br><br><sup>2</sup> Actual mileage may vary.<br><br>")
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'can have a reusable, readable ID assigned to it' do
|
41
|
+
Inkcite::Renderer.render('({footnote id="epa" text="EPA-estimated fuel economy."})({footnote id="epa"})', @view).must_equal("(1)(1)")
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'can have a custom template' do
|
45
|
+
Inkcite::Renderer.render('({footnote text="EPA-estimated fuel economy."}) {footnotes tmpl="<p><sup>$symbol$</sup> $text$</p>"}', @view).must_equal("(1) <p><sup>1</sup> EPA-estimated fuel economy.</p>")
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'can be defined silently' do
|
49
|
+
Inkcite::Renderer.render('{footnote hidden=1 text="EPA-estimated fuel economy."}{footnotes}', @view).must_equal("<sup>1</sup> EPA-estimated fuel economy.<br><br>")
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'converts "\n" within footnotes template to new-lines' do
|
53
|
+
text_view = Inkcite::Email.new('test/project/').view(:development, :text)
|
54
|
+
Inkcite::Renderer.render('({footnote text="EPA-estimated fuel economy."}) {footnotes tmpl="[$symbol$] $text$\n\n"}', text_view).must_equal("(1) [1] EPA-estimated fuel economy.\n\n")
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'inkcite'
|
4
|
+
|
5
|
+
describe Inkcite::Renderer::Image do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@view = Inkcite::Email.new('test/project/').view(:development, :email)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'warns when an image is missing' do
|
12
|
+
Inkcite::Renderer.render('{img src=missing.jpg}', @view)
|
13
|
+
@view.errors.must_include('Missing image (line 0) [src=missing.jpg]')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'warns when image dimesions are missing' do
|
17
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg}', @view)
|
18
|
+
@view.errors.must_include('Missing image dimensions (line 0) [src=inkcite.jpg]')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'substitutes a placeholder for a missing image of sufficient size' do
|
22
|
+
@view.config[Inkcite::Email::IMAGE_PLACEHOLDERS] = true
|
23
|
+
Inkcite::Renderer.render('{img src=missing.jpg height=50 width=100}', @view).must_equal('<img border=0 height=50 src="http://placehold.it/100x50.jpg" style="display:block" width=100>')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'has configurable placeholder text' do
|
27
|
+
@view.config[Inkcite::Email::IMAGE_PLACEHOLDERS] = true
|
28
|
+
Inkcite::Renderer.render('{img src=missing.jpg height=50 width=100 fpo="F P O"}', @view).must_equal('<img border=0 height=50 src="http://placehold.it/100x50.jpg&text=F%20P%20O" style="display:block" width=100>')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'does not substitute placeholders for small images' do
|
32
|
+
@view.config[Inkcite::Email::IMAGE_PLACEHOLDERS] = true
|
33
|
+
Inkcite::Renderer.render('{img src=missing.jpg height=5 width=15}', @view).must_equal('<img border=0 height=5 src="missing.jpg" style="display:block" width=15>')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'has configurable dimensions' do
|
37
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg height=73 width=73}', @view).must_equal('<img border=0 height=73 src="images/inkcite.jpg" style="display:block" width=73>')
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'has configurable background color' do
|
41
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg height=73 width=73 bgcolor=#f00}', @view).must_equal('<img border=0 height=73 src="images/inkcite.jpg" style="background-color:#ff0000;display:block" width=73>')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'has an inline display helper' do
|
45
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg height=73 width=73 display=inline}', @view).must_equal('<img align=absmiddle border=0 height=73 src="images/inkcite.jpg" style="display:inline;vertical-align:middle" width=73>')
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'defaults to "small" font styling when alt text is present' do
|
49
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg height=73 width=73 alt="Inkcite Avatar"}', @view).must_equal('<img alt="Inkcite Avatar" border=0 height=73 src="images/inkcite.jpg" style="color:#cccccc;display:block;font-size:11px" width=73>')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'supports blank alt text' do
|
53
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg height=73 width=73 alt=""}', @view).must_equal('<img alt="" border=0 height=73 src="images/inkcite.jpg" style="display:block" width=73>')
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'has configurable font size' do
|
58
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg height=73 width=73 font-size=18 alt="Inkcite Avatar"}', @view).must_equal('<img alt="Inkcite Avatar" border=0 height=73 src="images/inkcite.jpg" style="color:#cccccc;display:block;font-size:18px" width=73>')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'ignores font attributes when alt text is not present' do
|
62
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg height=73 width=73 font=large}', @view).must_equal('<img border=0 height=73 src="images/inkcite.jpg" style="display:block" width=73>')
|
63
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg height=73 width=73 font-size=24}', @view).must_equal('<img border=0 height=73 src="images/inkcite.jpg" style="display:block" width=73>')
|
64
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg height=73 width=73 text-shadow=#f00}', @view).must_equal('<img border=0 height=73 src="images/inkcite.jpg" style="display:block" width=73>')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'includes a timestamp when cache-busting is enabled' do
|
68
|
+
@view.config[:'cache-bust'] = true
|
69
|
+
|
70
|
+
html = Inkcite::Renderer.render('{img src=inkcite.jpg}', @view)
|
71
|
+
|
72
|
+
html[0,47].must_equal('<img border=0 height=0 src="images/inkcite.jpg?')
|
73
|
+
html[47,10].must_match(/[0-9]{10,}/)
|
74
|
+
html[57..-1].must_equal('" style="display:block" width=0>')
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'can substitute a different image on mobile' do
|
78
|
+
Inkcite::Renderer.render('{img src=inkcite.jpg mobile-src=inkcite-mobile.jpg height=75 width=125}', @view).must_equal('<img border=0 class="i01" height=75 src="images/inkcite.jpg" style="display:block" width=125>')
|
79
|
+
@view.media_query.find_by_klass('i01').to_css.must_equal('img[class~="i01"] { content: url("images/inkcite-mobile.jpg") !important; }')
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'inkcite'
|
4
|
+
|
5
|
+
describe Inkcite::Renderer::Link do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@view = Inkcite::Email.new('test/project/').view(:development, :email)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'renders an HTML anchor tag with default styling and _blank targeting' do
|
12
|
+
Inkcite::Renderer.render('{a id="blog" href="http://blog.inkceptional.com"}Our blog{/a}', @view).must_equal('<a href="http://blog.inkceptional.com" style="color:#0099cc;text-decoration:none" target=_blank>Our blog</a>')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'can be configured to tag all links' do
|
16
|
+
@view.config[:'tag-links'] = "tag=inkcite|{id}"
|
17
|
+
Inkcite::Renderer.render('{a id="litmus" href="http://litmus.com"}Test Emails Here{/a}', @view).must_equal('<a href="http://litmus.com?tag=inkcite|litmus" style="color:#0099cc;text-decoration:none" target=_blank>Test Emails Here</a>')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'can be configured to tag links to specific domains' do
|
21
|
+
@view.config[:'tag-links'] = "tag=inkcite|{id}"
|
22
|
+
@view.config[:'tag-links-domain'] = 'inkceptional.com'
|
23
|
+
Inkcite::Renderer.render('{a id="blog" href="http://blog.inkceptional.com"}Our blog{/a}', @view).must_equal('<a href="http://blog.inkceptional.com?tag=inkcite|blog" style="color:#0099cc;text-decoration:none" target=_blank>Our blog</a>')
|
24
|
+
Inkcite::Renderer.render('{a id="litmus" href="http://litmus.com"}Test Emails Here{/a}', @view).must_equal('<a href="http://litmus.com" style="color:#0099cc;text-decoration:none" target=_blank>Test Emails Here</a>')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'will not tag mailto: links' do
|
28
|
+
@view.config[:'tag-links'] = "tag=inkcite|{id}"
|
29
|
+
Inkcite::Renderer.render('{a id="contact-us" href="mailto:some.email@some.where"}Contact Us{/a}', @view).must_equal('<a href="mailto:some.email@some.where" style="color:#0099cc;text-decoration:none">Contact Us</a>')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'will not tag links that lead to an element in the email' do
|
33
|
+
@view.config[:'tag-links'] = "tag=inkcite|{id}"
|
34
|
+
Inkcite::Renderer.render('{a href="#news"}Latest News{/a}', @view).must_equal('<a href="#news" style="color:#0099cc;text-decoration:none">Latest News</a>')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'raises a warning and generates an ID if one is not present' do
|
38
|
+
Inkcite::Renderer.render('{a href="http://inkceptional.com"}Click Here{/a}', @view).must_equal('<a href="http://inkceptional.com" style="color:#0099cc;text-decoration:none" target=_blank>Click Here</a>')
|
39
|
+
@view.errors.must_include('Link missing ID (line 0) [href=http://inkceptional.com]')
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'increments its automatically generated link ID' do
|
43
|
+
Inkcite::Renderer.render('{a href="http://blog.inkceptional.com"}Our Blog{/a}', @view).must_equal('<a href="http://blog.inkceptional.com" style="color:#0099cc;text-decoration:none" target=_blank>Our Blog</a>')
|
44
|
+
Inkcite::Renderer.render('{a href="http://inkceptional.com"}Inkceptional.com{/a}', @view).must_equal('<a href="http://inkceptional.com" style="color:#0099cc;text-decoration:none" target=_blank>Inkceptional.com</a>')
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'can have a custom font color' do
|
48
|
+
Inkcite::Renderer.render('{a id="order-now" href="http://inkceptional.com" color=#fc9}Order Now{/a}', @view).must_equal('<a href="http://inkceptional.com" style="color:#ffcc99;text-decoration:none" target=_blank>Order Now</a>')
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'can inherit link color from a parent td' do
|
52
|
+
Inkcite::Renderer.render('{td link=#0c3}{a id="order-now" href="http://inkceptional.com"}Order Now{/a}{/td}', @view).must_equal('<td><a href="http://inkceptional.com" style="color:#00cc33;text-decoration:none" target=_blank>Order Now</a></td>')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'can inherit link color from a parent table' do
|
56
|
+
Inkcite::Renderer.render('{table link=#396}{td}{a id="order-now" href="http://inkceptional.com"}Order Now{/a}{/td}{/table}', @view).must_equal('<table border=0 cellpadding=0 cellspacing=0><tr><td><a href="http://inkceptional.com" style="color:#339966;text-decoration:none" target=_blank>Order Now</a></td></tr></table>')
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'can have a custom font family' do
|
60
|
+
Inkcite::Renderer.render('{a id="order-now" href="http://inkceptional.com" font-family="Comic Sans"}Order Now{/a}', @view).must_equal('<a href="http://inkceptional.com" style="color:#0099cc;font-family:Comic Sans;text-decoration:none" target=_blank>Order Now</a>')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'can have a custom font size' do
|
64
|
+
Inkcite::Renderer.render('{a id="order-now" href="http://inkceptional.com" font-size=72}Order Now{/a}', @view).must_equal('<a href="http://inkceptional.com" style="color:#0099cc;font-size:72px;text-decoration:none" target=_blank>Order Now</a>')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'can have a custom font weight' do
|
68
|
+
Inkcite::Renderer.render('{a id="order-now" href="http://inkceptional.com" font-weight=700}Order Now{/a}', @view).must_equal('<a href="http://inkceptional.com" style="color:#0099cc;font-weight:700;text-decoration:none" target=_blank>Order Now</a>')
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'can have a custom line height' do
|
72
|
+
Inkcite::Renderer.render('{a id="order-now" href="http://inkceptional.com" line-height=64}Order Now{/a}', @view).must_equal('<a href="http://inkceptional.com" style="color:#0099cc;line-height:64px;text-decoration:none" target=_blank>Order Now</a>')
|
73
|
+
Inkcite::Renderer.render('{a id="order-now" href="http://inkceptional.com" line-height=normal}Order Now{/a}', @view).must_equal('<a href="http://inkceptional.com" style="color:#0099cc;line-height:normal;text-decoration:none" target=_blank>Order Now</a>')
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'can inherit a font from the context' do
|
77
|
+
Inkcite::Renderer.render('{a id="order-now" href="http://inkceptional.com" font=large}Order Now{/a}', @view).must_equal('<a href="http://inkceptional.com" style="color:#0099cc;font-family:serif;font-size:24px;font-weight:bold;line-height:24px;text-decoration:none" target=_blank>Order Now</a>')
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'will wrap button-style responsive links in a div' do
|
81
|
+
Inkcite::Renderer.render('{a id="order-now" href="http://inkceptional.com" mobile="button"}Order Now{/a}', @view).must_equal('<div><a class="button" href="http://inkceptional.com" style="color:#0099cc;text-decoration:none" target=_blank>Order Now</a></div>')
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'inkcite'
|
4
|
+
|
5
|
+
describe Inkcite::Renderer::MobileImage do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@view = Inkcite::Email.new('test/project/').view(:development, :email)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'styles a span to show an image only on mobile' do
|
12
|
+
Inkcite::Renderer.render('{mobile-img src=inkcite-mobile.jpg height=100 width=300}{/mobile-img}', @view).must_equal('<span class="i01 img"></span>')
|
13
|
+
@view.media_query.find_by_klass('i01').to_css.must_equal('span[class~="i01"] { background-image:url("images/inkcite-mobile.jpg");height:100px;width:300px }')
|
14
|
+
@view.media_query.find_by_klass('img').to_css.must_equal('span[class~="img"] { display: block; background-position: center; background-size: cover; }')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'substitutes a placeholder for a missing image of sufficient size' do
|
18
|
+
@view.config[Inkcite::Email::IMAGE_PLACEHOLDERS] = true
|
19
|
+
Inkcite::Renderer.render('{mobile-img src=inkcite-mobile.jpg height=100 width=300}{/mobile-img}', @view).must_equal('<span class="i01 img"></span>')
|
20
|
+
@view.media_query.find_by_klass('i01').to_css.must_equal('span[class~="i01"] { background-image:url("http://placehold.it/300x100.jpg");height:100px;width:300px }')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'hides any images it wraps' do
|
24
|
+
Inkcite::Renderer.render('{mobile-img src=inkcite-mobile.jpg height=100 width=300}{img src=inkcite.jpg height=50 width=100}{/mobile-img}', @view).must_equal('<span class="i01 img"><img border=0 class="hide" height=50 src="images/inkcite.jpg" style="display:block" width=100></span>')
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'inkcite'
|
4
|
+
|
5
|
+
describe Inkcite::Renderer::MobileStyle do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@view = Inkcite::Email.new('test/project/').view(:development, :email)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'requires a class name' do
|
12
|
+
Inkcite::Renderer.render('{mobile-style}', @view).must_equal('')
|
13
|
+
@view.errors.must_include('Declaring a mobile style requires a name attribute (line 0)')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'requires a style declaration' do
|
17
|
+
Inkcite::Renderer.render('{mobile-style name="slider"}', @view).must_equal('')
|
18
|
+
@view.errors.must_include('Declaring a mobile style requires a style attribute (line 0) [name=slider]')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'raises a warning if the class name is not unique' do
|
22
|
+
Inkcite::Renderer.render('{mobile-style name="outlined" style="border: 1px solid #f00"}', @view).must_equal('')
|
23
|
+
Inkcite::Renderer.render('{mobile-style name="outlined" style="border: 1px solid #0f0"}', @view).must_equal('')
|
24
|
+
@view.errors.must_include('A mobile style was already defined with that class name (line 0) [name=outlined, style=border: 1px solid #0f0]')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'adds an inactive responsive style to the context' do
|
28
|
+
Inkcite::Renderer.render('{mobile-style name="outlined" style="border: 1px solid #f00"}', @view).must_equal('')
|
29
|
+
rule = @view.media_query.find_by_klass('outlined').to_css.must_equal('[class~="outlined"] { border: 1px solid #f00 }')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'can be applied to a responsive element' do
|
33
|
+
Inkcite::Renderer.render('{mobile-style name="outlined" style="border: 1px solid #f00"}', @view).must_equal('')
|
34
|
+
Inkcite::Renderer.render('{div mobile=outlined}{/div}', @view).must_equal('<div class="outlined"></div>')
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|