@useinsider/guido 3.2.0-beta.8e8f902 → 3.2.0-beta.8f147c3
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/README.md +1 -25
- package/dist/@types/config/schemas.js +163 -109
- package/dist/components/Guido.vue.js +4 -4
- package/dist/components/Guido.vue2.js +77 -77
- package/dist/components/organisms/header/RightSlot.vue.js +8 -8
- package/dist/components/organisms/header/RightSlot.vue2.js +8 -9
- package/dist/composables/useSave.js +15 -15
- package/dist/config/migrator/index.js +9 -9
- package/dist/config/migrator/recommendation/compositionMapper.js +98 -0
- package/dist/config/migrator/recommendation/extractors.js +27 -0
- package/dist/config/migrator/recommendation/htmlBuilder.js +486 -0
- package/dist/config/migrator/recommendation/parseLegacyConfig.js +33 -0
- package/dist/config/migrator/recommendation/settingsMapper.js +78 -0
- package/dist/config/migrator/recommendation/themeMapper.js +93 -0
- package/dist/config/migrator/recommendationMigrator.js +60 -290
- package/dist/enums/extensions/recommendationBlock.js +2 -1
- package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +5 -5
- package/dist/extensions/Blocks/Recommendation/services/configService.js +65 -29
- package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +8 -8
- package/dist/extensions/Blocks/Recommendation/templates/utils.js +1 -1
- package/dist/extensions/Blocks/Recommendation/utils/preserveTextStyles.js +13 -22
- package/dist/guido.css +1 -1
- package/dist/node_modules/valibot/dist/index.js +450 -235
- package/dist/services/templateLibraryApi.js +4 -5
- package/dist/src/@types/config/defaults.d.ts +5 -1
- package/dist/src/@types/config/index.d.ts +3 -3
- package/dist/src/@types/config/schemas.d.ts +213 -4
- package/dist/src/@types/config/types.d.ts +9 -1
- package/dist/src/components/Guido.vue.d.ts +1 -1
- package/dist/src/components/organisms/header/EditorActions.vue.d.ts +1 -1
- package/dist/src/components/organisms/header/HeaderWrapper.vue.d.ts +1 -1
- package/dist/src/components/organisms/header/RightSlot.vue.d.ts +1 -1
- package/dist/src/components/wrappers/WpModal.vue.d.ts +1 -1
- package/dist/src/composables/useConfig.d.ts +56 -2
- package/dist/src/composables/useSave.d.ts +1 -1
- package/dist/src/config/migrator/index.d.ts +2 -1
- package/dist/src/config/migrator/recommendation/compositionMapper.d.ts +2 -0
- package/dist/src/config/migrator/recommendation/compositionMapper.test.d.ts +1 -0
- package/dist/src/config/migrator/recommendation/extractors.d.ts +7 -0
- package/dist/src/config/migrator/recommendation/htmlBuilder.d.ts +11 -0
- package/dist/src/config/migrator/recommendation/parseLegacyConfig.d.ts +15 -0
- package/dist/src/config/migrator/recommendation/parseLegacyConfig.test.d.ts +1 -0
- package/dist/src/config/migrator/recommendation/settingsMapper.d.ts +7 -0
- package/dist/src/config/migrator/recommendation/settingsMapper.test.d.ts +1 -0
- package/dist/src/config/migrator/recommendation/themeMapper.d.ts +5 -0
- package/dist/src/config/migrator/recommendation/themeMapper.test.d.ts +1 -0
- package/dist/src/config/migrator/recommendation/types.d.ts +205 -0
- package/dist/src/config/migrator/recommendationMigrator.d.ts +13 -1
- package/dist/src/config/migrator/recommendationMigrator.test.d.ts +1 -0
- package/dist/src/extensions/Blocks/Recommendation/services/configService.d.ts +10 -0
- package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +1 -1
- package/dist/src/extensions/Blocks/Recommendation/utils/preserveTextStyles.d.ts +0 -3
- package/dist/src/stores/config.d.ts +504 -18
- package/dist/src/stores/editor.d.ts +0 -23
- package/dist/src/utils/htmlEscape.d.ts +5 -0
- package/dist/stores/editor.js +1 -3
- package/dist/utils/htmlEscape.js +13 -0
- package/dist/utils/pairProductVariables.js +88 -89
- package/package.json +5 -1
- package/dist/components/organisms/AutoSaveController.vue.js +0 -17
- package/dist/components/organisms/AutoSaveController.vue2.js +0 -13
- package/dist/components/organisms/header/AutoSaveToggle.vue.js +0 -22
- package/dist/components/organisms/header/AutoSaveToggle.vue2.js +0 -19
- package/dist/composables/useAutoSave.js +0 -71
- package/dist/extensions/Blocks/Recommendation/templates/grid/migration.js +0 -251
- package/dist/src/components/organisms/AutoSaveController.vue.d.ts +0 -2
- package/dist/src/components/organisms/header/AutoSaveToggle.vue.d.ts +0 -2
- package/dist/src/composables/useAutoSave.d.ts +0 -3
- package/dist/src/stores/autosave.d.ts +0 -12
- package/dist/src/utils/timeUtil.d.ts +0 -8
- package/dist/stores/autosave.js +0 -17
- package/dist/utils/timeUtil.js +0 -19
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
function r(n, t, o) {
|
|
2
|
+
o != null && o !== "" && n.push(`${t}: ${o}`);
|
|
3
|
+
}
|
|
4
|
+
function $(n) {
|
|
5
|
+
if (!n)
|
|
6
|
+
return null;
|
|
7
|
+
const t = n.top ?? n.all ?? 0, o = n.right ?? n.all ?? 0, i = n.bottom ?? n.all ?? 0, l = n.left ?? n.all ?? 0;
|
|
8
|
+
return t === 0 && o === 0 && i === 0 && l === 0 ? null : `${t}px ${o}px ${i}px ${l}px`;
|
|
9
|
+
}
|
|
10
|
+
function j(n) {
|
|
11
|
+
if (!n)
|
|
12
|
+
return null;
|
|
13
|
+
const { top: t, right: o, bottom: i, left: l } = n;
|
|
14
|
+
return t === void 0 ? null : t === o && t === i && t === l ? t : null;
|
|
15
|
+
}
|
|
16
|
+
function S(n, t, o, i) {
|
|
17
|
+
const l = j(o);
|
|
18
|
+
if (l !== null) {
|
|
19
|
+
r(n, `border-${t}`, i(l));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
o && (r(n, `border-top-${t}`, o.top !== void 0 ? i(o.top) : null), r(n, `border-right-${t}`, o.right !== void 0 ? i(o.right) : null), r(n, `border-bottom-${t}`, o.bottom !== void 0 ? i(o.bottom) : null), r(n, `border-left-${t}`, o.left !== void 0 ? i(o.left) : null));
|
|
23
|
+
}
|
|
24
|
+
function C(n) {
|
|
25
|
+
if (!n)
|
|
26
|
+
return null;
|
|
27
|
+
if (typeof n.radius == "number")
|
|
28
|
+
return `${n.radius}px`;
|
|
29
|
+
if (typeof n.lt == "number" || typeof n.rt == "number" || typeof n.rb == "number" || typeof n.lb == "number") {
|
|
30
|
+
const t = n.lt ?? 0, o = n.rt ?? 0, i = n.rb ?? 0, l = n.lb ?? 0;
|
|
31
|
+
return `${t}px ${o}px ${i}px ${l}px`;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
function I(n) {
|
|
36
|
+
var t, o;
|
|
37
|
+
return ((t = n.textLineSpacing) == null ? void 0 : t.lineSpacing) ?? ((o = n.textLineSpacing) == null ? void 0 : o["font-lineSpacing"]);
|
|
38
|
+
}
|
|
39
|
+
function L(n) {
|
|
40
|
+
var f, u, a, g, d, b, p, s;
|
|
41
|
+
const t = [], o = [], i = (f = n == null ? void 0 : n.textAlign) == null ? void 0 : f.align, l = $((u = n == null ? void 0 : n.textPadding) == null ? void 0 : u.desktop), x = (a = n == null ? void 0 : n.textStyle) == null ? void 0 : a["font-weight"], c = (g = n == null ? void 0 : n.textStyle) == null ? void 0 : g["font-style"];
|
|
42
|
+
return r(t, "background-color", (d = n == null ? void 0 : n.textBackgroundColor) == null ? void 0 : d.color), r(t, "padding", l), r(o, "font-family", (b = n == null ? void 0 : n.textStyle) == null ? void 0 : b["font-family"]), r(o, "font-size", (p = n == null ? void 0 : n.textStyle) == null ? void 0 : p["font-size"]), r(o, "font-weight", x), r(o, "font-style", c), r(o, "color", (s = n == null ? void 0 : n.textColor) == null ? void 0 : s.color), r(o, "line-height", I(n ?? {})), r(o, "text-align", i), {
|
|
43
|
+
tdStyle: t.join("; "),
|
|
44
|
+
pStyle: o.join("; "),
|
|
45
|
+
align: i || void 0,
|
|
46
|
+
wrapBold: x === "bold",
|
|
47
|
+
wrapItalic: c === "italic",
|
|
48
|
+
textTrimming: (n == null ? void 0 : n.textTrimming) === !0
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function N(n) {
|
|
52
|
+
var u, a, g, d, b, p, s, k, w, P, B, z;
|
|
53
|
+
const t = [], o = [], i = [];
|
|
54
|
+
r(t, "padding", $((u = n == null ? void 0 : n.buttonExternalPadding) == null ? void 0 : u.desktop)), r(i, "padding", $((a = n == null ? void 0 : n.buttonInternalPadding) == null ? void 0 : a.desktop)), r(i, "font-family", (g = n == null ? void 0 : n.buttonStyle) == null ? void 0 : g["font-family"]), r(i, "font-size", (d = n == null ? void 0 : n.buttonStyle) == null ? void 0 : d["font-size"]), r(i, "font-weight", (b = n == null ? void 0 : n.buttonStyle) == null ? void 0 : b["font-weight"]), r(i, "font-style", (p = n == null ? void 0 : n.buttonStyle) == null ? void 0 : p["font-style"]);
|
|
55
|
+
const l = (s = n == null ? void 0 : n.buttonColor) == null ? void 0 : s.color, x = (k = n == null ? void 0 : n.textButtonColor) == null ? void 0 : k.color;
|
|
56
|
+
r(o, "background", l), r(i, "background", l), r(i, "color", x);
|
|
57
|
+
const c = n == null ? void 0 : n.buttonBorder;
|
|
58
|
+
S(o, "width", c == null ? void 0 : c.width, (y) => `${y}px`), S(o, "style", c == null ? void 0 : c.style, (y) => y), S(o, "color", c == null ? void 0 : c.color, (y) => y);
|
|
59
|
+
const f = C(n == null ? void 0 : n.buttonBorderRadius);
|
|
60
|
+
return f && (r(o, "border-radius", f), r(i, "border-radius", f)), ((w = n == null ? void 0 : n.buttonStretch) == null ? void 0 : w.stretched) === !1 ? (r(o, "display", "inline-block"), r(i, "display", "inline-block")) : ((P = n == null ? void 0 : n.buttonStretch) == null ? void 0 : P.stretched) === !0 && (r(o, "display", "block"), r(i, "display", "block")), {
|
|
61
|
+
tdStyle: t.join("; "),
|
|
62
|
+
align: ((B = n == null ? void 0 : n.buttonAlign) == null ? void 0 : B.align) || void 0,
|
|
63
|
+
spanStyle: o.join("; "),
|
|
64
|
+
aStyle: i.join("; "),
|
|
65
|
+
text: (z = n == null ? void 0 : n.buttonText) == null ? void 0 : z.text
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function T(n) {
|
|
69
|
+
if (typeof n == "number" && Number.isFinite(n) && n >= 0)
|
|
70
|
+
return Math.trunc(n);
|
|
71
|
+
if (typeof n == "string" && /^\d+$/.test(n.trim())) {
|
|
72
|
+
const t = Number(n.trim());
|
|
73
|
+
if (Number.isFinite(t) && t >= 0)
|
|
74
|
+
return t;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function A(n) {
|
|
78
|
+
var t, o;
|
|
79
|
+
return {
|
|
80
|
+
width: T((t = n == null ? void 0 : n.imageSize) == null ? void 0 : t.width),
|
|
81
|
+
height: T((o = n == null ? void 0 : n.imageSize) == null ? void 0 : o.height)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function F(n, t) {
|
|
85
|
+
const o = (n ?? "").trim().replace(/;$/, "").trim(), i = (t ?? "").trim().replace(/;$/, "").trim();
|
|
86
|
+
return o ? i ? `${o}; ${i}` : o : i;
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
F as appendStyle,
|
|
90
|
+
N as mapButtonTheme,
|
|
91
|
+
A as mapImageTheme,
|
|
92
|
+
L as mapTextTheme
|
|
93
|
+
};
|
|
@@ -1,297 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
class
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
* @returns The background color value or empty string
|
|
52
|
-
*/
|
|
53
|
-
extractCardBgColor(e) {
|
|
54
|
-
const t = e.getAttribute("bgcolor");
|
|
55
|
-
if (t)
|
|
56
|
-
return t.trim();
|
|
57
|
-
const s = e.getAttribute("style");
|
|
58
|
-
if (s) {
|
|
59
|
-
const o = s.match(/background-color\s*:\s*([^;]+)/i);
|
|
60
|
-
if (o && o[1])
|
|
61
|
-
return o[1].trim();
|
|
62
|
-
}
|
|
63
|
-
return "";
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Extracts title from old block and converts to new structure
|
|
67
|
-
* @param block - The old recommendation block element
|
|
68
|
-
* @returns HTML string for the title block
|
|
69
|
-
*/
|
|
70
|
-
extractTitle(e) {
|
|
71
|
-
var g, a;
|
|
72
|
-
const t = e.querySelector(".ext-recommendation-title");
|
|
73
|
-
if (!t)
|
|
74
|
-
return this.buildTitleBlock({
|
|
75
|
-
text: "You May Also Like!",
|
|
76
|
-
isBold: !0,
|
|
77
|
-
isItalic: !1,
|
|
78
|
-
align: "center",
|
|
79
|
-
styles: "font-size: 28px; color: #333333;"
|
|
80
|
-
});
|
|
81
|
-
const s = t.querySelector("p");
|
|
82
|
-
if (!s) {
|
|
83
|
-
const p = ((g = t.textContent) == null ? void 0 : g.trim()) || "You May Also Like!", b = t.getAttribute("align") || "center";
|
|
84
|
-
return this.buildTitleBlock({
|
|
85
|
-
text: p,
|
|
86
|
-
isBold: !0,
|
|
87
|
-
isItalic: !1,
|
|
88
|
-
align: b,
|
|
89
|
-
styles: "font-size: 28px; color: #333333;"
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
const o = ((a = s.textContent) == null ? void 0 : a.trim()) || "You May Also Like!", i = t.getAttribute("align") || s.getAttribute("align") || "center", r = s.getAttribute("style") || "", n = /font-weight\s*:\s*bold/i.test(r) || !!s.querySelector("b, strong"), u = /font-style\s*:\s*italic/i.test(r) || !!s.querySelector("i, em"), c = this.removeStyleProperties(r, ["font-weight", "font-style"]), l = this.convertInlineToBlock(c);
|
|
93
|
-
return this.buildTitleBlock({
|
|
94
|
-
text: o,
|
|
95
|
-
isBold: n,
|
|
96
|
-
isItalic: u,
|
|
97
|
-
align: i,
|
|
98
|
-
styles: l
|
|
1
|
+
import { BlockId as f } from "../../enums/block.js";
|
|
2
|
+
import { useTemplateStore as u } from "../../stores/template.js";
|
|
3
|
+
import { mapComposition as b } from "./recommendation/compositionMapper.js";
|
|
4
|
+
import { extractTitleText as y, extractCardBgColor as v } from "./recommendation/extractors.js";
|
|
5
|
+
import { buildBlockHtml as C } from "./recommendation/htmlBuilder.js";
|
|
6
|
+
import { parseRecommendationId as R, parseLegacyConfig as S } from "./recommendation/parseLegacyConfig.js";
|
|
7
|
+
import { mapSettings as w } from "./recommendation/settingsMapper.js";
|
|
8
|
+
const x = 'td[esd-dev-product-config][class*="ins-recommendation-v3-block-"]:not(.recommendation-block-v2), td.product-block[esd-handler-name*="EmailRecommendationV3"][esd-dev-product-config]:not(.recommendation-block-v2)';
|
|
9
|
+
function M(i, o, c) {
|
|
10
|
+
var s;
|
|
11
|
+
const t = R(o);
|
|
12
|
+
if (t === null)
|
|
13
|
+
return console.warn(
|
|
14
|
+
"[RecommendationMigrator] Skipping block — missing/invalid `ins-recommendation-v3-campaign-id`"
|
|
15
|
+
), !1;
|
|
16
|
+
const r = S(o);
|
|
17
|
+
if (!r)
|
|
18
|
+
return console.warn(
|
|
19
|
+
`[RecommendationMigrator] Aborting block id=${t} — \`esd-dev-product-config\` missing or unable to be parsed`
|
|
20
|
+
), !1;
|
|
21
|
+
const n = c[String(t)];
|
|
22
|
+
if (!n)
|
|
23
|
+
return console.warn(
|
|
24
|
+
`[RecommendationMigrator] Aborting block id=${t} — recommendationConfigs entry missing in Guido Config`
|
|
25
|
+
), !1;
|
|
26
|
+
const m = w(n, r, t), e = b((s = r.composition) == null ? void 0 : s.variables), d = y(o), l = v(o), g = {
|
|
27
|
+
...m,
|
|
28
|
+
composition: e.composition,
|
|
29
|
+
visibility: e.visibility,
|
|
30
|
+
textTrimming: e.anyTextTrimming
|
|
31
|
+
}, p = C({
|
|
32
|
+
nodeConfig: g,
|
|
33
|
+
composition: e,
|
|
34
|
+
cardBg: l,
|
|
35
|
+
titleText: d,
|
|
36
|
+
legacyId: o.getAttribute("id") ?? void 0,
|
|
37
|
+
legacyBgColor: o.getAttribute("bgcolor") ?? void 0
|
|
38
|
+
}), a = i.parseFromString(`<table><tbody><tr>${p}</tr></tbody></table>`, "text/html").querySelector(".recommendation-block-v2");
|
|
39
|
+
return !a || !o.parentNode ? (console.warn(
|
|
40
|
+
`[RecommendationMigrator] Aborting block id=${t} — failed to construct new HTML element`
|
|
41
|
+
), !1) : (o.parentNode.replaceChild(a, o), !0);
|
|
42
|
+
}
|
|
43
|
+
function H(i, o = {}) {
|
|
44
|
+
const c = new DOMParser(), t = c.parseFromString(i, "text/html"), r = Array.from(t.querySelectorAll(x));
|
|
45
|
+
try {
|
|
46
|
+
u().$patch((e) => {
|
|
47
|
+
e.migrations = {
|
|
48
|
+
...e.migrations,
|
|
49
|
+
[f.Recommendation]: r.length
|
|
50
|
+
};
|
|
99
51
|
});
|
|
52
|
+
} catch {
|
|
100
53
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
*/
|
|
106
|
-
extractProductRows(e) {
|
|
107
|
-
const t = this.extractProductConfig(e);
|
|
108
|
-
if (!t)
|
|
109
|
-
return console.warn("[RecommendationMigrator] No product config found, using defaults"), this.generateProductRows(6, 3, {});
|
|
110
|
-
const { totalCount: s, productsPerRow: o } = t, i = this.extractProductStyles(e);
|
|
111
|
-
return this.generateProductRows(s, o, i);
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Extracts Stripo padding/margin utility classes from a class string
|
|
115
|
-
* @param classString - Space-separated class string from element
|
|
116
|
-
* @returns Filtered Stripo utility classes as a space-separated string
|
|
117
|
-
*/
|
|
118
|
-
extractStripoClasses(e) {
|
|
119
|
-
return e ? e.split(/\s+/).filter((o) => /^es-(p\d+|m[-\d])/.test(o)).join(" ") : "";
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Extracts product configuration from old block
|
|
123
|
-
* @param block - The old recommendation block element
|
|
124
|
-
* @returns Object with totalCount and productsPerRow, or null if parsing fails
|
|
125
|
-
*/
|
|
126
|
-
extractProductConfig(e) {
|
|
127
|
-
const t = e.getAttribute("esd-dev-product-config");
|
|
128
|
-
if (!t)
|
|
129
|
-
return null;
|
|
54
|
+
if (r.length === 0)
|
|
55
|
+
return i;
|
|
56
|
+
let n = 0;
|
|
57
|
+
return r.forEach((m) => {
|
|
130
58
|
try {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
productsPerRow: o.rowCount ?? 3
|
|
135
|
-
};
|
|
136
|
-
} catch (s) {
|
|
137
|
-
return console.error("[RecommendationMigrator] Failed to parse product config:", s), console.error(
|
|
138
|
-
"[RecommendationMigrator] Error details:",
|
|
139
|
-
s instanceof Error ? s.message : String(s)
|
|
140
|
-
), null;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Decodes HTML entities from JSON string
|
|
145
|
-
* @param text - The encoded string
|
|
146
|
-
* @returns Decoded string
|
|
147
|
-
*/
|
|
148
|
-
unescapeJsonString(e) {
|
|
149
|
-
return e.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/'/g, "'").replace(/"/g, '"').replace(/\\\\"/g, "'");
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Generates product rows using prepareProductRows with default product data
|
|
153
|
-
* @param totalCount - Total number of products to display
|
|
154
|
-
* @param productsPerRow - Number of products in each row
|
|
155
|
-
* @param extractedStyles - Styles extracted from old product elements
|
|
156
|
-
* @returns HTML string for product rows with applied styles
|
|
157
|
-
*/
|
|
158
|
-
generateProductRows(e, t, s) {
|
|
159
|
-
const o = $(), i = [];
|
|
160
|
-
for (let n = 0; n < e; n++) {
|
|
161
|
-
const u = o[n % o.length];
|
|
162
|
-
i.push({ ...u });
|
|
163
|
-
}
|
|
164
|
-
let r = q(i, t);
|
|
165
|
-
return r = this.applyExtractedStyles(r, s), r;
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Extracts styles from old product elements
|
|
169
|
-
* @param block - The old recommendation block element
|
|
170
|
-
* @returns Object with extracted styles for each element type
|
|
171
|
-
*/
|
|
172
|
-
extractProductStyles(e) {
|
|
173
|
-
const t = {}, s = e.querySelector(".product-card");
|
|
174
|
-
if (!s)
|
|
175
|
-
return console.warn("[RecommendationMigrator] No product card found, using default styles"), t;
|
|
176
|
-
const o = this.extractCardBgColor(s);
|
|
177
|
-
o && (t.cardBgColor = o);
|
|
178
|
-
const i = s.querySelector(".ext-product-image");
|
|
179
|
-
if (i) {
|
|
180
|
-
const l = i.querySelector("img"), g = l == null ? void 0 : l.getAttribute("width"), a = i.getAttribute("style") || "", p = i.getAttribute("align") || "center", b = i.getAttribute("class") || "", m = this.extractStripoClasses(b);
|
|
181
|
-
t.imageWidth = g || "120", t.imageAlign = p, t.imageTdStyle = a, t.imageClasses = m;
|
|
182
|
-
}
|
|
183
|
-
const r = s.querySelector(".ext-product-name");
|
|
184
|
-
if (r) {
|
|
185
|
-
const l = r.querySelector("p"), g = (l == null ? void 0 : l.getAttribute("style")) || "", a = r.getAttribute("align") || "center", p = r.getAttribute("style") || "", b = r.getAttribute("class") || "", m = this.extractStripoClasses(b);
|
|
186
|
-
t.nameStyle = g, t.nameAlign = a, t.nameTdStyle = p, t.nameClasses = m;
|
|
187
|
-
}
|
|
188
|
-
const n = s.querySelector(".ext-product-price");
|
|
189
|
-
if (n) {
|
|
190
|
-
const l = n.querySelector("p"), g = (l == null ? void 0 : l.getAttribute("style")) || "", a = n.getAttribute("align") || "center", p = n.getAttribute("style") || "", b = n.getAttribute("class") || "", m = this.extractStripoClasses(b);
|
|
191
|
-
t.priceStyle = g, t.priceAlign = a, t.priceTdStyle = p, t.priceClasses = m;
|
|
192
|
-
}
|
|
193
|
-
const u = s.querySelector(".ext-product-original-price");
|
|
194
|
-
if (u) {
|
|
195
|
-
const l = u.querySelector("p"), g = (l == null ? void 0 : l.getAttribute("style")) || "", a = u.getAttribute("align") || "center", p = u.getAttribute("style") || "", b = u.getAttribute("class") || "", m = this.extractStripoClasses(b);
|
|
196
|
-
t.oldPriceStyle = g, t.oldPriceAlign = a, t.oldPriceTdStyle = p, t.oldPriceClasses = m;
|
|
197
|
-
}
|
|
198
|
-
const c = s.querySelector(".ext-product-button");
|
|
199
|
-
if (c) {
|
|
200
|
-
const l = c.querySelector(".es-button-border"), g = c.querySelector("a.es-button"), a = (l == null ? void 0 : l.getAttribute("style")) || "", p = (g == null ? void 0 : g.getAttribute("style")) || "", b = c.getAttribute("align") || "center", m = c.getAttribute("style") || "", f = c.getAttribute("class") || "", C = this.extractStripoClasses(f), y = ((c == null ? void 0 : c.textContent) || "").trim();
|
|
201
|
-
t.buttonBorderStyle = a, t.buttonLinkStyle = p, t.buttonAlign = b, t.buttonTdStyle = m, t.buttonClasses = C, t.buttonText = y;
|
|
59
|
+
M(c, m, o) && (n += 1);
|
|
60
|
+
} catch (e) {
|
|
61
|
+
console.error("[RecommendationMigrator] Unexpected error migrating block:", e);
|
|
202
62
|
}
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Applies extracted styles to the generated HTML
|
|
207
|
-
* @param html - The generated HTML from prepareProductRows
|
|
208
|
-
* @param extractedStyles - Styles extracted from old product elements
|
|
209
|
-
* @returns HTML with applied styles
|
|
210
|
-
*/
|
|
211
|
-
applyExtractedStyles(e, t) {
|
|
212
|
-
if (!t || Object.keys(t).length === 0)
|
|
213
|
-
return e;
|
|
214
|
-
const s = this.parser.parseFromString(`<table>${e}</table>`, "text/html");
|
|
215
|
-
t.cardBgColor && s.querySelectorAll(".product-attribute-cell").forEach((r) => {
|
|
216
|
-
r.setAttribute("bgcolor", t.cardBgColor);
|
|
217
|
-
}), (t.imageWidth || t.imageAlign || t.imageTdStyle || t.imageClasses) && s.querySelectorAll(".product-image").forEach((r) => {
|
|
218
|
-
if (t.imageAlign && r.setAttribute("align", t.imageAlign), t.imageTdStyle && r.setAttribute("style", t.imageTdStyle), t.imageClasses) {
|
|
219
|
-
const c = `${r.getAttribute("class") || ""} ${t.imageClasses}`.trim();
|
|
220
|
-
r.setAttribute("class", c);
|
|
221
|
-
}
|
|
222
|
-
const n = r.querySelector("img");
|
|
223
|
-
n && t.imageWidth && n.setAttribute("width", t.imageWidth);
|
|
224
|
-
}), (t.nameStyle || t.nameAlign || t.nameTdStyle || t.nameClasses) && s.querySelectorAll(".product-name").forEach((r) => {
|
|
225
|
-
if (t.nameAlign && r.setAttribute("align", t.nameAlign), t.nameTdStyle && r.setAttribute("style", t.nameTdStyle), t.nameClasses) {
|
|
226
|
-
const c = `${r.getAttribute("class") || ""} ${t.nameClasses}`.trim();
|
|
227
|
-
r.setAttribute("class", c);
|
|
228
|
-
}
|
|
229
|
-
const n = r.querySelector("p");
|
|
230
|
-
n && t.nameStyle && n.setAttribute("style", t.nameStyle);
|
|
231
|
-
}), (t.priceStyle || t.priceAlign || t.priceTdStyle || t.priceClasses) && s.querySelectorAll(".product-price").forEach((r) => {
|
|
232
|
-
if (t.priceAlign && r.setAttribute("align", t.priceAlign), t.priceTdStyle && r.setAttribute("style", t.priceTdStyle), t.priceClasses) {
|
|
233
|
-
const c = `${r.getAttribute("class") || ""} ${t.priceClasses}`.trim();
|
|
234
|
-
r.setAttribute("class", c);
|
|
235
|
-
}
|
|
236
|
-
const n = r.querySelector("p");
|
|
237
|
-
n && t.priceStyle && n.setAttribute("style", t.priceStyle);
|
|
238
|
-
}), (t.oldPriceStyle || t.oldPriceAlign || t.oldPriceTdStyle || t.oldPriceClasses) && s.querySelectorAll(".product-old-price").forEach((r) => {
|
|
239
|
-
if (t.oldPriceAlign && r.setAttribute("align", t.oldPriceAlign), t.oldPriceTdStyle && r.setAttribute("style", t.oldPriceTdStyle), t.oldPriceClasses) {
|
|
240
|
-
const c = `${r.getAttribute("class") || ""} ${t.oldPriceClasses}`.trim();
|
|
241
|
-
r.setAttribute("class", c);
|
|
242
|
-
}
|
|
243
|
-
const n = r.querySelector("p");
|
|
244
|
-
n && t.oldPriceStyle && n.setAttribute("style", t.oldPriceStyle);
|
|
245
|
-
}), (t.buttonBorderStyle || t.buttonLinkStyle || t.buttonAlign || t.buttonTdStyle || t.buttonClasses) && s.querySelectorAll(".product-button").forEach((r) => {
|
|
246
|
-
if (t.buttonAlign && r.setAttribute("align", t.buttonAlign), t.buttonTdStyle && r.setAttribute("style", t.buttonTdStyle), t.buttonClasses) {
|
|
247
|
-
const l = `${r.getAttribute("class") || ""} ${t.buttonClasses}`.trim();
|
|
248
|
-
r.setAttribute("class", l);
|
|
249
|
-
}
|
|
250
|
-
const n = r.querySelector(".es-button-border");
|
|
251
|
-
n && t.buttonBorderStyle && n.setAttribute("style", t.buttonBorderStyle);
|
|
252
|
-
const u = r.querySelector("a.es-button");
|
|
253
|
-
u && (t.buttonLinkStyle && u.setAttribute("style", t.buttonLinkStyle), t.buttonText && (u.textContent = t.buttonText));
|
|
254
|
-
});
|
|
255
|
-
const o = s.querySelector("table");
|
|
256
|
-
return (o == null ? void 0 : o.innerHTML) || e;
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Builds title block with proper structure
|
|
260
|
-
*/
|
|
261
|
-
buildTitleBlock(e) {
|
|
262
|
-
let t = e.text;
|
|
263
|
-
e.isBold && e.isItalic ? t = `<strong path="1,0"><em path="1,0,0">${t}</em></strong>` : e.isBold ? t = `<strong path="1,0">${t}</strong>` : e.isItalic && (t = `<em path="1,0">${t}</em>`);
|
|
264
|
-
const s = e.align ? ` align="${e.align}"` : "", o = e.styles ? ` style="${e.styles}"` : "";
|
|
265
|
-
return `
|
|
266
|
-
<td class="esd-block-text es-p10t es-p10b es-p20l es-p20r"${s}>
|
|
267
|
-
<p path="1"${o}>
|
|
268
|
-
${t}
|
|
269
|
-
</p>
|
|
270
|
-
</td>
|
|
271
|
-
`;
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Removes specified style properties from a style string
|
|
275
|
-
*/
|
|
276
|
-
removeStyleProperties(e, t) {
|
|
277
|
-
return e ? t.reduce((o, i) => {
|
|
278
|
-
const r = new RegExp(`${i}\\s*:\\s*[^;]*;?`, "gi");
|
|
279
|
-
return o.replace(r, "");
|
|
280
|
-
}, e).replace(/;\s*;/g, ";").replace(/^;|;$/g, "").trim() : "";
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Converts inline display to block display
|
|
284
|
-
*/
|
|
285
|
-
convertInlineToBlock(e) {
|
|
286
|
-
if (!e)
|
|
287
|
-
return "";
|
|
288
|
-
let t = e.replace(/display\s*:\s*inline/gi, "display: block");
|
|
289
|
-
return /display\s*:/i.test(t) || (t = t ? `${t}; display: block` : "display: block"), t.replace(/;\s*;/g, ";").replace(/^;|;$/g, "").replace(/"/g, "'").trim();
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
function v(d) {
|
|
293
|
-
return new B().migrate(d);
|
|
63
|
+
}), n > 0 && console.info(`[RecommendationMigrator] Migrated ${n} legacy Recommendation block(s)`), t.documentElement.outerHTML;
|
|
294
64
|
}
|
|
295
65
|
export {
|
|
296
|
-
|
|
66
|
+
H as migrateRecommendation
|
|
297
67
|
};
|
|
@@ -18,7 +18,8 @@ const s = {
|
|
|
18
18
|
{ text: "after the amount", value: "1" }
|
|
19
19
|
], d = [
|
|
20
20
|
{ text: "dot(.)", value: "." },
|
|
21
|
-
{ text: "comma(,)", value: "," }
|
|
21
|
+
{ text: "comma(,)", value: "," },
|
|
22
|
+
{ text: "space( )", value: " " }
|
|
22
23
|
], p = [
|
|
23
24
|
{ text: "0", value: "0" },
|
|
24
25
|
{ text: "1", value: "1" },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEFAULT_COLUMN_SPACING as R, DEFAULT_ROW_SPACING as U, DEFAULT_MOBILE_ROW_SPACING as i, DEFAULT_MOBILE_COLUMN_SPACING as s, DEFAULT_MOBILE_CARDS_IN_ROW as o, DEFAULT_CARDS_IN_ROW as C } from "./layout.js";
|
|
2
2
|
import { ATTR_PRODUCT_IMAGE as _, ATTR_PRODUCT_NAME as e, ATTR_PRODUCT_OLD_PRICE as t, ATTR_PRODUCT_PRICE as T, ATTR_PRODUCT_OMNIBUS_PRICE as r, ATTR_PRODUCT_OMNIBUS_DISCOUNT as I, ATTR_PRODUCT_BUTTON as n } from "./selectors.js";
|
|
3
3
|
const O = {
|
|
4
4
|
code: "USD",
|
|
@@ -44,10 +44,10 @@ const O = {
|
|
|
44
44
|
mobileCardsInRow: o,
|
|
45
45
|
mobileLayoutEnabled: !1,
|
|
46
46
|
previousMobileCardsInRow: o,
|
|
47
|
-
columnSpacing:
|
|
48
|
-
rowSpacing:
|
|
49
|
-
mobileColumnSpacing:
|
|
50
|
-
mobileRowSpacing:
|
|
47
|
+
columnSpacing: R,
|
|
48
|
+
rowSpacing: U,
|
|
49
|
+
mobileColumnSpacing: s,
|
|
50
|
+
mobileRowSpacing: i,
|
|
51
51
|
// Composition
|
|
52
52
|
composition: a,
|
|
53
53
|
visibility: E,
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { ModificationDescription as
|
|
2
|
-
import { CURRENT_CONFIG_VERSION as
|
|
3
|
-
import { setCurrencyAttributes as
|
|
4
|
-
import { hasMinimalConfig as
|
|
5
|
-
|
|
1
|
+
import { ModificationDescription as h } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
2
|
+
import { CURRENT_CONFIG_VERSION as l, DEFAULT_NODE_CONFIG as r } from "../constants/defaultConfig.js";
|
|
3
|
+
import { setCurrencyAttributes as D } from "../controls/main/utils.js";
|
|
4
|
+
import { hasMinimalConfig as A } from "../types/nodeConfig.js";
|
|
5
|
+
function S(e) {
|
|
6
|
+
return e === "." || e === "," || e === " ";
|
|
7
|
+
}
|
|
8
|
+
function N(e) {
|
|
9
|
+
return e === "." || e === "," || e === " " || e === "";
|
|
10
|
+
}
|
|
11
|
+
class V {
|
|
6
12
|
// ========================================================================
|
|
7
13
|
// Read Operations
|
|
8
14
|
// ========================================================================
|
|
@@ -42,7 +48,7 @@ class C {
|
|
|
42
48
|
return !1;
|
|
43
49
|
try {
|
|
44
50
|
const t = i.getNodeConfig();
|
|
45
|
-
return
|
|
51
|
+
return A(t);
|
|
46
52
|
} catch {
|
|
47
53
|
return !1;
|
|
48
54
|
}
|
|
@@ -77,8 +83,8 @@ class C {
|
|
|
77
83
|
* @returns The new complete configuration
|
|
78
84
|
*/
|
|
79
85
|
static updateConfig(i, t, o, n) {
|
|
80
|
-
const
|
|
81
|
-
return this.saveConfig(i, t,
|
|
86
|
+
const c = this.getConfig(t), u = this.deepMerge(c, o);
|
|
87
|
+
return this.saveConfig(i, t, u, n), u;
|
|
82
88
|
}
|
|
83
89
|
/**
|
|
84
90
|
* Initialize configuration for a new block
|
|
@@ -95,7 +101,7 @@ class C {
|
|
|
95
101
|
*/
|
|
96
102
|
static initializeConfig(i, t, o) {
|
|
97
103
|
const n = o ? this.mergeWithDefaults(o) : this.cloneDefaults();
|
|
98
|
-
return this.saveConfig(i, t, n, "Initialize recommendation block"),
|
|
104
|
+
return this.saveConfig(i, t, n, "Initialize recommendation block"), D({
|
|
99
105
|
currentNode: t,
|
|
100
106
|
documentModifier: i.getDocumentModifier(),
|
|
101
107
|
currency: n.currency
|
|
@@ -112,9 +118,9 @@ class C {
|
|
|
112
118
|
*/
|
|
113
119
|
static saveConfig(i, t, o, n) {
|
|
114
120
|
try {
|
|
115
|
-
i.getDocumentModifier().modifyHtml(t).setNodeConfig(o).apply(new
|
|
116
|
-
} catch (
|
|
117
|
-
console.warn("[RecommendationConfigService] Failed to save config:",
|
|
121
|
+
i.getDocumentModifier().modifyHtml(t).setNodeConfig(o).apply(new h(n));
|
|
122
|
+
} catch (c) {
|
|
123
|
+
console.warn("[RecommendationConfigService] Failed to save config:", c);
|
|
118
124
|
}
|
|
119
125
|
}
|
|
120
126
|
// ========================================================================
|
|
@@ -125,23 +131,53 @@ class C {
|
|
|
125
131
|
*
|
|
126
132
|
* Reads existing data-attributes and creates a proper node config.
|
|
127
133
|
* Used when loading templates created before node config was implemented.
|
|
134
|
+
*
|
|
135
|
+
* Sources, in priority order (later overrides earlier):
|
|
136
|
+
* 1. `esd-ext-config` JSON blob — emitted by the recommendation migrator and
|
|
137
|
+
* by hand-authored new templates. Carries the full RecommendationNodeConfig
|
|
138
|
+
* (strategy, language, currency, filters, productIds, etc.) which the
|
|
139
|
+
* discrete data-* attrs below cannot capture.
|
|
140
|
+
* 2. Discrete `data-*` attributes — runtime source of truth for
|
|
141
|
+
* layout/composition/spacing; controls keep these in sync as the user
|
|
142
|
+
* edits, so we let them override the JSON blob if they disagree.
|
|
143
|
+
* 3. `currency-*` attributes — durable currency source on the block element.
|
|
128
144
|
* @param api - Stripo extension API with document modifier
|
|
129
145
|
* @param node - The block node to migrate
|
|
130
146
|
* @returns The migrated configuration
|
|
131
147
|
*/
|
|
132
148
|
static migrateFromDataAttributes(i, t) {
|
|
133
149
|
const o = {
|
|
134
|
-
configVersion:
|
|
150
|
+
configVersion: l
|
|
135
151
|
};
|
|
136
152
|
if ("getAttribute" in t && typeof t.getAttribute == "function") {
|
|
137
|
-
const n = t.getAttribute("
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
c
|
|
153
|
+
const n = t.getAttribute("esd-ext-config");
|
|
154
|
+
if (n)
|
|
155
|
+
try {
|
|
156
|
+
const s = JSON.parse(n);
|
|
157
|
+
s && typeof s == "object" && (Object.assign(o, s), o.configVersion = l);
|
|
158
|
+
} catch {
|
|
159
|
+
}
|
|
160
|
+
const c = t.getAttribute("data-layout");
|
|
161
|
+
c === "list" || c === "horizontal" ? o.layout = "list" : (c === "grid" || c === "vertical") && (o.layout = "grid");
|
|
162
|
+
const u = t.getAttribute("data-card-composition");
|
|
163
|
+
u && (o.composition = u.split(",").filter(Boolean));
|
|
164
|
+
const p = t.getAttribute("data-column-spacing");
|
|
165
|
+
p && (o.columnSpacing = parseInt(p) || r.columnSpacing);
|
|
166
|
+
const b = t.getAttribute("data-row-spacing");
|
|
167
|
+
if (b && (o.rowSpacing = parseInt(b) || r.rowSpacing), !o.currency) {
|
|
168
|
+
const s = t.getAttribute("currency"), y = t.getAttribute("currency-symbol"), d = t.getAttribute("currency-alignment"), f = t.getAttribute("currency-thousand-separator"), g = t.getAttribute("currency-decimal-separator"), m = t.getAttribute("currency-decimal-count");
|
|
169
|
+
if (s || y || d || f || g || m) {
|
|
170
|
+
const a = r.currency, C = m ? parseInt(m) : NaN;
|
|
171
|
+
o.currency = {
|
|
172
|
+
code: s ?? a.code,
|
|
173
|
+
symbol: y ?? a.symbol,
|
|
174
|
+
alignment: d === "0" ? "before" : "after",
|
|
175
|
+
decimalCount: Number.isFinite(C) ? C : a.decimalCount,
|
|
176
|
+
decimalSeparator: S(g) ? g : a.decimalSeparator,
|
|
177
|
+
thousandSeparator: N(f) ? f : a.thousandSeparator
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
145
181
|
}
|
|
146
182
|
return this.initializeConfig(i, t, o);
|
|
147
183
|
}
|
|
@@ -151,7 +187,7 @@ class C {
|
|
|
151
187
|
* @returns True if migration is needed
|
|
152
188
|
*/
|
|
153
189
|
static needsMigration(i) {
|
|
154
|
-
return i ? this.hasConfig(i) ? this.getConfigVersion(i) <
|
|
190
|
+
return i ? this.hasConfig(i) ? this.getConfigVersion(i) < l : !0 : !1;
|
|
155
191
|
}
|
|
156
192
|
// ========================================================================
|
|
157
193
|
// Internal Helpers
|
|
@@ -161,12 +197,12 @@ class C {
|
|
|
161
197
|
*/
|
|
162
198
|
static cloneDefaults() {
|
|
163
199
|
return {
|
|
164
|
-
...
|
|
165
|
-
currency: { ...
|
|
166
|
-
omnibusPrice: { ...
|
|
167
|
-
omnibusDiscount: { ...
|
|
168
|
-
composition: [...
|
|
169
|
-
visibility: { ...
|
|
200
|
+
...r,
|
|
201
|
+
currency: { ...r.currency },
|
|
202
|
+
omnibusPrice: { ...r.omnibusPrice },
|
|
203
|
+
omnibusDiscount: { ...r.omnibusDiscount },
|
|
204
|
+
composition: [...r.composition],
|
|
205
|
+
visibility: { ...r.visibility },
|
|
170
206
|
filters: [],
|
|
171
207
|
productIds: [],
|
|
172
208
|
recommendationId: 0
|
|
@@ -236,5 +272,5 @@ class C {
|
|
|
236
272
|
}
|
|
237
273
|
}
|
|
238
274
|
export {
|
|
239
|
-
|
|
275
|
+
V as RecommendationConfigService
|
|
240
276
|
};
|