inkcite 1.15.0 → 1.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/inkcite.gemspec +0 -3
- data/lib/inkcite.rb +0 -1
- data/lib/inkcite/cli/base.rb +12 -8
- data/lib/inkcite/cli/preview.rb +0 -10
- data/lib/inkcite/cli/server.rb +9 -1
- data/lib/inkcite/email.rb +5 -10
- data/lib/inkcite/facade/animation.rb +4 -1
- data/lib/inkcite/image_minifier.rb +96 -0
- data/lib/inkcite/mailer.rb +2 -2
- data/lib/inkcite/minifier.rb +1 -1
- data/lib/inkcite/renderer.rb +10 -0
- data/lib/inkcite/renderer/base.rb +47 -2
- data/lib/inkcite/renderer/button.rb +15 -5
- data/lib/inkcite/renderer/container_base.rb +15 -1
- data/lib/inkcite/renderer/image.rb +1 -1
- data/lib/inkcite/renderer/image_base.rb +8 -0
- data/lib/inkcite/renderer/list.rb +104 -0
- data/lib/inkcite/renderer/mobile_image.rb +3 -0
- data/lib/inkcite/renderer/responsive.rb +2 -0
- data/lib/inkcite/renderer/slant.rb +207 -0
- data/lib/inkcite/renderer/snow.rb +15 -1
- data/lib/inkcite/renderer/special_effect.rb +7 -0
- data/lib/inkcite/renderer/sup.rb +18 -4
- data/lib/inkcite/renderer/table.rb +9 -1
- data/lib/inkcite/renderer/table_base.rb +20 -2
- data/lib/inkcite/renderer/td.rb +7 -2
- data/lib/inkcite/renderer/video_preview.rb +1 -1
- data/lib/inkcite/uploader.rb +40 -27
- data/lib/inkcite/version.rb +1 -1
- data/lib/inkcite/view.rb +133 -13
- data/lib/inkcite/view/context.rb +6 -1
- data/lib/inkcite/view/developer_scripts.rb +56 -0
- data/test/renderer/background_spec.rb +4 -4
- data/test/renderer/button_spec.rb +14 -8
- data/test/renderer/div_spec.rb +26 -3
- data/test/renderer/image_spec.rb +9 -4
- data/test/renderer/list_spec.rb +36 -0
- data/test/renderer/mobile_image_spec.rb +5 -0
- data/test/renderer/slant_spec.rb +47 -0
- data/test/renderer/span_spec.rb +12 -1
- data/test/renderer/table_spec.rb +1 -1
- data/test/renderer/td_spec.rb +24 -8
- data/test/renderer/trademark_spec.rb +6 -6
- metadata +11 -50
- data/lib/inkcite/image/base.rb +0 -38
- data/lib/inkcite/image/guetzli_minifier.rb +0 -62
- data/lib/inkcite/image/image_minifier.rb +0 -143
- data/lib/inkcite/image/image_optim_minifier.rb +0 -90
- data/lib/inkcite/image/mozjpeg_minifier.rb +0 -92
@@ -258,6 +258,11 @@ module Inkcite
|
|
258
258
|
styles << Inkcite::Renderer::Style.new(".gmail-fix", sfx.ctx, { FONT_SIZE => '3*px' })
|
259
259
|
end
|
260
260
|
|
261
|
+
# True if we're limiting the rendering of the animation to iOS clients
|
262
|
+
only_ios = ctx.email? && !ctx.development?
|
263
|
+
|
264
|
+
styles << '@media screen and (-webkit-min-device-pixel-ratio:0) {' if only_ios
|
265
|
+
|
261
266
|
# Create the <div> that wraps the entire animation.
|
262
267
|
create_wrap_element html, sfx
|
263
268
|
|
@@ -276,6 +281,8 @@ module Inkcite
|
|
276
281
|
# the individual children are configured.
|
277
282
|
sfx.animations.each { |a| styles << a.to_keyframe_css }
|
278
283
|
|
284
|
+
styles << '}' if only_ios
|
285
|
+
|
279
286
|
# Push the completed list of styles into the context's stack.
|
280
287
|
ctx.styles << styles.join("\n")
|
281
288
|
|
data/lib/inkcite/renderer/sup.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Inkcite
|
2
2
|
module Renderer
|
3
|
+
|
4
|
+
# Renders a bulletproof superscript tag.
|
5
|
+
# https://litmus.com/community/discussions/488-best-method-for-superscripts
|
3
6
|
class Sup < Base
|
4
7
|
|
5
8
|
def render tag, opt, ctx
|
@@ -13,11 +16,14 @@ module Inkcite
|
|
13
16
|
|
14
17
|
sup = Element.new('sup', :style => { VERTICAL_ALIGN => :top })
|
15
18
|
|
16
|
-
font_size = (opt[FONT_SIZE] ||
|
17
|
-
sup.style[FONT_SIZE] =
|
19
|
+
font_size = (opt[FONT_SIZE] || DEFAULT_FONT_SIZE_PERCENT).to_i
|
20
|
+
sup.style[FONT_SIZE] = pct(font_size)
|
21
|
+
|
22
|
+
line_height = (opt[LINE_HEIGHT] || 1).to_i
|
23
|
+
sup.style[LINE_HEIGHT] = line_height
|
18
24
|
|
19
|
-
|
20
|
-
sup.style[
|
25
|
+
mso_text_raise = (font_size.to_f * (DEFAULT_MSO_TEST_RAISE_PERCENT / DEFAULT_FONT_SIZE_PERCENT)).round(0)
|
26
|
+
sup.style[MSO_TEXT_RAISE] = pct(mso_text_raise)
|
21
27
|
|
22
28
|
html << sup.to_s
|
23
29
|
|
@@ -26,6 +32,14 @@ module Inkcite
|
|
26
32
|
html
|
27
33
|
end
|
28
34
|
|
35
|
+
private
|
36
|
+
|
37
|
+
# Name of the CSS style used to force
|
38
|
+
MSO_TEXT_RAISE = :'mso-text-raise'
|
39
|
+
|
40
|
+
DEFAULT_FONT_SIZE_PERCENT = 70.0
|
41
|
+
DEFAULT_MSO_TEST_RAISE_PERCENT = 60.0
|
42
|
+
|
29
43
|
end
|
30
44
|
end
|
31
45
|
end
|
@@ -67,7 +67,15 @@ module Inkcite
|
|
67
67
|
# If Fluid-Drop is enabled, padding is always zero at this top-level table
|
68
68
|
# and will be applied in the TD renderer when it creates a new table to
|
69
69
|
# wrap itself in.
|
70
|
-
|
70
|
+
cellpadding = is_fluid_drop ? 0 : get_padding(opt)
|
71
|
+
table[:cellpadding] = cellpadding
|
72
|
+
|
73
|
+
# Need to specify padding as px to ensure that the table plays nicely
|
74
|
+
# with high-DPI email clients like Outlook.
|
75
|
+
if cellpadding > 0
|
76
|
+
cellpaddingpx = px(cellpadding)
|
77
|
+
table.style[MSO_PADDING_ALT] = "#{cellpaddingpx} #{cellpaddingpx} #{cellpaddingpx} #{cellpaddingpx}"
|
78
|
+
end
|
71
79
|
|
72
80
|
# Conveniently accept both float and align to mean the same thing.
|
73
81
|
align = opt[:align] || opt[:float]
|
@@ -73,13 +73,31 @@ module Inkcite
|
|
73
73
|
# Not taking .to_i because we want to accept both integer values
|
74
74
|
# or percentages - e.g. 50%
|
75
75
|
width = opt[:width]
|
76
|
-
|
76
|
+
unless width.blank?
|
77
|
+
element[:width] = width
|
78
|
+
|
79
|
+
# Need to redefine px-based width as a style to fix rendering
|
80
|
+
# problems in high DPI Outlook
|
81
|
+
# https://litmus.com/community/discussions/151-mystery-solved-dpi-scaling-in-outlook-2007-2013
|
82
|
+
element.style[:width] = px(width) unless width[-1] == '%' || is_fluid?(opt[:mobile])
|
83
|
+
|
84
|
+
end
|
85
|
+
|
77
86
|
|
78
87
|
mobile_width = opt[MOBILE_WIDTH]
|
79
88
|
element.mobile_style[:width] = px(mobile_width) unless none?(mobile_width)
|
80
89
|
|
81
90
|
height = opt[:height].to_i
|
82
|
-
|
91
|
+
if height > 0
|
92
|
+
element[:height] = height
|
93
|
+
|
94
|
+
# Height also needs to be copied into the style to ensure that
|
95
|
+
# high DPI Outlook displays the table properly.
|
96
|
+
# https://litmus.com/community/discussions/151-mystery-solved-dpi-scaling-in-outlook-2007-2013
|
97
|
+
element.style[:height] = px(height)
|
98
|
+
|
99
|
+
end
|
100
|
+
|
83
101
|
|
84
102
|
mobile_height = opt[MOBILE_HEIGHT]
|
85
103
|
element.mobile_style[:height] = px(mobile_height) unless none?(mobile_height)
|
data/lib/inkcite/renderer/td.rb
CHANGED
@@ -141,11 +141,16 @@ module Inkcite
|
|
141
141
|
# you know, Outlook.
|
142
142
|
align = opt[:align]
|
143
143
|
unless align.blank?
|
144
|
-
|
144
|
+
|
145
|
+
# If the alignment is justified, force the text alignment attribute to
|
146
|
+
# be left aligned so Outlook doesn't center the text.
|
147
|
+
td[:align] = align == JUSTIFY ? LEFT : align
|
145
148
|
|
146
149
|
# Must use style to reinforce left-align text in certain email clients.
|
147
150
|
# All other alignments are accepted naturally.
|
148
|
-
td.style[TEXT_ALIGN] = align if align == LEFT
|
151
|
+
td.style[TEXT_ALIGN] = align if align == LEFT || align == JUSTIFY
|
152
|
+
|
153
|
+
mix_text_justify(td, opt, ctx) if align === JUSTIFY
|
149
154
|
|
150
155
|
end
|
151
156
|
|
@@ -94,7 +94,7 @@ module Inkcite
|
|
94
94
|
|
95
95
|
# Using an Element to produce the appropriate anchor helper with
|
96
96
|
# the desired
|
97
|
-
html << Element.new('a', { :id => id, :href => quote(href), :class => hover_klass, :bgcolor => bgcolor, :bggradient => gradient, :block => true }).to_helper
|
97
|
+
html << Element.new('a', { :id => id, :href => quote(href), :class => hover_klass, :bgcolor => bgcolor, :bggradient => gradient, BACKGROUND_GRADIENT_SHAPE => CIRCLE, :block => true }).to_helper
|
98
98
|
|
99
99
|
table = Element.new('table', {
|
100
100
|
:width => '100%', :background => frame_srcs[0], BACKGROUND_SIZE => 'cover',
|
data/lib/inkcite/uploader.rb
CHANGED
@@ -4,45 +4,57 @@ require 'stringio'
|
|
4
4
|
module Inkcite
|
5
5
|
class Uploader
|
6
6
|
|
7
|
-
def self.upload email
|
7
|
+
def self.upload email, opts
|
8
8
|
|
9
|
-
|
9
|
+
# True if we're only uploading images.
|
10
|
+
images_only = !!opts[:images]
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
# Check to see if forcing the upload is specified. If not, check to see
|
13
|
+
# when the most recent file was updated and
|
14
|
+
force = !!opts[:force]
|
15
|
+
unless force
|
16
|
+
|
17
|
+
times = []
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
unless images_only
|
20
|
+
Dir.glob(File.join(email.path, '*.{html,tsv,txt,yml}')).each do |file|
|
21
|
+
times << File.mtime(file).to_i
|
22
|
+
end
|
19
23
|
end
|
20
|
-
end
|
21
24
|
|
22
|
-
|
23
|
-
|
25
|
+
local_images = email.image_dir
|
26
|
+
if File.exist?(local_images)
|
27
|
+
Dir.foreach(local_images) do |file|
|
28
|
+
times << File.mtime(File.join(local_images, file)).to_i unless file.starts_with?('.')
|
29
|
+
end
|
30
|
+
end
|
24
31
|
|
25
|
-
|
26
|
-
|
32
|
+
# Get the most recently updated file.
|
33
|
+
last_update = times.max
|
27
34
|
|
28
|
-
|
35
|
+
# Determine when the last upload was completed.
|
36
|
+
last_upload = email.meta(:last_upload).to_i
|
29
37
|
|
30
|
-
|
38
|
+
return unless last_update > last_upload
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
self.do_upload(email, force, images_only)
|
31
43
|
|
32
|
-
def self.upload! email
|
33
|
-
self.do_upload(email, true)
|
34
44
|
end
|
35
45
|
|
36
46
|
private
|
37
47
|
|
38
48
|
IMAGE_PATH = :'image-path'
|
39
49
|
|
40
|
-
def self.copy! sftp, local, remote, force=true
|
50
|
+
def self.copy! email, sftp, local, remote, force=true
|
41
51
|
|
42
52
|
# Nothing to copy unless the local directory exists (e.g. some emails don't
|
43
53
|
# have an images directory.)
|
44
54
|
return unless File.exist?(local)
|
45
55
|
|
56
|
+
last_upload = email.meta(:last_upload).to_i
|
57
|
+
|
46
58
|
Dir.foreach(local) do |file|
|
47
59
|
next if file.starts_with?('.')
|
48
60
|
|
@@ -52,11 +64,7 @@ module Inkcite
|
|
52
64
|
remote_file = File.join(remote, file)
|
53
65
|
|
54
66
|
unless force
|
55
|
-
next unless
|
56
|
-
File.stat(local_file).mtime > Time.at(sftp.stat!(remote_file).mtime)
|
57
|
-
rescue Net::SFTP::StatusException
|
58
|
-
true # File doesn't exist, so assume it's changed.
|
59
|
-
end
|
67
|
+
next unless File.mtime(local_file).to_i > last_upload
|
60
68
|
end
|
61
69
|
|
62
70
|
puts "Uploading #{local_file} -> #{remote_file} ..."
|
@@ -69,7 +77,7 @@ module Inkcite
|
|
69
77
|
|
70
78
|
# Internal method responsive for doing the actual upload and
|
71
79
|
# forcing (if necessary) the update of the graphics.
|
72
|
-
def self.do_upload email, force
|
80
|
+
def self.do_upload email, force, images_only
|
73
81
|
|
74
82
|
# The preview version defines the configuration for the server to which
|
75
83
|
# the files will be sftp'd.
|
@@ -122,8 +130,13 @@ module Inkcite
|
|
122
130
|
# to ensure that we're not repeatedly uploading the same images over and
|
123
131
|
# over when force is enabled -- but will re-upload images to distinct
|
124
132
|
# remote roots.
|
125
|
-
|
126
|
-
|
133
|
+
if last_remote_root != remote_root
|
134
|
+
copy! email, sftp, local_images, remote_root, force
|
135
|
+
last_remote_root = remote_root
|
136
|
+
end
|
137
|
+
|
138
|
+
# Nothing left to do if this is an image-only upload
|
139
|
+
next if images_only
|
127
140
|
|
128
141
|
# Check to see if we're creating an in-browser version of the email.
|
129
142
|
next unless email.formats.include?(:browser)
|
data/lib/inkcite/version.rb
CHANGED
data/lib/inkcite/view.rb
CHANGED
@@ -239,9 +239,6 @@ module Inkcite
|
|
239
239
|
|
240
240
|
tag = tag.to_sym
|
241
241
|
|
242
|
-
# Warn the user if the helper is already defined.
|
243
|
-
view.error("Helper '#{tag}' already defined", :open => open, :close => close) unless @config[tag].nil?
|
244
|
-
|
245
242
|
@config[tag] = open.to_s
|
246
243
|
@config[:"/#{tag}"] = close.to_s
|
247
244
|
|
@@ -262,7 +259,11 @@ module Inkcite
|
|
262
259
|
|
263
260
|
src_url = ''
|
264
261
|
|
265
|
-
if
|
262
|
+
# Check to see if images are disabled - if so, return a broken image.
|
263
|
+
if self[IMAGES_OFF]
|
264
|
+
src_url = "__#{src}"
|
265
|
+
|
266
|
+
elsif Util.is_fully_qualified?(src)
|
266
267
|
src_url << src
|
267
268
|
|
268
269
|
else
|
@@ -270,7 +271,7 @@ module Inkcite
|
|
270
271
|
# Prepend the image host onto the src if one is specified in the properties.
|
271
272
|
# During local development, images are always expected in an images/ subdirectory.
|
272
273
|
image_host = if development?
|
273
|
-
(@email.optimize_images? ?
|
274
|
+
(@email.optimize_images? ? ImageMinifier::IMAGE_CACHE : Email::IMAGES) + '/'
|
274
275
|
else
|
275
276
|
|
276
277
|
# Use the image host defined in config.yml or, out-of-the-box refer to images/
|
@@ -293,6 +294,14 @@ module Inkcite
|
|
293
294
|
Renderer.render(src_url, self)
|
294
295
|
end
|
295
296
|
|
297
|
+
def images_off?
|
298
|
+
is_enabled?(IMAGES_OFF)
|
299
|
+
end
|
300
|
+
|
301
|
+
def images_off= off
|
302
|
+
@config[IMAGES_OFF] = !!off
|
303
|
+
end
|
304
|
+
|
296
305
|
# Tests if a configuration value has been enabled. This assumes
|
297
306
|
# it is disabled by default but that a value of true, 'true' or 1
|
298
307
|
# for the value indicates it is enabled.
|
@@ -309,7 +318,6 @@ module Inkcite
|
|
309
318
|
!val.nil? && (val == false || val == false.to_s)
|
310
319
|
end
|
311
320
|
|
312
|
-
|
313
321
|
def links_file_name
|
314
322
|
|
315
323
|
# There is nothing to return if trackable links aren't enabled.
|
@@ -463,14 +471,20 @@ module Inkcite
|
|
463
471
|
|
464
472
|
# Resolve the HTML declaration for this email based on whether or not VML was used.
|
465
473
|
html_declaration = '<html xmlns="http://www.w3.org/1999/xhtml"'
|
466
|
-
html_declaration << ' xmlns:v="urn:schemas-microsoft-com:vml"
|
474
|
+
html_declaration << ' xmlns:v="urn:schemas-microsoft-com:vml"' if vml_used?
|
475
|
+
html_declaration << ' xmlns:o="urn:schemas-microsoft-com:office:office"' if email?
|
467
476
|
html_declaration << '>'
|
468
477
|
html << html_declaration
|
469
478
|
|
470
479
|
html << '<head>'
|
471
480
|
html << '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>'
|
481
|
+
|
482
|
+
# iOS 10 auto-scale fix
|
483
|
+
# https://emails.hteumeuleu.com/what-you-need-to-know-about-apple-mail-in-ios-10-c7031f6d704d
|
484
|
+
html << '<meta name="x-apple-disable-message-reformatting"/>'
|
472
485
|
html << '<meta name="viewport" content="width=device-width"/>'
|
473
|
-
|
486
|
+
|
487
|
+
html << %Q(<meta name="generator" content="Inkcite #{Inkcite::VERSION}"/>)
|
474
488
|
|
475
489
|
# Enable responsive media queries on Windows phones courtesy of @jamesmacwhite
|
476
490
|
# https://blog.jmwhite.co.uk/2014/03/01/windows-phone-does-support-css3-media-queries-in-html-email/
|
@@ -490,6 +504,8 @@ module Inkcite
|
|
490
504
|
|
491
505
|
html << outlook_styles
|
492
506
|
|
507
|
+
html << outlook_high_dpi_fix if email?
|
508
|
+
|
493
509
|
html << '</head>'
|
494
510
|
|
495
511
|
html << body_declaration
|
@@ -514,6 +530,13 @@ module Inkcite
|
|
514
530
|
# process) with a chance to operate on the final HTML.
|
515
531
|
@content = PostProcessor.run_all(@content, self)
|
516
532
|
|
533
|
+
# Some ESPs have link tracking/opt-out code that uses greater-than and
|
534
|
+
# less-than symbols. Encode them as their HTML escape code equivalents
|
535
|
+
# in the source and replace them with their original characters in the
|
536
|
+
# final output.
|
537
|
+
@content.gsub!('>', '>')
|
538
|
+
@content.gsub!('<', '<')
|
539
|
+
|
517
540
|
# Ensure that all failsafes pass
|
518
541
|
assert_failsafes
|
519
542
|
|
@@ -695,6 +718,10 @@ module Inkcite
|
|
695
718
|
# Tab-separated file containing global substitution values.
|
696
719
|
SUBSTITUTIONS_TSV_FILE = 'substitutions.tsv'
|
697
720
|
|
721
|
+
# Config value which disables images (e.g. shows their size, position
|
722
|
+
# background color and alt text).
|
723
|
+
IMAGES_OFF = :'images-off'
|
724
|
+
|
698
725
|
def assert_in_browser msg
|
699
726
|
raise msg if email? && !development?
|
700
727
|
end
|
@@ -907,7 +934,7 @@ module Inkcite
|
|
907
934
|
# http://www.ianhoar.com/2008/04/29/outlook-2007-borders-and-1px-padding-on-table-cells
|
908
935
|
# http://www.campaignmonitor.com/blog/post/3392/1px-borders-padding-on-table-cells-in-outlook-07
|
909
936
|
reset << 'table { border-spacing: 0; }'
|
910
|
-
reset << 'table, td { border-collapse: collapse; }'
|
937
|
+
reset << 'table, td { border-collapse: collapse; mso-table-lspace: 0pt !important; mso-table-rspace: 0pt !important; }'
|
911
938
|
|
912
939
|
# Ensure that telephone numbers are displayed using the same style as links.
|
913
940
|
reset << "a[href^=tel] { color: #{self[Renderer::Base::LINK_COLOR]}; text-decoration:none;}"
|
@@ -921,6 +948,9 @@ module Inkcite
|
|
921
948
|
# Reset the font on every cell to the default family.
|
922
949
|
reset << "td { font-family: #{self[Renderer::Base::FONT_FAMILY]}; }"
|
923
950
|
|
951
|
+
# Allow smoother rendering of resized image in Internet Explorer
|
952
|
+
reset << "img { -ms-interpolation-mode:bicubic !important; }"
|
953
|
+
|
924
954
|
reset.join(NEW_LINE)
|
925
955
|
end
|
926
956
|
|
@@ -971,24 +1001,108 @@ module Inkcite
|
|
971
1001
|
html.join(NEW_LINE)
|
972
1002
|
end
|
973
1003
|
|
1004
|
+
def outlook_high_dpi_fix
|
1005
|
+
|
1006
|
+
# This is the XML required to ensure high-DPI Outlook plays nicely with the
|
1007
|
+
# email when it is displayed.
|
1008
|
+
# https://www.emailonacid.com/blog/article/email-development/dpi_scaling_in_outlook_2007-2013
|
1009
|
+
html = []
|
1010
|
+
html << '<!--[if gte mso 9]>'
|
1011
|
+
html << '<xml>'
|
1012
|
+
html << '<o:OfficeDocumentSettings>'
|
1013
|
+
html << '<o:AllowPNG/>'
|
1014
|
+
html << '<o:PixelsPerInch>96</o:PixelsPerInch>'
|
1015
|
+
html << '</o:OfficeDocumentSettings>'
|
1016
|
+
html << '</xml>'
|
1017
|
+
html << '<![endif]-->'
|
1018
|
+
|
1019
|
+
return html.join(NEW_LINE)
|
1020
|
+
end
|
1021
|
+
|
974
1022
|
def outlook_styles
|
975
1023
|
|
976
1024
|
html = []
|
1025
|
+
html << '<!--[if mso]>' if email?
|
1026
|
+
html << '<style>'
|
1027
|
+
|
1028
|
+
if email?
|
1029
|
+
|
1030
|
+
# These are the Outlook-specific styles necessary to block the
|
1031
|
+
# visited link from changing color in Outlook 2007-2013.
|
1032
|
+
# https://litmus.com/community/discussions/4164-outlook-07-13-visited-link-color-fix
|
1033
|
+
vlink_styles = { :'mso-style-priority' => 99, :color => 'inherit' }
|
1034
|
+
%w(MsoHyperlink MsoHyperlinkFollowed).each do |l|
|
1035
|
+
html << Inkcite::Renderer::Style.new("span.#{l}", self, vlink_styles).to_s
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
end
|
977
1039
|
|
978
1040
|
# VML-specific CSS needed only if VML was used in the email.
|
979
1041
|
if vml_used?
|
980
|
-
html << '<style>'
|
981
|
-
|
982
1042
|
%w(v o).each do |l|
|
983
1043
|
html << Inkcite::Renderer::Style.new("#{l}\:*", self, { :behavior => 'url(#default#VML)', :display => 'inline-block' }).to_s
|
984
1044
|
end
|
1045
|
+
end
|
985
1046
|
|
986
1047
|
html << '</style>'
|
987
|
-
|
1048
|
+
html << '<![endif]-->' if email?
|
988
1049
|
|
989
1050
|
html.join(NEW_LINE)
|
990
1051
|
end
|
991
1052
|
|
1053
|
+
def load_google_sheets_helpers url, into
|
1054
|
+
|
1055
|
+
# Add a timestamp to break google's cache and force the page to
|
1056
|
+
# be reloaded each time
|
1057
|
+
url = Util::add_query_param(url, Time.now.to_i)
|
1058
|
+
|
1059
|
+
raw = Net::HTTP.get(URI.parse(url))
|
1060
|
+
|
1061
|
+
# Consolidate line-breaks for simplicity
|
1062
|
+
raw.gsub!(/[\r\f\n]{1,}/, NEW_LINE)
|
1063
|
+
raw.gsub!(/ \& /, " & ")
|
1064
|
+
|
1065
|
+
fields = nil
|
1066
|
+
|
1067
|
+
raw.split(NEW_LINE).each do |line|
|
1068
|
+
columns = line.split(TAB)
|
1069
|
+
if fields.nil?
|
1070
|
+
fields = columns.collect(&:to_sym)
|
1071
|
+
|
1072
|
+
else
|
1073
|
+
|
1074
|
+
version = columns[0]
|
1075
|
+
|
1076
|
+
# Check to see if this version includes an asterisk
|
1077
|
+
is_any_version = if version == '*'
|
1078
|
+
true
|
1079
|
+
elsif version.include?('*')
|
1080
|
+
prefix, suffix = version.split('*')
|
1081
|
+
(prefix.blank? || @version.to_s.start_with?(prefix)) && (suffix.blank? || @version.to_s.end_with?(suffix))
|
1082
|
+
else
|
1083
|
+
false
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
is_version = version.to_sym == @version
|
1087
|
+
|
1088
|
+
if is_any_version || is_version
|
1089
|
+
fields.each_with_index do |field, index|
|
1090
|
+
unless index == 0
|
1091
|
+
value = columns[index]
|
1092
|
+
into[field] = value unless value.blank?
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
break if is_version
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
|
1100
|
+
end
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
true
|
1104
|
+
end
|
1105
|
+
|
992
1106
|
def load_helper_file file, into, abort_on_fail=true
|
993
1107
|
|
994
1108
|
unless File.exist?(file)
|
@@ -1053,7 +1167,13 @@ module Inkcite
|
|
1053
1167
|
# Check to see if the config.yml includes a "helpers:" array which allows
|
1054
1168
|
# additional out-of-project, shared helper files to be loaded.
|
1055
1169
|
included_helpers = [*@email.config[:helpers]]
|
1056
|
-
included_helpers.each
|
1170
|
+
included_helpers.each do |file|
|
1171
|
+
if file.start_with?('http')
|
1172
|
+
load_google_sheets_helpers file, _helpers
|
1173
|
+
else
|
1174
|
+
load_helper_file(File.join(path, file), _helpers)
|
1175
|
+
end
|
1176
|
+
end
|
1057
1177
|
|
1058
1178
|
# Load the project's properties, which may include references to additional
|
1059
1179
|
# properties in other directories.
|