inkcite 1.14.0 → 1.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/assets/init/config.yml +2 -0
- data/assets/social/facebook.png +0 -0
- data/assets/social/instagram.png +0 -0
- data/assets/social/pintrest.png +0 -0
- data/assets/social/twitter.png +0 -0
- data/inkcite.gemspec +2 -2
- data/lib/inkcite.rb +1 -0
- data/lib/inkcite/cli/base.rb +32 -6
- data/lib/inkcite/cli/preview.rb +24 -28
- data/lib/inkcite/cli/server.rb +22 -19
- data/lib/inkcite/cli/test.rb +1 -1
- data/lib/inkcite/email.rb +8 -4
- data/lib/inkcite/facade/animation.rb +4 -0
- data/lib/inkcite/facade/keyframe.rb +26 -3
- data/lib/inkcite/image/base.rb +38 -0
- data/lib/inkcite/image/guetzli_minifier.rb +62 -0
- data/lib/inkcite/image/image_minifier.rb +143 -0
- data/lib/inkcite/image/image_optim_minifier.rb +90 -0
- data/lib/inkcite/image/mozjpeg_minifier.rb +92 -0
- data/lib/inkcite/mailer.rb +201 -112
- data/lib/inkcite/minifier.rb +2 -146
- data/lib/inkcite/post_processor.rb +13 -0
- data/lib/inkcite/renderer.rb +19 -0
- data/lib/inkcite/renderer/background.rb +53 -14
- data/lib/inkcite/renderer/base.rb +29 -15
- data/lib/inkcite/renderer/button.rb +1 -1
- data/lib/inkcite/renderer/carousel.rb +245 -0
- data/lib/inkcite/renderer/container_base.rb +10 -0
- data/lib/inkcite/renderer/div.rb +1 -3
- data/lib/inkcite/renderer/fireworks.rb +54 -40
- data/lib/inkcite/renderer/footnote.rb +22 -2
- data/lib/inkcite/renderer/image.rb +11 -0
- data/lib/inkcite/renderer/image_base.rb +3 -6
- data/lib/inkcite/renderer/in_browser.rb +4 -0
- data/lib/inkcite/renderer/link.rb +39 -12
- data/lib/inkcite/renderer/mobile_image.rb +1 -1
- data/lib/inkcite/renderer/responsive.rb +9 -1
- data/lib/inkcite/renderer/social.rb +31 -3
- data/lib/inkcite/renderer/special_effect.rb +22 -13
- data/lib/inkcite/renderer/sup.rb +32 -0
- data/lib/inkcite/renderer/table_base.rb +3 -0
- data/lib/inkcite/renderer/topic.rb +76 -0
- data/lib/inkcite/renderer/trademark.rb +47 -0
- data/lib/inkcite/renderer/video_preview.rb +3 -2
- data/lib/inkcite/uploader.rb +2 -3
- data/lib/inkcite/util.rb +51 -0
- data/lib/inkcite/version.rb +1 -1
- data/lib/inkcite/view.rb +140 -54
- data/lib/inkcite/view/context.rb +1 -31
- data/lib/inkcite/view/media_query.rb +6 -0
- data/test/animation_spec.rb +7 -0
- data/test/parser_spec.rb +1 -1
- data/test/renderer/background_spec.rb +16 -12
- data/test/renderer/div_spec.rb +11 -0
- data/test/renderer/footnote_spec.rb +5 -1
- data/test/renderer/image_spec.rb +51 -28
- data/test/renderer/link_spec.rb +20 -8
- data/test/renderer/lorem_spec.rb +2 -2
- data/test/renderer/mobile_image_spec.rb +6 -0
- data/test/renderer/mobile_style_spec.rb +3 -3
- data/test/renderer/redacted_spec.rb +2 -2
- data/test/renderer/social_spec.rb +6 -6
- data/test/renderer/table_spec.rb +4 -0
- data/test/renderer/topic_spec.rb +28 -0
- data/test/renderer/trademark_spec.rb +40 -0
- data/test/renderer/video_preview_spec.rb +1 -1
- data/test/test_helper.rb +14 -0
- data/test/view_spec.rb +4 -0
- metadata +26 -12
- data/assets/init/image_optim.yml +0 -37
@@ -0,0 +1,47 @@
|
|
1
|
+
module Inkcite
|
2
|
+
module Renderer
|
3
|
+
class Trademark < Base
|
4
|
+
|
5
|
+
def initialize sym
|
6
|
+
@sym = sym
|
7
|
+
end
|
8
|
+
|
9
|
+
def render tag, opt, ctx
|
10
|
+
|
11
|
+
# Check to see if there is an ID associated with this symbol.
|
12
|
+
# If so, it only needs to appear once.
|
13
|
+
id = opt[:id]
|
14
|
+
|
15
|
+
if id.blank?
|
16
|
+
ctx.error('Missing id on trademark/registered symbol')
|
17
|
+
id = "tm#{ctx.unique_id(:trademark)}"
|
18
|
+
end
|
19
|
+
|
20
|
+
return '' unless ctx.once?("#{id}-trademark")
|
21
|
+
|
22
|
+
no_sup = opt[:'no-sup']
|
23
|
+
|
24
|
+
html = ''
|
25
|
+
html << '{sup}' unless no_sup
|
26
|
+
html << @sym
|
27
|
+
|
28
|
+
# If the trademark symbol should be followed immediately with a footnote
|
29
|
+
# render the {footnote} Helper with the once flag and the no-sup attribute
|
30
|
+
# to ensure unnecessary superscripts don't get rendered.
|
31
|
+
footnote = opt[:footnote]
|
32
|
+
unless footnote.blank?
|
33
|
+
html << %Q({footnote id="#{id}")
|
34
|
+
|
35
|
+
# Only include the footnote text if the attribute is not boolean
|
36
|
+
html << %Q( text="#{footnote}") if footnote != true
|
37
|
+
html << %q( once}) unless footnote.blank?
|
38
|
+
end
|
39
|
+
|
40
|
+
html << '{/sup}' unless no_sup
|
41
|
+
|
42
|
+
html
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -242,9 +242,10 @@ module Inkcite
|
|
242
242
|
frames.each do |f|
|
243
243
|
this_frame_url = "url(#{f})"
|
244
244
|
|
245
|
-
animation.add_keyframe(percent, { BACKGROUND_IMAGE => this_frame_url })
|
245
|
+
keyframe = animation.add_keyframe(percent.round(0), { BACKGROUND_IMAGE => this_frame_url })
|
246
246
|
percent += percent_per_frame
|
247
|
-
|
247
|
+
keyframe.end_percent = percent.round(0)
|
248
|
+
|
248
249
|
percent += percent_per_transition
|
249
250
|
|
250
251
|
end
|
data/lib/inkcite/uploader.rb
CHANGED
@@ -8,9 +8,8 @@ module Inkcite
|
|
8
8
|
|
9
9
|
times = []
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
times << File.mtime(file).to_i if File.exist?(file)
|
11
|
+
Dir.glob(File.join(email.path, '*.{html,tsv,txt,yml}')).each do |file|
|
12
|
+
times << File.mtime(file).to_i
|
14
13
|
end
|
15
14
|
|
16
15
|
local_images = email.image_dir
|
data/lib/inkcite/util.rb
CHANGED
@@ -38,6 +38,10 @@ module Inkcite
|
|
38
38
|
opts.detect { |o| !o.blank? }
|
39
39
|
end
|
40
40
|
|
41
|
+
def self.dir_size path
|
42
|
+
Dir.glob(File.join(path, '*.*')).inject(0) { |size, file| size + File.size(file) }
|
43
|
+
end
|
44
|
+
|
41
45
|
# Centralizing the URL/CGI encoding for all HREF processing because
|
42
46
|
# URI.escape/encode is obsolete.
|
43
47
|
def self.encode *arg
|
@@ -52,6 +56,15 @@ module Inkcite
|
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
59
|
+
def self.exec command
|
60
|
+
command = command.join(' ') if command.is_a?(Array)
|
61
|
+
`#{command} 2>&1`
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.file_extension path_to_file
|
65
|
+
File.extname(path_to_file).delete('.').downcase
|
66
|
+
end
|
67
|
+
|
55
68
|
# Conversion of HSL to RGB color courtesy of
|
56
69
|
# http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
|
57
70
|
def self.hsl_to_color h, s, l
|
@@ -102,6 +115,40 @@ module Inkcite
|
|
102
115
|
p
|
103
116
|
end
|
104
117
|
|
118
|
+
def self.log message, meta=nil
|
119
|
+
|
120
|
+
msg = "#{Time.now.strftime(DATE_FORMAT)} - INFO - #{message}"
|
121
|
+
unless meta.blank?
|
122
|
+
msg << '['
|
123
|
+
msg << Renderer.join_hash(meta, '=', ', ')
|
124
|
+
msg << ']'
|
125
|
+
end
|
126
|
+
|
127
|
+
puts msg
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.pretty_file_size size
|
131
|
+
|
132
|
+
size = size.to_f
|
133
|
+
decimals = 2
|
134
|
+
ext = 'b'
|
135
|
+
|
136
|
+
if size > KB
|
137
|
+
size = size / KB
|
138
|
+
if size > KB
|
139
|
+
size = size / KB
|
140
|
+
ext = 'MB'
|
141
|
+
else
|
142
|
+
ext = 'Kb'
|
143
|
+
end
|
144
|
+
else
|
145
|
+
round = 0
|
146
|
+
"#{size}b"
|
147
|
+
end
|
148
|
+
|
149
|
+
"#{size.round(decimals)}#{ext}"
|
150
|
+
end
|
151
|
+
|
105
152
|
# RGB to hex courtesy of
|
106
153
|
# http://blog.lebrijo.com/converting-rgb-colors-to-hexadecimal-with-ruby/
|
107
154
|
def self.rgb_to_hex val
|
@@ -166,6 +213,10 @@ module Inkcite
|
|
166
213
|
BLACK = '#000000'
|
167
214
|
WHITE = '#111111'
|
168
215
|
|
216
|
+
DATE_FORMAT = '%H:%M:%S'
|
217
|
+
|
218
|
+
KB = 1024
|
219
|
+
|
169
220
|
# Recursive key symbolization for the provided Hash.
|
170
221
|
def self.symbolize_keys hash
|
171
222
|
unless hash.nil?
|
data/lib/inkcite/version.rb
CHANGED
data/lib/inkcite/view.rb
CHANGED
@@ -23,9 +23,6 @@ module Inkcite
|
|
23
23
|
# Manages the Responsive::Rules applied to this email view.
|
24
24
|
attr_reader :media_query
|
25
25
|
|
26
|
-
# Line number of the email file being processed
|
27
|
-
attr_accessor :line_number
|
28
|
-
|
29
26
|
# The configuration hash for the view
|
30
27
|
attr_accessor :config
|
31
28
|
|
@@ -37,6 +34,14 @@ module Inkcite
|
|
37
34
|
# after a rendering is complete.
|
38
35
|
attr_accessor :js_compressor
|
39
36
|
|
37
|
+
# Array of post-processors that can modify the HTML of the email
|
38
|
+
# after it is rendered but before it is saved.
|
39
|
+
attr_accessor :post_processors
|
40
|
+
|
41
|
+
# The most recently processed tag populated from the renderer and
|
42
|
+
# used when reporting errors.
|
43
|
+
attr_accessor :last_rendered_markup
|
44
|
+
|
40
45
|
def initialize email, environment, format, version
|
41
46
|
@email = email
|
42
47
|
@environment = environment
|
@@ -77,10 +82,6 @@ module Inkcite
|
|
77
82
|
# version in the list of those defined.
|
78
83
|
@config[:'version-index'] = (email.versions.index(version) + 1).to_s
|
79
84
|
|
80
|
-
# Tracks the line number and is recorded when errors are encountered
|
81
|
-
# while rendering said line.
|
82
|
-
@line_number = 0
|
83
|
-
|
84
85
|
# True if VML is used during the preparation of this email.
|
85
86
|
@vml_used = false
|
86
87
|
|
@@ -88,6 +89,9 @@ module Inkcite
|
|
88
89
|
@footnotes = nil
|
89
90
|
@substitutions = nil
|
90
91
|
|
92
|
+
# Will hold any post processors installed during rendering.
|
93
|
+
@post_processors = []
|
94
|
+
|
91
95
|
end
|
92
96
|
|
93
97
|
def [] key
|
@@ -149,9 +153,10 @@ module Inkcite
|
|
149
153
|
end
|
150
154
|
|
151
155
|
# Records an error message on the currently processing line of the source.
|
152
|
-
def error message, obj=
|
156
|
+
def error message, obj={}
|
157
|
+
|
158
|
+
obj[:markup] = %Q({#{self.last_rendered_markup}})
|
153
159
|
|
154
|
-
message << " (line #{self.line_number.to_i})"
|
155
160
|
unless obj.blank?
|
156
161
|
message << ' ['
|
157
162
|
message << obj.collect { |k, v| "#{k}=#{v}" }.join(', ')
|
@@ -206,12 +211,12 @@ module Inkcite
|
|
206
211
|
# Default naming based on the number of versions - only the format if there is
|
207
212
|
# a single version or version and format when there are multiple versions.
|
208
213
|
fn = if email.versions.length > 1
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
214
|
+
'{version}-{format}'
|
215
|
+
elsif text?
|
216
|
+
'email'
|
217
|
+
else
|
218
|
+
'{format}'
|
219
|
+
end
|
215
220
|
|
216
221
|
end
|
217
222
|
|
@@ -221,12 +226,27 @@ module Inkcite
|
|
221
226
|
|
222
227
|
# Sanity check to ensure there is an appropriate extension on the
|
223
228
|
# file name.
|
224
|
-
ext ||= (text
|
229
|
+
ext ||= (text? ? TXT_EXTENSION : HTML_EXTENSION)
|
225
230
|
fn << ext unless File.extname(fn) == ext
|
226
231
|
|
227
232
|
fn
|
228
233
|
end
|
229
234
|
|
235
|
+
# Defines a new helper, which allows designers to keep helper
|
236
|
+
# markup alongside the usage of it inside of partial. Helps keep
|
237
|
+
# code clean and prevents helper.tsv pollution for one-offs
|
238
|
+
def helper tag, open, close=nil
|
239
|
+
|
240
|
+
tag = tag.to_sym
|
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
|
+
@config[tag] = open.to_s
|
246
|
+
@config[:"/#{tag}"] = close.to_s
|
247
|
+
|
248
|
+
end
|
249
|
+
|
230
250
|
# Returns the fully-qualified URL to the designated image (e.g. logo.gif)
|
231
251
|
# appropriate for the current rendering environment. In development
|
232
252
|
# mode, local will have either images/ or images-optim/ prepended on them
|
@@ -250,7 +270,7 @@ module Inkcite
|
|
250
270
|
# Prepend the image host onto the src if one is specified in the properties.
|
251
271
|
# During local development, images are always expected in an images/ subdirectory.
|
252
272
|
image_host = if development?
|
253
|
-
(@email.optimize_images
|
273
|
+
(@email.optimize_images? ? Image::ImageMinifier::IMAGE_CACHE : Email::IMAGES) + '/'
|
254
274
|
else
|
255
275
|
|
256
276
|
# Use the image host defined in config.yml or, out-of-the-box refer to images/
|
@@ -327,7 +347,23 @@ module Inkcite
|
|
327
347
|
|
328
348
|
def meta key
|
329
349
|
md = meta_data
|
330
|
-
md.nil
|
350
|
+
md.nil? ? nil : md[key]
|
351
|
+
end
|
352
|
+
|
353
|
+
# Returns true if the specified key has been queried once and
|
354
|
+
# only once. Any additional queries will return false
|
355
|
+
def once? key
|
356
|
+
|
357
|
+
# Initialize the 'once' data hash which maps
|
358
|
+
data[:once] ||= {}
|
359
|
+
|
360
|
+
key = key.to_sym
|
361
|
+
|
362
|
+
# True if this is the first time we've encountered this key.
|
363
|
+
first_time = data[:once][key].nil?
|
364
|
+
data[:once][key] = true if first_time
|
365
|
+
|
366
|
+
first_time
|
331
367
|
end
|
332
368
|
|
333
369
|
# Returns the opts for the parent matching the designated
|
@@ -339,7 +375,7 @@ module Inkcite
|
|
339
375
|
# Returns the array of browser prefixes that need to be included in
|
340
376
|
# CSS styles based on which version of the email this is.
|
341
377
|
def prefixes
|
342
|
-
_prefixes = [
|
378
|
+
_prefixes = ['']
|
343
379
|
|
344
380
|
# In development mode, include all prefixes for maximum compatibility.
|
345
381
|
_prefixes += %w(-moz- -ms- -o-) if development?
|
@@ -365,7 +401,7 @@ module Inkcite
|
|
365
401
|
|
366
402
|
# Will be used to assemble the parameters passed to File.open.
|
367
403
|
# First, always open the file in read mode.
|
368
|
-
mode = [
|
404
|
+
mode = ['r']
|
369
405
|
|
370
406
|
# Detect abnormal file encoding and construct the string to
|
371
407
|
# convert such encoding to UTF-8 if specified.
|
@@ -398,7 +434,7 @@ module Inkcite
|
|
398
434
|
raise "Already rendered" unless @content.blank?
|
399
435
|
|
400
436
|
source_file = 'source'
|
401
|
-
source_file << (text
|
437
|
+
source_file << (text? ? TXT_EXTENSION : HTML_EXTENSION)
|
402
438
|
|
403
439
|
# Read the original source which may include embedded Ruby.
|
404
440
|
filtered = read_source(@email.project_file(source_file))
|
@@ -451,21 +487,12 @@ module Inkcite
|
|
451
487
|
html += external_styles
|
452
488
|
|
453
489
|
html << inline_styles
|
454
|
-
html << '</head>'
|
455
490
|
|
456
|
-
|
457
|
-
# controlled by the styles and attributes of the links themselves. By not
|
458
|
-
# setting it, links created sans-helper should be visually distinct.
|
459
|
-
html << '<body style="width: 100% !important; min-width: 100% !important; margin: 0 !important; padding: 0; -webkit-text-size-adjust: none; -ms-text-size-adjust: none;'
|
491
|
+
html << outlook_styles
|
460
492
|
|
461
|
-
|
462
|
-
# the designer that they have exposed the body background - which means
|
463
|
-
# unpredictable results if sent.
|
464
|
-
if development?
|
465
|
-
html << " background: #ccc url('data:image/png;base64,#{Inkcite.blueprint_image64}');"
|
466
|
-
end
|
493
|
+
html << '</head>'
|
467
494
|
|
468
|
-
html <<
|
495
|
+
html << body_declaration
|
469
496
|
|
470
497
|
html << minified
|
471
498
|
|
@@ -483,6 +510,10 @@ module Inkcite
|
|
483
510
|
|
484
511
|
end
|
485
512
|
|
513
|
+
# Provide each post processor (if any were installed during the rendering
|
514
|
+
# process) with a chance to operate on the final HTML.
|
515
|
+
@content = PostProcessor.run_all(@content, self)
|
516
|
+
|
486
517
|
# Ensure that all failsafes pass
|
487
518
|
assert_failsafes
|
488
519
|
|
@@ -619,17 +650,17 @@ module Inkcite
|
|
619
650
|
|
620
651
|
private
|
621
652
|
|
622
|
-
ASSETS
|
623
|
-
FILE_SCHEME
|
624
|
-
FILE_NAME
|
625
|
-
HTML_EXTENSION
|
653
|
+
ASSETS = 'assets'
|
654
|
+
FILE_SCHEME = 'file'
|
655
|
+
FILE_NAME = :'file-name'
|
656
|
+
HTML_EXTENSION = '.html'
|
626
657
|
LINKS_EXTENSION = '-links.csv'
|
627
|
-
NEW_LINE
|
628
|
-
REGEX_SLASH
|
658
|
+
NEW_LINE = "\n"
|
659
|
+
REGEX_SLASH = '/'
|
629
660
|
SOURCE_ENCODING = :'source-encoding'
|
630
|
-
TAB
|
631
|
-
TXT_EXTENSION
|
632
|
-
UTF_8
|
661
|
+
TAB = "\t"
|
662
|
+
TXT_EXTENSION = '.txt'
|
663
|
+
UTF_8 = 'utf-8'
|
633
664
|
|
634
665
|
# Empty hash used when there is no environment or format-specific configuration
|
635
666
|
EMPTY_HASH = {}
|
@@ -696,6 +727,31 @@ module Inkcite
|
|
696
727
|
passes
|
697
728
|
end
|
698
729
|
|
730
|
+
def body_declaration
|
731
|
+
|
732
|
+
# Intentionally not setting the link colors because those should be entirely
|
733
|
+
# controlled by the styles and attributes of the links themselves. By not
|
734
|
+
# setting it, links created sans-helper should be visually distinct.
|
735
|
+
body = '<body'
|
736
|
+
|
737
|
+
# The body class is used to fix the width problem in new Gmail iOS.
|
738
|
+
# https://litmus.com/community/discussions/5913-new-gmail-app-not-respect-full-width
|
739
|
+
body << ' class="body"' if email?
|
740
|
+
|
741
|
+
body << ' style="margin: 0; padding: 0; -webkit-text-size-adjust: none; -ms-text-size-adjust: none;'
|
742
|
+
|
743
|
+
# A pleasing but obvious background exposed in development mode to alert
|
744
|
+
# the designer that they have exposed the body background - which means
|
745
|
+
# unpredictable results if sent.
|
746
|
+
if development?
|
747
|
+
body << %Q( background: #ccc url('data:image/png;base64,#{Inkcite.blueprint_image64}');)
|
748
|
+
end
|
749
|
+
|
750
|
+
body << '">'
|
751
|
+
|
752
|
+
body
|
753
|
+
end
|
754
|
+
|
699
755
|
# Returns true if the content in this email either matches the
|
700
756
|
# regular expression provided or if it includes the exact string
|
701
757
|
# that is provided.
|
@@ -865,12 +921,6 @@ module Inkcite
|
|
865
921
|
# Reset the font on every cell to the default family.
|
866
922
|
reset << "td { font-family: #{self[Renderer::Base::FONT_FAMILY]}; }"
|
867
923
|
|
868
|
-
# VML-specific CSS needed only if VML was used in the email.
|
869
|
-
if vml_used?
|
870
|
-
reset << 'v\:* { behavior: url(#default#VML); display: inline-block; }'
|
871
|
-
reset << 'o\:* { behavior: url(#default#VML); display: inline-block; }'
|
872
|
-
end
|
873
|
-
|
874
924
|
reset.join(NEW_LINE)
|
875
925
|
end
|
876
926
|
|
@@ -907,7 +957,7 @@ module Inkcite
|
|
907
957
|
|
908
958
|
# Join all of the style blocks into a single block if this
|
909
959
|
# is not an email - otherwise, keep them separate.
|
910
|
-
style_blocks = [
|
960
|
+
style_blocks = [style_blocks.join(NEW_LINE)] unless email?
|
911
961
|
|
912
962
|
html = []
|
913
963
|
|
@@ -921,6 +971,24 @@ module Inkcite
|
|
921
971
|
html.join(NEW_LINE)
|
922
972
|
end
|
923
973
|
|
974
|
+
def outlook_styles
|
975
|
+
|
976
|
+
html = []
|
977
|
+
|
978
|
+
# VML-specific CSS needed only if VML was used in the email.
|
979
|
+
if vml_used?
|
980
|
+
html << '<style>'
|
981
|
+
|
982
|
+
%w(v o).each do |l|
|
983
|
+
html << Inkcite::Renderer::Style.new("#{l}\:*", self, { :behavior => 'url(#default#VML)', :display => 'inline-block' }).to_s
|
984
|
+
end
|
985
|
+
|
986
|
+
html << '</style>'
|
987
|
+
end
|
988
|
+
|
989
|
+
html.join(NEW_LINE)
|
990
|
+
end
|
991
|
+
|
924
992
|
def load_helper_file file, into, abort_on_fail=true
|
925
993
|
|
926
994
|
unless File.exist?(file)
|
@@ -973,7 +1041,7 @@ module Inkcite
|
|
973
1041
|
def load_helpers
|
974
1042
|
|
975
1043
|
_helpers = {
|
976
|
-
|
1044
|
+
:n => NEW_LINE
|
977
1045
|
}
|
978
1046
|
|
979
1047
|
# Get the project path from which most helpers will be loaded.
|
@@ -995,9 +1063,30 @@ module Inkcite
|
|
995
1063
|
# on its version - e.g. difference colors in the "no orders for 30 days" email.
|
996
1064
|
load_helper_file File.join(path, "helpers-#{@version}.tsv"), _helpers, false
|
997
1065
|
|
1066
|
+
project_path = File.basename(@email.path)
|
1067
|
+
|
1068
|
+
# If the project directory name is all numbers and is either six or eight
|
1069
|
+
# characters in length, assume it is a date - e.g. 201706 or 20170513.
|
1070
|
+
# Automatically extract the year, month and day (optional).
|
1071
|
+
if project_path.to_i.to_s == project_path
|
1072
|
+
path_length = project_path.length
|
1073
|
+
if path_length >= 4 && path_length <= 8
|
1074
|
+
|
1075
|
+
# These substrings need to remain strings so that properties can be
|
1076
|
+
# cloned when a view is instanted.
|
1077
|
+
_helpers[:yyyy] = project_path[0..3]
|
1078
|
+
_helpers[:mm] = project_path[4..5] if path_length >= 6
|
1079
|
+
_helpers[:dd] = project_path[6..7] if path_length == 8
|
1080
|
+
|
1081
|
+
end
|
1082
|
+
end
|
1083
|
+
|
998
1084
|
# As a convenience pre-populate the month name of the email.
|
999
1085
|
mm = _helpers[:mm].to_i
|
1000
|
-
|
1086
|
+
if mm > 0
|
1087
|
+
_helpers[:month] = Date::MONTHNAMES[mm]
|
1088
|
+
_helpers[:MONTH] = _helpers[:month].upcase
|
1089
|
+
end
|
1001
1090
|
|
1002
1091
|
_helpers
|
1003
1092
|
end
|
@@ -1036,9 +1125,6 @@ module Inkcite
|
|
1036
1125
|
|
1037
1126
|
filtered.split("\n").each do |line|
|
1038
1127
|
|
1039
|
-
# Increment the line number as we read the file.
|
1040
|
-
@line_number += 1
|
1041
|
-
|
1042
1128
|
begin
|
1043
1129
|
line = Renderer.render(line, self)
|
1044
1130
|
rescue Exception => e
|