bootstrap-email 0.0.0.alpha.1 → 0.0.0.alpha.2
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/lib/bootstrap-email.rb +143 -4
- data/lib/bootstrap-email/action_mailer.rb +15 -13
- data/lib/bootstrap-email/version.rb +1 -1
- metadata +40 -14
- data/lib/bootstrap-email/bootstrap_email.rb +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d697ca73b6f0d8dd482151f4fefb5362100bf574
|
4
|
+
data.tar.gz: 98fdfe5fe8d602cf595750bdad3a123799667db6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d2fc92efb6f6c04e261e3d306dc488c17ef0f17f40b686409b5a58c2d918acf3cd262352063c840880774285597f7222abfe17d178935247979d68258f3e4e4
|
7
|
+
data.tar.gz: 79aa08506d89efbc8856f15fde6e306e7c38ca5957065fa9a95373e467d3a8abe5097c253b0d11b438d8ce718236481a8433052198fac8aa6beac6ddffc8ed62
|
data/lib/bootstrap-email.rb
CHANGED
@@ -1,13 +1,152 @@
|
|
1
1
|
require 'nokogiri'
|
2
2
|
require 'erb'
|
3
3
|
require 'ostruct'
|
4
|
-
require '
|
4
|
+
require 'action_mailer'
|
5
5
|
require 'premailer'
|
6
|
+
require 'premailer/rails'
|
7
|
+
require 'rails'
|
6
8
|
|
7
|
-
|
9
|
+
module BootstrapEmail
|
10
|
+
class Compiler
|
8
11
|
|
12
|
+
def initialize mail
|
13
|
+
@mail = mail
|
14
|
+
@doc = Nokogiri::HTML(@mail.body.raw_source)
|
15
|
+
end
|
9
16
|
|
10
|
-
|
11
|
-
|
17
|
+
def compile_html!
|
18
|
+
button
|
19
|
+
badge
|
20
|
+
alert
|
21
|
+
align
|
22
|
+
card
|
23
|
+
hr
|
24
|
+
container
|
25
|
+
grid
|
26
|
+
padding
|
27
|
+
margin
|
28
|
+
table
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_mailer!
|
32
|
+
@mail.body = @doc.to_html
|
33
|
+
@mail
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def build_from_template template, locals_hash = {}
|
39
|
+
namespace = OpenStruct.new(locals_hash)
|
40
|
+
template = File.open(File.expand_path("../core/templates/#{template}.html.erb", __dir__)).read
|
41
|
+
Nokogiri::HTML::DocumentFragment.parse(ERB.new(template).result(namespace.instance_eval { binding }))
|
42
|
+
end
|
43
|
+
|
44
|
+
def each_node css_lookup, &blk
|
45
|
+
# sort by youngest child and traverse backwards up the tree
|
46
|
+
@doc.css(css_lookup).sort_by{ |n| n.ancestors.size }.reverse!.each(&blk)
|
47
|
+
end
|
48
|
+
|
49
|
+
def button
|
50
|
+
each_node('.btn') do |node| # move all classes up and remove all classes from the element
|
51
|
+
node.replace(build_from_template('table-left', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def badge
|
56
|
+
each_node('.badge') do |node| # move all classes up and remove all classes from the element
|
57
|
+
node.replace(build_from_template('table-left', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def alert
|
62
|
+
each_node('.alert') do |node| # move all classes up and remove all classes from the element
|
63
|
+
node.replace(build_from_template('table', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def align
|
68
|
+
each_node('.align-left') do |node| # align table and move contents
|
69
|
+
node['class'] = node['class'].sub(/align-left/, '')
|
70
|
+
node.replace(build_from_template('align-left', {contents: node.to_html}))
|
71
|
+
end
|
72
|
+
each_node('.align-center') do |node| # align table and move contents
|
73
|
+
node['class'] = node['class'].sub(/align-center/, '')
|
74
|
+
node.replace(build_from_template('align-center', {contents: node.to_html}))
|
75
|
+
end
|
76
|
+
each_node('.align-right') do |node| # align table and move contents
|
77
|
+
node['class'] = node['class'].sub(/align-right/, '')
|
78
|
+
node.replace(build_from_template('align-right', {contents: node.to_html}))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def card
|
83
|
+
each_node('.card') do |node| # move all classes up and remove all classes from element
|
84
|
+
node.replace(build_from_template('table', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
85
|
+
end
|
86
|
+
each_node('.card-body') do |node| # move all classes up and remove all classes from element
|
87
|
+
node.replace(build_from_template('table', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def hr
|
92
|
+
each_node('hr') do |node| # drop hr in place of current
|
93
|
+
node.replace(build_from_template('hr', {classes: "hr #{node['class']}"}))
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def container
|
98
|
+
each_node('.container') do |node|
|
99
|
+
node.replace(build_from_template('container', {classes: node['class'], contents: node.inner_html}))
|
100
|
+
end
|
101
|
+
each_node('.container-fluid') do |node|
|
102
|
+
node.replace(build_from_template('table', {classes: node['class'], contents: node.inner_html}))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def grid
|
107
|
+
each_node('.row') do |node|
|
108
|
+
node.replace(build_from_template('row', {classes: node['class'], contents: node.inner_html}))
|
109
|
+
end
|
110
|
+
each_node('*[class*=col]') do |node|
|
111
|
+
node.replace(build_from_template('col', {classes: node['class'], contents: node.inner_html}))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def padding
|
116
|
+
each_node('*[class*=p-], *[class*=pt-], *[class*=pr-], *[class*=pb-], *[class*=pl-], *[class*=px-], *[class*=py-]') do |node|
|
117
|
+
if node.name != 'table' # if it is already on a table, set the padding on the table, else wrap the content in a table
|
118
|
+
padding_regex = /(p[trblxy]?-\d)/
|
119
|
+
classes = node['class'].scan(padding_regex).join(' ')
|
120
|
+
node['class'] = node['class'].sub(padding_regex, '')
|
121
|
+
node.replace(build_from_template('table', {classes: classes, contents: node.to_html}))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def margin
|
127
|
+
each_node('*[class*=m-], *[class*=mt-], *[class*=mr-], *[class*=mb-], *[class*=ml-], *[class*=mx-], *[class*=my-]') do |node|
|
128
|
+
if node.name != 'div' # if it is already on a div, set the margin on the div, else wrap the content in a div
|
129
|
+
margin_regex = /(m[trblxy]?-\d)/
|
130
|
+
classes = node['class'].scan(margin_regex).join(' ')
|
131
|
+
node['class'] = node['class'].sub(margin_regex, '')
|
132
|
+
node.replace(build_from_template('div', {classes: classes, contents: node.to_html}))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def table
|
138
|
+
@doc.css('table').each do |node|
|
139
|
+
#border="0" cellpadding="0" cellspacing="0"
|
140
|
+
node['border'] = 0
|
141
|
+
node['cellpadding'] = 0
|
142
|
+
node['cellspacing'] = 0
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
require 'bootstrap-email/premailer_railtie'
|
150
|
+
require 'bootstrap-email/action_mailer'
|
12
151
|
require 'bootstrap-email/engine'
|
13
152
|
require 'bootstrap-email/version'
|
@@ -1,20 +1,22 @@
|
|
1
1
|
class ActionMailer::Base
|
2
|
-
helper BootstrapEmailHelper
|
3
2
|
|
3
|
+
# sit in the middle and compile the html
|
4
4
|
def bootstrap_mail *args
|
5
|
-
|
6
|
-
bootstrap
|
7
|
-
bootstrap.
|
5
|
+
bootstrap = BootstrapEmail::Compiler.new(mail(*args))
|
6
|
+
bootstrap.compile_html!
|
7
|
+
bootstrap.update_mailer!
|
8
8
|
end
|
9
|
-
end
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
# helper to inject style tags into head of the email template
|
11
|
+
module BootstrapEmailHelper
|
12
|
+
def bootstrap_email_head
|
13
|
+
html_string = <<-HEREDOC
|
14
|
+
<style type="text/css" data-premailer="ignore">
|
15
|
+
#{File.open(File.expand_path('../../core/head.css', __dir__)).read}
|
16
|
+
</style>
|
17
|
+
HEREDOC
|
18
|
+
html_string.html_safe
|
19
|
+
end
|
19
20
|
end
|
21
|
+
helper BootstrapEmailHelper
|
20
22
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bootstrap-email
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.0.alpha.
|
4
|
+
version: 0.0.0.alpha.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stuart Yamartino
|
@@ -26,33 +26,59 @@ dependencies:
|
|
26
26
|
version: '1.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: actionmailer
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - ">="
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
34
|
-
|
47
|
+
version: '3'
|
48
|
+
- - "<"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '6'
|
51
|
+
type: :runtime
|
35
52
|
prerelease: false
|
36
53
|
version_requirements: !ruby/object:Gem::Requirement
|
37
54
|
requirements:
|
38
55
|
- - ">="
|
39
56
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
57
|
+
version: '3'
|
58
|
+
- - "<"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '6'
|
41
61
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
62
|
+
name: rails
|
43
63
|
requirement: !ruby/object:Gem::Requirement
|
44
64
|
requirements:
|
45
65
|
- - ">="
|
46
66
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
48
|
-
|
67
|
+
version: '3'
|
68
|
+
- - "<"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '6'
|
71
|
+
type: :runtime
|
49
72
|
prerelease: false
|
50
73
|
version_requirements: !ruby/object:Gem::Requirement
|
51
74
|
requirements:
|
52
75
|
- - ">="
|
53
76
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
55
|
-
|
77
|
+
version: '3'
|
78
|
+
- - "<"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '6'
|
81
|
+
description:
|
56
82
|
email: stuartyamartino@gmail.com
|
57
83
|
executables: []
|
58
84
|
extensions: []
|
@@ -60,10 +86,9 @@ extra_rdoc_files: []
|
|
60
86
|
files:
|
61
87
|
- lib/bootstrap-email.rb
|
62
88
|
- lib/bootstrap-email/action_mailer.rb
|
63
|
-
- lib/bootstrap-email/bootstrap_email.rb
|
64
89
|
- lib/bootstrap-email/engine.rb
|
65
90
|
- lib/bootstrap-email/version.rb
|
66
|
-
homepage:
|
91
|
+
homepage: https://github.com/stuyam/bootstrap-email
|
67
92
|
licenses:
|
68
93
|
- MIT
|
69
94
|
metadata: {}
|
@@ -73,9 +98,9 @@ require_paths:
|
|
73
98
|
- lib
|
74
99
|
required_ruby_version: !ruby/object:Gem::Requirement
|
75
100
|
requirements:
|
76
|
-
- - "
|
101
|
+
- - "~>"
|
77
102
|
- !ruby/object:Gem::Version
|
78
|
-
version: '0'
|
103
|
+
version: '2.0'
|
79
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
105
|
requirements:
|
81
106
|
- - ">"
|
@@ -86,5 +111,6 @@ rubyforge_project:
|
|
86
111
|
rubygems_version: 2.6.8
|
87
112
|
signing_key:
|
88
113
|
specification_version: 4
|
89
|
-
summary: Bootstrap 4
|
114
|
+
summary: Bootstrap 4 stylesheet, compiler, and inliner for responsive and consistent
|
115
|
+
emails with the Bootstrap syntax you know and love.
|
90
116
|
test_files: []
|
@@ -1,75 +0,0 @@
|
|
1
|
-
class BootstrapEmail
|
2
|
-
|
3
|
-
def constructor mail
|
4
|
-
@mail = mail
|
5
|
-
end
|
6
|
-
|
7
|
-
def compiled_html!
|
8
|
-
doc = Nokogiri::HTML(@mail.body.raw_source)
|
9
|
-
doc.css('.btn').each do |node| # move all classes up and remove all classes from the element
|
10
|
-
node.replace(build_from_template('table-left', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
11
|
-
end
|
12
|
-
doc.css('.badge').each do |node| # move all classes up and remove all classes from the element
|
13
|
-
node.replace(build_from_template('table-left', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
14
|
-
end
|
15
|
-
doc.css('.alert').each do |node| # move all classes up and remove all classes from the element
|
16
|
-
node.replace(build_from_template('table', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
17
|
-
end
|
18
|
-
doc.css('.align-left').each do |node| # align table and move contents
|
19
|
-
node.replace(build_from_template('align-left', {contents: node.to_html}))
|
20
|
-
end
|
21
|
-
doc.css('.align-center').each do |node| # align table and move contents
|
22
|
-
node.replace(build_from_template('align-center', {contents: node.to_html}))
|
23
|
-
end
|
24
|
-
doc.css('.align-right').each do |node| # align table and move contents
|
25
|
-
node.replace(build_from_template('align-right', {contents: node.to_html}))
|
26
|
-
end
|
27
|
-
doc.css('.card').each do |node| # move all classes up and remove all classes from element
|
28
|
-
node.replace(build_from_template('table', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
29
|
-
end
|
30
|
-
doc.css('.card-body').each do |node| # move all classes up and remove all classes from element
|
31
|
-
node.replace(build_from_template('table', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
32
|
-
end
|
33
|
-
doc.css('hr').each do |node| # drop hr in place of current
|
34
|
-
node.replace(build_from_template('hr'))
|
35
|
-
end
|
36
|
-
doc.css('.container').each do |node|
|
37
|
-
node.replace(build_from_template('container', {classes: node['class'], contents: node.inner_html}))
|
38
|
-
end
|
39
|
-
doc.css('.container-fluid').each do |node|
|
40
|
-
node.replace(build_from_template('table', {classes: node['class'], contents: node.inner_html}))
|
41
|
-
end
|
42
|
-
doc.css('.row').each do |node|
|
43
|
-
node.replace(build_from_template('row', {classes: node['class'], contents: node.inner_html}))
|
44
|
-
end
|
45
|
-
doc.css('*[class^=col]').each do |node|
|
46
|
-
node.replace(build_from_template('col', {classes: node['class'], contents: node.inner_html}))
|
47
|
-
end
|
48
|
-
padding = %w( p- pt- pr- pb- pl- px- py- ).map{ |padding| "contains(@class, '#{padding}')" }.join(' or ')
|
49
|
-
doc.xpath("//*[#{padding}]").each do |node|
|
50
|
-
if node.name != 'table' # if it is already on a table, set the padding on the table, else wrap the content in a table
|
51
|
-
node.replace(build_from_template('table', {classes: node['class'], contents: node.delete('class') && node.to_html}))
|
52
|
-
end
|
53
|
-
end
|
54
|
-
margin = %w( m- mt- mr- mb- ml- mx- my- ).map{ |margin| "contains(@class, '#{margin}')" }.join(' or ')
|
55
|
-
doc.xpath("//*[#{margin}]").each do |node|
|
56
|
-
if node.name != 'div' # if it is already on a div, set the margin on the div, else wrap the content in a div
|
57
|
-
node.replace(build_from_template('div', {classes: node['class'].scan(/(m[trblxy]?-\d)/).join(' '), contents: node.delete('class') && node.to_html}))
|
58
|
-
end
|
59
|
-
end
|
60
|
-
doc.css('table').each do |node|
|
61
|
-
#border="0" cellpadding="0" cellspacing="0"
|
62
|
-
node['border'] = 0
|
63
|
-
node['cellpadding'] = 0
|
64
|
-
node['cellspacing'] = 0
|
65
|
-
end
|
66
|
-
@mail.body = doc.to_html
|
67
|
-
@mail
|
68
|
-
end
|
69
|
-
|
70
|
-
def build_from_template template, locals_hash = {}
|
71
|
-
namespace = OpenStruct.new(locals_hash)
|
72
|
-
template = File.open("../../core/templates/#{template}.html.erb").read
|
73
|
-
Nokogiri::HTML::DocumentFragment.parse(ERB.new(template).result(namespace.instance_eval { binding }))
|
74
|
-
end
|
75
|
-
end
|