mjml-rb 0.4.1 → 0.4.3
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/README.md +55 -155
- data/lib/mjml-rb/components/accordion.rb +9 -13
- data/lib/mjml-rb/components/attributes.rb +0 -4
- data/lib/mjml-rb/components/base.rb +1 -7
- data/lib/mjml-rb/components/body.rb +0 -4
- data/lib/mjml-rb/components/breakpoint.rb +0 -4
- data/lib/mjml-rb/components/button.rb +2 -6
- data/lib/mjml-rb/components/carousel.rb +0 -4
- data/lib/mjml-rb/components/carousel_image.rb +0 -4
- data/lib/mjml-rb/components/divider.rb +2 -6
- data/lib/mjml-rb/components/group.rb +0 -4
- data/lib/mjml-rb/components/head.rb +0 -4
- data/lib/mjml-rb/components/hero.rb +0 -4
- data/lib/mjml-rb/components/image.rb +2 -6
- data/lib/mjml-rb/components/navbar.rb +0 -4
- data/lib/mjml-rb/components/raw.rb +0 -4
- data/lib/mjml-rb/components/section.rb +1 -5
- data/lib/mjml-rb/components/social.rb +6 -10
- data/lib/mjml-rb/components/spacer.rb +0 -4
- data/lib/mjml-rb/components/table.rb +2 -6
- data/lib/mjml-rb/components/text.rb +2 -6
- data/lib/mjml-rb/renderer.rb +6 -0
- data/lib/mjml-rb/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a143101aa0a18f9aa1e77160d0810561f9b5e58fe6dbf8c68d9f809b91421d8d
|
|
4
|
+
data.tar.gz: b3fb93b17518384e6ce03e96162a30ef870ab4534bfc3c0fe62775b5db21c594
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a811a85d468e8332b29c533efe918038c68fccb9f7383d82bfceff42954cbe7c9faeccbe72dde57380b422881b620a358db2d6032bef62928053a6b25c001d71
|
|
7
|
+
data.tar.gz: c04f1e1df5835cbf5d0c2f81835ba942aa6f9d3149e592662cffeec22ece7c2841d89f44d4834e5ba29ef8b2891070c402a9da277b04363a7f59541740f2c785
|
data/README.md
CHANGED
|
@@ -11,198 +11,98 @@
|
|
|
11
11
|
> This is a **fully open source project** — feedback, bug reports, test cases,
|
|
12
12
|
> and pull requests are welcome!
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
A pure-Ruby MJML v4 compiler — no Node.js required.
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
16
|
+
- Library API compatible with `mjml2html`
|
|
17
|
+
- Command-line interface (`mjml`)
|
|
18
|
+
- Rails integration (ActionView template handler for `.mjml` views)
|
|
19
|
+
- Validation (soft, strict, skip)
|
|
20
|
+
- Custom component support
|
|
21
|
+
- Pure Ruby parser, AST, validator, and renderer
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
## Compatibility
|
|
25
|
-
|
|
26
|
-
This project targets **MJML v4 only**.
|
|
23
|
+
**[Full Usage Guide](docs/USAGE.md)** — API reference, all compiler options, component attribute tables, CLI flags, Rails setup, custom components, and more.
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
- component rules and attribute validation follow the MJML v4 model
|
|
25
|
+
## Installation
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
bundle install
|
|
35
|
-
bundle exec ruby -Ilib -e 'require "mjml-rb"; puts MjmlRb.mjml2html("<mjml><mj-body><mj-section><mj-column><mj-text>Hello</mj-text></mj-column></mj-section></mj-body></mjml>")[:html]'
|
|
27
|
+
```ruby
|
|
28
|
+
# Gemfile
|
|
29
|
+
gem "mjml-rb"
|
|
36
30
|
```
|
|
37
31
|
|
|
38
|
-
##
|
|
32
|
+
## Quick Start
|
|
39
33
|
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
```ruby
|
|
35
|
+
require "mjml-rb"
|
|
36
|
+
|
|
37
|
+
result = MjmlRb.mjml2html(<<~MJML)
|
|
38
|
+
<mjml>
|
|
39
|
+
<mj-body>
|
|
40
|
+
<mj-section>
|
|
41
|
+
<mj-column>
|
|
42
|
+
<mj-text>Hello World!</mj-text>
|
|
43
|
+
</mj-column>
|
|
44
|
+
</mj-section>
|
|
45
|
+
</mj-body>
|
|
46
|
+
</mjml>
|
|
47
|
+
MJML
|
|
48
|
+
|
|
49
|
+
puts result[:html] # compiled HTML
|
|
50
|
+
puts result[:errors] # validation errors (if any)
|
|
43
51
|
```
|
|
44
52
|
|
|
45
|
-
##
|
|
46
|
-
|
|
47
|
-
In a Rails app, requiring the gem registers an `ActionView` template handler for
|
|
48
|
-
`.mjml` templates through a `Railtie`.
|
|
49
|
-
|
|
50
|
-
By default, `.mjml` files are treated as raw MJML/XML source.
|
|
53
|
+
## CLI
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
```bash
|
|
56
|
+
mjml email.mjml -o email.html # compile to file
|
|
57
|
+
mjml -r "templates/*.mjml" -o output/ # batch compile
|
|
58
|
+
mjml -v email.mjml # validate only
|
|
59
|
+
mjml -i -s < email.mjml # stdin → stdout
|
|
56
60
|
```
|
|
57
61
|
|
|
58
|
-
|
|
62
|
+
See the [Usage Guide — CLI section](docs/USAGE.md#cli) for all flags and config options.
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
through that template engine first, so partials and embedded Ruby can assemble
|
|
62
|
-
MJML before the outer template is compiled to HTML. Without that setting,
|
|
63
|
-
non-XML MJML source is rejected instead of being guessed.
|
|
64
|
+
## Rails
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
registered in `ActionView` by the corresponding gem or integration layer.
|
|
66
|
+
Add the gem to your Gemfile — that's it. The `.mjml` template handler is registered automatically.
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
```mjml
|
|
68
|
+
```erb
|
|
69
|
+
<!-- app/views/user_mailer/welcome.html.mjml -->
|
|
71
70
|
<mjml>
|
|
72
71
|
<mj-body>
|
|
73
72
|
<mj-section>
|
|
74
73
|
<mj-column>
|
|
75
|
-
<mj-text>
|
|
74
|
+
<mj-text>Welcome, <%= @user.name %>!</mj-text>
|
|
76
75
|
</mj-column>
|
|
77
76
|
</mj-section>
|
|
78
77
|
</mj-body>
|
|
79
78
|
</mjml>
|
|
80
79
|
```
|
|
81
80
|
|
|
82
|
-
Then render it like any other Rails template:
|
|
83
|
-
|
|
84
81
|
```ruby
|
|
85
82
|
class UserMailer < ApplicationMailer
|
|
86
|
-
def welcome
|
|
87
|
-
|
|
83
|
+
def welcome(user)
|
|
84
|
+
@user = user
|
|
85
|
+
mail(to: user.email, subject: "Welcome")
|
|
88
86
|
end
|
|
89
87
|
end
|
|
90
88
|
```
|
|
91
89
|
|
|
92
|
-
|
|
93
|
-
compiler options in your application config:
|
|
94
|
-
|
|
95
|
-
```ruby
|
|
96
|
-
config.mjml_rb.compiler_options = { validation_level: "soft" }
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Custom components
|
|
90
|
+
Supports Slim and Haml via `config.mjml_rb.rails_template_language = :slim`. See the [Usage Guide — Rails section](docs/USAGE.md#rails-integration) for full configuration.
|
|
100
91
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
```ruby
|
|
104
|
-
class MjRating < MjmlRb::Components::Base
|
|
105
|
-
TAGS = ["mj-rating"].freeze
|
|
106
|
-
ALLOWED_ATTRIBUTES = { "stars" => "integer", "color" => "color" }.freeze
|
|
107
|
-
DEFAULT_ATTRIBUTES = { "stars" => "5", "color" => "#f4b400" }.freeze
|
|
108
|
-
|
|
109
|
-
def render(tag_name:, node:, context:, attrs:, parent:)
|
|
110
|
-
stars = (attrs["stars"] || "5").to_i
|
|
111
|
-
color = attrs["color"] || "#f4b400"
|
|
112
|
-
%(<div style="color:#{escape_attr(color)}">#{"\u2605" * stars}</div>)
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
MjmlRb.register_component(MjRating,
|
|
117
|
-
dependencies: { "mj-column" => ["mj-rating"] },
|
|
118
|
-
ending_tags: ["mj-rating"]
|
|
119
|
-
)
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
The `dependencies` hash declares which parent tags accept the new component as a child. The `ending_tags` list tells the parser to treat content as raw HTML (like `mj-text`). Both are optional.
|
|
123
|
-
|
|
124
|
-
Once registered, the component works in MJML markup and is validated like any built-in component.
|
|
125
|
-
|
|
126
|
-
## `.mjmlrc` config file
|
|
127
|
-
|
|
128
|
-
Place a `.mjmlrc` file (JSON) in your project root to auto-register custom components and set default compiler options:
|
|
92
|
+
## Architecture
|
|
129
93
|
|
|
130
|
-
```json
|
|
131
|
-
{
|
|
132
|
-
"packages": [
|
|
133
|
-
"./lib/mjml_components/mj_rating.rb"
|
|
134
|
-
],
|
|
135
|
-
"options": {
|
|
136
|
-
"beautify": true,
|
|
137
|
-
"validation-level": "soft"
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
94
|
```
|
|
141
|
-
|
|
142
|
-
- **`packages`** — Ruby files to `require`. Each file should call `MjmlRb.register_component` to register its components.
|
|
143
|
-
- **`options`** — Default compiler options. CLI flags and programmatic options override these.
|
|
144
|
-
|
|
145
|
-
The CLI loads `.mjmlrc` automatically from the working directory. For the library API, load it explicitly:
|
|
146
|
-
|
|
147
|
-
```ruby
|
|
148
|
-
MjmlRb::ConfigFile.load("/path/to/project")
|
|
149
|
-
result = MjmlRb.mjml2html(mjml_string)
|
|
95
|
+
MJML string → Parser → AST → Validator → Renderer → HTML
|
|
150
96
|
```
|
|
151
97
|
|
|
152
|
-
|
|
98
|
+
1. **Parser** — normalizes source, expands `mj-include`, builds `AstNode` tree
|
|
99
|
+
2. **Validator** — checks structure, hierarchy, and attribute types
|
|
100
|
+
3. **Renderer** — resolves head metadata, applies defaults, emits responsive HTML
|
|
153
101
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
1. `MjmlRb.mjml2html` calls `MjmlRb::Compiler`.
|
|
157
|
-
2. `MjmlRb::Parser` normalizes the source, expands `mj-include`, and builds an `AstNode` tree.
|
|
158
|
-
3. `MjmlRb::Validator` checks structural rules and supported attributes.
|
|
159
|
-
4. `MjmlRb::Renderer` resolves head metadata, applies component defaults, and renders HTML.
|
|
160
|
-
5. `MjmlRb::Compiler` post-processes the output and returns a `Result`.
|
|
161
|
-
|
|
162
|
-
The key architectural idea is that the project uses a small shared AST plus a component registry:
|
|
163
|
-
|
|
164
|
-
- the parser produces generic `AstNode` objects instead of component-specific node types
|
|
165
|
-
- structure rules live in `lib/mjml-rb/dependencies.rb`
|
|
166
|
-
- rendering logic lives in `lib/mjml-rb/components/*`
|
|
167
|
-
- head components populate a shared rendering context
|
|
168
|
-
- body components consume that context and emit the final HTML
|
|
169
|
-
|
|
170
|
-
That split keeps the compiler pipeline predictable:
|
|
171
|
-
|
|
172
|
-
- parsing is responsible for source normalization and include expansion
|
|
173
|
-
- validation is responsible for MJML structure and attribute checks
|
|
174
|
-
- rendering is responsible for HTML generation and responsive email output
|
|
175
|
-
|
|
176
|
-
## Project structure
|
|
177
|
-
|
|
178
|
-
The main files are organized like this:
|
|
179
|
-
|
|
180
|
-
```text
|
|
181
|
-
lib/mjml-rb.rb # public gem entry point
|
|
182
|
-
lib/mjml-rb/compiler.rb # orchestration: parse -> validate -> render
|
|
183
|
-
lib/mjml-rb/parser.rb # MJML/XML normalization, includes, AST building
|
|
184
|
-
lib/mjml-rb/ast_node.rb # shared tree representation
|
|
185
|
-
lib/mjml-rb/validator.rb # structural and attribute validation
|
|
186
|
-
lib/mjml-rb/dependencies.rb # allowed parent/child relationships
|
|
187
|
-
lib/mjml-rb/renderer.rb # HTML document assembly and render context
|
|
188
|
-
lib/mjml-rb/components/* # per-component rendering and head handling
|
|
189
|
-
lib/mjml-rb/result.rb # result object returned by the compiler
|
|
190
|
-
lib/mjml-rb/cli.rb # CLI implementation used by bin/mjml
|
|
191
|
-
docs/ARCHITECTURE.md # deeper architecture notes
|
|
192
|
-
docs/PARITY_AUDIT.md # npm vs Ruby parity tracking
|
|
193
|
-
```
|
|
102
|
+
For the full internal walkthrough, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
194
103
|
|
|
195
|
-
|
|
104
|
+
Remaining parity work is tracked in [npm ↔ Ruby Parity Audit](docs/PARITY_AUDIT.md).
|
|
196
105
|
|
|
197
|
-
##
|
|
106
|
+
## License
|
|
198
107
|
|
|
199
|
-
|
|
200
|
-
>
|
|
201
|
-
> The npm `mjml` package requires Node.js at build time (or runtime via a child
|
|
202
|
-
> process / FFI bridge). This project replaces that entire pipeline with a single
|
|
203
|
-
> Ruby library: XML parsing, AST construction, attribute resolution, validation,
|
|
204
|
-
> and HTML rendering — all in Ruby, with no Node.js runtime and no need to
|
|
205
|
-
> shell out to the official MJML renderer. Drop it into a Rails, Sinatra, or
|
|
206
|
-
> plain Ruby project and render MJML templates the same way you render ERB — no
|
|
207
|
-
> extra runtime, no
|
|
208
|
-
> `package.json`, no `node_modules`.
|
|
108
|
+
MIT
|
|
@@ -104,7 +104,7 @@ module MjmlRb
|
|
|
104
104
|
.moz-text-html input.mj-accordion-checkbox + * .mj-accordion-ico { display:none; }
|
|
105
105
|
CSS
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
DEFAULT_ATTRIBUTES = {
|
|
108
108
|
"border" => "2px solid black",
|
|
109
109
|
"font-family" => "Ubuntu, Helvetica, Arial, sans-serif",
|
|
110
110
|
"icon-align" => "middle",
|
|
@@ -118,21 +118,17 @@ module MjmlRb
|
|
|
118
118
|
"padding" => "10px 25px"
|
|
119
119
|
}.freeze
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
TITLE_DEFAULT_ATTRIBUTES = {
|
|
122
122
|
"font-size" => "13px",
|
|
123
123
|
"padding" => "16px"
|
|
124
124
|
}.freeze
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
TEXT_DEFAULT_ATTRIBUTES = {
|
|
127
127
|
"font-size" => "13px",
|
|
128
128
|
"line-height" => "1",
|
|
129
129
|
"padding" => "16px"
|
|
130
130
|
}.freeze
|
|
131
131
|
|
|
132
|
-
def tags
|
|
133
|
-
TAGS
|
|
134
|
-
end
|
|
135
|
-
|
|
136
132
|
def head_style
|
|
137
133
|
HEAD_STYLE
|
|
138
134
|
end
|
|
@@ -146,11 +142,11 @@ module MjmlRb
|
|
|
146
142
|
when "mj-accordion"
|
|
147
143
|
render_accordion(node, context, attrs)
|
|
148
144
|
when "mj-accordion-element"
|
|
149
|
-
render_accordion_element(node, context,
|
|
145
|
+
render_accordion_element(node, context, DEFAULT_ATTRIBUTES.merge(attrs))
|
|
150
146
|
when "mj-accordion-title"
|
|
151
|
-
render_accordion_title(node,
|
|
147
|
+
render_accordion_title(node, DEFAULT_ATTRIBUTES.merge(attrs))
|
|
152
148
|
when "mj-accordion-text"
|
|
153
|
-
render_accordion_text(node,
|
|
149
|
+
render_accordion_text(node, DEFAULT_ATTRIBUTES.merge(attrs))
|
|
154
150
|
else
|
|
155
151
|
render_children(node, context, parent: parent)
|
|
156
152
|
end
|
|
@@ -159,7 +155,7 @@ module MjmlRb
|
|
|
159
155
|
private
|
|
160
156
|
|
|
161
157
|
def render_accordion(node, context, attrs)
|
|
162
|
-
accordion_attrs =
|
|
158
|
+
accordion_attrs = DEFAULT_ATTRIBUTES.merge(attrs)
|
|
163
159
|
outer_style = style_join(
|
|
164
160
|
"padding" => accordion_attrs["padding"],
|
|
165
161
|
"background-color" => accordion_attrs["container-background-color"]
|
|
@@ -225,7 +221,7 @@ module MjmlRb
|
|
|
225
221
|
end
|
|
226
222
|
|
|
227
223
|
def render_accordion_title(node, attrs)
|
|
228
|
-
title_attrs =
|
|
224
|
+
title_attrs = TITLE_DEFAULT_ATTRIBUTES.merge(attrs)
|
|
229
225
|
td_style = style_join(
|
|
230
226
|
"width" => "100%",
|
|
231
227
|
"background-color" => title_attrs["background-color"],
|
|
@@ -262,7 +258,7 @@ module MjmlRb
|
|
|
262
258
|
end
|
|
263
259
|
|
|
264
260
|
def render_accordion_text(node, attrs)
|
|
265
|
-
text_attrs =
|
|
261
|
+
text_attrs = TEXT_DEFAULT_ATTRIBUTES.merge(attrs)
|
|
266
262
|
td_style = style_join(
|
|
267
263
|
"background" => text_attrs["background-color"],
|
|
268
264
|
"font-size" => text_attrs["font-size"],
|
|
@@ -14,13 +14,7 @@ module MjmlRb
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def default_attributes
|
|
17
|
-
|
|
18
|
-
const_get(:DEFAULT_ATTRIBUTES)
|
|
19
|
-
elsif const_defined?(:DEFAULTS)
|
|
20
|
-
const_get(:DEFAULTS)
|
|
21
|
-
else
|
|
22
|
-
{}
|
|
23
|
-
end
|
|
17
|
+
const_defined?(:DEFAULT_ATTRIBUTES) ? const_get(:DEFAULT_ATTRIBUTES) : {}
|
|
24
18
|
end
|
|
25
19
|
end
|
|
26
20
|
|
|
@@ -41,7 +41,7 @@ module MjmlRb
|
|
|
41
41
|
"width" => "unit(px,%)"
|
|
42
42
|
}.freeze
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
DEFAULT_ATTRIBUTES = {
|
|
45
45
|
"align" => "center",
|
|
46
46
|
"background-color" => "#414141",
|
|
47
47
|
"border" => "none",
|
|
@@ -59,12 +59,8 @@ module MjmlRb
|
|
|
59
59
|
"vertical-align" => "middle"
|
|
60
60
|
}.freeze
|
|
61
61
|
|
|
62
|
-
def tags
|
|
63
|
-
TAGS
|
|
64
|
-
end
|
|
65
|
-
|
|
66
62
|
def render(tag_name:, node:, context:, attrs:, parent:)
|
|
67
|
-
a =
|
|
63
|
+
a = DEFAULT_ATTRIBUTES.merge(attrs)
|
|
68
64
|
|
|
69
65
|
bg_color = a["background-color"]
|
|
70
66
|
inner_padding = a["inner-padding"]
|
|
@@ -19,7 +19,7 @@ module MjmlRb
|
|
|
19
19
|
"align" => "enum(left,center,right)"
|
|
20
20
|
}.freeze
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
DEFAULT_ATTRIBUTES = {
|
|
23
23
|
"align" => "center",
|
|
24
24
|
"border-color" => "#000000",
|
|
25
25
|
"border-style" => "solid",
|
|
@@ -28,12 +28,8 @@ module MjmlRb
|
|
|
28
28
|
"width" => "100%"
|
|
29
29
|
}.freeze
|
|
30
30
|
|
|
31
|
-
def tags
|
|
32
|
-
TAGS
|
|
33
|
-
end
|
|
34
|
-
|
|
35
31
|
def render(tag_name:, node:, context:, attrs:, parent:)
|
|
36
|
-
a =
|
|
32
|
+
a = DEFAULT_ATTRIBUTES.merge(attrs)
|
|
37
33
|
|
|
38
34
|
outer_td_style = style_join(
|
|
39
35
|
"background" => a["container-background-color"],
|
|
@@ -43,10 +43,6 @@ module MjmlRb
|
|
|
43
43
|
"vertical-align" => "top"
|
|
44
44
|
}.freeze
|
|
45
45
|
|
|
46
|
-
def tags
|
|
47
|
-
TAGS
|
|
48
|
-
end
|
|
49
|
-
|
|
50
46
|
def render(tag_name:, node:, context:, attrs:, parent:)
|
|
51
47
|
a = DEFAULT_ATTRIBUTES.merge(attrs)
|
|
52
48
|
container_width = normalize_container_width(context[:container_width] || "600px")
|
|
@@ -37,7 +37,7 @@ module MjmlRb
|
|
|
37
37
|
"usemap" => "string"
|
|
38
38
|
}.freeze
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
DEFAULT_ATTRIBUTES = {
|
|
41
41
|
"alt" => "",
|
|
42
42
|
"align" => "center",
|
|
43
43
|
"border" => "0",
|
|
@@ -47,10 +47,6 @@ module MjmlRb
|
|
|
47
47
|
"font-size" => "13px"
|
|
48
48
|
}.freeze
|
|
49
49
|
|
|
50
|
-
def tags
|
|
51
|
-
TAGS
|
|
52
|
-
end
|
|
53
|
-
|
|
54
50
|
def head_style(breakpoint)
|
|
55
51
|
lower_breakpoint = make_lower_breakpoint(breakpoint)
|
|
56
52
|
|
|
@@ -67,7 +63,7 @@ module MjmlRb
|
|
|
67
63
|
end
|
|
68
64
|
|
|
69
65
|
def render(tag_name:, node:, context:, attrs:, parent:)
|
|
70
|
-
a =
|
|
66
|
+
a = DEFAULT_ATTRIBUTES.merge(attrs)
|
|
71
67
|
|
|
72
68
|
fluid = a["fluid-on-mobile"] == "true"
|
|
73
69
|
full_width = a["full-width"] == "full-width"
|
|
@@ -54,10 +54,6 @@ module MjmlRb
|
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
def tags
|
|
58
|
-
TAGS
|
|
59
|
-
end
|
|
60
|
-
|
|
61
57
|
def render(tag_name:, node:, context:, attrs:, parent:)
|
|
62
58
|
case tag_name
|
|
63
59
|
when "mj-wrapper"
|
|
@@ -607,7 +603,7 @@ module MjmlRb
|
|
|
607
603
|
"overflow" => (has_border_radius ? "hidden" : nil),
|
|
608
604
|
"margin" => "0px auto",
|
|
609
605
|
"margin-top" => wrapper_gap,
|
|
610
|
-
"max-width" =>
|
|
606
|
+
"max-width" => "#{container_px}px"
|
|
611
607
|
}.merge(full_width ? {} : background_styles)
|
|
612
608
|
)
|
|
613
609
|
|
|
@@ -107,7 +107,7 @@ module MjmlRb
|
|
|
107
107
|
icon-size icon-height icon-padding text-padding line-height text-decoration
|
|
108
108
|
].freeze
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
SOCIAL_DEFAULT_ATTRIBUTES = {
|
|
111
111
|
"align" => "center",
|
|
112
112
|
"border-radius" => "3px",
|
|
113
113
|
"color" => "#333333",
|
|
@@ -120,7 +120,7 @@ module MjmlRb
|
|
|
120
120
|
"text-decoration" => "none"
|
|
121
121
|
}.freeze
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
ELEMENT_DEFAULT_ATTRIBUTES = {
|
|
124
124
|
"alt" => "",
|
|
125
125
|
"align" => "left",
|
|
126
126
|
"icon-position" => "left",
|
|
@@ -136,17 +136,13 @@ module MjmlRb
|
|
|
136
136
|
"vertical-align" => "middle"
|
|
137
137
|
}.freeze
|
|
138
138
|
|
|
139
|
-
def tags
|
|
140
|
-
TAGS
|
|
141
|
-
end
|
|
142
|
-
|
|
143
139
|
def render(tag_name:, node:, context:, attrs:, parent:)
|
|
144
140
|
case tag_name
|
|
145
141
|
when "mj-social"
|
|
146
142
|
render_social(node, context, attrs)
|
|
147
143
|
when "mj-social-element"
|
|
148
144
|
# Direct dispatch (no parent attrs merging) — fallback for standalone use
|
|
149
|
-
render_social_element(node,
|
|
145
|
+
render_social_element(node, ELEMENT_DEFAULT_ATTRIBUTES.merge(attrs))
|
|
150
146
|
end
|
|
151
147
|
end
|
|
152
148
|
|
|
@@ -155,7 +151,7 @@ module MjmlRb
|
|
|
155
151
|
# ── mj-social ──────────────────────────────────────────────────────────
|
|
156
152
|
|
|
157
153
|
def render_social(node, context, attrs)
|
|
158
|
-
a =
|
|
154
|
+
a = SOCIAL_DEFAULT_ATTRIBUTES.merge(attrs)
|
|
159
155
|
|
|
160
156
|
outer_td_style = style_join(
|
|
161
157
|
"background" => a["container-background-color"],
|
|
@@ -211,7 +207,7 @@ module MjmlRb
|
|
|
211
207
|
children_html = with_inherited_mj_class(context, node) do
|
|
212
208
|
elements.map.with_index do |child, idx|
|
|
213
209
|
child_attrs = resolved_attributes(child, context)
|
|
214
|
-
merged_attrs =
|
|
210
|
+
merged_attrs = ELEMENT_DEFAULT_ATTRIBUTES.merge(inherited).merge(child_attrs)
|
|
215
211
|
el_html = render_social_element(child, merged_attrs)
|
|
216
212
|
|
|
217
213
|
outlook_td_open = idx == 0 ? "<td>" : "</td><td>"
|
|
@@ -229,7 +225,7 @@ module MjmlRb
|
|
|
229
225
|
children_html = with_inherited_mj_class(context, node) do
|
|
230
226
|
elements.map do |child|
|
|
231
227
|
child_attrs = resolved_attributes(child, context)
|
|
232
|
-
merged_attrs =
|
|
228
|
+
merged_attrs = ELEMENT_DEFAULT_ATTRIBUTES.merge(inherited).merge(child_attrs)
|
|
233
229
|
render_social_element(child, merged_attrs)
|
|
234
230
|
end.join
|
|
235
231
|
end
|
|
@@ -27,7 +27,7 @@ module MjmlRb
|
|
|
27
27
|
"width" => "unit(px,%,auto)"
|
|
28
28
|
}.freeze
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
DEFAULT_ATTRIBUTES = {
|
|
31
31
|
"align" => "left",
|
|
32
32
|
"border" => "none",
|
|
33
33
|
"cellpadding" => "0",
|
|
@@ -41,12 +41,8 @@ module MjmlRb
|
|
|
41
41
|
"width" => "100%"
|
|
42
42
|
}.freeze
|
|
43
43
|
|
|
44
|
-
def tags
|
|
45
|
-
TAGS
|
|
46
|
-
end
|
|
47
|
-
|
|
48
44
|
def render(tag_name:, node:, context:, attrs:, parent:)
|
|
49
|
-
a =
|
|
45
|
+
a = DEFAULT_ATTRIBUTES.merge(attrs)
|
|
50
46
|
|
|
51
47
|
outer_td_style = style_join(
|
|
52
48
|
"background" => a["container-background-color"],
|
|
@@ -27,7 +27,7 @@ module MjmlRb
|
|
|
27
27
|
"vertical-align" => "enum(top,bottom,middle)"
|
|
28
28
|
}.freeze
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
DEFAULT_ATTRIBUTES = {
|
|
31
31
|
"align" => "left",
|
|
32
32
|
"color" => "#000000",
|
|
33
33
|
"font-family" => "Ubuntu, Helvetica, Arial, sans-serif",
|
|
@@ -36,12 +36,8 @@ module MjmlRb
|
|
|
36
36
|
"padding" => "10px 25px"
|
|
37
37
|
}.freeze
|
|
38
38
|
|
|
39
|
-
def tags
|
|
40
|
-
TAGS
|
|
41
|
-
end
|
|
42
|
-
|
|
43
39
|
def render(tag_name:, node:, context:, attrs:, parent:)
|
|
44
|
-
a =
|
|
40
|
+
a = DEFAULT_ATTRIBUTES.merge(attrs)
|
|
45
41
|
height = a["height"]
|
|
46
42
|
|
|
47
43
|
outer_td_style = style_join(
|
data/lib/mjml-rb/renderer.rb
CHANGED
|
@@ -545,6 +545,12 @@ module MjmlRb
|
|
|
545
545
|
end
|
|
546
546
|
|
|
547
547
|
def normalize_background_fallbacks!(node, declarations)
|
|
548
|
+
background_image = declaration_value(declarations["background-image"])
|
|
549
|
+
if background_image && !background_image.empty?
|
|
550
|
+
declarations.delete("background") if syncable_background?(declaration_value(declarations["background"]))
|
|
551
|
+
return
|
|
552
|
+
end
|
|
553
|
+
|
|
548
554
|
background_color = declaration_value(declarations["background-color"])
|
|
549
555
|
return if background_color.nil? || background_color.empty?
|
|
550
556
|
|
data/lib/mjml-rb/version.rb
CHANGED