mjml-rb 0.2.15 → 0.2.18
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/section.rb +274 -44
- data/lib/mjml-rb/components/text.rb +23 -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: b82bc910ae0c3ba34cd905a28e8d2f52e349d7a1b099981eb576592a3274ba5b
|
|
4
|
+
data.tar.gz: 6e8ffbc112105cb1d11b5ba46f7b7a44bd9377c52498edc34e97c1ee421d4ac2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2eb6640d8405e3f8297a8fbd081530a8565fed4d410b297b78443d93bb1640db84d611aec0746beab99b5183a41d1d7b24d658ea048a2806f4899175c613bc95
|
|
7
|
+
data.tar.gz: 5f29c238409b28d5048e1a7b85aff199f93a975afcbf4d59f7d5562c9abadf3c4c2eb5e0768bb3e2da14e976bb9ad99e7743ddc6f3325f6820d5e06c63f0a414
|
|
@@ -7,6 +7,12 @@ module MjmlRb
|
|
|
7
7
|
|
|
8
8
|
SECTION_ALLOWED_ATTRIBUTES = {
|
|
9
9
|
"background-color" => "color",
|
|
10
|
+
"background-url" => "string",
|
|
11
|
+
"background-repeat" => "enum(repeat,no-repeat)",
|
|
12
|
+
"background-size" => "string",
|
|
13
|
+
"background-position" => "string",
|
|
14
|
+
"background-position-x" => "string",
|
|
15
|
+
"background-position-y" => "string",
|
|
10
16
|
"border" => "string",
|
|
11
17
|
"border-bottom" => "string",
|
|
12
18
|
"border-left" => "string",
|
|
@@ -23,13 +29,17 @@ module MjmlRb
|
|
|
23
29
|
}.freeze
|
|
24
30
|
|
|
25
31
|
WRAPPER_ALLOWED_ATTRIBUTES = SECTION_ALLOWED_ATTRIBUTES.merge(
|
|
32
|
+
"gap" => "unit(px)",
|
|
26
33
|
"full-width" => "enum(full-width)"
|
|
27
34
|
).freeze
|
|
28
35
|
|
|
29
36
|
DEFAULT_ATTRIBUTES = {
|
|
30
|
-
"direction"
|
|
31
|
-
"padding"
|
|
32
|
-
"text-align"
|
|
37
|
+
"direction" => "ltr",
|
|
38
|
+
"padding" => "20px 0",
|
|
39
|
+
"text-align" => "center",
|
|
40
|
+
"background-repeat" => "repeat",
|
|
41
|
+
"background-size" => "auto",
|
|
42
|
+
"background-position" => "top center"
|
|
33
43
|
}.freeze
|
|
34
44
|
|
|
35
45
|
class << self
|
|
@@ -116,6 +126,166 @@ module MjmlRb
|
|
|
116
126
|
" #{parts.join(' ')} "
|
|
117
127
|
end
|
|
118
128
|
|
|
129
|
+
# ── Background helpers ───────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
VERTICAL_KEYWORDS = %w[top bottom].freeze
|
|
132
|
+
HORIZONTAL_KEYWORDS = %w[left right].freeze
|
|
133
|
+
|
|
134
|
+
def has_background?(a)
|
|
135
|
+
url = a["background-url"]
|
|
136
|
+
url && !url.to_s.strip.empty?
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def parse_background_position(position_str)
|
|
140
|
+
tokens = position_str.to_s.strip.split(/\s+/)
|
|
141
|
+
|
|
142
|
+
case tokens.size
|
|
143
|
+
when 0
|
|
144
|
+
{x: "center", y: "top"}
|
|
145
|
+
when 1
|
|
146
|
+
if VERTICAL_KEYWORDS.include?(tokens[0])
|
|
147
|
+
{x: "center", y: tokens[0]}
|
|
148
|
+
else
|
|
149
|
+
{x: tokens[0], y: "center"}
|
|
150
|
+
end
|
|
151
|
+
when 2
|
|
152
|
+
first, second = tokens
|
|
153
|
+
if VERTICAL_KEYWORDS.include?(first) ||
|
|
154
|
+
(first == "center" && HORIZONTAL_KEYWORDS.include?(second))
|
|
155
|
+
{x: second, y: first}
|
|
156
|
+
else
|
|
157
|
+
{x: first, y: second}
|
|
158
|
+
end
|
|
159
|
+
else
|
|
160
|
+
{x: "center", y: "top"}
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def get_background_position(a)
|
|
165
|
+
base = parse_background_position(a["background-position"] || "top center")
|
|
166
|
+
pos_x = a["background-position-x"]
|
|
167
|
+
pos_y = a["background-position-y"]
|
|
168
|
+
x = (pos_x && !pos_x.to_s.empty?) ? pos_x : base[:x]
|
|
169
|
+
y = (pos_y && !pos_y.to_s.empty?) ? pos_y : base[:y]
|
|
170
|
+
{x: x, y: y}
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def get_background_string(a)
|
|
174
|
+
pos = get_background_position(a)
|
|
175
|
+
"#{pos[:x]} #{pos[:y]}"
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def get_background(a)
|
|
179
|
+
bg_url = a["background-url"]
|
|
180
|
+
bg_color = a["background-color"]
|
|
181
|
+
bg_size = a["background-size"]
|
|
182
|
+
bg_repeat = a["background-repeat"]
|
|
183
|
+
|
|
184
|
+
if has_background?(a)
|
|
185
|
+
pos_str = get_background_string(a)
|
|
186
|
+
parts = []
|
|
187
|
+
parts << bg_color if bg_color && !bg_color.to_s.empty?
|
|
188
|
+
parts << "url('#{bg_url}')"
|
|
189
|
+
parts << pos_str
|
|
190
|
+
parts << "/ #{bg_size}"
|
|
191
|
+
parts << bg_repeat
|
|
192
|
+
parts.join(" ")
|
|
193
|
+
else
|
|
194
|
+
bg_color
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# ── VML background for Outlook ───────────────────────────────────────
|
|
199
|
+
|
|
200
|
+
PERCENTAGE_RE = /\A\d+(\.\d+)?%\z/
|
|
201
|
+
|
|
202
|
+
VML_KEYWORD_TO_PERCENT = {
|
|
203
|
+
"left" => "0%", "top" => "0%",
|
|
204
|
+
"center" => "50%",
|
|
205
|
+
"right" => "100%", "bottom" => "100%"
|
|
206
|
+
}.freeze
|
|
207
|
+
|
|
208
|
+
def render_with_background(section_html, a, container_px)
|
|
209
|
+
bg_url = a["background-url"]
|
|
210
|
+
bg_color = a["background-color"]
|
|
211
|
+
bg_repeat = a["background-repeat"] || "repeat"
|
|
212
|
+
bg_size = a["background-size"] || "auto"
|
|
213
|
+
is_repeat = bg_repeat == "repeat"
|
|
214
|
+
|
|
215
|
+
pos = get_background_position(a)
|
|
216
|
+
|
|
217
|
+
# Normalize keywords to percentages
|
|
218
|
+
bg_pos_x = VML_KEYWORD_TO_PERCENT.fetch(pos[:x], nil) || (pos[:x] =~ PERCENTAGE_RE ? pos[:x] : "50%")
|
|
219
|
+
bg_pos_y = VML_KEYWORD_TO_PERCENT.fetch(pos[:y], nil) || (pos[:y] =~ PERCENTAGE_RE ? pos[:y] : "0%")
|
|
220
|
+
|
|
221
|
+
# Compute VML origin/position per axis
|
|
222
|
+
v_origin_x, v_pos_x = vml_axis_values(bg_pos_x, is_repeat, true)
|
|
223
|
+
v_origin_y, v_pos_y = vml_axis_values(bg_pos_y, is_repeat, false)
|
|
224
|
+
|
|
225
|
+
# VML size attributes
|
|
226
|
+
v_size_attrs = vml_size_attributes(bg_size)
|
|
227
|
+
|
|
228
|
+
# VML type
|
|
229
|
+
is_auto = bg_size == "auto"
|
|
230
|
+
vml_type = (!is_repeat && !is_auto) ? "frame" : "tile"
|
|
231
|
+
|
|
232
|
+
# Auto special case: force tile, reset position
|
|
233
|
+
if is_auto
|
|
234
|
+
v_origin_x = 0.5; v_pos_x = 0.5
|
|
235
|
+
v_origin_y = 0; v_pos_y = 0
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Build v:fill attributes
|
|
239
|
+
fill_pairs = [
|
|
240
|
+
["origin", "#{v_origin_x}, #{v_origin_y}"],
|
|
241
|
+
["position", "#{v_pos_x}, #{v_pos_y}"],
|
|
242
|
+
["src", bg_url],
|
|
243
|
+
["color", bg_color],
|
|
244
|
+
["type", vml_type]
|
|
245
|
+
]
|
|
246
|
+
fill_pairs << ["size", v_size_attrs[:size]] if v_size_attrs[:size]
|
|
247
|
+
fill_pairs << ["aspect", v_size_attrs[:aspect]] if v_size_attrs[:aspect]
|
|
248
|
+
fill_str = fill_pairs.map { |(k, v)| %(#{k}="#{escape_attr(v.to_s)}") }.join(" ")
|
|
249
|
+
|
|
250
|
+
%(<!--[if mso | IE]><v:rect style="mso-width-percent:1000;" xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false"><v:fill #{fill_str} /><v:textbox style="mso-fit-shape-to-text:true" inset="0,0,0,0"><![endif]-->) +
|
|
251
|
+
section_html +
|
|
252
|
+
%(<!--[if mso | IE]></v:textbox></v:rect><![endif]-->)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def vml_axis_values(pct_str, is_repeat, is_x)
|
|
256
|
+
if pct_str =~ PERCENTAGE_RE
|
|
257
|
+
decimal = pct_str.to_f / 100.0
|
|
258
|
+
if is_repeat
|
|
259
|
+
[decimal, decimal]
|
|
260
|
+
else
|
|
261
|
+
val = (-50 + decimal * 100) / 100.0
|
|
262
|
+
[val, val]
|
|
263
|
+
end
|
|
264
|
+
elsif is_repeat
|
|
265
|
+
[is_x ? 0.5 : 0, is_x ? 0.5 : 0]
|
|
266
|
+
else
|
|
267
|
+
[is_x ? 0 : -0.5, is_x ? 0 : -0.5]
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def vml_size_attributes(bg_size)
|
|
272
|
+
case bg_size
|
|
273
|
+
when "cover"
|
|
274
|
+
{size: "1,1", aspect: "atleast"}
|
|
275
|
+
when "contain"
|
|
276
|
+
{size: "1,1", aspect: "atmost"}
|
|
277
|
+
when "auto"
|
|
278
|
+
{}
|
|
279
|
+
else
|
|
280
|
+
parts = bg_size.to_s.strip.split(/\s+/)
|
|
281
|
+
if parts.size == 1
|
|
282
|
+
{size: bg_size, aspect: "atmost"}
|
|
283
|
+
else
|
|
284
|
+
{size: parts.join(",")}
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
119
289
|
# ── mj-section ─────────────────────────────────────────────────────────
|
|
120
290
|
|
|
121
291
|
def render_section(node, context, attrs)
|
|
@@ -124,6 +294,8 @@ module MjmlRb
|
|
|
124
294
|
css_class = a["css-class"]
|
|
125
295
|
bg_color = a["background-color"]
|
|
126
296
|
border_radius = a["border-radius"]
|
|
297
|
+
bg_has = has_background?(a)
|
|
298
|
+
wrapper_gap = context[:_wrapper_child_gap]
|
|
127
299
|
|
|
128
300
|
# Box width: container minus horizontal padding and borders
|
|
129
301
|
border_left = parse_border_width(a["border-left"] || a["border"])
|
|
@@ -141,53 +313,94 @@ module MjmlRb
|
|
|
141
313
|
["cellspacing", "0"],
|
|
142
314
|
["class", outlook_class],
|
|
143
315
|
["role", "presentation"],
|
|
144
|
-
["style", "width
|
|
316
|
+
["style", style_join("width" => "#{container_px}px", "padding-top" => wrapper_gap) + ";"],
|
|
145
317
|
["width", container_px.to_s]
|
|
146
318
|
]
|
|
147
319
|
before_pairs << ["bgcolor", bg_color] if bg_color
|
|
148
320
|
|
|
149
321
|
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]-->)
|
|
150
322
|
|
|
151
|
-
# Section div, table, td
|
|
152
|
-
div_style = style_join(
|
|
153
|
-
"background" => bg_color,
|
|
154
|
-
"background-color" => bg_color,
|
|
155
|
-
"margin" => "0px auto",
|
|
156
|
-
"max-width" => "#{container_px}px"
|
|
157
|
-
)
|
|
158
|
-
|
|
323
|
+
# Section div, table, td — styles differ based on background-url presence
|
|
159
324
|
border_val = a["border"]
|
|
160
325
|
border_val = nil if border_val.nil? || border_val.to_s.strip.empty? || border_val.to_s.strip == "none"
|
|
161
326
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
327
|
+
if bg_has
|
|
328
|
+
bg_value = get_background(a)
|
|
329
|
+
bg_string = get_background_string(a)
|
|
330
|
+
bg_repeat = a["background-repeat"]
|
|
331
|
+
bg_size = a["background-size"]
|
|
332
|
+
|
|
333
|
+
div_style = style_join(
|
|
334
|
+
"background" => bg_value,
|
|
335
|
+
"background-position" => bg_string,
|
|
336
|
+
"background-repeat" => bg_repeat,
|
|
337
|
+
"background-size" => bg_size,
|
|
338
|
+
"margin" => "0px auto",
|
|
339
|
+
"margin-top" => wrapper_gap,
|
|
340
|
+
"max-width" => "#{container_px}px"
|
|
341
|
+
)
|
|
342
|
+
table_style = style_join(
|
|
343
|
+
"background" => bg_value,
|
|
344
|
+
"background-position" => bg_string,
|
|
345
|
+
"background-repeat" => bg_repeat,
|
|
346
|
+
"background-size" => bg_size,
|
|
347
|
+
"border-radius" => border_radius,
|
|
348
|
+
"width" => "100%"
|
|
349
|
+
)
|
|
350
|
+
td_style = style_join(
|
|
351
|
+
"border" => border_val,
|
|
352
|
+
"border-top" => a["border-top"],
|
|
353
|
+
"border-right" => a["border-right"],
|
|
354
|
+
"border-bottom" => a["border-bottom"],
|
|
355
|
+
"border-left" => a["border-left"],
|
|
356
|
+
"border-radius" => border_radius,
|
|
357
|
+
"direction" => a["direction"],
|
|
358
|
+
"font-size" => "0px",
|
|
359
|
+
"padding" => a["padding"],
|
|
360
|
+
"padding-top" => a["padding-top"],
|
|
361
|
+
"padding-right" => a["padding-right"],
|
|
362
|
+
"padding-bottom" => a["padding-bottom"],
|
|
363
|
+
"padding-left" => a["padding-left"],
|
|
364
|
+
"text-align" => a["text-align"]
|
|
365
|
+
)
|
|
366
|
+
else
|
|
367
|
+
div_style = style_join(
|
|
368
|
+
"background" => bg_color,
|
|
369
|
+
"background-color" => bg_color,
|
|
370
|
+
"margin" => "0px auto",
|
|
371
|
+
"margin-top" => wrapper_gap,
|
|
372
|
+
"max-width" => "#{container_px}px"
|
|
373
|
+
)
|
|
374
|
+
table_style = style_join(
|
|
375
|
+
"background" => bg_color,
|
|
376
|
+
"background-color" => bg_color,
|
|
377
|
+
"border-radius" => border_radius,
|
|
378
|
+
"width" => "100%"
|
|
379
|
+
)
|
|
380
|
+
td_style = style_join(
|
|
381
|
+
"border" => border_val,
|
|
382
|
+
"border-top" => a["border-top"],
|
|
383
|
+
"border-right" => a["border-right"],
|
|
384
|
+
"border-bottom" => a["border-bottom"],
|
|
385
|
+
"border-left" => a["border-left"],
|
|
386
|
+
"border-radius" => border_radius,
|
|
387
|
+
"background" => bg_color,
|
|
388
|
+
"background-color" => bg_color,
|
|
389
|
+
"direction" => a["direction"],
|
|
390
|
+
"font-size" => "0px",
|
|
391
|
+
"padding" => a["padding"],
|
|
392
|
+
"padding-top" => a["padding-top"],
|
|
393
|
+
"padding-right" => a["padding-right"],
|
|
394
|
+
"padding-bottom" => a["padding-bottom"],
|
|
395
|
+
"padding-left" => a["padding-left"],
|
|
396
|
+
"text-align" => a["text-align"]
|
|
397
|
+
)
|
|
398
|
+
end
|
|
187
399
|
|
|
188
400
|
div_attrs = {"class" => css_class, "style" => div_style}
|
|
189
401
|
table_attrs = {
|
|
190
402
|
"align" => "center",
|
|
403
|
+
"background" => bg_has ? a["background-url"] : nil,
|
|
191
404
|
"border" => "0",
|
|
192
405
|
"cellpadding" => "0",
|
|
193
406
|
"cellspacing" => "0",
|
|
@@ -202,14 +415,19 @@ module MjmlRb
|
|
|
202
415
|
}
|
|
203
416
|
inner = merge_outlook_conditionals(render_section_columns(node, context, box_width))
|
|
204
417
|
|
|
418
|
+
# Wrap in innerDiv when background image is present (prevents Yahoo whitespace gaps)
|
|
419
|
+
inner_content = bg_has ? %(<div style="line-height:0;font-size:0">#{inner}</div>) : inner
|
|
420
|
+
|
|
205
421
|
section_html =
|
|
206
422
|
%(<div#{html_attrs(div_attrs)}>) +
|
|
207
423
|
%(<table#{html_attrs(table_attrs)}>) +
|
|
208
|
-
%(<tbody><tr><td#{html_attrs(td_attrs)}>#{
|
|
424
|
+
%(<tbody><tr><td#{html_attrs(td_attrs)}>#{inner_content}</td></tr></tbody></table></div>)
|
|
209
425
|
|
|
210
426
|
render_after = %(<!--[if mso | IE]></td></tr></table><![endif]-->)
|
|
211
427
|
|
|
212
|
-
|
|
428
|
+
body = bg_has ? render_with_background(section_html, a, container_px) : section_html
|
|
429
|
+
|
|
430
|
+
"#{render_before}\n#{body}\n#{render_after}"
|
|
213
431
|
end
|
|
214
432
|
|
|
215
433
|
# Generate Outlook IE conditional wrappers around each column/group.
|
|
@@ -251,6 +469,7 @@ module MjmlRb
|
|
|
251
469
|
css_class = a["css-class"]
|
|
252
470
|
bg_color = a["background-color"]
|
|
253
471
|
full_width = a["full-width"] == "full-width"
|
|
472
|
+
wrapper_gap = context[:_wrapper_child_gap]
|
|
254
473
|
|
|
255
474
|
# renderBefore — same structure as section
|
|
256
475
|
outlook_class = css_class ? "#{css_class}-outlook" : ""
|
|
@@ -261,7 +480,7 @@ module MjmlRb
|
|
|
261
480
|
["cellspacing", "0"],
|
|
262
481
|
["class", outlook_class],
|
|
263
482
|
["role", "presentation"],
|
|
264
|
-
["style", "width
|
|
483
|
+
["style", style_join("width" => "#{container_px}px", "padding-top" => wrapper_gap) + ";"],
|
|
265
484
|
["width", container_px.to_s]
|
|
266
485
|
]
|
|
267
486
|
before_pairs << ["bgcolor", bg_color] if bg_color
|
|
@@ -272,6 +491,7 @@ module MjmlRb
|
|
|
272
491
|
"background" => bg_color,
|
|
273
492
|
"background-color" => bg_color,
|
|
274
493
|
"margin" => "0px auto",
|
|
494
|
+
"margin-top" => wrapper_gap,
|
|
275
495
|
"max-width" => (full_width ? nil : "#{container_px}px")
|
|
276
496
|
)
|
|
277
497
|
|
|
@@ -293,7 +513,7 @@ module MjmlRb
|
|
|
293
513
|
)
|
|
294
514
|
|
|
295
515
|
div_attrs = {"class" => css_class, "style" => div_style}
|
|
296
|
-
inner = merge_outlook_conditionals(render_wrapped_children_wrapper(node, context, container_px))
|
|
516
|
+
inner = merge_outlook_conditionals(render_wrapped_children_wrapper(node, context, container_px, a["gap"]))
|
|
297
517
|
|
|
298
518
|
wrapper_html =
|
|
299
519
|
%(<div#{html_attrs(div_attrs)}>) +
|
|
@@ -306,7 +526,7 @@ module MjmlRb
|
|
|
306
526
|
end
|
|
307
527
|
|
|
308
528
|
# Wrap each child mj-section/mj-wrapper in an Outlook conditional <td>.
|
|
309
|
-
def render_wrapped_children_wrapper(node, context, container_px)
|
|
529
|
+
def render_wrapped_children_wrapper(node, context, container_px, gap)
|
|
310
530
|
children = node.element_children.select { |e| %w[mj-section mj-wrapper].include?(e.tag_name) }
|
|
311
531
|
return render_children(node, context, parent: "mj-wrapper") if children.empty?
|
|
312
532
|
|
|
@@ -316,16 +536,26 @@ module MjmlRb
|
|
|
316
536
|
close_table = %(<!--[if mso | IE]></table><![endif]-->)
|
|
317
537
|
|
|
318
538
|
section_parts = with_inherited_mj_class(context, node) do
|
|
319
|
-
children.map do |child|
|
|
539
|
+
children.each_with_index.map do |child, index|
|
|
320
540
|
td_open = %(<!--[if mso | IE]><td class="" width="#{container_px}px" ><![endif]-->)
|
|
321
541
|
td_close = %(<!--[if mso | IE]></td><![endif]-->)
|
|
322
|
-
child_html =
|
|
542
|
+
child_html = with_wrapper_child_gap(context, index.zero? ? nil : gap) do
|
|
543
|
+
render_node(child, context, parent: "mj-wrapper")
|
|
544
|
+
end
|
|
323
545
|
"#{td_open}\n#{child_html}\n#{td_close}"
|
|
324
546
|
end
|
|
325
547
|
end
|
|
326
548
|
|
|
327
549
|
([open_table, open_tr] + section_parts + [close_tr, close_table]).join("\n")
|
|
328
550
|
end
|
|
551
|
+
|
|
552
|
+
def with_wrapper_child_gap(context, gap)
|
|
553
|
+
previous = context[:_wrapper_child_gap]
|
|
554
|
+
context[:_wrapper_child_gap] = gap
|
|
555
|
+
yield
|
|
556
|
+
ensure
|
|
557
|
+
context[:_wrapper_child_gap] = previous
|
|
558
|
+
end
|
|
329
559
|
end
|
|
330
560
|
end
|
|
331
561
|
end
|
|
@@ -5,6 +5,28 @@ module MjmlRb
|
|
|
5
5
|
class Text < Base
|
|
6
6
|
TAGS = ["mj-text"].freeze
|
|
7
7
|
|
|
8
|
+
ALLOWED_ATTRIBUTES = {
|
|
9
|
+
"align" => "enum(left,right,center,justify)",
|
|
10
|
+
"background-color" => "color",
|
|
11
|
+
"color" => "color",
|
|
12
|
+
"container-background-color" => "color",
|
|
13
|
+
"font-family" => "string",
|
|
14
|
+
"font-size" => "string",
|
|
15
|
+
"font-style" => "string",
|
|
16
|
+
"font-weight" => "string",
|
|
17
|
+
"height" => "string",
|
|
18
|
+
"letter-spacing" => "string",
|
|
19
|
+
"line-height" => "string",
|
|
20
|
+
"padding" => "unit(px,%){1,4}",
|
|
21
|
+
"padding-top" => "unit(px,%)",
|
|
22
|
+
"padding-right" => "unit(px,%)",
|
|
23
|
+
"padding-bottom" => "unit(px,%)",
|
|
24
|
+
"padding-left" => "unit(px,%)",
|
|
25
|
+
"text-decoration" => "string",
|
|
26
|
+
"text-transform" => "string",
|
|
27
|
+
"vertical-align" => "enum(top,bottom,middle)"
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
8
30
|
DEFAULTS = {
|
|
9
31
|
"align" => "left",
|
|
10
32
|
"color" => "#000000",
|
|
@@ -40,6 +62,7 @@ module MjmlRb
|
|
|
40
62
|
}
|
|
41
63
|
|
|
42
64
|
div_style = style_join(
|
|
65
|
+
"background-color" => a["background-color"],
|
|
43
66
|
"font-family" => a["font-family"],
|
|
44
67
|
"font-size" => a["font-size"],
|
|
45
68
|
"font-style" => a["font-style"],
|
data/lib/mjml-rb/version.rb
CHANGED