mjml-rb 0.2.30 → 0.2.32
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/mjml-rb/components/column.rb +11 -4
- data/lib/mjml-rb/components/group.rb +3 -3
- data/lib/mjml-rb/components/section.rb +51 -13
- data/lib/mjml-rb/renderer.rb +6 -6
- 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: 5f70adefb32b3a7bb2df503b8749cfbd2fde06bb819c6bfc3e587a1a8eb65772
|
|
4
|
+
data.tar.gz: ef1c17cd44ec046c37c75b3a6650610161fe74f71824dfe64b72db2958e24f77
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 64230656cfbf00b6d220cb579e078cddda30edeb5ccf1faa9f4245ed389ba76f6fe1990a10f48a6ccc2e67ecc3deb0c09cb6d4d146079d992e08cf5376f55c60
|
|
7
|
+
data.tar.gz: cb12486d8dd7571e11f19bbed0054a7698def27350678874c65c07688baf28a5b2e19f5bb31db4d4ce7c761e3509114c6d2b85155567a842e1812a1d82ba985b
|
|
@@ -42,11 +42,18 @@ module MjmlRb
|
|
|
42
42
|
css_class = attrs["css-class"]
|
|
43
43
|
a = self.class.default_attributes.merge(attrs)
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
explicit_width = a["width"]
|
|
46
|
+
if explicit_width && explicit_width.strip.end_with?("px")
|
|
47
|
+
px_val = explicit_width.to_f.to_s.sub(/\.?0+$/, "")
|
|
48
|
+
col_class_name = "mj-column-px-#{px_val.gsub('.', '-')}"
|
|
49
|
+
context[:column_widths][col_class_name] = "#{px_val}px" if context[:column_widths]
|
|
50
|
+
else
|
|
51
|
+
pct_str = width_pct.to_f.to_s.sub(/\.?0+$/, "")
|
|
52
|
+
col_class_name = "mj-column-per-#{pct_str.gsub('.', '-')}"
|
|
53
|
+
context[:column_widths][col_class_name] = "#{pct_str}%" if context[:column_widths]
|
|
54
|
+
end
|
|
48
55
|
|
|
49
|
-
col_class = "
|
|
56
|
+
col_class = "#{col_class_name} mj-outlook-group-fix"
|
|
50
57
|
col_class = "#{col_class} #{css_class}" if css_class && !css_class.empty?
|
|
51
58
|
|
|
52
59
|
vertical_align = a["vertical-align"]
|
|
@@ -26,10 +26,10 @@ module MjmlRb
|
|
|
26
26
|
css_class = a["css-class"]
|
|
27
27
|
|
|
28
28
|
pct_str = width_pct.to_f.to_s.sub(/\.?0+$/, "")
|
|
29
|
-
|
|
30
|
-
context[:column_widths][
|
|
29
|
+
col_class_name = "mj-column-per-#{pct_str.gsub('.', '-')}"
|
|
30
|
+
context[:column_widths][col_class_name] = "#{pct_str}%" if context[:column_widths]
|
|
31
31
|
|
|
32
|
-
group_class = "
|
|
32
|
+
group_class = "#{col_class_name} mj-outlook-group-fix"
|
|
33
33
|
group_class = "#{group_class} #{css_class}" if css_class && !css_class.empty?
|
|
34
34
|
|
|
35
35
|
group_width = group_container_width(context, a, width_pct)
|
|
@@ -123,6 +123,12 @@ module MjmlRb
|
|
|
123
123
|
value && !value.to_s.strip.empty?
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
# Matches npm's suffixCssClasses: "foo bar" → "foo-outlook bar-outlook"
|
|
127
|
+
def suffix_css_classes(classes, suffix = "outlook")
|
|
128
|
+
return "" unless classes && !classes.strip.empty?
|
|
129
|
+
classes.split(" ").map { |c| "#{c}-#{suffix}" }.join(" ")
|
|
130
|
+
end
|
|
131
|
+
|
|
126
132
|
# Merge adjacent Outlook conditional comments. Applied locally within
|
|
127
133
|
# each section/wrapper to avoid incorrectly merging across sibling sections.
|
|
128
134
|
def merge_outlook_conditionals(html)
|
|
@@ -388,7 +394,8 @@ module MjmlRb
|
|
|
388
394
|
end
|
|
389
395
|
|
|
390
396
|
def render_section_before(css_class, container_px, bg_color, wrapper_gap)
|
|
391
|
-
outlook_class = css_class
|
|
397
|
+
outlook_class = suffix_css_classes(css_class)
|
|
398
|
+
has_gap = wrapper_gap && !wrapper_gap.to_s.strip.empty?
|
|
392
399
|
before_pairs = [
|
|
393
400
|
["align", "center"],
|
|
394
401
|
["border", "0"],
|
|
@@ -399,7 +406,7 @@ module MjmlRb
|
|
|
399
406
|
["style", style_join("width" => "#{container_px}px", "padding-top" => wrapper_gap) + ";"],
|
|
400
407
|
["width", container_px.to_s]
|
|
401
408
|
]
|
|
402
|
-
before_pairs << ["bgcolor", bg_color] if bg_color
|
|
409
|
+
before_pairs << ["bgcolor", bg_color] if bg_color && !has_gap
|
|
403
410
|
|
|
404
411
|
%(<!--[if mso | IE]><table#{outlook_attrs(before_pairs)}><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->)
|
|
405
412
|
end
|
|
@@ -502,7 +509,12 @@ module MjmlRb
|
|
|
502
509
|
end
|
|
503
510
|
|
|
504
511
|
# Generate Outlook IE conditional wrappers around each column/group.
|
|
512
|
+
# Mirrors npm section's getChildContext() by setting containerWidth to
|
|
513
|
+
# the section's box width so that column children compute correct widths.
|
|
505
514
|
def render_section_columns(node, context, box_width)
|
|
515
|
+
previous_container_width = context[:container_width]
|
|
516
|
+
context[:container_width] = "#{box_width}px"
|
|
517
|
+
|
|
506
518
|
columns = node.element_children.select { |e| %w[mj-column mj-group].include?(e.tag_name) }
|
|
507
519
|
return render_children(node, context, parent: "mj-section") if columns.empty?
|
|
508
520
|
|
|
@@ -517,9 +529,16 @@ module MjmlRb
|
|
|
517
529
|
columns.each_with_index.map do |col, i|
|
|
518
530
|
col_attrs = resolved_attributes(col, context)
|
|
519
531
|
v_align = col_attrs["vertical-align"] || "top"
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
532
|
+
col_css = col_attrs["css-class"]
|
|
533
|
+
outlook_class = col_css ? col_css.split(" ").map { |c| "#{c}-outlook" }.join(" ") : ""
|
|
534
|
+
col_width_attr = col_attrs["width"]
|
|
535
|
+
col_px = if col_width_attr && col_width_attr.strip.end_with?("px")
|
|
536
|
+
col_width_attr.to_f.round
|
|
537
|
+
else
|
|
538
|
+
(box_width.to_f * widths[i] / 100.0).round
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
td_open = %(<!--[if mso | IE]><td class="#{escape_attr(outlook_class)}" style="vertical-align:#{v_align};width:#{col_px}px;" ><![endif]-->)
|
|
523
542
|
td_close = %(<!--[if mso | IE]></td><![endif]-->)
|
|
524
543
|
|
|
525
544
|
context[:_column_width_pct] = widths[i]
|
|
@@ -530,6 +549,8 @@ module MjmlRb
|
|
|
530
549
|
end
|
|
531
550
|
|
|
532
551
|
([open_table, open_tr] + col_parts + [close_tr, close_table]).join("\n")
|
|
552
|
+
ensure
|
|
553
|
+
context[:container_width] = previous_container_width
|
|
533
554
|
end
|
|
534
555
|
|
|
535
556
|
# ── mj-wrapper ─────────────────────────────────────────────────────────
|
|
@@ -562,7 +583,8 @@ module MjmlRb
|
|
|
562
583
|
end
|
|
563
584
|
|
|
564
585
|
# renderBefore — Outlook conditional table wrapper
|
|
565
|
-
outlook_class = css_class
|
|
586
|
+
outlook_class = suffix_css_classes(css_class)
|
|
587
|
+
has_gap = wrapper_gap && !wrapper_gap.to_s.strip.empty?
|
|
566
588
|
before_pairs = [
|
|
567
589
|
["align", "center"],
|
|
568
590
|
["border", "0"],
|
|
@@ -573,7 +595,7 @@ module MjmlRb
|
|
|
573
595
|
["style", style_join("width" => "#{container_px}px", "padding-top" => wrapper_gap) + ";"],
|
|
574
596
|
["width", container_px.to_s]
|
|
575
597
|
]
|
|
576
|
-
before_pairs << ["bgcolor", bg_color] if bg_color
|
|
598
|
+
before_pairs << ["bgcolor", bg_color] if bg_color && !has_gap
|
|
577
599
|
|
|
578
600
|
render_before = %(<!--[if mso | IE]><table#{outlook_attrs(before_pairs)}><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->)
|
|
579
601
|
|
|
@@ -608,6 +630,17 @@ module MjmlRb
|
|
|
608
630
|
"text-align" => a["text-align"]
|
|
609
631
|
)
|
|
610
632
|
|
|
633
|
+
# Compute box width and update context for children, matching npm
|
|
634
|
+
# wrapper's getChildContext() which sets containerWidth to box width.
|
|
635
|
+
border_left = parse_border_width(a["border-left"] || a["border"])
|
|
636
|
+
border_right = parse_border_width(a["border-right"] || a["border"])
|
|
637
|
+
pad_left = parse_padding_side(a, "left")
|
|
638
|
+
pad_right = parse_padding_side(a, "right")
|
|
639
|
+
box_width = container_px - pad_left - pad_right - border_left - border_right
|
|
640
|
+
|
|
641
|
+
previous_container_width = context[:container_width]
|
|
642
|
+
context[:container_width] = "#{box_width}px"
|
|
643
|
+
|
|
611
644
|
div_attrs = {"class" => (full_width ? nil : css_class), "style" => div_style}
|
|
612
645
|
inner = merge_outlook_conditionals(render_wrapped_children_wrapper(node, context, container_px, a["gap"]))
|
|
613
646
|
inner_content = bg_has ? %(<div style="line-height:0;font-size:0">#{inner}</div>) : inner
|
|
@@ -651,22 +684,27 @@ module MjmlRb
|
|
|
651
684
|
body = bg_has ? render_with_background(wrapper_html, a, container_px) : wrapper_html
|
|
652
685
|
"#{render_before}\n#{body}\n#{render_after}"
|
|
653
686
|
end
|
|
687
|
+
ensure
|
|
688
|
+
context[:container_width] = previous_container_width if previous_container_width
|
|
654
689
|
end
|
|
655
690
|
|
|
656
|
-
# Wrap each child mj-section/mj-wrapper in an Outlook conditional <td>.
|
|
691
|
+
# Wrap each child mj-section/mj-wrapper in an Outlook conditional <tr><td>.
|
|
692
|
+
# npm wrapper renders each child in its own row, unlike section which
|
|
693
|
+
# places all columns in a single row.
|
|
657
694
|
def render_wrapped_children_wrapper(node, context, container_px, gap)
|
|
658
695
|
children = node.element_children.select { |e| %w[mj-section mj-wrapper].include?(e.tag_name) }
|
|
659
696
|
return render_children(node, context, parent: "mj-wrapper") if children.empty?
|
|
660
697
|
|
|
661
698
|
open_table = %(<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><![endif]-->)
|
|
662
|
-
open_tr = %(<!--[if mso | IE]><tr><![endif]-->)
|
|
663
|
-
close_tr = %(<!--[if mso | IE]></tr><![endif]-->)
|
|
664
699
|
close_table = %(<!--[if mso | IE]></table><![endif]-->)
|
|
665
700
|
|
|
666
701
|
section_parts = with_inherited_mj_class(context, node) do
|
|
667
702
|
children.each_with_index.map do |child, index|
|
|
668
|
-
|
|
669
|
-
|
|
703
|
+
child_attrs = resolved_attributes(child, context)
|
|
704
|
+
child_css = child_attrs["css-class"]
|
|
705
|
+
outlook_class = suffix_css_classes(child_css)
|
|
706
|
+
td_open = %(<!--[if mso | IE]><tr><td class="#{escape_attr(outlook_class)}" width="#{container_px}px" ><![endif]-->)
|
|
707
|
+
td_close = %(<!--[if mso | IE]></td></tr><![endif]-->)
|
|
670
708
|
child_html = with_wrapper_child_gap(context, index.zero? ? nil : gap) do
|
|
671
709
|
render_node(child, context, parent: "mj-wrapper")
|
|
672
710
|
end
|
|
@@ -674,7 +712,7 @@ module MjmlRb
|
|
|
674
712
|
end
|
|
675
713
|
end
|
|
676
714
|
|
|
677
|
-
([open_table
|
|
715
|
+
([open_table] + section_parts + [close_table]).join("\n")
|
|
678
716
|
end
|
|
679
717
|
|
|
680
718
|
def with_wrapper_child_gap(context, gap)
|
data/lib/mjml-rb/renderer.rb
CHANGED
|
@@ -235,14 +235,14 @@ module MjmlRb
|
|
|
235
235
|
widths = column_widths || {}
|
|
236
236
|
return "" if widths.empty?
|
|
237
237
|
|
|
238
|
-
base_rules = widths.map do |
|
|
239
|
-
"
|
|
238
|
+
base_rules = widths.map do |class_name, width_str|
|
|
239
|
+
".#{class_name} { width:#{width_str} !important; max-width: #{width_str}; }"
|
|
240
240
|
end
|
|
241
|
-
moz_rules = widths.map do |
|
|
242
|
-
".moz-text-html
|
|
241
|
+
moz_rules = widths.map do |class_name, width_str|
|
|
242
|
+
".moz-text-html .#{class_name} { width:#{width_str} !important; max-width: #{width_str}; }"
|
|
243
243
|
end
|
|
244
|
-
owa_rules = widths.map do |
|
|
245
|
-
"[owa]
|
|
244
|
+
owa_rules = widths.map do |class_name, width_str|
|
|
245
|
+
"[owa] .#{class_name} { width:#{width_str} !important; max-width: #{width_str}; }"
|
|
246
246
|
end
|
|
247
247
|
|
|
248
248
|
bp = breakpoint.to_s.strip
|
data/lib/mjml-rb/version.rb
CHANGED