mjml-rb 0.2.27 → 0.2.29
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 +12 -42
- data/lib/mjml-rb/components/carousel.rb +1 -1
- data/lib/mjml-rb/components/head.rb +1 -1
- data/lib/mjml-rb/components/image.rb +1 -0
- data/lib/mjml-rb/renderer.rb +37 -21
- data/lib/mjml-rb/validator.rb +2 -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: 5cd5e68ad11e8256180f4be4f8d00e86f647327695c9391904eb4ddd31ddc7ad
|
|
4
|
+
data.tar.gz: a7f4f27a8db1ab489a3ae5d2e4e52f556fed859cfc5c8d33beb6ea29a581e6e9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 34a43b990be0b2cb7176e8c4736f17a79adc327a67ab91bab09b80af9d5776ad908f18bfba5cf41cdb7ea7ff5a40ea3e2b1cfd088eb3db99e23eab8132023ade
|
|
7
|
+
data.tar.gz: c5dd780d2529994abcc89680862d29dcba174fa6b085e5d0c3fa588ab0048899c010d9ce4ff9565289459d95c86004ffa6bd328920782746ce94241433e4bc9e
|
data/README.md
CHANGED
|
@@ -34,46 +34,16 @@ bundle exec bin/mjml --validate example.mjml
|
|
|
34
34
|
bundle exec bin/mjml --migrate old.mjml -s
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
##
|
|
37
|
+
## Implementation idea
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
| `mj-button` | migrated | Implemented in `button.rb`. |
|
|
51
|
-
| `mj-divider` | migrated | Implemented in `divider.rb`. |
|
|
52
|
-
| `mj-table` | migrated | Implemented in `table.rb`. |
|
|
53
|
-
| `mj-social` | migrated | Implemented in `social.rb`. |
|
|
54
|
-
| `mj-social-element` | migrated | Implemented in `social.rb`. |
|
|
55
|
-
| `mj-accordion` | migrated | Implemented in `accordion.rb`. |
|
|
56
|
-
| `mj-accordion-element` | migrated | Implemented in `accordion.rb`. |
|
|
57
|
-
| `mj-accordion-title` | migrated | Implemented in `accordion.rb`. |
|
|
58
|
-
| `mj-accordion-text` | migrated | Implemented in `accordion.rb`. |
|
|
59
|
-
| `mj-spacer` | migrated | Implemented in `spacer.rb`. |
|
|
60
|
-
| `mj-hero` | migrated | Implemented in `hero.rb` with fixed/fluid modes, inner content wrapper, and Outlook VML background fallback. |
|
|
61
|
-
| `mj-navbar` | migrated | Implemented in `navbar.rb`, including `base-url` propagation and breakpoint-aware hamburger CSS. |
|
|
62
|
-
| `mj-navbar-link` | migrated | Implemented in `navbar.rb` as an ending-tag navbar child component. |
|
|
63
|
-
| `mj-raw` | migrated | Implemented in `raw.rb`, including head insertion and top-level `position="file-start"` output before the doctype. |
|
|
64
|
-
| `mj-head` | migrated | Implemented in `head.rb` and dispatches supported head children through component handlers. |
|
|
65
|
-
| `mj-attributes` | migrated | Implemented in `attributes.rb`, including npm-style `mj-class` descendant defaults. |
|
|
66
|
-
| `mj-all` | migrated | Implemented through `attributes.rb` with npm-style global default attribute precedence. |
|
|
67
|
-
| `mj-class` | migrated | Supported through `attributes.rb`, including nested per-tag descendant defaults. |
|
|
68
|
-
| `mj-title` | migrated | Implemented in `head.rb`. |
|
|
69
|
-
| `mj-preview` | migrated | Implemented in `head.rb`. |
|
|
70
|
-
| `mj-style` | migrated | Implemented in `head.rb`, including inline-style registration. |
|
|
71
|
-
| `mj-font` | migrated | Implemented in `head.rb`. |
|
|
72
|
-
| `mj-carousel` | migrated | Implemented in `carousel.rb`, including per-instance radio/thumbnail CSS, Outlook fallback rendering, and thumbnail/control output. |
|
|
73
|
-
| `mj-carousel-image` | migrated | Implemented in `carousel_image.rb`, including radio, thumbnail, and main image rendering helpers used by `mj-carousel`. |
|
|
74
|
-
| `mj-breakpoint` | migrated | Supported in `mj-head` and used to control desktop column media-query widths. |
|
|
75
|
-
| `mj-html-attributes` | migrated | Supported in `mj-head` and applied to the rendered HTML via CSS selectors. |
|
|
76
|
-
| `mj-selector` | migrated | Supported as the selector container for `mj-html-attribute` rules. |
|
|
77
|
-
| `mj-html-attribute` | migrated | Supported for injecting custom HTML attributes into matched rendered nodes. |
|
|
78
|
-
|
|
79
|
-
A more detailed parity backlog lives in [doc/TODO.md](/doc/TODO.md).
|
|
39
|
+
> **Zero-dependency pure-Ruby MJML renderer.**
|
|
40
|
+
>
|
|
41
|
+
> The npm `mjml` package requires Node.js at build time (or runtime via a child
|
|
42
|
+
> process / FFI bridge). This project replaces that entire pipeline with a single
|
|
43
|
+
> Ruby library: XML parsing, AST construction, attribute resolution, validation,
|
|
44
|
+
> and HTML rendering — all in Ruby, with no native extensions and no Node.js
|
|
45
|
+
> dependency. Drop it into a Rails, Sinatra, or plain Ruby project and render
|
|
46
|
+
> MJML templates the same way you render ERB — no extra runtime, no
|
|
47
|
+
> `package.json`, no `node_modules`.
|
|
48
|
+
|
|
49
|
+
Remaining parity work is tracked in [doc/TODO.md](/doc/TODO.md).
|
|
@@ -50,7 +50,7 @@ module MjmlRb
|
|
|
50
50
|
return "" if children.empty?
|
|
51
51
|
|
|
52
52
|
carousel_id = SecureRandom.hex(8)
|
|
53
|
-
context[:
|
|
53
|
+
context[:component_head_styles] << component_head_style(carousel_id, children.length, a)
|
|
54
54
|
|
|
55
55
|
outer_td_attrs = {
|
|
56
56
|
"align" => a["align"],
|
|
@@ -23,6 +23,7 @@ module MjmlRb
|
|
|
23
23
|
"border-radius" => "unit(px,%){1,4}",
|
|
24
24
|
"container-background-color" => "color",
|
|
25
25
|
"fluid-on-mobile" => "boolean",
|
|
26
|
+
"full-width" => "enum(full-width)",
|
|
26
27
|
"padding" => "unit(px,%){1,4}",
|
|
27
28
|
"padding-bottom" => "unit(px,%)",
|
|
28
29
|
"padding-left" => "unit(px,%)",
|
data/lib/mjml-rb/renderer.rb
CHANGED
|
@@ -71,7 +71,6 @@ module MjmlRb
|
|
|
71
71
|
context[:column_widths] = {}
|
|
72
72
|
append_component_head_styles(document, context)
|
|
73
73
|
content = render_node(body, context, parent: "mjml")
|
|
74
|
-
append_column_width_styles(context)
|
|
75
74
|
build_html_document(content, context)
|
|
76
75
|
end
|
|
77
76
|
|
|
@@ -84,7 +83,8 @@ module MjmlRb
|
|
|
84
83
|
breakpoint: "480px",
|
|
85
84
|
before_doctype: "",
|
|
86
85
|
head_raw: [],
|
|
87
|
-
|
|
86
|
+
component_head_styles: [],
|
|
87
|
+
user_styles: [],
|
|
88
88
|
inline_styles: [],
|
|
89
89
|
html_attributes: {},
|
|
90
90
|
fonts: DEFAULT_FONTS.merge(hash_or_empty(options[:fonts])),
|
|
@@ -108,10 +108,12 @@ module MjmlRb
|
|
|
108
108
|
def build_html_document(content, context)
|
|
109
109
|
title = context[:title].to_s
|
|
110
110
|
preview = context[:preview]
|
|
111
|
-
head_styles = ([DOCUMENT_RESET_CSS] + unique_strings(context[:head_styles])).join("\n")
|
|
112
111
|
head_raw = Array(context[:head_raw]).join("\n")
|
|
113
112
|
before_doctype = context[:before_doctype].to_s
|
|
114
113
|
font_tags = build_font_tags(content, context[:inline_styles], context[:fonts])
|
|
114
|
+
media_queries_tags = build_media_queries_tags(context[:breakpoint], context[:column_widths])
|
|
115
|
+
component_styles_tag = build_style_tag(unique_strings(context[:component_head_styles]))
|
|
116
|
+
user_styles_tag = build_style_tag(unique_strings(context[:user_styles]))
|
|
115
117
|
preview_block = preview.empty? ? "" : %(<div style="display:none;max-height:0;overflow:hidden;opacity:0;">#{escape_html(preview)}</div>)
|
|
116
118
|
html_attributes = {
|
|
117
119
|
"lang" => context[:lang],
|
|
@@ -133,10 +135,13 @@ module MjmlRb
|
|
|
133
135
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
134
136
|
<meta charset="utf-8">
|
|
135
137
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
138
|
+
<style type="text/css">#{DOCUMENT_RESET_CSS}</style>
|
|
136
139
|
#{OUTLOOK_DOCUMENT_SETTINGS}
|
|
137
140
|
#{OUTLOOK_GROUP_FIX}
|
|
138
141
|
#{font_tags}
|
|
139
|
-
|
|
142
|
+
#{media_queries_tags}
|
|
143
|
+
#{component_styles_tag}
|
|
144
|
+
#{user_styles_tag}
|
|
140
145
|
#{head_raw}
|
|
141
146
|
</head>
|
|
142
147
|
<body style="#{body_style}">
|
|
@@ -226,28 +231,39 @@ module MjmlRb
|
|
|
226
231
|
end
|
|
227
232
|
end
|
|
228
233
|
|
|
229
|
-
def
|
|
230
|
-
widths =
|
|
231
|
-
return if widths.empty?
|
|
234
|
+
def build_media_queries_tags(breakpoint, column_widths)
|
|
235
|
+
widths = column_widths || {}
|
|
236
|
+
return "" if widths.empty?
|
|
232
237
|
|
|
233
|
-
|
|
238
|
+
base_rules = widths.map do |suffix, pct|
|
|
234
239
|
".mj-column-per-#{suffix} { width:#{pct}% !important; max-width: #{pct}%; }"
|
|
235
|
-
end
|
|
236
|
-
|
|
240
|
+
end
|
|
241
|
+
moz_rules = widths.map do |suffix, pct|
|
|
237
242
|
".moz-text-html .mj-column-per-#{suffix} { width:#{pct}% !important; max-width: #{pct}%; }"
|
|
238
|
-
end
|
|
239
|
-
|
|
243
|
+
end
|
|
244
|
+
owa_rules = widths.map do |suffix, pct|
|
|
240
245
|
"[owa] .mj-column-per-#{suffix} { width:#{pct}% !important; max-width: #{pct}%; }"
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
bp = breakpoint.to_s.strip
|
|
249
|
+
parts = []
|
|
250
|
+
|
|
251
|
+
if bp.empty?
|
|
252
|
+
parts << "<style type=\"text/css\">\n#{base_rules.join("\n")}\n</style>"
|
|
253
|
+
parts << "<style type=\"text/css\">\n#{moz_rules.join("\n")}\n</style>"
|
|
246
254
|
else
|
|
247
|
-
|
|
248
|
-
|
|
255
|
+
parts << "<style type=\"text/css\">\n@media only screen and (min-width:#{bp}) {\n#{base_rules.join("\n")}\n}\n</style>"
|
|
256
|
+
parts << "<style media=\"screen and (min-width:#{bp})\">\n#{moz_rules.join("\n")}\n</style>"
|
|
249
257
|
end
|
|
250
|
-
|
|
258
|
+
|
|
259
|
+
parts << "<style type=\"text/css\">\n#{owa_rules.join("\n")}\n</style>"
|
|
260
|
+
parts.join("\n")
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def build_style_tag(styles)
|
|
264
|
+
return "" if styles.empty?
|
|
265
|
+
|
|
266
|
+
"<style type=\"text/css\">#{styles.join("\n")}</style>"
|
|
251
267
|
end
|
|
252
268
|
|
|
253
269
|
def merge_outlook_conditionals(html)
|
|
@@ -482,7 +498,7 @@ module MjmlRb
|
|
|
482
498
|
end
|
|
483
499
|
next unless Array(tags).any? { |tag| contains_tag?(document, tag) }
|
|
484
500
|
|
|
485
|
-
context[:
|
|
501
|
+
context[:component_head_styles] << style
|
|
486
502
|
end
|
|
487
503
|
end
|
|
488
504
|
|
data/lib/mjml-rb/validator.rb
CHANGED
data/lib/mjml-rb/version.rb
CHANGED