inkcite 1.13.0 → 1.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/inkcite.gemspec +1 -0
- data/lib/inkcite.rb +1 -1
- data/lib/inkcite/cli/server.rb +31 -6
- data/lib/inkcite/facade.rb +6 -0
- data/lib/inkcite/{animation.rb → facade/animation.rb} +19 -56
- data/lib/inkcite/{renderer → facade}/element.rb +0 -0
- data/lib/inkcite/facade/keyframe.rb +83 -0
- data/lib/inkcite/{renderer → facade}/style.rb +4 -0
- data/lib/inkcite/minifier.rb +141 -57
- data/lib/inkcite/parser.rb +1 -1
- data/lib/inkcite/renderer.rb +2 -2
- data/lib/inkcite/renderer/background.rb +1 -1
- data/lib/inkcite/renderer/base.rb +1 -1
- data/lib/inkcite/renderer/container_base.rb +3 -4
- data/lib/inkcite/renderer/fireworks.rb +231 -0
- data/lib/inkcite/renderer/in_browser.rb +1 -2
- data/lib/inkcite/renderer/responsive.rb +29 -2
- data/lib/inkcite/renderer/snow.rb +1 -1
- data/lib/inkcite/renderer/special_effect.rb +66 -29
- data/lib/inkcite/renderer/table_base.rb +6 -0
- data/lib/inkcite/renderer/td.rb +7 -2
- data/lib/inkcite/renderer/video_preview.rb +7 -1
- data/lib/inkcite/util.rb +56 -0
- data/lib/inkcite/version.rb +1 -1
- data/lib/inkcite/view.rb +42 -1
- data/test/animation_spec.rb +38 -5
- data/test/renderer/div_spec.rb +30 -0
- data/test/renderer/td_spec.rb +25 -0
- data/test/renderer/video_preview_spec.rb +1 -1
- data/test/util_spec.rb +11 -0
- metadata +24 -5
@@ -72,9 +72,15 @@ module Inkcite
|
|
72
72
|
width = opt[:width]
|
73
73
|
element[:width] = width unless width.blank?
|
74
74
|
|
75
|
+
mobile_width = opt[MOBILE_WIDTH]
|
76
|
+
element.mobile_style[:width] = px(mobile_width) unless none?(mobile_width)
|
77
|
+
|
75
78
|
height = opt[:height].to_i
|
76
79
|
element[:height] = height if height > 0
|
77
80
|
|
81
|
+
mobile_height = opt[MOBILE_HEIGHT]
|
82
|
+
element.mobile_style[:height] = px(mobile_height) unless none?(mobile_height)
|
83
|
+
|
78
84
|
end
|
79
85
|
|
80
86
|
private
|
data/lib/inkcite/renderer/td.rb
CHANGED
@@ -75,8 +75,10 @@ module Inkcite
|
|
75
75
|
# If the table defines mobile-padding, then apply the correct mobile
|
76
76
|
# style to this td - and its !important if there is padding on
|
77
77
|
# the td already.
|
78
|
-
|
79
|
-
|
78
|
+
unless mobile == HIDE
|
79
|
+
mix_mobile_padding td, table_opt, ctx
|
80
|
+
mix_mobile_padding td, opt, ctx
|
81
|
+
end
|
80
82
|
|
81
83
|
# Need to handle Fluid-Drop HTML injection here before the rest of the
|
82
84
|
# TD is formalized. Fluid-Drop removes the width attribute of the cell
|
@@ -147,6 +149,9 @@ module Inkcite
|
|
147
149
|
|
148
150
|
end
|
149
151
|
|
152
|
+
# Support custom alignment on mobile devices
|
153
|
+
mix_mobile_text_align td, opt, ctx
|
154
|
+
|
150
155
|
rowspan = opt[:rowspan].to_i
|
151
156
|
td[:rowspan] = rowspan if rowspan > 0
|
152
157
|
|
@@ -24,6 +24,11 @@ module Inkcite
|
|
24
24
|
# image name is frozen to ensure it isn't modified later.
|
25
25
|
src = opt[:src].freeze
|
26
26
|
|
27
|
+
# This will hold the names of each of the frames, sans any full
|
28
|
+
# URL qualification (e.g. images/) These are interpolated to
|
29
|
+
# include the index
|
30
|
+
frame_srcs = []
|
31
|
+
|
27
32
|
# This will hold all frame source file names interpolated to include
|
28
33
|
# index (e.g. %1 being replaced with the frame number, if present).
|
29
34
|
frames = []
|
@@ -40,6 +45,7 @@ module Inkcite
|
|
40
45
|
# this loop also verifies that the referenced image exists.
|
41
46
|
frame_count.times do |n|
|
42
47
|
frame_src = src.gsub('%1', "#{n + 1}")
|
48
|
+
frame_srcs << frame_src
|
43
49
|
frames << image_url(frame_src, opt, ctx, false, false)
|
44
50
|
end
|
45
51
|
|
@@ -91,7 +97,7 @@ module Inkcite
|
|
91
97
|
html << Element.new('a', { :id => id, :href => quote(href), :class => hover_klass, :bgcolor => bgcolor, :bggradient => gradient, :block => true }).to_helper
|
92
98
|
|
93
99
|
table = Element.new('table', {
|
94
|
-
:width => '100%', :background =>
|
100
|
+
:width => '100%', :background => frame_srcs[0], BACKGROUND_SIZE => 'cover',
|
95
101
|
Table::TR_TRANSITION => %q("all .5s cubic-bezier(0.075, 0.82, 0.165, 1)")
|
96
102
|
})
|
97
103
|
|
data/lib/inkcite/util.rb
CHANGED
@@ -52,6 +52,62 @@ module Inkcite
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
# Conversion of HSL to RGB color courtesy of
|
56
|
+
# http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
|
57
|
+
def self.hsl_to_color h, s, l
|
58
|
+
|
59
|
+
# The algorithm expects h, s and l to be values between 0-1.
|
60
|
+
h = h / 360.0
|
61
|
+
s = s / 100.0
|
62
|
+
l = l / 100.0
|
63
|
+
|
64
|
+
# Wrap the color wheel if the hue provided is less than or
|
65
|
+
# greater than 1
|
66
|
+
h += 1.0 while h < 0
|
67
|
+
h -= 1.0 while h > 1
|
68
|
+
|
69
|
+
s = 0.0 if s < 0
|
70
|
+
s = 1.0 if s > 1
|
71
|
+
|
72
|
+
l = 0.0 if l < 0
|
73
|
+
l = 1.0 if l > 1
|
74
|
+
|
75
|
+
r = g = b = 0
|
76
|
+
|
77
|
+
if s == 0
|
78
|
+
r = g = b = l
|
79
|
+
|
80
|
+
else
|
81
|
+
q = l < 0.5 ? l * (1 + s) : l + s - l * s
|
82
|
+
p = 2 * l - q
|
83
|
+
r = hue_to_rgb(p, q, h + 1/3.0)
|
84
|
+
g = hue_to_rgb(p, q, h)
|
85
|
+
b = hue_to_rgb(p, q, h - 1/3.0)
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
r = (r * 255).round(0)
|
90
|
+
g = (g * 255).round(0)
|
91
|
+
b = (b * 255).round(0)
|
92
|
+
|
93
|
+
"##{rgb_to_hex(r)}#{rgb_to_hex(g)}#{rgb_to_hex(b)}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.hue_to_rgb p, q, t
|
97
|
+
t += 1 if t < 0
|
98
|
+
t -= 1 if t > 1
|
99
|
+
return (p + (q - p) * 6.0 * t) if (t < 1.0/6.0)
|
100
|
+
return q if (t < 0.5)
|
101
|
+
return (p + (q - p) * (2/3.0 - t) * 6) if (t < 2/3.0)
|
102
|
+
p
|
103
|
+
end
|
104
|
+
|
105
|
+
# RGB to hex courtesy of
|
106
|
+
# http://blog.lebrijo.com/converting-rgb-colors-to-hexadecimal-with-ruby/
|
107
|
+
def self.rgb_to_hex val
|
108
|
+
val.to_s(16).rjust(2, '0').downcase
|
109
|
+
end
|
110
|
+
|
55
111
|
def self.lighten color, amount=0.6
|
56
112
|
return WHITE if color.nil?
|
57
113
|
rgb = color.gsub('#', '').scan(/../).map { |c| c.hex }
|
data/lib/inkcite/version.rb
CHANGED
data/lib/inkcite/view.rb
CHANGED
@@ -86,6 +86,7 @@ module Inkcite
|
|
86
86
|
|
87
87
|
# Initializing to prevent a ruby verbose warning.
|
88
88
|
@footnotes = nil
|
89
|
+
@substitutions = nil
|
89
90
|
|
90
91
|
end
|
91
92
|
|
@@ -338,7 +339,15 @@ module Inkcite
|
|
338
339
|
# Returns the array of browser prefixes that need to be included in
|
339
340
|
# CSS styles based on which version of the email this is.
|
340
341
|
def prefixes
|
341
|
-
[ ''
|
342
|
+
_prefixes = [ '' ]
|
343
|
+
|
344
|
+
# In development mode, include all prefixes for maximum compatibility.
|
345
|
+
_prefixes += %w(-moz- -ms- -o-) if development?
|
346
|
+
|
347
|
+
# Always include webkit for targeting mobile devices.
|
348
|
+
_prefixes << '-webkit-'
|
349
|
+
|
350
|
+
_prefixes
|
342
351
|
end
|
343
352
|
|
344
353
|
def preview?
|
@@ -376,6 +385,9 @@ module Inkcite
|
|
376
385
|
# <!-- commented out --> to ensure the email is as small as possible.
|
377
386
|
source = Minifier.remove_comments(source, self)
|
378
387
|
|
388
|
+
# Perform global substitution of characters - e.g. ’ into ' if that's
|
389
|
+
substitution_map.each_pair { |orig, replace| source.gsub!(orig, replace) }
|
390
|
+
|
379
391
|
# Protect against unsupported characters
|
380
392
|
source = Renderer.fix_illegal_characters(source, self)
|
381
393
|
|
@@ -509,6 +521,32 @@ module Inkcite
|
|
509
521
|
@subject ||= Renderer.render((self[:subject] || self[:title] || UNTITLED_EMAIL), self)
|
510
522
|
end
|
511
523
|
|
524
|
+
# Returns a map where the strings are an original string
|
525
|
+
# and the value is what should replace it - used for
|
526
|
+
# automating common replacements - e.g. trademark symbols
|
527
|
+
# or apostrophes going in the wrong direction
|
528
|
+
def substitution_map
|
529
|
+
|
530
|
+
if @substitutions.nil?
|
531
|
+
|
532
|
+
# Initialize the substitutions map which will be populated
|
533
|
+
# if the local file exists.
|
534
|
+
@substitutions = {}
|
535
|
+
|
536
|
+
# Preload the array of footnotes if they exist
|
537
|
+
substitutions_tsv_file = @email.project_file(SUBSTITUTIONS_TSV_FILE)
|
538
|
+
if File.exist?(substitutions_tsv_file)
|
539
|
+
CSV.foreach(substitutions_tsv_file, { :col_sep => "\t" }) do |fn|
|
540
|
+
original = fn[0]
|
541
|
+
@substitutions[original] = fn[1].to_s unless original.blank?
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
end
|
546
|
+
|
547
|
+
@substitutions
|
548
|
+
end
|
549
|
+
|
512
550
|
def tag_stack tag
|
513
551
|
@tag_stack ||= Hash.new()
|
514
552
|
@tag_stack[tag] ||= TagStack.new(tag, self)
|
@@ -623,6 +661,9 @@ module Inkcite
|
|
623
661
|
# Tab-separated file containing footnote declarations.
|
624
662
|
FOOTNOTES_TSV_FILE = 'footnotes.tsv'
|
625
663
|
|
664
|
+
# Tab-separated file containing global substitution values.
|
665
|
+
SUBSTITUTIONS_TSV_FILE = 'substitutions.tsv'
|
666
|
+
|
626
667
|
def assert_in_browser msg
|
627
668
|
raise msg if email? && !development?
|
628
669
|
end
|
data/test/animation_spec.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
|
-
|
2
|
-
|
3
1
|
describe Inkcite::Animation do
|
4
2
|
|
5
3
|
before do
|
6
4
|
@view = Inkcite::Email.new('test/project/').view(:development, :email)
|
5
|
+
@production_view = Inkcite::Email.new('test/project/').view(:production, :email)
|
7
6
|
end
|
8
7
|
|
9
8
|
it 'supports browser prefixing' do
|
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')
|
9
|
+
Inkcite::Renderer::Style.new(nil, @view, { :animation => 'video-frames 5s ease infinite' }).to_s.must_equal('-moz-animation:video-frames 5s ease infinite;-ms-animation:video-frames 5s ease infinite;-o-animation:video-frames 5s ease infinite;-webkit-animation:video-frames 5s ease infinite;animation:video-frames 5s ease infinite')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'supports limited browser prefixing in production' do
|
13
|
+
Inkcite::Renderer::Style.new(nil, @production_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
14
|
end
|
12
15
|
|
13
16
|
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%')
|
17
|
+
Inkcite::Renderer::Style.new(nil, @view, { :left => '25%', :animation => 'video-frames 5s ease infinite' }).to_s.must_equal('-moz-animation:video-frames 5s ease infinite;-ms-animation:video-frames 5s ease infinite;-o-animation:video-frames 5s ease infinite;-webkit-animation:video-frames 5s ease infinite;animation:video-frames 5s ease infinite;left:25%')
|
15
18
|
end
|
16
19
|
|
17
20
|
it 'can instantiate an animation keyframe' do
|
@@ -35,8 +38,38 @@ describe Inkcite::Animation do
|
|
35
38
|
anim = Inkcite::Animation.new('snowflake7', @view)
|
36
39
|
anim.add_keyframe 5, { :top => '-10px', :left => '22%', :transform => 'rotate(14deg)' }
|
37
40
|
anim.add_keyframe 25, { :top => '100%', :left => '18%' }
|
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))
|
41
|
+
anim.to_keyframe_css.must_equal(%Q(@keyframes snowflake7 {\n5% { left:22%;top:-10px;transform:rotate(14deg) }\n25% { left:18%;top:100% }\n}\n@-moz-keyframes snowflake7 {\n5% { -moz-transform:rotate(14deg);left:22%;top:-10px }\n25% { left:18%;top:100% }\n}\n@-ms-keyframes snowflake7 {\n5% { -ms-transform:rotate(14deg);left:22%;top:-10px }\n25% { left:18%;top:100% }\n}\n@-o-keyframes snowflake7 {\n5% { -o-transform:rotate(14deg);left:22%;top:-10px }\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))
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'supports keyframe duration' do
|
45
|
+
keyframe = Inkcite::Animation::Keyframe.new(25, @view)
|
46
|
+
keyframe.duration = 15.9
|
47
|
+
keyframe[:top] = '-15%'
|
48
|
+
keyframe.to_css('').must_equal('25%, 40.9% { top:-15% }')
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'reports when an animation is blank' do
|
52
|
+
anim = Inkcite::Animation.new('snowflake7', @view)
|
53
|
+
anim.blank?.must_equal(true)
|
54
|
+
anim.add_keyframe 25, { :top => '100%', :left => '18%' }
|
55
|
+
anim.blank?.must_equal(false)
|
39
56
|
end
|
40
57
|
|
58
|
+
it 'supports composite animations' do
|
59
|
+
|
60
|
+
comp_anim = Inkcite::Animation::Composite.new()
|
61
|
+
|
62
|
+
explosion = Inkcite::Animation.new('explosion', @view)
|
63
|
+
explosion.duration = 8
|
64
|
+
explosion.timing_function = Inkcite::Animation::EASE_OUT
|
65
|
+
comp_anim << explosion
|
66
|
+
|
67
|
+
gravity = Inkcite::Animation.new('gravity', @view)
|
68
|
+
gravity.iteration_count = 4
|
69
|
+
comp_anim << gravity
|
70
|
+
|
71
|
+
comp_anim.to_s.must_equal(%q(8s ease-out infinite explosion, 1s linear 4 gravity))
|
72
|
+
|
73
|
+
end
|
41
74
|
|
42
75
|
end
|
data/test/renderer/div_spec.rb
CHANGED
@@ -117,4 +117,34 @@ describe Inkcite::Renderer::Div do
|
|
117
117
|
@view.media_query.find_by_klass('m1').declarations.must_match('width:78px !important')
|
118
118
|
end
|
119
119
|
|
120
|
+
it 'supports mobile padding' do
|
121
|
+
Inkcite::Renderer.render('{div mobile-padding="15px 10px"}{/div}', @view).must_equal('<div class="m1"></div>')
|
122
|
+
@view.media_query.find_by_klass('m1').declarations.must_match('padding:15px 10px')
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'supports directional mobile padding' do
|
126
|
+
Inkcite::Renderer.render('{div mobile-padding-top=15}{/div}', @view).must_equal('<div class="m1"></div>')
|
127
|
+
@view.media_query.find_by_klass('m1').declarations.must_match('padding-top:15px')
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'supports directional mobile padding override' do
|
131
|
+
Inkcite::Renderer.render('{div mobile-padding=30px mobile-padding-top=15}{/div}', @view).must_equal('<div class="m1"></div>')
|
132
|
+
@view.media_query.find_by_klass('m1').declarations.must_match('padding:30px;padding-top:15px')
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'supports mobile text alignment' do
|
136
|
+
Inkcite::Renderer.render('{div mobile-text-align="center"}{/div}', @view).must_equal('<div class="m1"></div>')
|
137
|
+
@view.media_query.find_by_klass('m1').declarations.must_match('text-align:center')
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'supports mobile text alignment override' do
|
141
|
+
Inkcite::Renderer.render('{div text-align="right" mobile-text-align="center"}{/div}', @view).must_equal('<div class="m1" style="text-align:right"></div>')
|
142
|
+
@view.media_query.find_by_klass('m1').declarations.must_match('text-align:center !important')
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'supports mobile display override' do
|
146
|
+
Inkcite::Renderer.render('{div mobile-display="block"}{/div}', @view).must_equal('<div class="m1"></div>')
|
147
|
+
@view.media_query.find_by_klass('m1').declarations.must_match('display:block')
|
148
|
+
end
|
149
|
+
|
120
150
|
end
|
data/test/renderer/td_spec.rb
CHANGED
@@ -17,6 +17,16 @@ describe Inkcite::Renderer::Td do
|
|
17
17
|
@view.media_query.find_by_klass('m1').to_css.must_equal('td.m1 { padding:15px }')
|
18
18
|
end
|
19
19
|
|
20
|
+
it 'supports directional mobile padding' do
|
21
|
+
Inkcite::Renderer.render('{td mobile-padding-top=15}', @view).must_equal('<td class="m1">')
|
22
|
+
@view.media_query.find_by_klass('m1').to_css.must_equal('td.m1 { padding-top:15px }')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'supports mobile text alignment' do
|
26
|
+
Inkcite::Renderer.render('{td mobile-text-align="center"}{/td}', @view).must_equal('<td class="m1"></td>')
|
27
|
+
@view.media_query.find_by_klass('m1').declarations.must_match('text-align:center')
|
28
|
+
end
|
29
|
+
|
20
30
|
it 'reuses a style that matches mobile padding' do
|
21
31
|
Inkcite::Renderer.render('{table mobile-padding=15}{td}{table mobile-padding=15}{td}', @view).must_equal('<table border=0 cellpadding=0 cellspacing=0><tr><td class="m1"><table border=0 cellpadding=0 cellspacing=0><tr><td class="m1">')
|
22
32
|
@view.media_query.find_by_klass('m1').to_css.must_equal('td.m1 { padding:15px }')
|
@@ -148,4 +158,19 @@ describe Inkcite::Renderer::Td do
|
|
148
158
|
Inkcite::Renderer.render('{td nowrap}', @view).must_equal('<td nowrap>')
|
149
159
|
end
|
150
160
|
|
161
|
+
it 'supports mobile width override' do
|
162
|
+
Inkcite::Renderer.render('{td width=30 mobile-width=15}', @view).must_equal('<td class="m1" width=30>')
|
163
|
+
@view.media_query.find_by_klass('m1').to_css.must_equal('td.m1 { width:15px }')
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'supports mobile height override' do
|
167
|
+
Inkcite::Renderer.render('{td height=30 mobile-height=15}', @view).must_equal('<td class="m1" height=30>')
|
168
|
+
@view.media_query.find_by_klass('m1').to_css.must_equal('td.m1 { height:15px }')
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'supports multiple mobile override attributes' do
|
172
|
+
Inkcite::Renderer.render('{td width=15 border-left="1px dotted #cccccc" mobile-display="block" mobile-width="100%" mobile-border-left="none" mobile-border-top="1px dotted #ccc"}', @view).must_equal('<td class="m1" style="border-left:1px dotted #cccccc" width=15>')
|
173
|
+
@view.media_query.find_by_klass('m1').to_css.must_equal('td.m1 { border-left:none !important;border-top:1px dotted #ccc;display:block;width:100% }')
|
174
|
+
end
|
175
|
+
|
151
176
|
end
|
@@ -6,7 +6,7 @@ describe Inkcite::Renderer::VideoPreview do
|
|
6
6
|
|
7
7
|
it 'renders an animated video preview' do
|
8
8
|
Inkcite::Renderer.render('{video-preview id="ripcurl" href="https://www.campaignmonitor.com/customers/ripcurl" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame%1.jpg" width=600 height=337 frames=3 bgcolor="#5b5f66" gradient="#1d1f21"}', @view).must_equal(%Q(<!--[if !mso]><!-- -->\n<a class="video" href="https://www.campaignmonitor.com/customers/ripcurl" style="background-color:#5b5f66;background-image:radial-gradient(circle at center, #5b5f66, #1d1f21);color:#0099cc;display:block;text-decoration:none" target=_blank>\n<table border=0 cellpadding=0 cellspacing=0 style="-webkit-animation:15s ease infinite video1-frames;animation:15s ease infinite video1-frames;background:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) 0% 0% / cover no-repeat" width=100%><tr style="transition:all .5s cubic-bezier(0.075, 0.82, 0.165, 1)">\n<td width=25%><img alt="" border=0 src=images/vp-150x337.png style="display:block;height:auto;opacity:0;visibility:hidden" width=100%></td>\n<td align=center valign=middle width=50%>\n<div class="play-button" style="background-image: linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.1)); border: 4px solid white; border-radius: 50%; box-shadow: 0 1px 2px rgba(0,0,0,0.3), inset 0 1px 2px rgba(0,0,0,0.3); height: 34px; margin: 0 auto; padding: 18px 16px 18px 24px; transition: transform .5s cubic-bezier(0.075, 0.82, 0.165, 1); width: 34px;">\n<div style="border-color: transparent transparent transparent white; border-style: solid; border-width: 17px 0 17px 30px; display: block; font-size: 0; height: 0; Margin: 0 auto; width: 0;"> </div>\n</div>\n</td>\n<td width=25%> </td>\n</tr></table>\n</a>\n<div style="background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg),url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg),url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg);display:none"></div>\n<!--<![endif]-->\n<!--[if mso]>\n<v:group xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" coordsize="600,337" coordorigin="0,0" href="https://www.campaignmonitor.com/customers/ripcurl" style="width:600px;height:337px;">\n<v:rect fill="t" stroked="f" style="position:absolute;width:600;height:337;"><v:fill src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg" type="frame"/></v:rect>\n<v:oval fill="t" strokecolor="white" strokeweight="4px" style="position:absolute;left:261;top:129;width:78;height:78"><v:fill color="black" opacity="30%"/></v:oval>\n<v:shape coordsize="24,32" path="m,l,32,24,16,xe" fillcolor="white" stroked="f" style="position:absolute;left:285;top:153;width:30;height:30;"/>\n</v:group>\n<![endif]-->))
|
9
|
-
@view.styles.first.must_equal(%Q(.video:hover .play-button {\n transform: scale(1.1);\n}\n.video:hover tr {\n background-color: rgba(255, 255, 255, .2);\n}\n@keyframes video1-frames {\n0% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n22% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n33% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n55% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n66% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n88% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n100% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n}\n@-webkit-keyframes video1-frames {\n0% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n22% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n33% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n55% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n66% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n88% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n100% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n}\n))
|
9
|
+
@view.styles.first.must_equal(%Q(.video:hover .play-button {\n transform: scale(1.1);\n}\n.video:hover tr {\n background-color: rgba(255, 255, 255, .2);\n}\n@keyframes video1-frames {\n0% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n22% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n33% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n55% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n66% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n88% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n100% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n}\n@-moz-keyframes video1-frames {\n0% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n22% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n33% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n55% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n66% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n88% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n100% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n}\n@-ms-keyframes video1-frames {\n0% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n22% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n33% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n55% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n66% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n88% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n100% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n}\n@-o-keyframes video1-frames {\n0% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n22% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n33% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n55% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n66% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n88% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n100% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n}\n@-webkit-keyframes video1-frames {\n0% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n22% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n33% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n55% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame2.jpg) }\n66% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n88% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame3.jpg) }\n100% { background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/103009/frame1.jpg) }\n}\n))
|
10
10
|
|
11
11
|
# Verify that the transparent spacer image was created and then
|
12
12
|
# clean it up.
|
data/test/util_spec.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
describe Inkcite::Util do
|
2
|
+
|
3
|
+
it 'can convert an HSL color to a hex color' do
|
4
|
+
Inkcite::Util.hsl_to_color(78, 78, 78).must_equal('#d8f39b')
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'can convert an HSL color to a hex color' do
|
8
|
+
Inkcite::Util.hsl_to_color(128, 100, 50).must_equal('#00ff22')
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inkcite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeffrey D. Hoffman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: kraken-io
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
168
|
name: listen
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -361,7 +375,6 @@ files:
|
|
361
375
|
- bin/inkcite
|
362
376
|
- inkcite.gemspec
|
363
377
|
- lib/inkcite.rb
|
364
|
-
- lib/inkcite/animation.rb
|
365
378
|
- lib/inkcite/cli/base.rb
|
366
379
|
- lib/inkcite/cli/build.rb
|
367
380
|
- lib/inkcite/cli/init.rb
|
@@ -371,6 +384,11 @@ files:
|
|
371
384
|
- lib/inkcite/cli/test.rb
|
372
385
|
- lib/inkcite/cli/validate.rb
|
373
386
|
- lib/inkcite/email.rb
|
387
|
+
- lib/inkcite/facade.rb
|
388
|
+
- lib/inkcite/facade/animation.rb
|
389
|
+
- lib/inkcite/facade/element.rb
|
390
|
+
- lib/inkcite/facade/keyframe.rb
|
391
|
+
- lib/inkcite/facade/style.rb
|
374
392
|
- lib/inkcite/mailer.rb
|
375
393
|
- lib/inkcite/minifier.rb
|
376
394
|
- lib/inkcite/parser.rb
|
@@ -380,7 +398,7 @@ files:
|
|
380
398
|
- lib/inkcite/renderer/button.rb
|
381
399
|
- lib/inkcite/renderer/container_base.rb
|
382
400
|
- lib/inkcite/renderer/div.rb
|
383
|
-
- lib/inkcite/renderer/
|
401
|
+
- lib/inkcite/renderer/fireworks.rb
|
384
402
|
- lib/inkcite/renderer/footnote.rb
|
385
403
|
- lib/inkcite/renderer/google_analytics.rb
|
386
404
|
- lib/inkcite/renderer/image.rb
|
@@ -405,7 +423,6 @@ files:
|
|
405
423
|
- lib/inkcite/renderer/span.rb
|
406
424
|
- lib/inkcite/renderer/sparkle.rb
|
407
425
|
- lib/inkcite/renderer/special_effect.rb
|
408
|
-
- lib/inkcite/renderer/style.rb
|
409
426
|
- lib/inkcite/renderer/table.rb
|
410
427
|
- lib/inkcite/renderer/table_base.rb
|
411
428
|
- lib/inkcite/renderer/td.rb
|
@@ -445,6 +462,7 @@ files:
|
|
445
462
|
- test/renderer/video_preview_spec.rb
|
446
463
|
- test/renderer_spec.rb
|
447
464
|
- test/test_helper.rb
|
465
|
+
- test/util_spec.rb
|
448
466
|
- test/view_spec.rb
|
449
467
|
homepage: https://github.com/inkceptional/inkcite
|
450
468
|
licenses:
|
@@ -499,4 +517,5 @@ test_files:
|
|
499
517
|
- test/renderer/video_preview_spec.rb
|
500
518
|
- test/renderer_spec.rb
|
501
519
|
- test/test_helper.rb
|
520
|
+
- test/util_spec.rb
|
502
521
|
- test/view_spec.rb
|