email-builder-utils 1.1.13 → 1.1.15
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertJsonToHtml.d.ts","sourceRoot":"","sources":["../../src/utils/convertJsonToHtml.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,GAAU,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"convertJsonToHtml.d.ts","sourceRoot":"","sources":["../../src/utils/convertJsonToHtml.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,GAAU,UAAU,GAAG,oBA+EpD,CAAC"}
|
|
@@ -12,21 +12,23 @@ const convertJsonToHtml = async (jsonData) => {
|
|
|
12
12
|
}
|
|
13
13
|
const { fontFamily, canvasColor, textColor, padding = {}, borderColor, borderRadius, borderWidth, borderStyle, } = rootData.style || {};
|
|
14
14
|
const { top = 0, right = 0, bottom = 0, left = 0 } = padding;
|
|
15
|
-
const rawHtml =
|
|
16
|
-
<!DOCTYPE html>
|
|
15
|
+
const rawHtml = `<!DOCTYPE html>
|
|
17
16
|
<html lang="en">
|
|
18
17
|
<head>
|
|
19
18
|
<meta charset="UTF-8" />
|
|
20
19
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
21
|
-
<
|
|
20
|
+
<meta name="x-apple-disable-message-reformatting" />
|
|
22
21
|
<style>
|
|
23
22
|
.responsive-table {
|
|
24
23
|
width: 100%;
|
|
25
24
|
max-width: 600px;
|
|
26
25
|
}
|
|
27
|
-
|
|
28
26
|
@media only screen and (max-width: 600px) {
|
|
29
|
-
.
|
|
27
|
+
.responsive-table {
|
|
28
|
+
width: 100% !important;
|
|
29
|
+
}
|
|
30
|
+
.stack-column,
|
|
31
|
+
.stack-column td {
|
|
30
32
|
display: block !important;
|
|
31
33
|
width: 100% !important;
|
|
32
34
|
max-width: 100% !important;
|
|
@@ -38,15 +40,15 @@ const convertJsonToHtml = async (jsonData) => {
|
|
|
38
40
|
<center>
|
|
39
41
|
<table
|
|
40
42
|
class="responsive-table"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
style="
|
|
44
|
+
font-family: ${fontFamily};
|
|
45
|
+
margin: 0 auto;
|
|
46
|
+
table-layout:fixed;
|
|
47
|
+
background-color: ${canvasColor};
|
|
48
|
+
color: ${textColor};
|
|
49
|
+
padding: ${top}px ${right}px ${bottom}px ${left}px;
|
|
50
|
+
border: ${borderWidth}px ${borderStyle} ${borderColor};
|
|
51
|
+
border-radius: ${borderRadius}px; "
|
|
50
52
|
>
|
|
51
53
|
<tbody>
|
|
52
54
|
<tr>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonToHTML.d.ts","sourceRoot":"","sources":["../../src/utils/jsonToHTML.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"jsonToHTML.d.ts","sourceRoot":"","sources":["../../src/utils/jsonToHTML.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AASrC,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE;QACJ,KAAK,EAAE,cAAc,CAAC;QACtB,KAAK,EAAE,GAAG,CAAC;QACX,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;KAC7B,CAAC;CACH;AAYD,eAAO,MAAM,gBAAgB,kDAAkD,CAAC;AA2DhF,wBAAsB,aAAa,CACjC,SAAS,EAAE,UAAU,EACrB,QAAQ,EAAE,GAAG,EACb,aAAa,EAAE,MAAM,mBAkBtB"}
|
package/dist/utils/jsonToHTML.js
CHANGED
|
@@ -4,7 +4,12 @@ exports.tableCommonStyle = void 0;
|
|
|
4
4
|
exports.convertToHtml = convertToHtml;
|
|
5
5
|
const jimp_1 = require("jimp");
|
|
6
6
|
const types_1 = require("../types");
|
|
7
|
-
const addPxToAttributes = [
|
|
7
|
+
const addPxToAttributes = [
|
|
8
|
+
"fontSize",
|
|
9
|
+
"lineHeight",
|
|
10
|
+
"borderRadius",
|
|
11
|
+
"borderWidth",
|
|
12
|
+
];
|
|
8
13
|
const addPxOrPerToAttributes = ["width", "height"];
|
|
9
14
|
const allPxAttributes = [...addPxToAttributes, ...addPxOrPerToAttributes];
|
|
10
15
|
exports.tableCommonStyle = "border-collapse:collapse; table-layout:fixed;";
|
|
@@ -35,7 +40,8 @@ function buildStyles(style, { pxChanges, perChanges }) {
|
|
|
35
40
|
return;
|
|
36
41
|
if (value === undefined || value === null || value === "")
|
|
37
42
|
return;
|
|
38
|
-
if ((key === "padding" || key === "buttonPadding") &&
|
|
43
|
+
if ((key === "padding" || key === "buttonPadding") &&
|
|
44
|
+
typeof value === "object") {
|
|
39
45
|
const padding = value;
|
|
40
46
|
value = `${padding.top}px ${padding.right}px ${padding.bottom}px ${padding.left}px`;
|
|
41
47
|
}
|
|
@@ -84,7 +90,10 @@ function appendOutlookSupport(content, contentStyle) {
|
|
|
84
90
|
function convertDividerBlockToHtml(blockData) {
|
|
85
91
|
const { style } = blockData.data;
|
|
86
92
|
const { thickness, dividerColor, ...rest } = style;
|
|
87
|
-
const convertedStyle = buildStyles(rest, {
|
|
93
|
+
const convertedStyle = buildStyles(rest, {
|
|
94
|
+
perChanges: [],
|
|
95
|
+
pxChanges: allPxAttributes,
|
|
96
|
+
});
|
|
88
97
|
const dividerContent = `
|
|
89
98
|
<table width="100%" cellpadding="0" cellspacing="0">
|
|
90
99
|
<tr>
|
|
@@ -96,16 +105,24 @@ function convertDividerBlockToHtml(blockData) {
|
|
|
96
105
|
}
|
|
97
106
|
function convertSpacerBlockToHtml(blockData) {
|
|
98
107
|
const { style } = blockData.data;
|
|
99
|
-
const styles = buildStyles(style, {
|
|
108
|
+
const styles = buildStyles(style, {
|
|
109
|
+
perChanges: [],
|
|
110
|
+
pxChanges: allPxAttributes,
|
|
111
|
+
});
|
|
100
112
|
return appendOutlookSupport(``, styles);
|
|
101
113
|
}
|
|
102
114
|
function convertTextBlock(blockData) {
|
|
103
115
|
const { style, props } = blockData.data;
|
|
104
|
-
const styles = buildStyles(style, {
|
|
116
|
+
const styles = buildStyles(style, {
|
|
117
|
+
perChanges: [],
|
|
118
|
+
pxChanges: allPxAttributes,
|
|
119
|
+
});
|
|
105
120
|
const text = props.text || "";
|
|
106
121
|
const navigateToUrl = props.navigateToUrl || "";
|
|
107
122
|
const textContent = appendOutlookSupport(text.replaceAll(/\n/g, "<br>"), styles);
|
|
108
|
-
return navigateToUrl
|
|
123
|
+
return navigateToUrl
|
|
124
|
+
? `<a href="${navigateToUrl}" rel="noreferrer noopener" style="color:inherit; text-decoration:none; cursor:pointer;">${textContent}</a>`
|
|
125
|
+
: textContent;
|
|
109
126
|
}
|
|
110
127
|
async function appendOutlookForImage(content, outerContainerWidth, innerContainerWidth, imageUrl, style = {}) {
|
|
111
128
|
const image = await jimp_1.Jimp.read(imageUrl);
|
|
@@ -152,7 +169,7 @@ async function convertImageBlock(blockData, cellWidthInPx) {
|
|
|
152
169
|
objectFit,
|
|
153
170
|
borderStyle,
|
|
154
171
|
borderRadius: borderRadius,
|
|
155
|
-
borderColor
|
|
172
|
+
borderColor,
|
|
156
173
|
};
|
|
157
174
|
// Add border styles to container for fallback clients
|
|
158
175
|
const containerStyles = buildStyles({
|
|
@@ -163,12 +180,15 @@ async function convertImageBlock(blockData, cellWidthInPx) {
|
|
|
163
180
|
pxChanges: addPxToAttributes,
|
|
164
181
|
});
|
|
165
182
|
const imageElement = `<img src="${imageUrl}" alt="${altText}" style="${imageTagStyles}" />`;
|
|
166
|
-
const innerContainerWidth = ((typeof width === "string" ? parseInt(width.replace("%", "")) : width) /
|
|
167
|
-
|
|
183
|
+
const innerContainerWidth = ((typeof width === "string" ? parseInt(width.replace("%", "")) : width) /
|
|
184
|
+
100) *
|
|
185
|
+
(cellWidthInPx -
|
|
186
|
+
(style?.padding?.left || 0) -
|
|
187
|
+
(style?.padding?.right || 0));
|
|
168
188
|
const outlookImage = await appendOutlookForImage(imageElement, cellWidthInPx, innerContainerWidth, imageUrl, style);
|
|
169
189
|
const imageContent = appendOutlookSupport(outlookImage, containerStyles);
|
|
170
190
|
return navigateToUrl
|
|
171
|
-
? `<a href="${navigateToUrl}" target="_blank" style="display:block; text-decoration:none; cursor:pointer;">${imageContent}</a>`
|
|
191
|
+
? `<a href="${navigateToUrl}" target="_blank" rel="noreferrer noopener" style="display:block; text-decoration:none; cursor:pointer;">${imageContent}</a>`
|
|
172
192
|
: imageContent;
|
|
173
193
|
}
|
|
174
194
|
function appendOutlookForButton(content, buttonStyle, navigateToUrl, text) {
|
|
@@ -213,48 +233,93 @@ function convertButtonBlock(blockData) {
|
|
|
213
233
|
color,
|
|
214
234
|
backgroundColor: buttonColor,
|
|
215
235
|
};
|
|
216
|
-
const convertedButtonStyle = buildStyles(buttonStyle, {
|
|
217
|
-
|
|
218
|
-
|
|
236
|
+
const convertedButtonStyle = buildStyles(buttonStyle, {
|
|
237
|
+
perChanges: [],
|
|
238
|
+
pxChanges: allPxAttributes,
|
|
239
|
+
});
|
|
240
|
+
const convertedStyles = buildStyles(rest, {
|
|
241
|
+
perChanges: [],
|
|
242
|
+
pxChanges: allPxAttributes,
|
|
243
|
+
});
|
|
244
|
+
const buttonElement = `<a href="${navigateToUrl}" rel="noreferrer noopener" style="display:inline-block; text-decoration:none; cursor:pointer;"><button style="${convertedButtonStyle}">${text}</button></a>`;
|
|
219
245
|
const buttonContent = appendOutlookSupport(appendOutlookForButton(buttonElement, style, navigateToUrl, text), convertedStyles);
|
|
220
246
|
return buttonContent;
|
|
221
247
|
}
|
|
222
|
-
async function processGridItemsInParallel(columns, childrenIds, cellWidths, cellWidthInPx, rootData) {
|
|
223
|
-
const gridItemPromises = [];
|
|
224
|
-
for (let colIndex = 0; colIndex < columns; colIndex++) {
|
|
225
|
-
const childId = childrenIds[colIndex];
|
|
226
|
-
const cellWidth = cellWidths ? cellWidths[colIndex] : 100 / columns;
|
|
227
|
-
const childBlockData = rootData[childId];
|
|
228
|
-
if (childBlockData) {
|
|
229
|
-
const gridItemPromise = convertGridCellBlock(childBlockData, rootData, cellWidth, cellWidthInPx);
|
|
230
|
-
gridItemPromises.push(gridItemPromise);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
const gridItems = await Promise.all(gridItemPromises);
|
|
234
|
-
return gridItems;
|
|
235
|
-
}
|
|
236
248
|
async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
237
|
-
const { style, childrenIds = [], props } = blockData.data;
|
|
238
|
-
const {
|
|
239
|
-
const {
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
249
|
+
const { style = {}, childrenIds = [], props } = blockData.data;
|
|
250
|
+
const { columns = 1, cellWidths = [] } = props;
|
|
251
|
+
const { columnGap = 0, ...restStyle } = style;
|
|
252
|
+
const tableStyles = buildStyles(restStyle, {
|
|
253
|
+
perChanges: [],
|
|
254
|
+
pxChanges: allPxAttributes,
|
|
255
|
+
});
|
|
256
|
+
const total = childrenIds.length;
|
|
257
|
+
const visualRows = Math.ceil(total / columns);
|
|
258
|
+
let html = `
|
|
259
|
+
<!--[if mso]>
|
|
260
|
+
<table border="0" cellpadding="0" cellspacing="${columnGap}" width="100%" style="${exports.tableCommonStyle}">
|
|
261
|
+
<![endif]-->
|
|
262
|
+
<table border="0" cellpadding="0" cellspacing="${columnGap}" width="100%" role="presentation" style="${exports.tableCommonStyle} ${tableStyles}">
|
|
248
263
|
`;
|
|
264
|
+
for (let r = 0; r < visualRows; r++) {
|
|
265
|
+
html += "<tr>";
|
|
266
|
+
for (let c = 0; c < columns; c++) {
|
|
267
|
+
const idx = r * columns + c;
|
|
268
|
+
const childId = childrenIds[idx];
|
|
269
|
+
const widthPercent = cellWidths[c] ?? 100 / columns;
|
|
270
|
+
if (childId) {
|
|
271
|
+
const child = rootData[childId];
|
|
272
|
+
const { style: cellStyle = {} } = child.data || {};
|
|
273
|
+
const verticalAlign = cellStyle.verticalAlign || "top";
|
|
274
|
+
const childHtml = child
|
|
275
|
+
? await convertGridCellBlock(child, rootData, widthPercent, cellWidthInPx)
|
|
276
|
+
: "";
|
|
277
|
+
html += `
|
|
278
|
+
<td
|
|
279
|
+
width="${widthPercent}%"
|
|
280
|
+
class="stack-column"
|
|
281
|
+
style="vertical-align:${verticalAlign}; padding:0; word-break:break-word;"
|
|
282
|
+
>
|
|
283
|
+
${childHtml}
|
|
284
|
+
</td>`;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
html += `<td width="${widthPercent}%" class="stack-column" style="padding:0;"></td>`;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
html += "</tr>";
|
|
291
|
+
}
|
|
292
|
+
html += `</table><!--[if mso]></table><![endif]-->`;
|
|
293
|
+
return html;
|
|
249
294
|
}
|
|
250
|
-
async function convertGridCellBlock(blockData, rootData,
|
|
251
|
-
const { style, childrenIds } = blockData.data;
|
|
252
|
-
const styles = buildStyles(style, {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
295
|
+
async function convertGridCellBlock(blockData, rootData, cellWidthPercent, parentCellWidthPx) {
|
|
296
|
+
const { style = {}, childrenIds = [] } = blockData.data;
|
|
297
|
+
const styles = buildStyles(style, {
|
|
298
|
+
perChanges: [],
|
|
299
|
+
pxChanges: allPxAttributes,
|
|
300
|
+
});
|
|
301
|
+
const innerHtmlParts = [];
|
|
302
|
+
for (const childId of childrenIds) {
|
|
303
|
+
const child = rootData[childId];
|
|
304
|
+
if (child) {
|
|
305
|
+
const cellWidthPx = parentCellWidthPx * (cellWidthPercent / 100);
|
|
306
|
+
innerHtmlParts.push(await convertToHtml(child, rootData, cellWidthPx));
|
|
257
307
|
}
|
|
258
308
|
}
|
|
259
|
-
|
|
309
|
+
const innerContent = innerHtmlParts.join("");
|
|
310
|
+
return `
|
|
311
|
+
<table
|
|
312
|
+
role="presentation"
|
|
313
|
+
border="0"
|
|
314
|
+
cellpadding="0"
|
|
315
|
+
cellspacing="0"
|
|
316
|
+
width="100%"
|
|
317
|
+
style="border-collapse:collapse;table-layout:fixed;${styles}"
|
|
318
|
+
>
|
|
319
|
+
<tr>
|
|
320
|
+
<td style="padding:0;">
|
|
321
|
+
${innerContent}
|
|
322
|
+
</td>
|
|
323
|
+
</tr>
|
|
324
|
+
</table>`;
|
|
260
325
|
}
|