email-builder-utils 1.1.42 → 1.1.44
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.
- package/dist/utils/convertJsonToHtml.d.ts.map +1 -1
- package/dist/utils/convertJsonToHtml.js +90 -83
- package/dist/utils/jsonToHTML.d.ts.map +1 -1
- package/dist/utils/jsonToHTML.js +556 -473
- package/dist/utils/outlookSupport.d.ts +210 -0
- package/dist/utils/outlookSupport.d.ts.map +1 -0
- package/dist/utils/outlookSupport.js +479 -0
- package/package.json +34 -33
package/dist/utils/jsonToHTML.js
CHANGED
|
@@ -15,6 +15,11 @@ const addPxToAttributes = [
|
|
|
15
15
|
const addPxOrPerToAttributes = ["width", "height"];
|
|
16
16
|
const allPxAttributes = [...addPxToAttributes, ...addPxOrPerToAttributes];
|
|
17
17
|
exports.tableCommonStyle = "border-collapse:collapse; table-layout:fixed;";
|
|
18
|
+
function encodeBlockProps(props) {
|
|
19
|
+
return JSON.stringify(props)
|
|
20
|
+
.replace(/&/g, '&')
|
|
21
|
+
.replace(/"/g, '"');
|
|
22
|
+
}
|
|
18
23
|
async function loadImageNaturalDimensions(imageUrl) {
|
|
19
24
|
return new Promise((resolve, reject) => {
|
|
20
25
|
const img = new Image();
|
|
@@ -58,13 +63,13 @@ function buildStyles(style, { pxChanges, perChanges }) {
|
|
|
58
63
|
};
|
|
59
64
|
value = `${safePad.top}px ${safePad.right}px ${safePad.bottom}px ${safePad.left}px`;
|
|
60
65
|
}
|
|
61
|
-
// Sanitize fontFamily: replace double quotes with single quotes to avoid
|
|
62
|
-
// breaking the surrounding style="..." HTML attribute
|
|
63
66
|
if (key === "fontFamily" && typeof value === "string") {
|
|
64
67
|
value = (0, fontFallback_1.withFontFallback)(value).replace(/"/g, "'");
|
|
65
68
|
}
|
|
66
|
-
// Wrap backgroundImage values in url() if not already wrapped
|
|
67
|
-
if (key === "backgroundImage" && typeof value === "string"
|
|
69
|
+
// Wrap backgroundImage values in url() if not already wrapped — skip gradients
|
|
70
|
+
if (key === "backgroundImage" && typeof value === "string"
|
|
71
|
+
&& !String(value).startsWith("url(")
|
|
72
|
+
&& !String(value).toLowerCase().includes("gradient(")) {
|
|
68
73
|
value = `url('${value}')`;
|
|
69
74
|
}
|
|
70
75
|
// lineHeight: values >= 4 are pixel values; smaller values are unitless multipliers (e.g. 1.5)
|
|
@@ -104,7 +109,7 @@ function buildStyles(style, { pxChanges, perChanges }) {
|
|
|
104
109
|
.map(([k, v]) => `${k}:${v}`);
|
|
105
110
|
if (style.customCss)
|
|
106
111
|
parts.push(style.customCss);
|
|
107
|
-
return parts.join('; ').trim();
|
|
112
|
+
return parts.join('; ').replace(/;\s*$/, '').trim();
|
|
108
113
|
}
|
|
109
114
|
async function convertToHtml(blockData, rootData, cellWidthInPx) {
|
|
110
115
|
switch (blockData.type) {
|
|
@@ -134,32 +139,32 @@ function appendOutlookSupport(content, contentStyle, className, msoWidth) {
|
|
|
134
139
|
const visibilityClass = className || "";
|
|
135
140
|
const shouldHideInOutlook = visibilityClass.includes("hide-desktop");
|
|
136
141
|
if (shouldHideInOutlook) {
|
|
137
|
-
return `
|
|
138
|
-
<!--[if !mso]><!-->
|
|
139
|
-
<table width="100%" style="${exports.tableCommonStyle}" class="${visibilityClass}"><tr><td style="${contentStyle}">${content}</td></tr></table>
|
|
140
|
-
<!--<![endif]-->
|
|
142
|
+
return `
|
|
143
|
+
<!--[if !mso]><!-->
|
|
144
|
+
<table width="100%" style="${exports.tableCommonStyle}" class="${visibilityClass}"><tr><td style="${contentStyle}">${content}</td></tr></table>
|
|
145
|
+
<!--<![endif]-->
|
|
141
146
|
`;
|
|
142
147
|
}
|
|
143
148
|
// When an explicit pixel width is provided (e.g. inside a column cell), use dual MSO/non-MSO
|
|
144
149
|
// tables. Old Outlook (Word engine) ignores max-width and can resolve width="100%" to the
|
|
145
150
|
// full email width (600px) rather than the column width, causing images/buttons to expand.
|
|
146
151
|
if (msoWidth) {
|
|
147
|
-
return `
|
|
148
|
-
<!--[if mso]>
|
|
149
|
-
<table border="0" cellpadding="0" cellspacing="0" width="${msoWidth}" style="border-collapse:collapse;width:${msoWidth}px;"><tr><td width="${msoWidth}" style="${contentStyle}">
|
|
150
|
-
<![endif]-->
|
|
151
|
-
<!--[if !mso]><!-->
|
|
152
|
-
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="${exports.tableCommonStyle}; max-width:600px;" class="${visibilityClass}"><tr><td width="100%" style="${contentStyle}">
|
|
153
|
-
<!--<![endif]-->
|
|
154
|
-
${content}
|
|
155
|
-
<!--[if mso]></td></tr></table><![endif]-->
|
|
156
|
-
<!--[if !mso]><!-->
|
|
157
|
-
</td></tr></table>
|
|
158
|
-
<!--<![endif]-->
|
|
152
|
+
return `
|
|
153
|
+
<!--[if mso]>
|
|
154
|
+
<table border="0" cellpadding="0" cellspacing="0" width="${msoWidth}" style="border-collapse:collapse;width:${msoWidth}px;"><tr><td width="${msoWidth}" style="${contentStyle}">
|
|
155
|
+
<![endif]-->
|
|
156
|
+
<!--[if !mso]><!-->
|
|
157
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="${exports.tableCommonStyle}; max-width:600px;" class="${visibilityClass}"><tr><td width="100%" style="${contentStyle}">
|
|
158
|
+
<!--<![endif]-->
|
|
159
|
+
${content}
|
|
160
|
+
<!--[if mso]></td></tr></table><![endif]-->
|
|
161
|
+
<!--[if !mso]><!-->
|
|
162
|
+
</td></tr></table>
|
|
163
|
+
<!--<![endif]-->
|
|
159
164
|
`;
|
|
160
165
|
}
|
|
161
|
-
return `
|
|
162
|
-
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="${exports.tableCommonStyle}; max-width:600px;" class="${visibilityClass}"><tr><td width="100%" style="${contentStyle}">${content}</td></tr></table>
|
|
166
|
+
return `
|
|
167
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="${exports.tableCommonStyle}; max-width:600px;" class="${visibilityClass}"><tr><td width="100%" style="${contentStyle}">${content}</td></tr></table>
|
|
163
168
|
`;
|
|
164
169
|
}
|
|
165
170
|
function convertDividerBlockToHtml(blockData) {
|
|
@@ -178,21 +183,21 @@ function convertDividerBlockToHtml(blockData) {
|
|
|
178
183
|
]
|
|
179
184
|
.filter(Boolean)
|
|
180
185
|
.join(" ");
|
|
181
|
-
const dividerContent = `
|
|
182
|
-
<table
|
|
183
|
-
width="${dividerWidth}%"
|
|
184
|
-
cellpadding="0"
|
|
185
|
-
cellspacing="0"
|
|
186
|
-
>
|
|
187
|
-
<tr>
|
|
188
|
-
<td
|
|
189
|
-
height="${thickness}"
|
|
190
|
-
style="font-size:1px; line-height:1px; background:${dividerColor}; width:${dividerWidth};"
|
|
191
|
-
>
|
|
192
|
-
|
|
193
|
-
</td>
|
|
194
|
-
</tr>
|
|
195
|
-
</table>
|
|
186
|
+
const dividerContent = `
|
|
187
|
+
<table
|
|
188
|
+
width="${dividerWidth}%"
|
|
189
|
+
cellpadding="0"
|
|
190
|
+
cellspacing="0"
|
|
191
|
+
>
|
|
192
|
+
<tr>
|
|
193
|
+
<td
|
|
194
|
+
height="${thickness}"
|
|
195
|
+
style="font-size:1px; line-height:1px; background:${dividerColor}; width:${dividerWidth};"
|
|
196
|
+
>
|
|
197
|
+
|
|
198
|
+
</td>
|
|
199
|
+
</tr>
|
|
200
|
+
</table>
|
|
196
201
|
`;
|
|
197
202
|
return appendOutlookSupport(dividerContent, convertedStyle, visibilityClass);
|
|
198
203
|
}
|
|
@@ -287,21 +292,21 @@ async function appendOutlookForImage(content, outerContainerWidth, innerContaine
|
|
|
287
292
|
if (useRoundRect && borderRadius > 0) {
|
|
288
293
|
// Use VML for border radius - wrap in table to constrain width for Old Outlook (Word engine)
|
|
289
294
|
// Use aspect="atmost" to prevent image from stretching beyond its bounds
|
|
290
|
-
outlookImage = `<!--[if mso]>
|
|
291
|
-
<table border="0" cellpadding="0" cellspacing="0" width="${vmlWidth}" style="width:${vmlWidth}px;">
|
|
292
|
-
<tr>
|
|
293
|
-
<td align="center" valign="top" width="${vmlWidth}" style="width:${vmlWidth}px;">
|
|
294
|
-
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml"
|
|
295
|
-
style="width:${vmlWidth}px;height:${vmlHeight}px;"
|
|
296
|
-
${borderAttributes}
|
|
297
|
-
arcsize="${arcsize}"
|
|
298
|
-
fill="true" fillcolor="none">
|
|
299
|
-
<v:fill src="${imageUrl}" type="tile" aspect="atmost" />
|
|
300
|
-
<v:textbox inset="0,0,0,0"><div style="display:none;">.</div></v:textbox>
|
|
301
|
-
</v:roundrect>
|
|
302
|
-
</td>
|
|
303
|
-
</tr>
|
|
304
|
-
</table>
|
|
295
|
+
outlookImage = `<!--[if mso]>
|
|
296
|
+
<table border="0" cellpadding="0" cellspacing="0" width="${vmlWidth}" style="width:${vmlWidth}px;">
|
|
297
|
+
<tr>
|
|
298
|
+
<td align="center" valign="top" width="${vmlWidth}" style="width:${vmlWidth}px;">
|
|
299
|
+
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml"
|
|
300
|
+
style="width:${vmlWidth}px;height:${vmlHeight}px;"
|
|
301
|
+
${borderAttributes}
|
|
302
|
+
arcsize="${arcsize}"
|
|
303
|
+
fill="true" fillcolor="none">
|
|
304
|
+
<v:fill src="${imageUrl}" type="tile" aspect="atmost" />
|
|
305
|
+
<v:textbox inset="0,0,0,0"><div style="display:none;">.</div></v:textbox>
|
|
306
|
+
</v:roundrect>
|
|
307
|
+
</td>
|
|
308
|
+
</tr>
|
|
309
|
+
</table>
|
|
305
310
|
<![endif]-->`;
|
|
306
311
|
}
|
|
307
312
|
else {
|
|
@@ -310,21 +315,21 @@ async function appendOutlookForImage(content, outerContainerWidth, innerContaine
|
|
|
310
315
|
const borderStyleAttr = borderWidth > 0
|
|
311
316
|
? `border: ${borderWidth}px solid ${borderColor};`
|
|
312
317
|
: '';
|
|
313
|
-
outlookImage = `<!--[if mso]>
|
|
314
|
-
<table border="0" cellpadding="0" cellspacing="0" width="${vmlWidth}" style="width:${vmlWidth}px;">
|
|
315
|
-
<tr>
|
|
316
|
-
<td align="center" valign="top" width="${vmlWidth}" style="width:${vmlWidth}px;">
|
|
317
|
-
<img src="${imageUrl}" alt="Image" border="0" width="${vmlWidth}" height="${vmlHeight}" style="display:block; width:${vmlWidth}px; height:${vmlHeight}px; max-width:${vmlWidth}px; ${borderStyleAttr}" />
|
|
318
|
-
</td>
|
|
319
|
-
</tr>
|
|
320
|
-
</table>
|
|
318
|
+
outlookImage = `<!--[if mso]>
|
|
319
|
+
<table border="0" cellpadding="0" cellspacing="0" width="${vmlWidth}" style="width:${vmlWidth}px;">
|
|
320
|
+
<tr>
|
|
321
|
+
<td align="center" valign="top" width="${vmlWidth}" style="width:${vmlWidth}px;">
|
|
322
|
+
<img src="${imageUrl}" alt="Image" border="0" width="${vmlWidth}" height="${vmlHeight}" style="display:block; width:${vmlWidth}px; height:${vmlHeight}px; max-width:${vmlWidth}px; ${borderStyleAttr}" />
|
|
323
|
+
</td>
|
|
324
|
+
</tr>
|
|
325
|
+
</table>
|
|
321
326
|
<![endif]-->`;
|
|
322
327
|
}
|
|
323
|
-
return `
|
|
324
|
-
${outlookImage}
|
|
325
|
-
<!--[if !mso]><!-->
|
|
326
|
-
${content}
|
|
327
|
-
<!--<![endif]-->
|
|
328
|
+
return `
|
|
329
|
+
${outlookImage}
|
|
330
|
+
<!--[if !mso]><!-->
|
|
331
|
+
${content}
|
|
332
|
+
<!--<![endif]-->
|
|
328
333
|
`;
|
|
329
334
|
}
|
|
330
335
|
async function computeScaledDimensions(imageUrl, maxContainerWidthPx) {
|
|
@@ -435,51 +440,51 @@ function appendOutlookForButton(content, buttonStyle, navigateToUrl, text) {
|
|
|
435
440
|
const width = typeof buttonStyle.width === "number"
|
|
436
441
|
? `width="${buttonStyle.width}"`
|
|
437
442
|
: "";
|
|
438
|
-
return `<!--[if mso]>
|
|
439
|
-
<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="display:inline-table;">
|
|
440
|
-
<tr>
|
|
441
|
-
<td align="center"
|
|
442
|
-
valign="middle"
|
|
443
|
-
${width}
|
|
444
|
-
${finalHeight ? `height="${finalHeight}"` : ""}
|
|
445
|
-
bgcolor="${bgColor}"
|
|
446
|
-
style="
|
|
447
|
-
${finalHeight ? `height:${finalHeight}px;` : ""}
|
|
448
|
-
background-color:${bgColor};
|
|
449
|
-
border-radius:${borderRadius}px;
|
|
450
|
-
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
451
|
-
overflow:hidden;
|
|
452
|
-
mso-line-height-rule:exactly;
|
|
453
|
-
">
|
|
454
|
-
|
|
455
|
-
<table role="presentation" cellspacing="0" cellpadding="0" border="0">
|
|
456
|
-
<tr>
|
|
457
|
-
<td align="center" valign="middle"
|
|
458
|
-
style="padding:${padTop}px ${padRight}px ${padBottom}px ${padLeft}px;">
|
|
459
|
-
|
|
460
|
-
<a href="${navigateToUrl}"
|
|
461
|
-
style="
|
|
462
|
-
display:inline-block;
|
|
463
|
-
color:${color};
|
|
464
|
-
text-decoration:none;
|
|
465
|
-
font-family:${fontFamily};
|
|
466
|
-
font-size:${fontSize}px;
|
|
467
|
-
font-weight:${fontWeight};
|
|
468
|
-
line-height:normal;
|
|
469
|
-
">
|
|
470
|
-
${text}
|
|
471
|
-
</a>
|
|
472
|
-
|
|
473
|
-
</td>
|
|
474
|
-
</tr>
|
|
475
|
-
</table>
|
|
476
|
-
|
|
477
|
-
</td>
|
|
478
|
-
</tr>
|
|
479
|
-
</table>
|
|
480
|
-
<![endif]-->
|
|
481
|
-
<!--[if !mso]><!-->
|
|
482
|
-
${content}
|
|
443
|
+
return `<!--[if mso]>
|
|
444
|
+
<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="display:inline-table;">
|
|
445
|
+
<tr>
|
|
446
|
+
<td align="center"
|
|
447
|
+
valign="middle"
|
|
448
|
+
${width}
|
|
449
|
+
${finalHeight ? `height="${finalHeight}"` : ""}
|
|
450
|
+
bgcolor="${bgColor}"
|
|
451
|
+
style="
|
|
452
|
+
${finalHeight ? `height:${finalHeight}px;` : ""}
|
|
453
|
+
background-color:${bgColor};
|
|
454
|
+
border-radius:${borderRadius}px;
|
|
455
|
+
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
456
|
+
overflow:hidden;
|
|
457
|
+
mso-line-height-rule:exactly;
|
|
458
|
+
">
|
|
459
|
+
|
|
460
|
+
<table role="presentation" cellspacing="0" cellpadding="0" border="0">
|
|
461
|
+
<tr>
|
|
462
|
+
<td align="center" valign="middle"
|
|
463
|
+
style="padding:${padTop}px ${padRight}px ${padBottom}px ${padLeft}px;">
|
|
464
|
+
|
|
465
|
+
<a href="${navigateToUrl}"
|
|
466
|
+
style="
|
|
467
|
+
display:inline-block;
|
|
468
|
+
color:${color};
|
|
469
|
+
text-decoration:none;
|
|
470
|
+
font-family:${fontFamily};
|
|
471
|
+
font-size:${fontSize}px;
|
|
472
|
+
font-weight:${fontWeight};
|
|
473
|
+
line-height:normal;
|
|
474
|
+
">
|
|
475
|
+
${text}
|
|
476
|
+
</a>
|
|
477
|
+
|
|
478
|
+
</td>
|
|
479
|
+
</tr>
|
|
480
|
+
</table>
|
|
481
|
+
|
|
482
|
+
</td>
|
|
483
|
+
</tr>
|
|
484
|
+
</table>
|
|
485
|
+
<![endif]-->
|
|
486
|
+
<!--[if !mso]><!-->
|
|
487
|
+
${content}
|
|
483
488
|
<!--<![endif]-->`;
|
|
484
489
|
}
|
|
485
490
|
function convertButtonBlock(blockData) {
|
|
@@ -509,89 +514,139 @@ function convertButtonBlock(blockData) {
|
|
|
509
514
|
? `width="${width}"`
|
|
510
515
|
: "";
|
|
511
516
|
// ✅ FIX: no width=100% anywhere
|
|
512
|
-
const buttonTable = `
|
|
513
|
-
<table role="presentation" cellspacing="0" cellpadding="0" border="0"
|
|
514
|
-
style="display:inline-table; border-collapse:separate;"
|
|
515
|
-
${widthAttr}>
|
|
516
|
-
<tr>
|
|
517
|
-
<td
|
|
518
|
-
align="center"
|
|
519
|
-
valign="middle"
|
|
520
|
-
${finalHeight ? `height="${finalHeight}"` : ""}
|
|
521
|
-
style="
|
|
522
|
-
${finalHeight ? `height:${finalHeight}px;` : ""}
|
|
523
|
-
background-color:${bgColor};
|
|
524
|
-
border-radius:${br}px;
|
|
525
|
-
border:${bw}px ${bdStyle} ${bdColor};
|
|
526
|
-
overflow:hidden;
|
|
527
|
-
mso-line-height-rule:exactly;
|
|
528
|
-
"
|
|
529
|
-
>
|
|
530
|
-
|
|
531
|
-
<table role="presentation" cellspacing="0" cellpadding="0" border="0">
|
|
532
|
-
<tr>
|
|
533
|
-
<td align="center" valign="middle"
|
|
534
|
-
style="padding:${padTop}px ${padRight}px ${padBottom}px ${padLeft}px;">
|
|
535
|
-
|
|
536
|
-
<a href="${navigateToUrl}"
|
|
537
|
-
style="
|
|
538
|
-
display:inline-block;
|
|
539
|
-
color:${safeColor};
|
|
540
|
-
text-decoration:none;
|
|
541
|
-
font-family:${safeFF};
|
|
542
|
-
font-size:${fs}px;
|
|
543
|
-
font-weight:${fontWeight || 400};
|
|
544
|
-
line-height:normal;
|
|
545
|
-
white-space:nowrap;
|
|
546
|
-
">
|
|
547
|
-
${text}
|
|
548
|
-
</a>
|
|
549
|
-
|
|
550
|
-
</td>
|
|
551
|
-
</tr>
|
|
552
|
-
</table>
|
|
553
|
-
|
|
554
|
-
</td>
|
|
555
|
-
</tr>
|
|
556
|
-
</table>
|
|
517
|
+
const buttonTable = `
|
|
518
|
+
<table role="presentation" cellspacing="0" cellpadding="0" border="0"
|
|
519
|
+
style="display:inline-table; border-collapse:separate;"
|
|
520
|
+
${widthAttr}>
|
|
521
|
+
<tr>
|
|
522
|
+
<td
|
|
523
|
+
align="center"
|
|
524
|
+
valign="middle"
|
|
525
|
+
${finalHeight ? `height="${finalHeight}"` : ""}
|
|
526
|
+
style="
|
|
527
|
+
${finalHeight ? `height:${finalHeight}px;` : ""}
|
|
528
|
+
background-color:${bgColor};
|
|
529
|
+
border-radius:${br}px;
|
|
530
|
+
border:${bw}px ${bdStyle} ${bdColor};
|
|
531
|
+
overflow:hidden;
|
|
532
|
+
mso-line-height-rule:exactly;
|
|
533
|
+
"
|
|
534
|
+
>
|
|
535
|
+
|
|
536
|
+
<table role="presentation" cellspacing="0" cellpadding="0" border="0">
|
|
537
|
+
<tr>
|
|
538
|
+
<td align="center" valign="middle"
|
|
539
|
+
style="padding:${padTop}px ${padRight}px ${padBottom}px ${padLeft}px;">
|
|
540
|
+
|
|
541
|
+
<a href="${navigateToUrl}"
|
|
542
|
+
style="
|
|
543
|
+
display:inline-block;
|
|
544
|
+
color:${safeColor};
|
|
545
|
+
text-decoration:none;
|
|
546
|
+
font-family:${safeFF};
|
|
547
|
+
font-size:${fs}px;
|
|
548
|
+
font-weight:${fontWeight || 400};
|
|
549
|
+
line-height:normal;
|
|
550
|
+
white-space:nowrap;
|
|
551
|
+
">
|
|
552
|
+
${text}
|
|
553
|
+
</a>
|
|
554
|
+
|
|
555
|
+
</td>
|
|
556
|
+
</tr>
|
|
557
|
+
</table>
|
|
558
|
+
|
|
559
|
+
</td>
|
|
560
|
+
</tr>
|
|
561
|
+
</table>
|
|
557
562
|
`;
|
|
558
563
|
const aligned = containerAlign === "center"
|
|
559
564
|
? `<center>${buttonTable}</center>`
|
|
560
565
|
: `<div style="text-align:${containerAlign};">${buttonTable}</div>`;
|
|
561
566
|
const buttonWithOutlook = appendOutlookForButton(aligned, style, navigateToUrl, text);
|
|
562
|
-
return `
|
|
563
|
-
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
|
|
564
|
-
<tr>
|
|
565
|
-
<td align="${containerAlign}"
|
|
566
|
-
style="padding:${padding?.top || 0}px ${padding?.right || 0}px ${padding?.bottom || 0}px ${padding?.left || 0}px;
|
|
567
|
-
background-color:${containerBg || "transparent"};">
|
|
568
|
-
${buttonWithOutlook}
|
|
569
|
-
</td>
|
|
570
|
-
</tr>
|
|
571
|
-
</table>
|
|
567
|
+
return `
|
|
568
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
|
|
569
|
+
<tr>
|
|
570
|
+
<td align="${containerAlign}"
|
|
571
|
+
style="padding:${padding?.top || 0}px ${padding?.right || 0}px ${padding?.bottom || 0}px ${padding?.left || 0}px;
|
|
572
|
+
background-color:${containerBg || "transparent"};">
|
|
573
|
+
${buttonWithOutlook}
|
|
574
|
+
</td>
|
|
575
|
+
</tr>
|
|
576
|
+
</table>
|
|
572
577
|
`;
|
|
573
578
|
}
|
|
579
|
+
// Words inside a gradient() that are NOT color names
|
|
580
|
+
const GRADIENT_KEYWORDS = new Set([
|
|
581
|
+
'linear', 'radial', 'conic', 'gradient',
|
|
582
|
+
'to', 'at', 'top', 'bottom', 'left', 'right', 'center',
|
|
583
|
+
'closest', 'farthest', 'corner', 'side', 'circle', 'ellipse',
|
|
584
|
+
'deg', 'turn', 'rad', 'grad', 'from', 'in',
|
|
585
|
+
'url', // url() prefix sometimes appears when gradient is wrapped incorrectly
|
|
586
|
+
]);
|
|
587
|
+
/** Extract the first color stop (hex, rgb, or named CSS color) from a gradient string. */
|
|
588
|
+
function firstGradientColor(gradient) {
|
|
589
|
+
const tokenRe = /#[0-9a-fA-F]{3,8}|rgba?\([^)]+\)|([a-zA-Z-]+)/g;
|
|
590
|
+
let m;
|
|
591
|
+
while ((m = tokenRe.exec(gradient)) !== null) {
|
|
592
|
+
const namedWord = m[1];
|
|
593
|
+
if (namedWord) {
|
|
594
|
+
if (!GRADIENT_KEYWORDS.has(namedWord.toLowerCase()))
|
|
595
|
+
return namedWord;
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
return m[0]; // hex or rgb()
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return '';
|
|
602
|
+
}
|
|
574
603
|
/**
|
|
575
604
|
* Extract the first solid-color stop from a CSS gradient in customCss.
|
|
576
|
-
* Used as a MSO/Outlook bgcolor fallback
|
|
577
|
-
* but the block has a gradient in customCss (e.g. linear-gradient imports).
|
|
605
|
+
* Used as a MSO/Outlook bgcolor fallback. Handles hex, rgb, and named colors.
|
|
578
606
|
*/
|
|
579
607
|
function extractCssFallbackColor(customCss) {
|
|
580
608
|
if (!customCss)
|
|
581
609
|
return '';
|
|
582
|
-
const
|
|
583
|
-
|
|
610
|
+
const gradientMatch = customCss.match(/(?:linear|radial|conic)-gradient\(([^)]+(?:\([^)]*\)[^)]*)*)\)/);
|
|
611
|
+
if (!gradientMatch)
|
|
612
|
+
return '';
|
|
613
|
+
return firstGradientColor(gradientMatch[1]);
|
|
584
614
|
}
|
|
585
615
|
function parseGradient(gradient) {
|
|
586
616
|
if (!gradient)
|
|
587
617
|
return null;
|
|
588
|
-
const
|
|
589
|
-
|
|
590
|
-
const
|
|
618
|
+
const lower = gradient.toLowerCase();
|
|
619
|
+
// Determine angle from deg value or direction keyword
|
|
620
|
+
const degMatch = gradient.match(/(\d+(?:\.\d+)?)deg/);
|
|
621
|
+
let angle = 180;
|
|
622
|
+
if (degMatch) {
|
|
623
|
+
angle = parseFloat(degMatch[1]);
|
|
624
|
+
}
|
|
625
|
+
else if (lower.includes('to right'))
|
|
626
|
+
angle = 90;
|
|
627
|
+
else if (lower.includes('to left'))
|
|
628
|
+
angle = 270;
|
|
629
|
+
else if (lower.includes('to top'))
|
|
630
|
+
angle = 0;
|
|
631
|
+
// 'to bottom' and bare gradient() both default to 180
|
|
632
|
+
// Extract ALL color tokens: hex, rgb/rgba, and named CSS color words
|
|
633
|
+
const colors = [];
|
|
634
|
+
const tokenRe = /#[0-9a-fA-F]{3,8}|rgba?\([^)]+\)|([a-zA-Z-]+)/g;
|
|
635
|
+
let m;
|
|
636
|
+
while ((m = tokenRe.exec(gradient)) !== null) {
|
|
637
|
+
const namedWord = m[1];
|
|
638
|
+
if (namedWord) {
|
|
639
|
+
if (!GRADIENT_KEYWORDS.has(namedWord.toLowerCase()))
|
|
640
|
+
colors.push(namedWord);
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
colors.push(m[0]);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
591
646
|
return {
|
|
592
647
|
angle,
|
|
593
648
|
colors,
|
|
594
|
-
fallback: colors[0] ||
|
|
649
|
+
fallback: colors[0] || '#ffffff',
|
|
595
650
|
};
|
|
596
651
|
}
|
|
597
652
|
function cssAngleToVml(angle) {
|
|
@@ -602,18 +657,37 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
602
657
|
const { columns = 1, cellWidths = [], responsive = true } = props;
|
|
603
658
|
const { columnGap = 0, backgroundImage, backgroundColor, ...restStyle } = style;
|
|
604
659
|
const gridVisibilityClass = (0, common_1.getVisibilityClass)(props);
|
|
605
|
-
//
|
|
606
|
-
|
|
607
|
-
const
|
|
660
|
+
// Detect gradient — check both backgroundImage prop and customCss (gradient may land in
|
|
661
|
+
// customCss when the block was built via CSS shorthand or custom CSS input).
|
|
662
|
+
const bgImageStr = typeof backgroundImage === "string" ? backgroundImage : '';
|
|
663
|
+
const customCssStr = restStyle.customCss || '';
|
|
664
|
+
// Extract gradient string from customCss if not already in backgroundImage
|
|
665
|
+
const gradientInCustomCss = !bgImageStr.includes('gradient(') && customCssStr.includes('gradient(')
|
|
666
|
+
? (customCssStr.match(/(?:linear|radial|conic)-gradient\([^)]+(?:\([^)]*\)[^)]*)*\)/)?.[0] || '')
|
|
667
|
+
: '';
|
|
668
|
+
const effectiveGradient = bgImageStr.includes('gradient(')
|
|
669
|
+
? bgImageStr
|
|
670
|
+
: gradientInCustomCss;
|
|
671
|
+
const isGradient = Boolean(effectiveGradient);
|
|
672
|
+
const parsedGradient = isGradient ? parseGradient(effectiveGradient) : null;
|
|
608
673
|
const fallbackBgColor = backgroundColor ||
|
|
609
674
|
parsedGradient?.fallback ||
|
|
610
|
-
extractCssFallbackColor(
|
|
675
|
+
extractCssFallbackColor(customCssStr) ||
|
|
611
676
|
"#ffffff";
|
|
612
|
-
const rawBgImageUrl = !isGradient &&
|
|
613
|
-
?
|
|
677
|
+
const rawBgImageUrl = !isGradient && bgImageStr
|
|
678
|
+
? bgImageStr.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "")
|
|
614
679
|
: null;
|
|
615
|
-
//
|
|
616
|
-
|
|
680
|
+
// When gradient came from customCss, strip background-image from customCss so it
|
|
681
|
+
// doesn't duplicate into the inner table style (the outer <td> wrapper carries it).
|
|
682
|
+
const innerCustomCss = gradientInCustomCss
|
|
683
|
+
? customCssStr.replace(/background-image\s*:[^;]+;?/gi, '').trim()
|
|
684
|
+
: customCssStr;
|
|
685
|
+
// Build inner table styles — when gradient/bg-image is on the outer wrapper, strip
|
|
686
|
+
// background props from the inner table so the outer <td> background shows through.
|
|
687
|
+
const innerRestStyle = (rawBgImageUrl || isGradient)
|
|
688
|
+
? { ...restStyle, customCss: innerCustomCss, backgroundSize: undefined, backgroundPosition: undefined, backgroundRepeat: undefined }
|
|
689
|
+
: { ...restStyle, customCss: innerCustomCss };
|
|
690
|
+
const tableStyles = buildStyles({ backgroundColor: (rawBgImageUrl || isGradient) ? undefined : backgroundColor, ...innerRestStyle }, {
|
|
617
691
|
perChanges: [],
|
|
618
692
|
pxChanges: allPxAttributes,
|
|
619
693
|
});
|
|
@@ -621,48 +695,31 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
621
695
|
const visualRows = Math.ceil(total / columns);
|
|
622
696
|
// OUTLOOK FIX: Use explicit pixel width for Old Outlook (Word engine)
|
|
623
697
|
const msoTableWidth = Math.min(cellWidthInPx, 600);
|
|
624
|
-
// When a background image is present, the background is applied on an outer
|
|
625
|
-
// wrapper <td> (see bottom of function). The inner grid tables must be clean
|
|
626
|
-
//
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
? (backgroundColor || extractCssFallbackColor(restStyle.customCss))
|
|
698
|
+
// When a background image/gradient is present, the background is applied on an outer
|
|
699
|
+
// wrapper <td> (see bottom of function). The inner grid tables must be clean.
|
|
700
|
+
// When no background, the MSO table gets bgcolor for solid-color sections.
|
|
701
|
+
const msoBgColor = !rawBgImageUrl && !isGradient
|
|
702
|
+
? (backgroundColor || '')
|
|
630
703
|
: '';
|
|
631
704
|
const msoBgAttr = msoBgColor ? ` bgcolor="${msoBgColor}"` : '';
|
|
632
705
|
const msoBgStyle = msoBgColor ? `background-color:${msoBgColor};` : '';
|
|
633
|
-
// Inner
|
|
634
|
-
// wrapper is used. background-position/repeat/size without a background-image
|
|
635
|
-
// are harmless, but keeping them in the inner table style is confusing and
|
|
636
|
-
// could conflict with email client default styles.
|
|
637
|
-
const innerNonMsoStyle = rawBgImageUrl
|
|
638
|
-
? buildStyles({
|
|
639
|
-
...restStyle,
|
|
640
|
-
customCss: '',
|
|
641
|
-
backgroundSize: undefined,
|
|
642
|
-
backgroundPosition: undefined,
|
|
643
|
-
backgroundRepeat: undefined,
|
|
644
|
-
}, { perChanges: [], pxChanges: allPxAttributes })
|
|
645
|
-
: tableStyles;
|
|
646
|
-
// When bg image is present, inner tables must be explicitly transparent so the
|
|
647
|
-
// outer <td> background shows through (email clients may default table bg to white).
|
|
706
|
+
// Inner tables must be explicitly transparent when outer <td> carries the background.
|
|
648
707
|
const innerBgTransparent = (rawBgImageUrl || isGradient)
|
|
649
708
|
? 'background-color:transparent;'
|
|
650
709
|
: '';
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
class="${gridVisibilityClass}">
|
|
665
|
-
<!--<![endif]-->
|
|
710
|
+
const nonMsoBgAttr = !rawBgImageUrl && !isGradient && backgroundColor ? ` bgcolor="${backgroundColor}"` : '';
|
|
711
|
+
let html = `
|
|
712
|
+
<!--[if mso]>
|
|
713
|
+
<table border="0" cellpadding="0" cellspacing="0" width="${msoTableWidth}"${msoBgAttr}
|
|
714
|
+
style="border-collapse:collapse;width:${msoTableWidth}px;${msoBgStyle}${innerBgTransparent}"
|
|
715
|
+
class="${gridVisibilityClass}">
|
|
716
|
+
<![endif]-->
|
|
717
|
+
<!--[if !mso]><!-->
|
|
718
|
+
<table border="0" cellpadding="0" cellspacing="0" width="100%"
|
|
719
|
+
role="presentation"${nonMsoBgAttr}
|
|
720
|
+
style="border-collapse:collapse; ${innerBgTransparent}${tableStyles}; max-width:600px;"
|
|
721
|
+
class="${gridVisibilityClass}">
|
|
722
|
+
<!--<![endif]-->
|
|
666
723
|
`;
|
|
667
724
|
for (let r = 0; r < visualRows; r++) {
|
|
668
725
|
html += "<tr>";
|
|
@@ -721,13 +778,13 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
721
778
|
// compose paste (Word/Web editors strip CSS but keep bgcolor attribute).
|
|
722
779
|
const cellBgColor = cellStyle.backgroundColor || '';
|
|
723
780
|
const cellBgAttr = cellBgColor ? ` bgcolor="${cellBgColor}"` : '';
|
|
724
|
-
html += `
|
|
725
|
-
<td
|
|
726
|
-
width="${cellWidthPx}"${cellBgAttr}
|
|
727
|
-
class="${[responsive ? "stack-column" : "", visibilityClass].filter(Boolean).join(" ")}"
|
|
728
|
-
style="width:${cellWidthPx}px;vertical-align:${verticalAlign};word-break:break-word;${styles}"
|
|
729
|
-
>
|
|
730
|
-
${childHtml}
|
|
781
|
+
html += `
|
|
782
|
+
<td
|
|
783
|
+
width="${cellWidthPx}"${cellBgAttr}
|
|
784
|
+
class="${[responsive ? "stack-column" : "", visibilityClass].filter(Boolean).join(" ")}"
|
|
785
|
+
style="width:${cellWidthPx}px;vertical-align:${verticalAlign};word-break:break-word;${styles}"
|
|
786
|
+
>
|
|
787
|
+
${childHtml}
|
|
731
788
|
</td>`;
|
|
732
789
|
// Spacer td between columns — fixed pixel width, invisible to screen readers
|
|
733
790
|
if (columnGap > 0 && c !== lastVisibleCol) {
|
|
@@ -736,10 +793,10 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
736
793
|
}
|
|
737
794
|
}
|
|
738
795
|
else {
|
|
739
|
-
html += `
|
|
740
|
-
<td width="${cellWidthPx}"
|
|
741
|
-
${responsive ? 'class="stack-column"' : ""}
|
|
742
|
-
style="width:${cellWidthPx}px;vertical-align:top;">
|
|
796
|
+
html += `
|
|
797
|
+
<td width="${cellWidthPx}"
|
|
798
|
+
${responsive ? 'class="stack-column"' : ""}
|
|
799
|
+
style="width:${cellWidthPx}px;vertical-align:top;">
|
|
743
800
|
</td>`;
|
|
744
801
|
if (columnGap > 0 && c !== lastVisibleCol) {
|
|
745
802
|
html += `<td width="${columnGap}" style="width:${columnGap}px;font-size:0;line-height:0;padding:0;" aria-hidden="true"></td>`;
|
|
@@ -749,13 +806,13 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
749
806
|
html += "</tr>";
|
|
750
807
|
}
|
|
751
808
|
// Close both MSO and non-MSO tables
|
|
752
|
-
html += `
|
|
753
|
-
<!--[if mso]>
|
|
754
|
-
</table>
|
|
755
|
-
<![endif]-->
|
|
756
|
-
<!--[if !mso]><!-->
|
|
757
|
-
</table>
|
|
758
|
-
<!--<![endif]-->
|
|
809
|
+
html += `
|
|
810
|
+
<!--[if mso]>
|
|
811
|
+
</table>
|
|
812
|
+
<![endif]-->
|
|
813
|
+
<!--[if !mso]><!-->
|
|
814
|
+
</table>
|
|
815
|
+
<!--<![endif]-->
|
|
759
816
|
`;
|
|
760
817
|
// ── Background image: canonical multi-client approach ────────────────────
|
|
761
818
|
//
|
|
@@ -781,34 +838,34 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
781
838
|
return `<v:fill type="gradient" color="${c1}" color2="${c2}" angle="${vmlAngle}" />`;
|
|
782
839
|
})()
|
|
783
840
|
: `<v:fill type="frame" src="${rawBgImageUrl}" color="${fallbackBgColor}" />`;
|
|
784
|
-
html = `
|
|
785
|
-
<table border="0" cellpadding="0" cellspacing="0" width="${msoTableWidth}" role="presentation"
|
|
786
|
-
style="border-collapse:collapse;width:${msoTableWidth}px;">
|
|
787
|
-
<tr>
|
|
788
|
-
<td width="${msoTableWidth}" bgcolor="${fallbackBgColor}" valign="top"
|
|
789
|
-
style="
|
|
790
|
-
width:${msoTableWidth}px;
|
|
791
|
-
background-color:${fallbackBgColor};
|
|
792
|
-
${isGradient ? `background:${
|
|
793
|
-
">
|
|
794
|
-
|
|
795
|
-
<!--[if gte mso 9]>
|
|
796
|
-
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
|
|
797
|
-
fill="true" stroke="false"
|
|
798
|
-
style="width:${msoTableWidth}px;">
|
|
799
|
-
${vmlFill}
|
|
800
|
-
<v:textbox inset="0,0,0,0">
|
|
801
|
-
<![endif]-->
|
|
802
|
-
|
|
803
|
-
${html}
|
|
804
|
-
|
|
805
|
-
<!--[if gte mso 9]>
|
|
806
|
-
</v:textbox>
|
|
807
|
-
</v:rect>
|
|
808
|
-
<![endif]-->
|
|
809
|
-
|
|
810
|
-
</td>
|
|
811
|
-
</tr>
|
|
841
|
+
html = `
|
|
842
|
+
<table border="0" cellpadding="0" cellspacing="0" width="${msoTableWidth}" role="presentation"
|
|
843
|
+
style="border-collapse:collapse;width:${msoTableWidth}px;">
|
|
844
|
+
<tr>
|
|
845
|
+
<td width="${msoTableWidth}" bgcolor="${fallbackBgColor}" valign="top"
|
|
846
|
+
style="
|
|
847
|
+
width:${msoTableWidth}px;
|
|
848
|
+
background-color:${fallbackBgColor};
|
|
849
|
+
${isGradient ? `background:${effectiveGradient};` : `background:url('${rawBgImageUrl}') center/cover no-repeat;`}
|
|
850
|
+
">
|
|
851
|
+
|
|
852
|
+
<!--[if gte mso 9]>
|
|
853
|
+
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
|
|
854
|
+
fill="true" stroke="false"
|
|
855
|
+
style="width:${msoTableWidth}px;">
|
|
856
|
+
${vmlFill}
|
|
857
|
+
<v:textbox inset="0,0,0,0">
|
|
858
|
+
<![endif]-->
|
|
859
|
+
|
|
860
|
+
${html}
|
|
861
|
+
|
|
862
|
+
<!--[if gte mso 9]>
|
|
863
|
+
</v:textbox>
|
|
864
|
+
</v:rect>
|
|
865
|
+
<![endif]-->
|
|
866
|
+
|
|
867
|
+
</td>
|
|
868
|
+
</tr>
|
|
812
869
|
</table>`;
|
|
813
870
|
}
|
|
814
871
|
return html;
|
|
@@ -842,18 +899,18 @@ async function convertGridCellBlock(blockData, rootData, cellWidthPercent, paren
|
|
|
842
899
|
const borderRadius = style?.borderRadius || 0;
|
|
843
900
|
const bgColor = style?.backgroundColor || "transparent";
|
|
844
901
|
// IMPORTANT: radius only for non-Outlook
|
|
845
|
-
const wrapped = `
|
|
846
|
-
<!--[if !mso]><!-->
|
|
847
|
-
<div style="
|
|
848
|
-
border-radius:${borderRadius}px;
|
|
849
|
-
overflow:hidden;
|
|
850
|
-
background-color:${bgColor};
|
|
851
|
-
">
|
|
852
|
-
<!--<![endif]-->
|
|
853
|
-
${parts.join("")}
|
|
854
|
-
<!--[if !mso]><!-->
|
|
855
|
-
</div>
|
|
856
|
-
<!--<![endif]-->
|
|
902
|
+
const wrapped = `
|
|
903
|
+
<!--[if !mso]><!-->
|
|
904
|
+
<div style="
|
|
905
|
+
border-radius:${borderRadius}px;
|
|
906
|
+
overflow:hidden;
|
|
907
|
+
background-color:${bgColor};
|
|
908
|
+
">
|
|
909
|
+
<!--<![endif]-->
|
|
910
|
+
${parts.join("")}
|
|
911
|
+
<!--[if !mso]><!-->
|
|
912
|
+
</div>
|
|
913
|
+
<!--<![endif]-->
|
|
857
914
|
`;
|
|
858
915
|
return {
|
|
859
916
|
html: wrapped,
|
|
@@ -867,7 +924,9 @@ async function convertVideoBlock(blockData, cellWidthInPx) {
|
|
|
867
924
|
const { hideOnDesktop } = props; // Get the hideOnDesktop prop
|
|
868
925
|
const { videoUrl, youtubeVideoUrl, thumbnailUrl, altText } = props;
|
|
869
926
|
const videoLink = youtubeVideoUrl || videoUrl || "#";
|
|
870
|
-
|
|
927
|
+
// via.placeholder.com is defunct — use a data-URI grey box as the default thumbnail
|
|
928
|
+
const FALLBACK_THUMBNAIL = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='360'%3E%3Crect width='480' height='360' fill='%23cccccc'/%3E%3C/svg%3E`;
|
|
929
|
+
let resolvedThumbnail = thumbnailUrl || FALLBACK_THUMBNAIL;
|
|
871
930
|
if (youtubeVideoUrl) {
|
|
872
931
|
const youtubeId = (0, common_1.extractYouTubeId)(youtubeVideoUrl);
|
|
873
932
|
const vimeoId = (0, common_1.extractVimeoId)(youtubeVideoUrl);
|
|
@@ -921,117 +980,103 @@ async function convertVideoBlock(blockData, cellWidthInPx) {
|
|
|
921
980
|
const vmlTop = calculatedHeight / 2 - playIconHeight / 2;
|
|
922
981
|
const shouldHideInOutlook = hideOnDesktop;
|
|
923
982
|
const outlookVideoContent = shouldHideInOutlook
|
|
924
|
-
? `<!--[if !mso]><!-->
|
|
925
|
-
<v:group xmlns:v="urn:schemas-microsoft-com:vml"
|
|
926
|
-
coordsize="${innerContainerWidth},${calculatedHeight}"
|
|
927
|
-
href="${videoLink}"
|
|
928
|
-
style="width:${innerContainerWidth}px;height:${calculatedHeight}px;">
|
|
929
|
-
<v:rect fill="t" style="position:absolute;width:${innerContainerWidth}px;height:${calculatedHeight}px;"
|
|
930
|
-
strokeweight="${borderWidth}px"
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
</v:group>
|
|
983
|
+
? `<!--[if !mso]><!-->
|
|
984
|
+
<v:group xmlns:v="urn:schemas-microsoft-com:vml"
|
|
985
|
+
coordsize="${innerContainerWidth},${calculatedHeight}"
|
|
986
|
+
href="${videoLink}"
|
|
987
|
+
style="width:${innerContainerWidth}px;height:${calculatedHeight}px;">
|
|
988
|
+
<v:rect fill="t" style="position:absolute;width:${innerContainerWidth}px;height:${calculatedHeight}px;"
|
|
989
|
+
${borderWidth > 0 ? `stroked="t" strokeweight="${borderWidth}px" strokecolor="${borderColor}"` : `stroked="f"`}
|
|
990
|
+
${borderRadius > 0 ? `arcsize="${Math.min(borderRadius / calculatedHeight, 1).toFixed(2)}"` : ""}
|
|
991
|
+
>
|
|
992
|
+
<v:fill src="${resolvedThumbnail}" type="frame" color="${style?.backgroundColor || "#FFFFFF"}"/>
|
|
993
|
+
</v:rect>
|
|
994
|
+
<v:shape type="#_x0000_t75"
|
|
995
|
+
style="position:absolute;
|
|
996
|
+
left:${vmlLeft.toFixed(1)}px;
|
|
997
|
+
top:${vmlTop.toFixed(1)}px;
|
|
998
|
+
width:${playIconWidth}px;
|
|
999
|
+
height:${playIconHeight}px;"
|
|
1000
|
+
alt="Play" href="${videoLink}" title="${altText || "Video"}"
|
|
1001
|
+
stroked="f" filled="t">
|
|
1002
|
+
<v:imagedata src="https://app-rsrc.getbee.io/public/resources/components/widgetBar/video-content-icon-sets/light/type-01.png" />
|
|
1003
|
+
</v:shape>
|
|
1004
|
+
</v:group>
|
|
947
1005
|
<!--<![endif]-->`
|
|
948
|
-
: `<!--[if mso]>
|
|
949
|
-
<v:group xmlns:v="urn:schemas-microsoft-com:vml"
|
|
950
|
-
coordsize="${innerContainerWidth},${calculatedHeight}"
|
|
951
|
-
href="${videoLink}"
|
|
952
|
-
style="width:${innerContainerWidth}px;height:${calculatedHeight}px;">
|
|
953
|
-
<v:rect fill="t" style="position:absolute;width:${innerContainerWidth}px;height:${calculatedHeight}px;"
|
|
954
|
-
stroked="t"
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
${
|
|
958
|
-
>
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
</v:shape>
|
|
971
|
-
</v:group>
|
|
1006
|
+
: `<!--[if mso]>
|
|
1007
|
+
<v:group xmlns:v="urn:schemas-microsoft-com:vml"
|
|
1008
|
+
coordsize="${innerContainerWidth},${calculatedHeight}"
|
|
1009
|
+
href="${videoLink}"
|
|
1010
|
+
style="width:${innerContainerWidth}px;height:${calculatedHeight}px;">
|
|
1011
|
+
<v:rect fill="t" style="position:absolute;width:${innerContainerWidth}px;height:${calculatedHeight}px;"
|
|
1012
|
+
${borderWidth > 0 ? `stroked="t" strokeweight="${borderWidth}px" strokecolor="${borderColor}"` : `stroked="f"`}
|
|
1013
|
+
${borderRadius > 0 ? `arcsize="${Math.min(borderRadius / calculatedHeight, 1).toFixed(2)}"` : ""}
|
|
1014
|
+
>
|
|
1015
|
+
<v:fill src="${resolvedThumbnail}" type="frame" color="${style?.backgroundColor || "#FFFFFF"}"/>
|
|
1016
|
+
</v:rect>
|
|
1017
|
+
<v:shape type="#_x0000_t75"
|
|
1018
|
+
style="position:absolute;
|
|
1019
|
+
left:${vmlLeft.toFixed(1)}px;
|
|
1020
|
+
top:${vmlTop.toFixed(1)}px;
|
|
1021
|
+
width:${playIconWidth}px;
|
|
1022
|
+
height:${playIconHeight}px;"
|
|
1023
|
+
alt="Play" href="${videoLink}" title="${altText || "Video"}"
|
|
1024
|
+
stroked="f" filled="t">
|
|
1025
|
+
<v:imagedata src="https://app-rsrc.getbee.io/public/resources/components/widgetBar/video-content-icon-sets/light/type-01.png" />
|
|
1026
|
+
</v:shape>
|
|
1027
|
+
</v:group>
|
|
972
1028
|
<![endif]-->`;
|
|
973
|
-
|
|
974
|
-
<table
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
style="display: block;
|
|
1003
|
-
border: 0;
|
|
1004
|
-
outline: none;
|
|
1005
|
-
text-decoration: none;
|
|
1006
|
-
height: auto;"
|
|
1007
|
-
/>
|
|
1008
|
-
</a>
|
|
1009
|
-
</td>
|
|
1010
|
-
</tr>
|
|
1011
|
-
</table>
|
|
1012
|
-
<!--<![endif]-->`;
|
|
1029
|
+
// Non-Outlook: use a real <img> for the thumbnail so it renders in Gmail / Yahoo / webmail.
|
|
1030
|
+
// background-image on <table> is stripped by virtually every email client.
|
|
1031
|
+
// position:absolute for the play-button overlay is safe here because this block
|
|
1032
|
+
// is already inside <!--[if !mso]> — Outlook is handled separately via VML above.
|
|
1033
|
+
const thumbnailW = Math.round(innerContainerWidth);
|
|
1034
|
+
const thumbnailH = Math.round(calculatedHeight);
|
|
1035
|
+
const playMarginTop = -Math.round(playIconHeight / 2);
|
|
1036
|
+
const playMarginLeft = -Math.round(playIconWidth / 2);
|
|
1037
|
+
const borderAttr = borderWidth > 0 ? `border:${borderWidth}px ${style?.borderStyle || "solid"} ${borderColor};` : "border:0;";
|
|
1038
|
+
const radiusAttr = borderRadius > 0 ? `border-radius:${borderRadius}px; overflow:hidden;` : "";
|
|
1039
|
+
const nonOutlookVideoContent = `<!--[if !mso]><!-->
|
|
1040
|
+
<div style="display:block; width:100%; max-width:${thumbnailW}px; position:relative; line-height:0; font-size:0; ${borderAttr}${radiusAttr}">
|
|
1041
|
+
<a href="${videoLink}" target="_blank" style="display:block; text-decoration:none; line-height:0; font-size:0;">
|
|
1042
|
+
<img
|
|
1043
|
+
src="${resolvedThumbnail}"
|
|
1044
|
+
width="${thumbnailW}"
|
|
1045
|
+
height="${thumbnailH}"
|
|
1046
|
+
alt="${altText || "Video"}"
|
|
1047
|
+
style="display:block; width:100%; max-width:${thumbnailW}px; height:auto; border:0;"
|
|
1048
|
+
/>
|
|
1049
|
+
<img
|
|
1050
|
+
src="https://app-rsrc.getbee.io/public/resources/components/widgetBar/video-content-icon-sets/light/type-01.png"
|
|
1051
|
+
width="${playIconWidth}"
|
|
1052
|
+
alt="Play"
|
|
1053
|
+
style="display:block; position:absolute; top:50%; left:50%; margin-top:${playMarginTop}px; margin-left:${playMarginLeft}px; border:0; outline:none;"
|
|
1054
|
+
/>
|
|
1055
|
+
</a>
|
|
1056
|
+
</div>
|
|
1057
|
+
<!--<![endif]-->`;
|
|
1013
1058
|
const videoContent = `${outlookVideoContent}${nonOutlookVideoContent}`;
|
|
1014
|
-
const wrapperHtml = `
|
|
1015
|
-
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin:0; padding:0; border-collapse: collapse; max-width:600px;" class="${visibilityClass}">
|
|
1016
|
-
<tr>
|
|
1017
|
-
<td align="${style?.textAlign || "left"}" style="padding:0; ${outerContainerStyles}">
|
|
1018
|
-
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
1019
|
-
align="${style?.textAlign || "left"}"
|
|
1020
|
-
style="
|
|
1021
|
-
margin:0;
|
|
1022
|
-
max-width:${cellWidthInPx}px;
|
|
1023
|
-
width:${percentWidth};
|
|
1024
|
-
border-collapse:collapse;
|
|
1025
|
-
">
|
|
1026
|
-
<tr>
|
|
1027
|
-
<td align="${style?.textAlign || "left"}" style="text-align:${style?.textAlign || "left"}; padding:0;">
|
|
1028
|
-
${videoContent}
|
|
1029
|
-
</td>
|
|
1030
|
-
</tr>
|
|
1031
|
-
</table>
|
|
1032
|
-
</td>
|
|
1033
|
-
</tr>
|
|
1034
|
-
</table>
|
|
1059
|
+
const wrapperHtml = `
|
|
1060
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin:0; padding:0; border-collapse: collapse; max-width:600px;" class="${visibilityClass}">
|
|
1061
|
+
<tr>
|
|
1062
|
+
<td align="${style?.textAlign || "left"}" style="padding:0; ${outerContainerStyles}">
|
|
1063
|
+
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
1064
|
+
align="${style?.textAlign || "left"}"
|
|
1065
|
+
style="
|
|
1066
|
+
margin:0;
|
|
1067
|
+
max-width:${cellWidthInPx}px;
|
|
1068
|
+
width:${percentWidth};
|
|
1069
|
+
border-collapse:collapse;
|
|
1070
|
+
">
|
|
1071
|
+
<tr>
|
|
1072
|
+
<td align="${style?.textAlign || "left"}" style="text-align:${style?.textAlign || "left"}; padding:0;">
|
|
1073
|
+
${videoContent}
|
|
1074
|
+
</td>
|
|
1075
|
+
</tr>
|
|
1076
|
+
</table>
|
|
1077
|
+
</td>
|
|
1078
|
+
</tr>
|
|
1079
|
+
</table>
|
|
1035
1080
|
`;
|
|
1036
1081
|
return wrapperHtml;
|
|
1037
1082
|
}
|
|
@@ -1113,44 +1158,44 @@ async function convertShapeBlock(blockData) {
|
|
|
1113
1158
|
let nonMsoContent = "";
|
|
1114
1159
|
// --- Case 1: Image + Text ---
|
|
1115
1160
|
if (imageUrl && text) {
|
|
1116
|
-
nonMsoContent = `
|
|
1117
|
-
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;
|
|
1118
|
-
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
1119
|
-
border-radius:${resolvedBorderRadius};
|
|
1120
|
-
background:${finalBackgroundColor} url('${imageUrl}') center/cover no-repeat;
|
|
1121
|
-
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
1122
|
-
<div style="width:100%;height:100%;display:flex;justify-content:${flexJustify};align-items:${flexAlign};overflow:hidden;padding:6px;box-sizing:border-box;">
|
|
1123
|
-
<div style="${textSizeStyle}text-align:${textAlignStyle};max-width:90%;overflow:hidden;">
|
|
1124
|
-
${text}
|
|
1125
|
-
</div>
|
|
1126
|
-
</div>
|
|
1161
|
+
nonMsoContent = `
|
|
1162
|
+
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;
|
|
1163
|
+
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
1164
|
+
border-radius:${resolvedBorderRadius};
|
|
1165
|
+
background:${finalBackgroundColor} url('${imageUrl}') center/cover no-repeat;
|
|
1166
|
+
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
1167
|
+
<div style="width:100%;height:100%;display:flex;justify-content:${flexJustify};align-items:${flexAlign};overflow:hidden;padding:6px;box-sizing:border-box;">
|
|
1168
|
+
<div style="${textSizeStyle}text-align:${textAlignStyle};max-width:90%;overflow:hidden;">
|
|
1169
|
+
${text}
|
|
1170
|
+
</div>
|
|
1171
|
+
</div>
|
|
1127
1172
|
</div>`;
|
|
1128
1173
|
}
|
|
1129
1174
|
// --- Case 2: Image only ---
|
|
1130
1175
|
else if (imageUrl) {
|
|
1131
|
-
nonMsoContent = `
|
|
1132
|
-
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;
|
|
1133
|
-
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
1134
|
-
border-radius:${resolvedBorderRadius};
|
|
1135
|
-
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
1136
|
-
<img src="${imageUrl}" alt="${text || "shape image"}"
|
|
1137
|
-
width="${resolvedWidthPx}" height="${resolvedHeightPx}"
|
|
1138
|
-
style="width:100%;height:100%;object-fit:cover;border-radius:${resolvedBorderRadius};display:block;" />
|
|
1176
|
+
nonMsoContent = `
|
|
1177
|
+
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;
|
|
1178
|
+
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
1179
|
+
border-radius:${resolvedBorderRadius};
|
|
1180
|
+
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
1181
|
+
<img src="${imageUrl}" alt="${text || "shape image"}"
|
|
1182
|
+
width="${resolvedWidthPx}" height="${resolvedHeightPx}"
|
|
1183
|
+
style="width:100%;height:100%;object-fit:cover;border-radius:${resolvedBorderRadius};display:block;" />
|
|
1139
1184
|
</div>`;
|
|
1140
1185
|
}
|
|
1141
1186
|
// --- Case 3: Text only ---
|
|
1142
1187
|
else {
|
|
1143
|
-
nonMsoContent = `
|
|
1144
|
-
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;
|
|
1145
|
-
background:${finalBackgroundColor};
|
|
1146
|
-
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
1147
|
-
border-radius:${resolvedBorderRadius};
|
|
1148
|
-
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
1149
|
-
<div style="width:100%;height:100%;display:flex;justify-content:${flexJustify};align-items:${flexAlign};padding:8px;box-sizing:border-box;">
|
|
1150
|
-
<div style="${textSizeStyle}text-align:${textAlignStyle};max-width:90%;overflow:hidden;">
|
|
1151
|
-
${text || ""}
|
|
1152
|
-
</div>
|
|
1153
|
-
</div>
|
|
1188
|
+
nonMsoContent = `
|
|
1189
|
+
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;
|
|
1190
|
+
background:${finalBackgroundColor};
|
|
1191
|
+
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
1192
|
+
border-radius:${resolvedBorderRadius};
|
|
1193
|
+
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
1194
|
+
<div style="width:100%;height:100%;display:flex;justify-content:${flexJustify};align-items:${flexAlign};padding:8px;box-sizing:border-box;">
|
|
1195
|
+
<div style="${textSizeStyle}text-align:${textAlignStyle};max-width:90%;overflow:hidden;">
|
|
1196
|
+
${text || ""}
|
|
1197
|
+
</div>
|
|
1198
|
+
</div>
|
|
1154
1199
|
</div>`;
|
|
1155
1200
|
}
|
|
1156
1201
|
// Outlook (VML) fallback
|
|
@@ -1172,17 +1217,45 @@ async function convertShapeBlock(blockData) {
|
|
|
1172
1217
|
padding,
|
|
1173
1218
|
msoBakeImageWithText,
|
|
1174
1219
|
}, visibilityClass);
|
|
1220
|
+
// Embed block metadata so the HTML importer can reconstruct the Shape block exactly.
|
|
1221
|
+
const shapeProps = encodeBlockProps({
|
|
1222
|
+
shape,
|
|
1223
|
+
width: resolvedWidthPx,
|
|
1224
|
+
height: resolvedHeightPx,
|
|
1225
|
+
shapeColor: String(finalBackgroundColor || '#BEBEBE'),
|
|
1226
|
+
backgroundColor: String(finalBackgroundColor || '#BEBEBE'),
|
|
1227
|
+
borderRadius: borderRadius !== undefined ? borderRadius : 0,
|
|
1228
|
+
borderWidth: borderWidth || 0,
|
|
1229
|
+
borderColor: borderColor || 'transparent',
|
|
1230
|
+
borderStyle: borderStyle || 'solid',
|
|
1231
|
+
imageUrl: imageUrl || '',
|
|
1232
|
+
text: text || '',
|
|
1233
|
+
color: String(color || '#000000'),
|
|
1234
|
+
fontSize: fontSize || 14,
|
|
1235
|
+
textAlign: textAlignStyle,
|
|
1236
|
+
verticalAlign: verticalAlign || 'middle',
|
|
1237
|
+
alignment: alignment || 'left',
|
|
1238
|
+
padding: {
|
|
1239
|
+
top: padding.top || 0,
|
|
1240
|
+
right: padding.right || 0,
|
|
1241
|
+
bottom: padding.bottom || 0,
|
|
1242
|
+
left: padding.left || 0,
|
|
1243
|
+
},
|
|
1244
|
+
hideOnDesktop: Boolean(props.hideOnDesktop),
|
|
1245
|
+
hideOnMobile: Boolean(props.hideOnMobile),
|
|
1246
|
+
customCss: customCss || '',
|
|
1247
|
+
});
|
|
1175
1248
|
// Combine into table wrapper
|
|
1176
|
-
return `
|
|
1177
|
-
<table width="100%" style="border-collapse:collapse;table-layout:fixed;max-width:600px;" class="${visibilityClass}">
|
|
1178
|
-
<tr>
|
|
1179
|
-
<td style="padding:${padding.top || 0}px ${padding.right || 0}px ${padding.bottom || 0}px ${padding.left || 0}px;text-align:${alignment};">
|
|
1180
|
-
${outlookContent}
|
|
1181
|
-
<!--[if !mso]><!-->
|
|
1182
|
-
${nonMsoContent}
|
|
1183
|
-
<!--<![endif]-->
|
|
1184
|
-
</td>
|
|
1185
|
-
</tr>
|
|
1249
|
+
return `
|
|
1250
|
+
<table width="100%" style="border-collapse:collapse;table-layout:fixed;max-width:600px;" class="${visibilityClass}" data-block-type="shape" data-block-props="${shapeProps}">
|
|
1251
|
+
<tr>
|
|
1252
|
+
<td style="padding:${padding.top || 0}px ${padding.right || 0}px ${padding.bottom || 0}px ${padding.left || 0}px;text-align:${alignment};">
|
|
1253
|
+
${outlookContent}
|
|
1254
|
+
<!--[if !mso]><!-->
|
|
1255
|
+
${nonMsoContent}
|
|
1256
|
+
<!--<![endif]-->
|
|
1257
|
+
</td>
|
|
1258
|
+
</tr>
|
|
1186
1259
|
</table>`;
|
|
1187
1260
|
}
|
|
1188
1261
|
// ---------- Updated VML builder ----------
|
|
@@ -1215,24 +1288,24 @@ function buildVMLShape({ shape, widthPx, heightPx, imageUrl, backgroundColor, bo
|
|
|
1215
1288
|
const safeFontSize = Math.max(Math.round(textSize), 10);
|
|
1216
1289
|
// Build the textbox with table/cell for reliable vertical centering in Outlook
|
|
1217
1290
|
const textboxMarkup = text && !msoHasBakedText
|
|
1218
|
-
? `<v:textbox inset="6pt,6pt,6pt,6pt" style="mso-fit-shape-to-text:false;">
|
|
1219
|
-
<div style="display:table;width:100%;height:100%;">
|
|
1220
|
-
<div style="display:table-cell;vertical-align:${vAlign};text-align:${hAlign};padding:0 6px;">
|
|
1221
|
-
<div style="color:${textColor};font-family:Arial, sans-serif;font-size:${safeFontSize}px;line-height:1.3;word-wrap:break-word;">
|
|
1222
|
-
${text}
|
|
1223
|
-
</div>
|
|
1224
|
-
</div>
|
|
1225
|
-
</div>
|
|
1291
|
+
? `<v:textbox inset="6pt,6pt,6pt,6pt" style="mso-fit-shape-to-text:false;">
|
|
1292
|
+
<div style="display:table;width:100%;height:100%;">
|
|
1293
|
+
<div style="display:table-cell;vertical-align:${vAlign};text-align:${hAlign};padding:0 6px;">
|
|
1294
|
+
<div style="color:${textColor};font-family:Arial, sans-serif;font-size:${safeFontSize}px;line-height:1.3;word-wrap:break-word;">
|
|
1295
|
+
${text}
|
|
1296
|
+
</div>
|
|
1297
|
+
</div>
|
|
1298
|
+
</div>
|
|
1226
1299
|
</v:textbox>`
|
|
1227
1300
|
: `<v:textbox inset="0,0,0,0"><div style="display:none;">.</div></v:textbox>`;
|
|
1228
1301
|
// Return VML shape
|
|
1229
|
-
return `
|
|
1230
|
-
<v:${tag} xmlns:v="urn:schemas-microsoft-com:vml"
|
|
1231
|
-
style="width:${widthPx}px;height:${heightPx}px;display:inline-block;"
|
|
1232
|
-
${borderAttrs}
|
|
1233
|
-
fill="true" fillcolor="${fillColor}"${extraAttr}>
|
|
1234
|
-
${fillMarkup}
|
|
1235
|
-
${textboxMarkup}
|
|
1302
|
+
return `
|
|
1303
|
+
<v:${tag} xmlns:v="urn:schemas-microsoft-com:vml"
|
|
1304
|
+
style="width:${widthPx}px;height:${heightPx}px;display:inline-block;"
|
|
1305
|
+
${borderAttrs}
|
|
1306
|
+
fill="true" fillcolor="${fillColor}"${extraAttr}>
|
|
1307
|
+
${fillMarkup}
|
|
1308
|
+
${textboxMarkup}
|
|
1236
1309
|
</v:${tag}>`;
|
|
1237
1310
|
}
|
|
1238
1311
|
function appendOutlookForShape(content, outerContainerWidth, innerContainerWidth, opts, visibilityClass) {
|
|
@@ -1260,28 +1333,28 @@ function appendOutlookForShape(content, outerContainerWidth, innerContainerWidth
|
|
|
1260
1333
|
const shouldHideInOutlook = visibilityClass.includes("hide-desktop");
|
|
1261
1334
|
// Fix: Properly handle Outlook visibility with conditional comments
|
|
1262
1335
|
if (shouldHideInOutlook) {
|
|
1263
|
-
return `<!--[if !mso]><!-->
|
|
1264
|
-
<table align="${align}" border="0" cellpadding="0" cellspacing="0"
|
|
1265
|
-
style="width:${widthPx}px;height:${heightPx}px;border-collapse:collapse;" class="${visibilityClass}">
|
|
1266
|
-
<tr>
|
|
1267
|
-
<td valign="${valign}"
|
|
1268
|
-
style="padding:${pad.top || 0}px ${pad.right || 0}px ${pad.bottom || 0}px ${pad.left || 0}px;">
|
|
1269
|
-
${vml}
|
|
1270
|
-
</td>
|
|
1271
|
-
</tr>
|
|
1272
|
-
</table>
|
|
1336
|
+
return `<!--[if !mso]><!-->
|
|
1337
|
+
<table align="${align}" border="0" cellpadding="0" cellspacing="0"
|
|
1338
|
+
style="width:${widthPx}px;height:${heightPx}px;border-collapse:collapse;" class="${visibilityClass}">
|
|
1339
|
+
<tr>
|
|
1340
|
+
<td valign="${valign}"
|
|
1341
|
+
style="padding:${pad.top || 0}px ${pad.right || 0}px ${pad.bottom || 0}px ${pad.left || 0}px;">
|
|
1342
|
+
${vml}
|
|
1343
|
+
</td>
|
|
1344
|
+
</tr>
|
|
1345
|
+
</table>
|
|
1273
1346
|
<!--<![endif]-->`;
|
|
1274
1347
|
}
|
|
1275
|
-
return `<!--[if mso]>
|
|
1276
|
-
<table align="${align}" border="0" cellpadding="0" cellspacing="0"
|
|
1277
|
-
style="width:${widthPx}px;height:${heightPx}px;border-collapse:collapse;" class="${visibilityClass}">
|
|
1278
|
-
<tr>
|
|
1279
|
-
<td valign="${valign}"
|
|
1280
|
-
style="padding:${pad.top || 0}px ${pad.right || 0}px ${pad.bottom || 0}px ${pad.left || 0}px;">
|
|
1281
|
-
${vml}
|
|
1282
|
-
</td>
|
|
1283
|
-
</tr>
|
|
1284
|
-
</table>
|
|
1348
|
+
return `<!--[if mso]>
|
|
1349
|
+
<table align="${align}" border="0" cellpadding="0" cellspacing="0"
|
|
1350
|
+
style="width:${widthPx}px;height:${heightPx}px;border-collapse:collapse;" class="${visibilityClass}">
|
|
1351
|
+
<tr>
|
|
1352
|
+
<td valign="${valign}"
|
|
1353
|
+
style="padding:${pad.top || 0}px ${pad.right || 0}px ${pad.bottom || 0}px ${pad.left || 0}px;">
|
|
1354
|
+
${vml}
|
|
1355
|
+
</td>
|
|
1356
|
+
</tr>
|
|
1357
|
+
</table>
|
|
1285
1358
|
<![endif]-->`;
|
|
1286
1359
|
}
|
|
1287
1360
|
function convertVerticalDividerBlockToHtml(blockData) {
|
|
@@ -1292,18 +1365,28 @@ function convertVerticalDividerBlockToHtml(blockData) {
|
|
|
1292
1365
|
perChanges: [],
|
|
1293
1366
|
pxChanges: allPxAttributes,
|
|
1294
1367
|
});
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1368
|
+
const vDividerProps = encodeBlockProps({
|
|
1369
|
+
width: width || 5,
|
|
1370
|
+
height: height || 100,
|
|
1371
|
+
dividerColor: dividerColor || '#808080',
|
|
1372
|
+
backgroundColor: backgroundColor || '',
|
|
1373
|
+
alignment: 'left',
|
|
1374
|
+
padding: padding || { top: 0, right: 0, bottom: 0, left: 0 },
|
|
1375
|
+
hideOnDesktop: Boolean(props.hideOnDesktop),
|
|
1376
|
+
hideOnMobile: Boolean(props.hideOnMobile),
|
|
1377
|
+
});
|
|
1378
|
+
return `
|
|
1379
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
1380
|
+
style="${exports.tableCommonStyle} max-width:600px;" class="${visibilityClass}" data-block-type="vdivider" data-block-props="${vDividerProps}">
|
|
1381
|
+
<tr>
|
|
1382
|
+
<td style="${outerStyles}; text-align:center; vertical-align:middle;">
|
|
1383
|
+
<!--[if mso | IE]>
|
|
1384
|
+
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fillcolor="${dividerColor}" style="width:${width}px;height:${height}px;" stroke="f"></v:rect>
|
|
1385
|
+
<![endif]-->
|
|
1386
|
+
<!--[if !mso]><!-->
|
|
1387
|
+
<div style="display:inline-block;width:${width}px;height:${height}px;background:${dividerColor};line-height:0;font-size:0;"> </div>
|
|
1388
|
+
<!--<![endif]-->
|
|
1389
|
+
</td>
|
|
1390
|
+
</tr>
|
|
1308
1391
|
</table>`;
|
|
1309
1392
|
}
|