inkcite 1.11.0 → 1.12.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 +4 -4
- data/Rakefile +2 -2
- data/assets/init/helpers.tsv +7 -0
- data/assets/social/facebook.png +0 -0
- data/assets/social/pintrest.png +0 -0
- data/assets/social/twitter.png +0 -0
- data/inkcite.gemspec +5 -4
- data/lib/inkcite.rb +17 -6
- data/lib/inkcite/animation.rb +135 -0
- data/lib/inkcite/cli/base.rb +5 -14
- data/lib/inkcite/cli/build.rb +3 -3
- data/lib/inkcite/cli/init.rb +3 -3
- data/lib/inkcite/cli/preview.rb +25 -1
- data/lib/inkcite/cli/server.rb +1 -1
- data/lib/inkcite/cli/validate.rb +2 -11
- data/lib/inkcite/email.rb +1 -1
- data/lib/inkcite/mailer.rb +5 -0
- data/lib/inkcite/minifier.rb +58 -11
- data/lib/inkcite/renderer.rb +10 -2
- data/lib/inkcite/renderer/base.rb +45 -3
- data/lib/inkcite/renderer/button.rb +16 -12
- data/lib/inkcite/renderer/container_base.rb +14 -4
- data/lib/inkcite/renderer/element.rb +13 -3
- data/lib/inkcite/renderer/image.rb +46 -19
- data/lib/inkcite/renderer/image_base.rb +3 -3
- data/lib/inkcite/renderer/in_browser.rb +1 -1
- data/lib/inkcite/renderer/link.rb +91 -59
- data/lib/inkcite/renderer/lorem.rb +9 -1
- data/lib/inkcite/renderer/mobile_image.rb +3 -11
- data/lib/inkcite/renderer/mobile_only.rb +48 -0
- data/lib/inkcite/renderer/outlook_background.rb +61 -13
- data/lib/inkcite/renderer/property.rb +1 -1
- data/lib/inkcite/renderer/responsive.rb +10 -8
- data/lib/inkcite/renderer/snow.rb +20 -10
- data/lib/inkcite/renderer/social.rb +128 -0
- data/lib/inkcite/renderer/table.rb +13 -1
- data/lib/inkcite/renderer/table_base.rb +3 -3
- data/lib/inkcite/renderer/td.rb +32 -7
- data/lib/inkcite/renderer/video_preview.rb +257 -0
- data/lib/inkcite/uploader.rb +3 -3
- data/lib/inkcite/util.rb +19 -5
- data/lib/inkcite/version.rb +1 -1
- data/lib/inkcite/view.rb +29 -18
- data/lib/inkcite/view/context.rb +30 -0
- data/test/animation_spec.rb +38 -0
- data/test/email_spec.rb +0 -4
- data/test/minifier_spec.rb +243 -4
- data/test/parser_spec.rb +0 -4
- data/test/project/helpers.tsv +3 -0
- data/test/renderer/button_spec.rb +15 -13
- data/test/renderer/div_spec.rb +13 -4
- data/test/renderer/element_spec.rb +1 -5
- data/test/renderer/footnote_spec.rb +0 -4
- data/test/renderer/image_spec.rb +27 -11
- data/test/renderer/link_spec.rb +14 -4
- data/test/renderer/lorem_spec.rb +0 -4
- data/test/renderer/mobile_image_spec.rb +3 -11
- data/test/renderer/mobile_only_spec.rb +21 -0
- data/test/renderer/mobile_style_spec.rb +1 -5
- data/test/renderer/outlook_background_spec.rb +61 -0
- data/test/renderer/redacted_spec.rb +0 -4
- data/test/renderer/social_spec.rb +53 -0
- data/test/renderer/span_spec.rb +0 -4
- data/test/renderer/table_spec.rb +8 -4
- data/test/renderer/td_spec.rb +0 -4
- data/test/renderer/video_preview_spec.rb +19 -0
- data/test/renderer_spec.rb +0 -4
- data/test/test_helper.rb +7 -0
- data/test/view_spec.rb +12 -4
- metadata +89 -56
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c14c10f673644c60a3e92d4c511858d562c16f58
|
|
4
|
+
data.tar.gz: 0690d93ebed3be3f26735c9e6ecdd70301936a43
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2553f347fb054d2cf5ab68be3696a1223eabda24b7f1196d09871c3068c6cab2ccdda81214b8890720f8bf9463bd560d9093bee9f4db9d9c2e1aeaae1f240f30
|
|
7
|
+
data.tar.gz: 62224686033d05c4587995d4c92268287fac082a16013f54d71d9f185d5fb98ca7afbc54d14b9576170c24d4792069cfa0478841448cab82ec29e77296f9bb37
|
data/Rakefile
CHANGED
|
@@ -2,7 +2,7 @@ require "bundler/gem_tasks"
|
|
|
2
2
|
require 'rake/testtask'
|
|
3
3
|
|
|
4
4
|
Rake::TestTask.new do |t|
|
|
5
|
-
t.libs.push
|
|
6
|
-
t.test_files = FileList['test/*_spec.rb', 'test/renderer/*_spec.rb']
|
|
5
|
+
t.libs.push 'lib'
|
|
6
|
+
t.test_files = FileList['test/test_helper.rb', 'test/*_spec.rb', 'test/renderer/*_spec.rb']
|
|
7
7
|
t.verbose = false
|
|
8
8
|
end
|
data/assets/init/helpers.tsv
CHANGED
|
@@ -15,3 +15,10 @@ title Welcome to Inkcite
|
|
|
15
15
|
|
|
16
16
|
// This defines the default font family used throughout your email.
|
|
17
17
|
font-family sans-serif
|
|
18
|
+
|
|
19
|
+
// Defaults for all buttons in the email
|
|
20
|
+
button-border 2px solid #0099cc
|
|
21
|
+
button-border-radius 5
|
|
22
|
+
button-color #99ffff
|
|
23
|
+
button-float center
|
|
24
|
+
button-padding 8
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/inkcite.gemspec
CHANGED
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
|
|
26
26
|
spec.add_dependency 'activesupport'
|
|
27
27
|
spec.add_dependency 'builder'
|
|
28
|
+
spec.add_dependency 'chunky_png'
|
|
28
29
|
spec.add_dependency 'erubis'
|
|
29
30
|
spec.add_dependency 'faker'
|
|
30
31
|
spec.add_dependency 'guard'
|
|
@@ -32,19 +33,19 @@ Gem::Specification.new do |spec|
|
|
|
32
33
|
spec.add_dependency 'htmlbeautifier'
|
|
33
34
|
spec.add_dependency 'image_optim'
|
|
34
35
|
spec.add_dependency 'image_optim_pack'
|
|
36
|
+
spec.add_dependency 'listen'
|
|
35
37
|
spec.add_dependency 'litmus'
|
|
36
38
|
spec.add_dependency 'mail'
|
|
37
39
|
spec.add_dependency 'mailgun-ruby'
|
|
38
40
|
spec.add_dependency 'net-sftp'
|
|
39
|
-
spec.add_dependency 'nokogiri'
|
|
40
41
|
spec.add_dependency 'rack'
|
|
41
42
|
spec.add_dependency 'rack-livereload'
|
|
42
43
|
spec.add_dependency 'rubyzip'
|
|
43
44
|
spec.add_dependency 'thor'
|
|
44
45
|
spec.add_dependency 'yui-compressor'
|
|
45
46
|
|
|
46
|
-
spec.add_development_dependency
|
|
47
|
-
spec.add_development_dependency
|
|
48
|
-
spec.add_development_dependency
|
|
47
|
+
spec.add_development_dependency 'bundler'
|
|
48
|
+
spec.add_development_dependency 'rake'
|
|
49
|
+
spec.add_development_dependency 'minitest'
|
|
49
50
|
|
|
50
51
|
end
|
data/lib/inkcite.rb
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
require '
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
require 'active_support/core_ext/kernel/reporting.rb' # silence_warnings
|
|
2
|
+
|
|
3
|
+
# Need to silence warnings when we import these other gems as
|
|
4
|
+
# there are numerous messages produced as a result of circular
|
|
5
|
+
# dependencies and other problems within these gems, outside
|
|
6
|
+
# of my control.
|
|
7
|
+
silence_warnings do
|
|
8
|
+
require 'csv'
|
|
9
|
+
require 'erubis'
|
|
10
|
+
require 'i18n'
|
|
11
|
+
require 'image_optim'
|
|
12
|
+
require 'set'
|
|
13
|
+
require 'uri'
|
|
14
|
+
require 'yaml'
|
|
15
|
+
require 'yui/compressor'
|
|
16
|
+
end
|
|
7
17
|
|
|
8
18
|
require 'active_support/core_ext/hash/keys.rb' # Symbolize keys!
|
|
9
19
|
require 'active_support/core_ext/module/delegation.rb'
|
|
@@ -19,6 +29,7 @@ require 'inkcite/view'
|
|
|
19
29
|
require 'inkcite/minifier'
|
|
20
30
|
require 'inkcite/parser'
|
|
21
31
|
require 'inkcite/renderer'
|
|
32
|
+
require 'inkcite/animation'
|
|
22
33
|
|
|
23
34
|
module Inkcite
|
|
24
35
|
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
module Inkcite
|
|
2
|
+
module Animation
|
|
3
|
+
|
|
4
|
+
class Keyframe
|
|
5
|
+
|
|
6
|
+
attr_reader :percent
|
|
7
|
+
|
|
8
|
+
def initialize percent, styles={}
|
|
9
|
+
# Animation percents are always rounded to the nearest whole number.
|
|
10
|
+
@percent = percent.round(0)
|
|
11
|
+
@styles = styles
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def [] key
|
|
15
|
+
@styles[key]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def []= key, val
|
|
19
|
+
@styles[key] = val
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def add key, val
|
|
23
|
+
self[key] = val
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def add_with_prefixes key, val, ctx
|
|
28
|
+
|
|
29
|
+
Animation.get_prefixes(ctx).each do |prefix|
|
|
30
|
+
_key = "#{prefix}#{key}".to_sym
|
|
31
|
+
self[_key] = val
|
|
32
|
+
end
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def to_s
|
|
37
|
+
|
|
38
|
+
css = ''
|
|
39
|
+
css << " #{@percent}%"
|
|
40
|
+
css << ' ' * (7 - css.length)
|
|
41
|
+
css << '{ '
|
|
42
|
+
css << Renderer.render_styles(@styles)
|
|
43
|
+
css << ' }'
|
|
44
|
+
|
|
45
|
+
css
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class Keyframes
|
|
51
|
+
|
|
52
|
+
def initialize name, context
|
|
53
|
+
@name = name
|
|
54
|
+
@ctx = context
|
|
55
|
+
@keyframes = []
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def << keyframe
|
|
59
|
+
@keyframes << keyframe
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def add_keyframe percent, styles
|
|
63
|
+
self << Keyframe.new(percent, styles)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def to_s
|
|
67
|
+
|
|
68
|
+
css = ''
|
|
69
|
+
|
|
70
|
+
keyframe_css = @keyframes.sort { |kf1,kf2| kf1.percent <=> kf2.percent }.collect(&:to_s).join("\n")
|
|
71
|
+
|
|
72
|
+
prefixes = Animation.get_prefixes(@ctx)
|
|
73
|
+
|
|
74
|
+
prefixes.each do |prefix|
|
|
75
|
+
css << "@#{prefix}keyframes #{@name} {\n"
|
|
76
|
+
css << keyframe_css
|
|
77
|
+
css << "\n}\n"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
css
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.get_prefixes ctx
|
|
86
|
+
ALL_BROWSERS
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# True if we're limiting the animation to webkit only. In development
|
|
90
|
+
# or in the browser version of the email, the animation should be as
|
|
91
|
+
# compatible as possible but in all other cases it should be webkit only.
|
|
92
|
+
def self.webkit_only? ctx
|
|
93
|
+
false #&& !(ctx.development? || ctx.browser?)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Renders the CSS with the appropriate browser prefixes based
|
|
97
|
+
# on whether or not this version of the email is webkit only.
|
|
98
|
+
def self.with_browser_prefixes css, ctx, opts={}
|
|
99
|
+
|
|
100
|
+
indentation = opts[:indentation] || ''
|
|
101
|
+
|
|
102
|
+
# Convert an integer indentation value into that number of spaces.
|
|
103
|
+
indentation = ' ' * indentation if indentation.is_a?(Integer)
|
|
104
|
+
|
|
105
|
+
separator = opts[:separator] || "\n"
|
|
106
|
+
|
|
107
|
+
# Determine which prefixes will be applied.
|
|
108
|
+
browser_prefixes = webkit_only?(ctx) ? WEBKIT_BROWSERS : ALL_BROWSERS
|
|
109
|
+
|
|
110
|
+
# This will hold the completed CSS with all prefixes applied.
|
|
111
|
+
_css = ''
|
|
112
|
+
|
|
113
|
+
# Iterate through the prefixes and apply them with the indentation
|
|
114
|
+
# and CSS declaration with line breaks.
|
|
115
|
+
browser_prefixes.each do |prefix|
|
|
116
|
+
_css << indentation
|
|
117
|
+
_css << prefix
|
|
118
|
+
_css << css
|
|
119
|
+
_css << separator
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
_css
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# Static arrays with browser prefixes. Turns out that Firefox, IE and Opera
|
|
129
|
+
# don't require a prefix so to target everything we need the non-prefixed version
|
|
130
|
+
# (hence the blank entry) plus the webkit prefix.
|
|
131
|
+
WEBKIT_BROWSERS = ['-webkit-']
|
|
132
|
+
ALL_BROWSERS = [''] + WEBKIT_BROWSERS
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
end
|
data/lib/inkcite/cli/base.rb
CHANGED
|
@@ -45,6 +45,10 @@ module Inkcite
|
|
|
45
45
|
option :version,
|
|
46
46
|
:aliases => '-v',
|
|
47
47
|
:desc => 'Preview a specific version of the email'
|
|
48
|
+
option :also,
|
|
49
|
+
:aliases => '-a',
|
|
50
|
+
:desc => 'Add one or more (space-separated) recipients to this specific mailing',
|
|
51
|
+
:type => :array
|
|
48
52
|
def preview to=:developer
|
|
49
53
|
require_relative 'preview'
|
|
50
54
|
Cli::Preview.invoke(email, to, options)
|
|
@@ -75,7 +79,7 @@ module Inkcite
|
|
|
75
79
|
:desc => 'The ip address Inkcite will bind to'
|
|
76
80
|
method_option :port,
|
|
77
81
|
:aliases => '-p',
|
|
78
|
-
:default =>
|
|
82
|
+
:default => 4567,
|
|
79
83
|
:desc => 'The port Inkcite will listen on',
|
|
80
84
|
:type => :numeric
|
|
81
85
|
option :version,
|
|
@@ -113,19 +117,6 @@ module Inkcite
|
|
|
113
117
|
options[:force] ? email.upload! : email.upload
|
|
114
118
|
end
|
|
115
119
|
|
|
116
|
-
desc 'validate', 'Validate the email against W3C standards'
|
|
117
|
-
option :environment,
|
|
118
|
-
:aliases => '-e',
|
|
119
|
-
:default => 'production',
|
|
120
|
-
:desc => 'The environment (production, preview, development) to be Inkcite will run under'
|
|
121
|
-
option :version,
|
|
122
|
-
:aliases => '-v',
|
|
123
|
-
:desc => 'Preview a specific version of the email'
|
|
124
|
-
def validate
|
|
125
|
-
require_relative 'validate'
|
|
126
|
-
Cli::Validate.invoke(email, options)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
120
|
private
|
|
130
121
|
|
|
131
122
|
# Resolves the desired environment (e.g. :development or :preview)
|
data/lib/inkcite/cli/build.rb
CHANGED
|
@@ -45,7 +45,7 @@ module Inkcite
|
|
|
45
45
|
|
|
46
46
|
# The Zip::File will try to update an existing archive so just blow the old
|
|
47
47
|
# one away if it still exists.
|
|
48
|
-
File.delete(zip_file) if File.
|
|
48
|
+
File.delete(zip_file) if File.exist?(zip_file)
|
|
49
49
|
|
|
50
50
|
# The absolute path to the build directories
|
|
51
51
|
build_html_to = build_path(email)
|
|
@@ -54,7 +54,7 @@ module Inkcite
|
|
|
54
54
|
Zip::File.open(zip_file, Zip::File::CREATE) do |zip|
|
|
55
55
|
|
|
56
56
|
# Add the minified images to the .zip archive
|
|
57
|
-
if File.
|
|
57
|
+
if File.exist?(build_images_to)
|
|
58
58
|
Dir.foreach(build_images_to) do |img|
|
|
59
59
|
img_path = File.join(build_images_to, img)
|
|
60
60
|
zip.add(File.join(Inkcite::Email::IMAGES, img), img_path) unless File.directory?(img_path)
|
|
@@ -113,7 +113,7 @@ module Inkcite
|
|
|
113
113
|
# Copy all of the source images into the build directory in preparation
|
|
114
114
|
# for optimization
|
|
115
115
|
build_images_from = email.optimized_image_dir
|
|
116
|
-
FileUtils.cp_r(File.join(build_images_from, '.'), build_images_to) if File.
|
|
116
|
+
FileUtils.cp_r(File.join(build_images_from, '.'), build_images_to) if File.exist?(build_images_from)
|
|
117
117
|
|
|
118
118
|
end
|
|
119
119
|
|
data/lib/inkcite/cli/init.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Inkcite
|
|
|
8
8
|
|
|
9
9
|
# Sanity check to make sure we're not writing over an existing
|
|
10
10
|
# Inkcite project.
|
|
11
|
-
abort "It appears that an Inkcite already exists in #{path}" if File.
|
|
11
|
+
abort "It appears that an Inkcite already exists in #{path}" if File.exist?(File.join(full_init_path, 'config.yml'))
|
|
12
12
|
|
|
13
13
|
# Check to see if the user specified a --from path that is used to
|
|
14
14
|
# clone an existing project rather than init a new one.
|
|
@@ -41,7 +41,7 @@ module Inkcite
|
|
|
41
41
|
|
|
42
42
|
# Verify that the source directory contains the config.yml file
|
|
43
43
|
# signifying an existing Inkcite project.
|
|
44
|
-
abort "Can't find #{from_path} or it isn't an existing Inkcite project" unless File.
|
|
44
|
+
abort "Can't find #{from_path} or it isn't an existing Inkcite project" unless File.exist?(File.join(from_path, 'config.yml'))
|
|
45
45
|
|
|
46
46
|
# Copy the main Inkcite project files
|
|
47
47
|
Dir.glob(File.join(from_path, '*.{html,tsv,txt,yml}')).each do |from_file|
|
|
@@ -59,7 +59,7 @@ module Inkcite
|
|
|
59
59
|
|
|
60
60
|
# Check to see if there are images and copy those as well.
|
|
61
61
|
from_path = File.join(from_path, Inkcite::Email::IMAGES)
|
|
62
|
-
if File.
|
|
62
|
+
if File.exist?(from_path)
|
|
63
63
|
FileUtils.cp_r(File.join(from_path, '.'), full_init_image_path)
|
|
64
64
|
puts "Copied images to #{init_image_path}"
|
|
65
65
|
end
|
data/lib/inkcite/cli/preview.rb
CHANGED
|
@@ -10,6 +10,23 @@ module Inkcite
|
|
|
10
10
|
# latest images and "view in browser" versions are available.
|
|
11
11
|
email.upload
|
|
12
12
|
|
|
13
|
+
also = opt[:also]
|
|
14
|
+
unless also.blank?
|
|
15
|
+
|
|
16
|
+
# Sometimes people use commas to separate the --also addresses so
|
|
17
|
+
# explode those into an array for convenience. Email is already
|
|
18
|
+
# hard enough.
|
|
19
|
+
if also.any? { |a| a.match(',') }
|
|
20
|
+
also = also.collect { |a| a.split(',') }.flatten
|
|
21
|
+
|
|
22
|
+
# Since opt is frozen by Thor we need to make a copy of it in order
|
|
23
|
+
# to inject the new array of recipients back into it.
|
|
24
|
+
opt = opt.dup
|
|
25
|
+
opt[:also] = also
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
13
30
|
case to.to_sym
|
|
14
31
|
when :client
|
|
15
32
|
Inkcite::Mailer.client(email, opt)
|
|
@@ -18,7 +35,14 @@ module Inkcite
|
|
|
18
35
|
when :developer
|
|
19
36
|
Inkcite::Mailer.developer(email, opt)
|
|
20
37
|
else
|
|
21
|
-
|
|
38
|
+
abort <<-USAGE.strip_heredoc
|
|
39
|
+
|
|
40
|
+
Oops! Inkcite doesn't recognize that distribution list. It needs
|
|
41
|
+
to be one of 'client', 'internal' or 'developer':
|
|
42
|
+
|
|
43
|
+
inkcite preview internal
|
|
44
|
+
|
|
45
|
+
USAGE
|
|
22
46
|
end
|
|
23
47
|
|
|
24
48
|
end
|
data/lib/inkcite/cli/server.rb
CHANGED
data/lib/inkcite/cli/validate.rb
CHANGED
|
@@ -20,28 +20,19 @@ module Inkcite
|
|
|
20
20
|
# The version of the email we will be sending.
|
|
21
21
|
view = email.view(environment, :email, version)
|
|
22
22
|
|
|
23
|
-
# Always disable minification
|
|
24
|
-
view.config[:minify] = false
|
|
25
|
-
|
|
26
23
|
subject = view.subject
|
|
27
24
|
|
|
28
25
|
print "Validating '#{subject}' ... "
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
validator = Nokogiri::HTML(source) do |config|
|
|
27
|
+
validator = Nokogiri::HTML(view.render!) do |config|
|
|
33
28
|
config.strict
|
|
34
29
|
end
|
|
35
30
|
|
|
36
31
|
if validator.errors.any?
|
|
37
32
|
puts 'Invalid!'
|
|
38
|
-
|
|
39
|
-
lines = source.split(/\n/)
|
|
40
|
-
|
|
41
33
|
validator.errors.each do |err|
|
|
42
34
|
puts err.inspect
|
|
43
|
-
puts
|
|
44
|
-
puts [ err.column, err.int1, err.str1, err.str2, err.str3 ].inspect
|
|
35
|
+
puts err.line
|
|
45
36
|
end
|
|
46
37
|
|
|
47
38
|
else
|
data/lib/inkcite/email.rb
CHANGED
data/lib/inkcite/mailer.rb
CHANGED
|
@@ -64,6 +64,11 @@ module Inkcite
|
|
|
64
64
|
# Sends each version of the provided email with the indicated options.
|
|
65
65
|
def self.send email, opts
|
|
66
66
|
|
|
67
|
+
# Check to see if additional one-time recipients have been added
|
|
68
|
+
# to the command line.
|
|
69
|
+
also_to = opts[:also]
|
|
70
|
+
opts[:cc] = [*opts[:cc]] + also_to unless also_to.blank?
|
|
71
|
+
|
|
67
72
|
# Check to see if a specific version is requested or if unspecified
|
|
68
73
|
# all versions of the email should be sent.
|
|
69
74
|
versions = Array(opts[:version] || email.versions)
|
data/lib/inkcite/minifier.rb
CHANGED
|
@@ -1,14 +1,60 @@
|
|
|
1
|
-
require 'image_optim'
|
|
2
|
-
require 'yui/compressor'
|
|
3
|
-
|
|
4
1
|
module Inkcite
|
|
5
2
|
class Minifier
|
|
6
3
|
|
|
7
4
|
# Directory of optimized images
|
|
8
5
|
IMAGE_CACHE = "images-optim"
|
|
9
6
|
|
|
7
|
+
# Maximum line length for CSS and HTML - lines exceeding this length cause
|
|
8
|
+
# problems in certain email clients.
|
|
9
|
+
MAXIMUM_LINE_LENGTH = 800
|
|
10
|
+
|
|
10
11
|
def self.css code, ctx
|
|
11
|
-
|
|
12
|
+
|
|
13
|
+
# Do nothing to the code unless minification is enabled.
|
|
14
|
+
if minify?(ctx)
|
|
15
|
+
|
|
16
|
+
# After YUI's CSS compressor started introducing problems into CSS3
|
|
17
|
+
# animations, I've switched to a homegrown, extremely simple compression
|
|
18
|
+
# algorithm for CSS. Instead of messing with parameters, we're simply
|
|
19
|
+
# eliminating whitespace.
|
|
20
|
+
|
|
21
|
+
# Replace all line breaks with spaces
|
|
22
|
+
code.gsub!(/[\n\r\f]/, ' ')
|
|
23
|
+
|
|
24
|
+
# Remove whitespace at the beginning or ending of the code
|
|
25
|
+
code.gsub!(/^\s+/, '')
|
|
26
|
+
code.gsub!(/\s+$/, '')
|
|
27
|
+
|
|
28
|
+
# Compress multiple whitespace characters into a single space.
|
|
29
|
+
code.gsub!(/\s{2,}/, ' ')
|
|
30
|
+
|
|
31
|
+
# Remove whitespace preceding or following open and close curly brackets.
|
|
32
|
+
code.gsub!(/\s*([{};:])\s*/, "\\1")
|
|
33
|
+
|
|
34
|
+
# Remove semicolons preceding close brackets.
|
|
35
|
+
code.gsub!(';}', '}')
|
|
36
|
+
|
|
37
|
+
# Certain versions of outlook have a problem with excessively long lines
|
|
38
|
+
# so if this minified code now exceeds the maximum line limit, re-introduce
|
|
39
|
+
# wrapping in spots where it won't break anything to do so - e.g. following
|
|
40
|
+
# a semicolon or close bracket.
|
|
41
|
+
if ctx.email? && code.length > MAXIMUM_LINE_LENGTH
|
|
42
|
+
|
|
43
|
+
# Position at which a line break will be inserted at.
|
|
44
|
+
break_at = 0
|
|
45
|
+
|
|
46
|
+
# Work through the code injecting line breaks until either no further
|
|
47
|
+
# breakable characters are found or we've reached the end of the code.
|
|
48
|
+
while break_at < code.length
|
|
49
|
+
break_at = code.rindex(/[;}]/, break_at + MAXIMUM_LINE_LENGTH) + 1
|
|
50
|
+
code.insert(break_at, "\n") if break_at && break_at < code.length
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
code
|
|
12
58
|
end
|
|
13
59
|
|
|
14
60
|
def self.html lines, ctx
|
|
@@ -72,7 +118,7 @@ module Inkcite
|
|
|
72
118
|
|
|
73
119
|
# If the image cache exists, we need to check to see if any images have been
|
|
74
120
|
# removed since the last build.
|
|
75
|
-
if File.
|
|
121
|
+
if File.exist?(cache_path)
|
|
76
122
|
|
|
77
123
|
# Get a list of the files in the cache that do not also exist in the
|
|
78
124
|
# project's images/ directory.
|
|
@@ -137,7 +183,7 @@ module Inkcite
|
|
|
137
183
|
end
|
|
138
184
|
|
|
139
185
|
def self.remove_comments html, ctx
|
|
140
|
-
|
|
186
|
+
remove_comments?(ctx) ? html.gsub(HTML_COMMENT_REGEX, '') : html
|
|
141
187
|
end
|
|
142
188
|
|
|
143
189
|
private
|
|
@@ -148,7 +194,6 @@ module Inkcite
|
|
|
148
194
|
IMAGE_OPTIM_CONFIG_YML = 'image_optim.yml'
|
|
149
195
|
|
|
150
196
|
NEW_LINE = "\n"
|
|
151
|
-
MAXIMUM_LINE_LENGTH = 800
|
|
152
197
|
|
|
153
198
|
# Used to match inline styles that will be compressed when minifying
|
|
154
199
|
# the entire email.
|
|
@@ -163,12 +208,14 @@ module Inkcite
|
|
|
163
208
|
ctx.is_enabled?(:minify)
|
|
164
209
|
end
|
|
165
210
|
|
|
166
|
-
|
|
167
|
-
|
|
211
|
+
# Config attribute that allows for comment striping to be disabled.
|
|
212
|
+
# e.g. strip-comments: false
|
|
213
|
+
def self.remove_comments? ctx
|
|
214
|
+
minify?(ctx) && !ctx.is_disabled?(:'strip-comments')
|
|
168
215
|
end
|
|
169
216
|
|
|
170
|
-
def self.
|
|
171
|
-
ctx.
|
|
217
|
+
def self.js_compressor ctx
|
|
218
|
+
ctx.js_compressor ||= YUI::JavaScriptCompressor.new(:munge => true)
|
|
172
219
|
end
|
|
173
220
|
|
|
174
221
|
end
|