@useinsider/guido 3.5.0-beta.b7a6d77 → 3.5.1-beta.4b9dd49
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/composables/useRecommendation.js +33 -34
- package/dist/config/compiler/utils/recommendationCompilerUtils.js +84 -78
- package/dist/config/migrator/checkboxMigrator.js +20 -69
- package/dist/config/migrator/radioButtonMigrator.js +36 -91
- package/dist/config/migrator/textBlockMigration.js +65 -0
- package/dist/extensions/Blocks/Recommendation/block.js +100 -46
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +9 -13
- package/dist/src/config/migrator/textBlockMigration.d.ts +24 -0
- package/dist/src/extensions/Blocks/Recommendation/block.d.ts +29 -2
- package/dist/static/styles/components/wide-panel.css.js +5 -0
- package/package.json +1 -1
- package/dist/extensions/Blocks/Recommendation/utils/partnerCustomizations.js +0 -21
- package/dist/src/extensions/Blocks/Recommendation/utils/partnerCustomizations.d.ts +0 -7
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
import { getRecommendationFeedSourceMaps as I, URLS as
|
|
2
|
-
import { MinDeviceViewport as
|
|
3
|
-
import { useRecommendationExtensionStore as
|
|
1
|
+
import { getRecommendationFeedSourceMaps as I, URLS as C } from "../enums/extensions/recommendationBlock.js";
|
|
2
|
+
import { MinDeviceViewport as R, DefaultPadding as b } from "../enums/recommendation.js";
|
|
3
|
+
import { useRecommendationExtensionStore as m } from "../extensions/Blocks/Recommendation/store/recommendation.js";
|
|
4
4
|
import { generateCompleteFilterQuery as h } from "../extensions/Blocks/Recommendation/utils/filterUtil.js";
|
|
5
|
-
import { getPartnerRecommendationParams as y } from "../extensions/Blocks/Recommendation/utils/partnerCustomizations.js";
|
|
6
5
|
import { useConfigStore as x } from "../stores/config.js";
|
|
7
|
-
const
|
|
6
|
+
const w = () => ({
|
|
8
7
|
calculateCardWidth: ({
|
|
9
8
|
mobileLeftPadding: s,
|
|
10
9
|
mobileRightPadding: a,
|
|
11
10
|
cardsInRow: c,
|
|
12
|
-
unresponsive:
|
|
11
|
+
unresponsive: n
|
|
13
12
|
}) => {
|
|
14
|
-
const
|
|
15
|
-
return (
|
|
13
|
+
const r = n ? c : 1, e = s + a + (r - 1) * b;
|
|
14
|
+
return (R - e) / r;
|
|
16
15
|
},
|
|
17
16
|
getRecommendationCampaignData: (s) => {
|
|
18
|
-
const a =
|
|
19
|
-
if (!
|
|
17
|
+
const a = m(), c = Number(s), n = a.blockStates[c];
|
|
18
|
+
if (!n)
|
|
20
19
|
return {
|
|
21
20
|
textTrimming: !1,
|
|
22
21
|
orientation: "vertical",
|
|
@@ -29,14 +28,14 @@ const A = () => ({
|
|
|
29
28
|
discountBeforeTextValue: "",
|
|
30
29
|
discountAfterTextValue: ""
|
|
31
30
|
};
|
|
32
|
-
const { recommendationConfigs:
|
|
31
|
+
const { recommendationConfigs: r } = n, e = r.orientation === "grid" ? "vertical" : "horizontal";
|
|
33
32
|
return {
|
|
34
|
-
textTrimming:
|
|
33
|
+
textTrimming: r.textTrimming,
|
|
35
34
|
orientation: e,
|
|
36
35
|
mobileLeftPadding: 0,
|
|
37
36
|
mobileRightPadding: 0,
|
|
38
|
-
cardsInRow:
|
|
39
|
-
unresponsive:
|
|
37
|
+
cardsInRow: r.cardsInRow,
|
|
38
|
+
unresponsive: r.unresponsive,
|
|
40
39
|
priceBeforeTextValue: "",
|
|
41
40
|
priceAfterTextValue: "",
|
|
42
41
|
discountBeforeTextValue: "",
|
|
@@ -44,38 +43,38 @@ const A = () => ({
|
|
|
44
43
|
};
|
|
45
44
|
},
|
|
46
45
|
buildCampaignUrl: (s, a) => {
|
|
47
|
-
var
|
|
48
|
-
const c =
|
|
46
|
+
var l;
|
|
47
|
+
const c = m(), n = x(), r = Number(s);
|
|
49
48
|
let e;
|
|
50
49
|
if (a)
|
|
51
50
|
e = a;
|
|
52
51
|
else {
|
|
53
|
-
const
|
|
54
|
-
if (!
|
|
52
|
+
const i = c.blockStates[r];
|
|
53
|
+
if (!i)
|
|
55
54
|
return "";
|
|
56
|
-
const { recommendationConfigs:
|
|
55
|
+
const { recommendationConfigs: o } = i;
|
|
57
56
|
e = {
|
|
58
|
-
strategy:
|
|
59
|
-
language:
|
|
60
|
-
currencyCode:
|
|
61
|
-
size:
|
|
62
|
-
productIds:
|
|
63
|
-
filters:
|
|
64
|
-
shuffleProducts:
|
|
57
|
+
strategy: o.strategy,
|
|
58
|
+
language: o.language,
|
|
59
|
+
currencyCode: o.currencySettings.value,
|
|
60
|
+
size: o.size,
|
|
61
|
+
productIds: o.productIds,
|
|
62
|
+
filters: o.filters,
|
|
63
|
+
shuffleProducts: o.shuffleProducts
|
|
65
64
|
};
|
|
66
65
|
}
|
|
67
|
-
const f = ((
|
|
68
|
-
if (t.set("locale", e.language), t.set("currency", e.currencyCode), t.set("partnerName",
|
|
69
|
-
const
|
|
70
|
-
t.set("productId", e.productIds.slice(0,
|
|
66
|
+
const f = ((l = I().find((i) => i.key === e.strategy)) == null ? void 0 : l.path) || "", t = new URLSearchParams();
|
|
67
|
+
if (t.set("locale", e.language), t.set("currency", e.currencyCode), t.set("partnerName", n.partnerName), t.set("size", e.size), t.set("details", "true"), t.set("campaignId", n.variationId), e.strategy === "manualMerchandising") {
|
|
68
|
+
const i = parseInt(e.size) || 6;
|
|
69
|
+
t.set("productId", e.productIds.slice(0, i).join(","));
|
|
71
70
|
} else e.strategy === "similarViewed" && t.set("productId", "{itemId}");
|
|
72
71
|
e.strategy === "userBased" && t.set("userId", "{user_id}");
|
|
73
|
-
const g = e.filters.filter((
|
|
74
|
-
d && t.set("filter", d), e.shuffleProducts && t.set("shuffle", "true")
|
|
75
|
-
const p = decodeURIComponent(t.toString()), u = `${
|
|
72
|
+
const g = e.filters.filter((i) => i.isValid), d = h(g);
|
|
73
|
+
d && t.set("filter", d), e.shuffleProducts && t.set("shuffle", "true");
|
|
74
|
+
const p = decodeURIComponent(t.toString()), u = `${C.RECOMMENDATION_API_URL}/v2/${f}?${p}`;
|
|
76
75
|
return c.recommendationCampaignUrls[s] = u, u;
|
|
77
76
|
}
|
|
78
77
|
});
|
|
79
78
|
export {
|
|
80
|
-
|
|
79
|
+
w as useRecommendation
|
|
81
80
|
};
|
|
@@ -1,127 +1,133 @@
|
|
|
1
|
-
import { useConfig as
|
|
2
|
-
import { useRecommendation as
|
|
3
|
-
import { CSS_CLASS_RECO_BUTTON as
|
|
4
|
-
import { useRecommendationExtensionStore as
|
|
5
|
-
function y(r,
|
|
6
|
-
const
|
|
7
|
-
return o === "before" ? `${t} ${
|
|
1
|
+
import { useConfig as g } from "../../../composables/useConfig.js";
|
|
2
|
+
import { useRecommendation as _ } from "../../../composables/useRecommendation.js";
|
|
3
|
+
import { CSS_CLASS_RECO_BUTTON as q } from "../../../extensions/Blocks/Recommendation/constants/selectors.js";
|
|
4
|
+
import { useRecommendationExtensionStore as C } from "../../../extensions/Blocks/Recommendation/store/recommendation.js";
|
|
5
|
+
function y(r, n, e, o, i = "") {
|
|
6
|
+
const c = `{{${i}${r}_${n}_${e}}}`, t = `{{${i}${r}_${n}_currency}}`;
|
|
7
|
+
return o === "before" ? `${t} ${c}` : `${c} ${t}`;
|
|
8
8
|
}
|
|
9
|
-
function
|
|
10
|
-
|
|
9
|
+
function A(r) {
|
|
10
|
+
let n = r;
|
|
11
|
+
for (; n.children.length === 1; )
|
|
12
|
+
[n] = n.children;
|
|
13
|
+
return n;
|
|
14
|
+
}
|
|
15
|
+
function f(r, n, e, o, i, c) {
|
|
16
|
+
switch (n) {
|
|
11
17
|
case "productImage": {
|
|
12
18
|
const t = r.querySelector("img");
|
|
13
|
-
t && (t.setAttribute("src", `{{${
|
|
14
|
-
const
|
|
15
|
-
|
|
19
|
+
t && (t.setAttribute("src", `{{${c}${e}_${o}_image_url}}`), t.setAttribute("alt", `{{${c}${e}_${o}_name}}`));
|
|
20
|
+
const s = r.querySelector("a");
|
|
21
|
+
s && (s.setAttribute("href", `{{${c}${e}_${o}_url}}`), s.classList.add(q));
|
|
16
22
|
break;
|
|
17
23
|
}
|
|
18
24
|
case "productName": {
|
|
19
25
|
const t = r.querySelector("p");
|
|
20
26
|
if (t) {
|
|
21
|
-
const
|
|
22
|
-
|
|
27
|
+
const s = t.querySelector("strong") || t;
|
|
28
|
+
s.textContent = `{{${c}${e}_${o}_name}}`;
|
|
23
29
|
}
|
|
24
30
|
break;
|
|
25
31
|
}
|
|
26
32
|
case "productPrice": {
|
|
27
33
|
const t = r.querySelector("p");
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
t && (A(t).textContent = y(
|
|
35
|
+
e,
|
|
36
|
+
o,
|
|
37
|
+
"price",
|
|
38
|
+
i,
|
|
39
|
+
c
|
|
40
|
+
));
|
|
32
41
|
break;
|
|
33
42
|
}
|
|
34
43
|
case "productOldPrice": {
|
|
35
44
|
const t = r.querySelector("p");
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
n
|
|
44
|
-
), t.setAttribute("product-attr", "discount");
|
|
45
|
-
}
|
|
45
|
+
t && (A(t).textContent = y(
|
|
46
|
+
e,
|
|
47
|
+
o,
|
|
48
|
+
"original_price",
|
|
49
|
+
i,
|
|
50
|
+
c
|
|
51
|
+
), t.setAttribute("product-attr", "discount"));
|
|
46
52
|
break;
|
|
47
53
|
}
|
|
48
54
|
case "productButton": {
|
|
49
55
|
const t = r.querySelector("a");
|
|
50
|
-
t && t.setAttribute("href", `{{${
|
|
56
|
+
t && t.setAttribute("href", `{{${c}${e}_${o}_url}}`);
|
|
51
57
|
break;
|
|
52
58
|
}
|
|
53
59
|
case "productOmnibusPrice": {
|
|
54
60
|
const t = r.querySelector(".omnibus-price-value");
|
|
55
61
|
if (t) {
|
|
56
|
-
t.textContent = `{{${
|
|
57
|
-
const
|
|
58
|
-
|
|
62
|
+
t.textContent = `{{${c}${e}_${o}_omnibus_price}}`;
|
|
63
|
+
const s = t.closest("p");
|
|
64
|
+
s && (s.setAttribute("product-attr", "omnibus_price"), s.setAttribute("composition", "true"));
|
|
59
65
|
}
|
|
60
66
|
break;
|
|
61
67
|
}
|
|
62
68
|
case "productOmnibusDiscount": {
|
|
63
69
|
const t = r.querySelector(".omnibus-discount-value");
|
|
64
70
|
if (t) {
|
|
65
|
-
t.textContent = `{{${
|
|
66
|
-
const
|
|
67
|
-
|
|
71
|
+
t.textContent = `{{${c}${e}_${o}_omnibus_discount}}`;
|
|
72
|
+
const s = t.closest("p");
|
|
73
|
+
s && (s.setAttribute("product-attr", "omnibus_discount"), s.setAttribute("composition", "true"));
|
|
68
74
|
}
|
|
69
75
|
break;
|
|
70
76
|
}
|
|
71
77
|
default: {
|
|
72
78
|
const t = r.getAttribute("product-attr") ? r : r.querySelector("[product-attr]");
|
|
73
79
|
if (t) {
|
|
74
|
-
const
|
|
80
|
+
const s = t.getAttribute("product-attr"), a = t.querySelector("p");
|
|
75
81
|
if (a) {
|
|
76
82
|
const u = a.querySelector("strong") || a;
|
|
77
|
-
u.textContent = `{{${
|
|
83
|
+
u.textContent = `{{${c}${e}_${o}_${s}}}`;
|
|
78
84
|
}
|
|
79
85
|
}
|
|
80
86
|
break;
|
|
81
87
|
}
|
|
82
88
|
}
|
|
83
89
|
}
|
|
84
|
-
function
|
|
85
|
-
r.querySelectorAll(".recommendation-product-row").forEach((
|
|
86
|
-
|
|
90
|
+
function w(r, n, e, o) {
|
|
91
|
+
r.querySelectorAll(".recommendation-product-row").forEach((c, t) => {
|
|
92
|
+
c.querySelectorAll("[data-attribute-type]").forEach((a) => {
|
|
87
93
|
const u = a.getAttribute("data-attribute-type") || "", p = a.querySelectorAll(".attribute-cell");
|
|
88
94
|
p.length > 0 ? p.forEach((l) => {
|
|
89
|
-
f(l, u,
|
|
90
|
-
}) : f(a, u,
|
|
95
|
+
f(l, u, n, t, e, o);
|
|
96
|
+
}) : f(a, u, n, t, e, o);
|
|
91
97
|
});
|
|
92
98
|
});
|
|
93
99
|
}
|
|
94
|
-
function E(r,
|
|
95
|
-
const
|
|
96
|
-
if (!
|
|
100
|
+
function E(r, n, e, o) {
|
|
101
|
+
const i = r.querySelectorAll(".recommendation-product-row");
|
|
102
|
+
if (!i.length)
|
|
97
103
|
return;
|
|
98
|
-
const [
|
|
99
|
-
|
|
104
|
+
const [c] = i, t = c.querySelector("[data-attribute-type]"), s = t ? t.querySelectorAll(".attribute-cell").length : 1;
|
|
105
|
+
i.forEach((a, u) => {
|
|
100
106
|
a.querySelectorAll("[data-attribute-type]").forEach((l) => {
|
|
101
107
|
const d = l.getAttribute("data-attribute-type") || "";
|
|
102
|
-
l.querySelectorAll(".attribute-cell").forEach((
|
|
103
|
-
const
|
|
104
|
-
f(
|
|
108
|
+
l.querySelectorAll(".attribute-cell").forEach((h, $) => {
|
|
109
|
+
const S = u * s + $;
|
|
110
|
+
f(h, d, n, S, e, o);
|
|
105
111
|
});
|
|
106
112
|
});
|
|
107
113
|
});
|
|
108
114
|
}
|
|
109
|
-
function
|
|
110
|
-
r.querySelectorAll(".ins-recommendation-product-container").forEach((
|
|
111
|
-
E(
|
|
115
|
+
function R(r, n, e, o) {
|
|
116
|
+
r.querySelectorAll(".ins-recommendation-product-container").forEach((c) => {
|
|
117
|
+
E(c, n, e, o);
|
|
112
118
|
});
|
|
113
119
|
}
|
|
114
|
-
function
|
|
115
|
-
const o = r.getAttribute("data-layout") || "grid",
|
|
116
|
-
o === "list" ?
|
|
120
|
+
function P(r, n, e) {
|
|
121
|
+
const o = r.getAttribute("data-layout") || "grid", i = r.getAttribute("currency-alignment") || "after";
|
|
122
|
+
o === "list" ? w(r, n, i, e) : R(r, n, i, e);
|
|
117
123
|
}
|
|
118
|
-
function b(r,
|
|
119
|
-
const o = new RegExp(`${
|
|
120
|
-
return
|
|
124
|
+
function b(r, n, e) {
|
|
125
|
+
const o = new RegExp(`${n}\\s*:\\s*(\\d+)\\s*px`, "i"), i = r.match(o);
|
|
126
|
+
return i ? parseInt(i[1]) : e;
|
|
121
127
|
}
|
|
122
|
-
function
|
|
128
|
+
function T(r, n) {
|
|
123
129
|
let e = r.parentElement;
|
|
124
|
-
for (; e && e !==
|
|
130
|
+
for (; e && e !== n; ) {
|
|
125
131
|
if (e.tagName === "TD") {
|
|
126
132
|
const o = e.getAttribute("width");
|
|
127
133
|
if (o && o.endsWith("%") && parseFloat(o) < 100)
|
|
@@ -131,40 +137,40 @@ function P(r, c) {
|
|
|
131
137
|
}
|
|
132
138
|
return null;
|
|
133
139
|
}
|
|
134
|
-
function
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
if (
|
|
140
|
+
function v(r) {
|
|
141
|
+
const n = r.getAttribute("style") || "", e = b(n, "width", 600), o = b(n, "padding", 0) * 2, i = Math.max(0, e - o);
|
|
142
|
+
i !== 0 && r.querySelectorAll("img.adapt-img").forEach((c) => {
|
|
143
|
+
if (c.hasAttribute("width"))
|
|
138
144
|
return;
|
|
139
|
-
const t =
|
|
145
|
+
const t = T(c, r);
|
|
140
146
|
if (!t)
|
|
141
147
|
return;
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
const d =
|
|
148
|
+
const s = t.getAttribute("width"), a = parseFloat(s), u = b(t.getAttribute("style") || "", "padding", 0) * 2, p = Math.floor(i * a / 100), l = Math.max(1, p - u);
|
|
149
|
+
c.setAttribute("width", String(l));
|
|
150
|
+
const d = c.getAttribute("style") || "";
|
|
145
151
|
if (!/\bwidth\s*:\s*\d/i.test(d)) {
|
|
146
152
|
const m = d && !d.trim().endsWith(";") ? "; " : "";
|
|
147
|
-
|
|
153
|
+
c.setAttribute("style", `${d}${m}width: ${l}px`);
|
|
148
154
|
}
|
|
149
155
|
});
|
|
150
156
|
}
|
|
151
|
-
function
|
|
157
|
+
function O(r, n) {
|
|
152
158
|
const e = r.match(/<!DOCTYPE[^>]*>/i);
|
|
153
159
|
return (e ? `${e[0]}
|
|
154
|
-
` : "") +
|
|
160
|
+
` : "") + n.documentElement.outerHTML;
|
|
155
161
|
}
|
|
156
162
|
function N(r) {
|
|
157
|
-
const
|
|
163
|
+
const n = r.replaceAll("{%", "<!--{%").replaceAll("%}", "%}-->"), e = new DOMParser().parseFromString(n, "text/html"), o = e.querySelectorAll(".recommendation-block-v2");
|
|
158
164
|
if (!o.length)
|
|
159
165
|
return r;
|
|
160
|
-
const { buildCampaignUrl:
|
|
161
|
-
|
|
162
|
-
const { isFeatureEnabled: t } =
|
|
166
|
+
const { buildCampaignUrl: i } = _(), c = C();
|
|
167
|
+
c.recommendationCampaignUrls = {};
|
|
168
|
+
const { isFeatureEnabled: t } = g(), s = t("liquidSyntax") ? "reco_" : "";
|
|
163
169
|
return o.forEach((u) => {
|
|
164
170
|
var l, d;
|
|
165
171
|
const p = u.getAttribute("recommendation-id");
|
|
166
|
-
p && ((l = u.parentNode) == null || l.insertBefore(e.createComment("REC_START"), u), (d = u.parentNode) == null || d.insertBefore(e.createComment("REC_END"), u.nextSibling), u.querySelectorAll('[data-visibility="0"]').forEach((m) => m.remove()),
|
|
167
|
-
}),
|
|
172
|
+
p && ((l = u.parentNode) == null || l.insertBefore(e.createComment("REC_START"), u), (d = u.parentNode) == null || d.insertBefore(e.createComment("REC_END"), u.nextSibling), u.querySelectorAll('[data-visibility="0"]').forEach((m) => m.remove()), i(p), P(u, p, s), v(u));
|
|
173
|
+
}), O(n, e).replaceAll("<!--{%", "{%").replaceAll("%}-->", "%}").replaceAll("<!--{%", "{%").replaceAll("%}-->", "%}");
|
|
168
174
|
}
|
|
169
175
|
export {
|
|
170
176
|
y as formatPriceVariable,
|
|
@@ -1,85 +1,36 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import
|
|
5
|
-
|
|
1
|
+
var h = Object.defineProperty;
|
|
2
|
+
var g = (r, t, e) => t in r ? h(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
|
|
3
|
+
var l = (r, t, e) => g(r, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import f from "../../extensions/Blocks/Checkbox/template.js";
|
|
5
|
+
import { extractTextFromElement as m, buildTextBlock as p } from "./textBlockMigration.js";
|
|
6
|
+
class C {
|
|
6
7
|
constructor() {
|
|
7
|
-
|
|
8
|
+
l(this, "parser");
|
|
8
9
|
this.parser = new DOMParser();
|
|
9
10
|
}
|
|
10
11
|
migrate(t) {
|
|
11
12
|
try {
|
|
12
|
-
const e = this.parser.parseFromString(t, "text/html"),
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const e = this.parser.parseFromString(t, "text/html"), n = e.querySelectorAll("td.checkbox-block");
|
|
14
|
+
if (n.length === 0)
|
|
15
|
+
return t;
|
|
16
|
+
let i = !1;
|
|
17
|
+
return n.forEach((o) => {
|
|
18
|
+
if (o.classList.contains("checkbox-block-v2"))
|
|
15
19
|
return;
|
|
16
|
-
const
|
|
17
|
-
`<table id="tempDoc"><tbody><tr>${
|
|
20
|
+
const b = o.getAttribute("id"), s = m(o, "ins-title"), a = m(o, "ins-description"), u = p(s, s.containerClass), x = p(a, a.containerClass), d = f.replace("{-{-TITLE-}-}", u).replace("{-{-DESCRIPTION-}-}", x), c = this.parser.parseFromString(
|
|
21
|
+
`<table id="tempDoc"><tbody><tr>${d}</tr></tbody></table>`,
|
|
18
22
|
"text/html"
|
|
19
23
|
).querySelector(".checkbox-block-v2");
|
|
20
|
-
|
|
21
|
-
}), e.documentElement.outerHTML
|
|
24
|
+
c && o.parentNode && (c.setAttribute("id", b || ""), o.parentNode.replaceChild(c, o), i = !0);
|
|
25
|
+
}), i ? e.documentElement.outerHTML : t;
|
|
22
26
|
} catch (e) {
|
|
23
27
|
return console.error("CheckboxMigrator failed:", e), t;
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
|
-
extractTextFromElement(t, e) {
|
|
27
|
-
var o, d;
|
|
28
|
-
const i = t.querySelector(`.${e}`);
|
|
29
|
-
if (!i)
|
|
30
|
-
return {
|
|
31
|
-
text: e === "ins-title" ? "Title" : "Description",
|
|
32
|
-
isBold: !1,
|
|
33
|
-
isItalic: !1,
|
|
34
|
-
align: "left",
|
|
35
|
-
styles: ""
|
|
36
|
-
};
|
|
37
|
-
const r = i.querySelector("p");
|
|
38
|
-
if (!r)
|
|
39
|
-
return {
|
|
40
|
-
text: ((o = i.textContent) == null ? void 0 : o.trim()) || (e === "ins-title" ? "Title" : "Description"),
|
|
41
|
-
isBold: !1,
|
|
42
|
-
isItalic: !1,
|
|
43
|
-
align: i.getAttribute("align") || "left",
|
|
44
|
-
styles: ""
|
|
45
|
-
};
|
|
46
|
-
const n = ((d = r.textContent) == null ? void 0 : d.trim()) || (e === "ins-title" ? "Title" : "Description"), l = r.getAttribute("style") || "", c = i.getAttribute("align") || r.getAttribute("align") || "left", a = /font-weight\s*:\s*bold/i.test(l) || !!r.querySelector("b, strong"), p = /font-style\s*:\s*italic/i.test(l) || !!r.querySelector("i, em"), g = this.removeStyleProperties(l, ["font-weight", "font-style"]), u = this.convertInlineToBlock(g);
|
|
47
|
-
return {
|
|
48
|
-
text: n,
|
|
49
|
-
isBold: a,
|
|
50
|
-
isItalic: p,
|
|
51
|
-
align: c,
|
|
52
|
-
styles: u
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
buildTextBlock(t) {
|
|
56
|
-
let e = t.text;
|
|
57
|
-
t.isBold && t.isItalic ? e = `<strong path="1,0"><em path="1,0,0">${e}</em></strong>` : t.isBold ? e = `<strong path="1,0">${e}</strong>` : t.isItalic && (e = `<em path="1,0">${e}</em>`);
|
|
58
|
-
const i = t.align ? ` align="${t.align}"` : "", r = t.styles ? ` style="${t.styles}"` : "";
|
|
59
|
-
return `
|
|
60
|
-
<td class="esd-block-text" ${i}>
|
|
61
|
-
<p path="1" ${r}>
|
|
62
|
-
${e}
|
|
63
|
-
</p>
|
|
64
|
-
</td>
|
|
65
|
-
`;
|
|
66
|
-
}
|
|
67
|
-
removeStyleProperties(t, e) {
|
|
68
|
-
return t ? e.reduce((r, n) => {
|
|
69
|
-
const l = new RegExp(`${n}\\s*:\\s*[^;]*;?`, "gi");
|
|
70
|
-
return r.replace(l, "");
|
|
71
|
-
}, t).replace(/;\s*;/g, ";").replace(/^;|;$/g, "").trim() : "";
|
|
72
|
-
}
|
|
73
|
-
convertInlineToBlock(t) {
|
|
74
|
-
if (!t)
|
|
75
|
-
return "";
|
|
76
|
-
let e = t.replace(/display\s*:\s*inline/gi, "display: block");
|
|
77
|
-
return /display\s*:/i.test(e) || (e = e ? `${e}; display: block` : "display: block"), e.replace(/;\s*;/g, ";").replace(/^;|;$/g, "").trim();
|
|
78
|
-
}
|
|
79
30
|
}
|
|
80
|
-
function
|
|
81
|
-
return new
|
|
31
|
+
function E(r) {
|
|
32
|
+
return new C().migrate(r);
|
|
82
33
|
}
|
|
83
34
|
export {
|
|
84
|
-
|
|
35
|
+
E as migrateCheckbox
|
|
85
36
|
};
|
|
@@ -1,109 +1,54 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import
|
|
5
|
-
|
|
1
|
+
var q = Object.defineProperty;
|
|
2
|
+
var C = (o, t, e) => t in o ? q(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e;
|
|
3
|
+
var g = (o, t, e) => C(o, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import N from "../../extensions/Blocks/RadioButton/template.js";
|
|
5
|
+
import { extractTextFromElement as b, buildTextBlock as f } from "./textBlockMigration.js";
|
|
6
|
+
class R {
|
|
6
7
|
constructor() {
|
|
7
|
-
|
|
8
|
+
g(this, "parser");
|
|
8
9
|
this.parser = new DOMParser();
|
|
9
10
|
}
|
|
10
|
-
migrate(
|
|
11
|
+
migrate(t) {
|
|
11
12
|
try {
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
14
|
-
return
|
|
15
|
-
let
|
|
16
|
-
return
|
|
13
|
+
const e = this.parser.parseFromString(t, "text/html"), n = e.querySelectorAll("td.radio-button-block"), a = e.querySelectorAll("td.radio-button-v2");
|
|
14
|
+
if (n.length === 0 && a.length === 0)
|
|
15
|
+
return t;
|
|
16
|
+
let i = !1;
|
|
17
|
+
return n.forEach((r) => {
|
|
17
18
|
if (r.classList.contains("radio-button-v2"))
|
|
18
19
|
return;
|
|
19
|
-
const
|
|
20
|
-
`<table id="tempDoc"><tbody><tr>${
|
|
20
|
+
const s = r.getAttribute("id"), c = b(r, "ins-title"), d = b(r, "ins-description"), u = b(r, "ins-subscribe"), l = b(r, "ins-unsubscribe"), p = f(c, c.containerClass), m = f(d, d.containerClass), h = f(u), S = f(l), T = N.replace("{-{-TITLE-}-}", p).replace("{-{-DESCRIPTION-}-}", m).replace("{-{-YES-}-}", h).replace("{-{-NO-}-}", S), y = this.parser.parseFromString(
|
|
21
|
+
`<table id="tempDoc"><tbody><tr>${T}</tr></tbody></table>`,
|
|
21
22
|
"text/html"
|
|
22
23
|
).querySelector(".radio-button-v2");
|
|
23
|
-
|
|
24
|
-
}),
|
|
25
|
-
} catch (
|
|
26
|
-
return console.error("RadioButtonMigrator failed:",
|
|
24
|
+
y && r.parentNode && (y.setAttribute("id", s || ""), r.parentNode.replaceChild(y, r), i = !0);
|
|
25
|
+
}), i = this.healRadioButtonV2(e) || i, i ? e.documentElement.outerHTML : t;
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return console.error("RadioButtonMigrator failed:", e), t;
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
|
-
healRadioButtonV2(
|
|
30
|
-
let
|
|
31
|
-
return
|
|
32
|
-
var
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
if (!
|
|
30
|
+
healRadioButtonV2(t) {
|
|
31
|
+
let e = !1;
|
|
32
|
+
return t.querySelectorAll("td.radio-button-v2").forEach((n) => {
|
|
33
|
+
var m;
|
|
34
|
+
n.classList.contains("radio-button-block") || (n.classList.add("radio-button-block"), e = !0);
|
|
35
|
+
const a = n.querySelector("input#radioYes"), i = n.querySelector("input#radioNo");
|
|
36
|
+
if (!a || !i)
|
|
36
37
|
return;
|
|
37
|
-
const r = ((
|
|
38
|
-
if (!r && !
|
|
38
|
+
const r = ((m = a.parentElement) == null ? void 0 : m.querySelector(":scope > p")) || null;
|
|
39
|
+
if (!r && !a.hasAttribute("align"))
|
|
39
40
|
return;
|
|
40
|
-
const
|
|
41
|
-
if (!
|
|
41
|
+
const s = a.closest("tr"), c = i.closest("tr");
|
|
42
|
+
if (!s || !c || s === c || !s.parentNode)
|
|
42
43
|
return;
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
}),
|
|
46
|
-
}
|
|
47
|
-
extractTextFromElement(e, t) {
|
|
48
|
-
var d, y;
|
|
49
|
-
const s = e.querySelector(`.${t}`);
|
|
50
|
-
if (!s)
|
|
51
|
-
return {
|
|
52
|
-
text: t === "ins-title" ? "Title" : "Description",
|
|
53
|
-
isBold: !1,
|
|
54
|
-
isItalic: !1,
|
|
55
|
-
align: "left",
|
|
56
|
-
styles: "",
|
|
57
|
-
classList: ""
|
|
58
|
-
};
|
|
59
|
-
const i = s.querySelector("p");
|
|
60
|
-
if (!i)
|
|
61
|
-
return {
|
|
62
|
-
text: ((d = s.textContent) == null ? void 0 : d.trim()) || (t === "ins-title" ? "Title" : "Description"),
|
|
63
|
-
isBold: !1,
|
|
64
|
-
isItalic: !1,
|
|
65
|
-
align: s.getAttribute("align") || "left",
|
|
66
|
-
styles: "",
|
|
67
|
-
classList: ""
|
|
68
|
-
};
|
|
69
|
-
const o = ((y = i.textContent) == null ? void 0 : y.trim()) || (t === "ins-title" ? "Title" : "Description"), r = i.getAttribute("style") || "", n = s.getAttribute("align") || i.getAttribute("align") || "left", a = /font-weight\s*:\s*bold/i.test(r) || !!i.querySelector("b, strong"), g = /font-style\s*:\s*italic/i.test(r) || !!i.querySelector("i, em"), c = this.removeStyleProperties(r, ["font-weight", "font-style"]), u = this.convertInlineToBlock(c), p = s.getAttribute("class") || "";
|
|
70
|
-
return {
|
|
71
|
-
text: o,
|
|
72
|
-
isBold: a,
|
|
73
|
-
isItalic: g,
|
|
74
|
-
align: n,
|
|
75
|
-
styles: u,
|
|
76
|
-
classList: p
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
buildTextBlock(e) {
|
|
80
|
-
let t = e.text;
|
|
81
|
-
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>`);
|
|
82
|
-
const s = e.align ? ` align="${e.align}"` : "", i = e.styles ? ` style="${e.styles.replaceAll('"', "'")}"` : "";
|
|
83
|
-
return `
|
|
84
|
-
<td class="esd-block-text ${e.classList}" ${s}>
|
|
85
|
-
<p path="1" ${i}>
|
|
86
|
-
${t}
|
|
87
|
-
</p>
|
|
88
|
-
</td>
|
|
89
|
-
`;
|
|
90
|
-
}
|
|
91
|
-
removeStyleProperties(e, t) {
|
|
92
|
-
return e ? t.reduce((i, o) => {
|
|
93
|
-
const r = new RegExp(`${o}\\s*:\\s*[^;]*;?`, "gi");
|
|
94
|
-
return i.replace(r, "");
|
|
95
|
-
}, e).replace(/;\s*;/g, ";").replace(/^;|;$/g, "").trim() : "";
|
|
96
|
-
}
|
|
97
|
-
convertInlineToBlock(e) {
|
|
98
|
-
if (!e)
|
|
99
|
-
return "";
|
|
100
|
-
let t = e.replace(/display\s*:\s*inline/gi, "display: block");
|
|
101
|
-
return /display\s*:/i.test(t) || (t = t ? `${t}; display: block` : "display: block"), t.replace(/;\s*;/g, ";").replace(/^;|;$/g, "").trim();
|
|
44
|
+
const d = (r == null ? void 0 : r.innerHTML.trim()) || "Yes", u = c.cloneNode(!0), l = u.querySelector("input#radioNo"), p = u.querySelector("p");
|
|
45
|
+
l && (l.setAttribute("id", "radioYes"), l.removeAttribute("align")), p && (p.innerHTML = d), s.parentNode.replaceChild(u, s), e = !0;
|
|
46
|
+
}), e;
|
|
102
47
|
}
|
|
103
48
|
}
|
|
104
|
-
function
|
|
105
|
-
return new
|
|
49
|
+
function w(o) {
|
|
50
|
+
return new R().migrate(o);
|
|
106
51
|
}
|
|
107
52
|
export {
|
|
108
|
-
|
|
53
|
+
w as migrateRadioButton
|
|
109
54
|
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const I = {
|
|
2
|
+
"ins-title": "Title",
|
|
3
|
+
"ins-description": "Description",
|
|
4
|
+
"ins-subscribe": "Yes",
|
|
5
|
+
"ins-unsubscribe": "No"
|
|
6
|
+
}, y = /font-weight\s*:\s*[^;]*;?/gi, S = /font-style\s*:\s*[^;]*;?/gi, u = /;\s*;/g, T = /^;|;$/g, d = /display\s*:\s*inline/gi, m = /display\s*:/i, b = /font-weight\s*:\s*bold/i, A = /font-style\s*:\s*italic/i, R = /^<(?:strong|b)\b/i, $ = /^<(?:em|i)\b/i;
|
|
7
|
+
function L(t) {
|
|
8
|
+
return t ? t.replace(y, "").replace(S, "").replace(u, ";").replace(T, "").trim() : "";
|
|
9
|
+
}
|
|
10
|
+
function O(t) {
|
|
11
|
+
if (!t)
|
|
12
|
+
return "";
|
|
13
|
+
let e = t.replace(d, "display: block");
|
|
14
|
+
return m.test(e) || (e = e ? `${e}; display: block` : "display: block"), e.replace(u, ";").replace(T, "").trim();
|
|
15
|
+
}
|
|
16
|
+
function B(t, e) {
|
|
17
|
+
var c, a;
|
|
18
|
+
const o = I[e], l = t.querySelector(`.${e}`);
|
|
19
|
+
if (!l)
|
|
20
|
+
return {
|
|
21
|
+
paragraphs: [{ innerHtml: o, isBold: !1, isItalic: !1, styles: "" }],
|
|
22
|
+
align: "left",
|
|
23
|
+
containerClass: ""
|
|
24
|
+
};
|
|
25
|
+
const n = Array.from(l.querySelectorAll("p")), p = l.getAttribute("align") || ((c = n[0]) == null ? void 0 : c.getAttribute("align")) || "left", i = l.getAttribute("class") || "";
|
|
26
|
+
return n.length === 0 ? {
|
|
27
|
+
paragraphs: [{
|
|
28
|
+
innerHtml: ((a = l.textContent) == null ? void 0 : a.trim()) || o,
|
|
29
|
+
isBold: !1,
|
|
30
|
+
isItalic: !1,
|
|
31
|
+
styles: ""
|
|
32
|
+
}],
|
|
33
|
+
align: p,
|
|
34
|
+
containerClass: ""
|
|
35
|
+
} : { paragraphs: n.map((r) => {
|
|
36
|
+
const _ = r.getAttribute("style") || "", f = b.test(_) || !!r.querySelector("b, strong"), g = A.test(_) || !!r.querySelector("i, em"), E = L(_);
|
|
37
|
+
return {
|
|
38
|
+
// Legacy parity: empty <p> → fallback placeholder; <p><br></p> is not empty.
|
|
39
|
+
innerHtml: r.innerHTML.trim() || o,
|
|
40
|
+
isBold: f,
|
|
41
|
+
isItalic: g,
|
|
42
|
+
styles: O(E)
|
|
43
|
+
};
|
|
44
|
+
}), align: p, containerClass: i };
|
|
45
|
+
}
|
|
46
|
+
function C(t, e = "") {
|
|
47
|
+
const o = t.align ? ` align="${t.align}"` : "", l = t.paragraphs.map((n, p) => {
|
|
48
|
+
const i = p + 1;
|
|
49
|
+
let s = n.innerHtml;
|
|
50
|
+
const c = n.isBold && !R.test(s), a = n.isItalic && !$.test(s);
|
|
51
|
+
c && a ? s = `<strong path="${i},0"><em path="${i},0,0">${s}</em></strong>` : c ? s = `<strong path="${i},0">${s}</strong>` : a && (s = `<em path="${i},0">${s}</em>`);
|
|
52
|
+
const r = n.styles ? ` style="${n.styles.replaceAll('"', "'")}"` : "";
|
|
53
|
+
return `<p path="${i}"${r}>${s}</p>`;
|
|
54
|
+
}).join(`
|
|
55
|
+
`);
|
|
56
|
+
return `
|
|
57
|
+
<td class="esd-block-text ${e}" ${o}>
|
|
58
|
+
${l}
|
|
59
|
+
</td>
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
C as buildTextBlock,
|
|
64
|
+
B as extractTextFromElement
|
|
65
|
+
};
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { BlockId as
|
|
5
|
-
import { getMigrationBannerHtml as
|
|
6
|
-
import { Block as
|
|
7
|
-
import { regenerateMobileProductRows as
|
|
8
|
-
import { ensureMobileCssRulesExist as
|
|
1
|
+
var k = Object.defineProperty;
|
|
2
|
+
var y = (a, r, t) => r in a ? k(a, r, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[r] = t;
|
|
3
|
+
var d = (a, r, t) => y(a, typeof r != "symbol" ? r + "" : r, t);
|
|
4
|
+
import { BlockId as B } from "../../../enums/block.js";
|
|
5
|
+
import { getMigrationBannerHtml as D } from "../../../utils/migrationBannerHtml.js";
|
|
6
|
+
import { Block as R, BlockCompositionType as C, ModificationDescription as h } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
7
|
+
import { regenerateMobileProductRows as b } from "./controls/main/utils.js";
|
|
8
|
+
import { ensureMobileCssRulesExist as p, setMobileLayoutOptOut as f, hasMobileLayoutOptOut as A } from "./controls/mobileLayout/cssRules.js";
|
|
9
9
|
import { RecommendationConfigService as c } from "./services/configService.js";
|
|
10
10
|
import { useRecommendationExtensionStore as g } from "./store/recommendation.js";
|
|
11
|
-
import { getDefaultTemplate as
|
|
12
|
-
const
|
|
13
|
-
let
|
|
14
|
-
class q extends
|
|
11
|
+
import { getDefaultTemplate as E } from "./templates/grid/template.js";
|
|
12
|
+
const _ = B.Recommendation, m = "recommendation-block-v2", u = "recommendation-id";
|
|
13
|
+
let I = !1;
|
|
14
|
+
class q extends R {
|
|
15
15
|
constructor() {
|
|
16
16
|
super();
|
|
17
17
|
/**
|
|
18
18
|
* Stores the ID generated in getTemplate() so onCreated() can reuse it.
|
|
19
19
|
* This avoids generating a new (different) ID in onCreated().
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
d(this, "_pendingBlockId", null);
|
|
22
22
|
}
|
|
23
23
|
getId() {
|
|
24
|
-
return
|
|
24
|
+
return _;
|
|
25
25
|
}
|
|
26
26
|
getIcon() {
|
|
27
27
|
return "recommendation-icon";
|
|
28
28
|
}
|
|
29
29
|
getBlockCompositionType() {
|
|
30
|
-
return
|
|
30
|
+
return C.CONTAINER;
|
|
31
31
|
}
|
|
32
32
|
getName() {
|
|
33
33
|
return this.api.translate("Recommendation Block");
|
|
@@ -38,8 +38,8 @@ class q extends A {
|
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
getSettingsPanelTitleHtml() {
|
|
41
|
-
return
|
|
42
|
-
|
|
41
|
+
return D(
|
|
42
|
+
_,
|
|
43
43
|
this.api.translate("Recommendation Block"),
|
|
44
44
|
this.api.translate("This block is switched from the Old Version to the New Version. We recommend you check the Recommendation block and test your message to ensure it works properly.")
|
|
45
45
|
);
|
|
@@ -59,7 +59,7 @@ class q extends A {
|
|
|
59
59
|
*/
|
|
60
60
|
getTemplate() {
|
|
61
61
|
const t = this._generateNextId();
|
|
62
|
-
return this._pendingBlockId = t,
|
|
62
|
+
return this._pendingBlockId = t, E(t);
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
65
|
* Called when a new block is dropped into the template
|
|
@@ -71,7 +71,13 @@ class q extends A {
|
|
|
71
71
|
onCreated(t) {
|
|
72
72
|
const e = this._getRecommendationId(t);
|
|
73
73
|
if (e !== null && e > 0) {
|
|
74
|
-
this._detectDuplicate(e)
|
|
74
|
+
if (this._detectDuplicate(e)) {
|
|
75
|
+
this._handleDuplicate(t, e);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this._pendingBlockId === null && setTimeout(() => {
|
|
79
|
+
this._getBlockElement(t) && this._detectDuplicate(e) && this._handleDuplicate(t, e);
|
|
80
|
+
}, 0);
|
|
75
81
|
return;
|
|
76
82
|
}
|
|
77
83
|
const i = this._pendingBlockId ?? this._generateNextId();
|
|
@@ -80,16 +86,16 @@ class q extends A {
|
|
|
80
86
|
this.api,
|
|
81
87
|
t,
|
|
82
88
|
{ recommendationId: i }
|
|
83
|
-
),
|
|
84
|
-
if (
|
|
85
|
-
|
|
89
|
+
), s = g();
|
|
90
|
+
if (s.setCurrentBlock(i), o) {
|
|
91
|
+
p(this.api);
|
|
86
92
|
const l = this._getBlockElement(t);
|
|
87
|
-
l && (
|
|
93
|
+
l && (f(this.api, l, !0), b({
|
|
88
94
|
currentNode: t,
|
|
89
95
|
documentModifier: this.api.getDocumentModifier()
|
|
90
96
|
}));
|
|
91
97
|
}
|
|
92
|
-
|
|
98
|
+
s.patchCurrentBlockConfig({ language: n.language }, { triggerRefetch: !1 });
|
|
93
99
|
}
|
|
94
100
|
/**
|
|
95
101
|
* Called when the document changes or template is loaded
|
|
@@ -109,13 +115,13 @@ class q extends A {
|
|
|
109
115
|
"Assign recommendation ID to legacy block"
|
|
110
116
|
);
|
|
111
117
|
}
|
|
112
|
-
c.needsMigration(t) && this._migrateFromLegacy(t);
|
|
118
|
+
this._healLingeringDuplicate(t), c.needsMigration(t) && this._migrateFromLegacy(t);
|
|
113
119
|
try {
|
|
114
|
-
|
|
120
|
+
I || (p(this.api), I = !0);
|
|
115
121
|
const e = c.getConfig(t), i = this._getBlockElement(t);
|
|
116
122
|
if (i) {
|
|
117
123
|
const n = !e.mobileLayoutEnabled;
|
|
118
|
-
|
|
124
|
+
A(i) !== n && f(this.api, i, n);
|
|
119
125
|
}
|
|
120
126
|
} catch {
|
|
121
127
|
}
|
|
@@ -141,14 +147,53 @@ class q extends A {
|
|
|
141
147
|
const e = this.api.getDocumentRoot();
|
|
142
148
|
e && "querySelectorAll" in e && e.querySelectorAll(`.${m}`).forEach((n) => {
|
|
143
149
|
if ("getAttribute" in n) {
|
|
144
|
-
const o = n.getAttribute(u),
|
|
145
|
-
|
|
150
|
+
const o = n.getAttribute(u), s = o ? parseInt(o) : 0;
|
|
151
|
+
s > t && (t = s);
|
|
146
152
|
}
|
|
147
153
|
});
|
|
148
154
|
} catch {
|
|
149
155
|
}
|
|
150
156
|
return t + 1;
|
|
151
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Heals a duplicate that slipped past the create-time `_detectDuplicate`
|
|
160
|
+
* scan (or that was persisted by an older template before SD-142352).
|
|
161
|
+
* When two blocks share a `recommendation-id`, the first occurrence in DOM
|
|
162
|
+
* order is treated as the source and any later sibling is reassigned a
|
|
163
|
+
* fresh id. The store entry and active-block focus are intentionally not
|
|
164
|
+
* touched here: each block's persisted `esd-ext-config` carries its own
|
|
165
|
+
* truth and the regular save-time hydration (`hydrateRecommendationStore`)
|
|
166
|
+
* will seed the new id from that. Skipping `setCurrentBlock` avoids
|
|
167
|
+
* yanking the user's current selection mid-edit when the heal fires from
|
|
168
|
+
* `onDocumentChanged`.
|
|
169
|
+
*/
|
|
170
|
+
_healLingeringDuplicate(t) {
|
|
171
|
+
const e = this._getRecommendationId(t);
|
|
172
|
+
if (!(e === null || e <= 0))
|
|
173
|
+
try {
|
|
174
|
+
const i = this.api.getDocumentRoot();
|
|
175
|
+
if (!i || !("querySelectorAll" in i))
|
|
176
|
+
return;
|
|
177
|
+
const n = i.querySelectorAll(
|
|
178
|
+
`.${m}[${u}="${e}"]`
|
|
179
|
+
);
|
|
180
|
+
if (n.length <= 1)
|
|
181
|
+
return;
|
|
182
|
+
const o = this._getBlockElement(t);
|
|
183
|
+
if (!o)
|
|
184
|
+
return;
|
|
185
|
+
let s = -1;
|
|
186
|
+
for (let l = 0; l < n.length; l++)
|
|
187
|
+
if (n[l] === o) {
|
|
188
|
+
s = l;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
if (s <= 0)
|
|
192
|
+
return;
|
|
193
|
+
this._reassignDuplicateId(t, e);
|
|
194
|
+
} catch {
|
|
195
|
+
}
|
|
196
|
+
}
|
|
152
197
|
/** True when another block already holds the same id — Stripo's duplication signal. */
|
|
153
198
|
_detectDuplicate(t) {
|
|
154
199
|
try {
|
|
@@ -163,33 +208,42 @@ class q extends A {
|
|
|
163
208
|
}
|
|
164
209
|
/** Assigns a fresh id to a duplicated block and syncs DOM, node config and store. */
|
|
165
210
|
_handleDuplicate(t, e) {
|
|
211
|
+
const i = this._reassignDuplicateId(t, e), n = g();
|
|
212
|
+
n.cloneBlockState(e, i), n.setCurrentBlock(i);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Core id-reassignment for a duplicated block: rewrites the DOM
|
|
216
|
+
* `recommendation-id`, the instance class and the persisted node config to
|
|
217
|
+
* a fresh id. Returns the new id.
|
|
218
|
+
*
|
|
219
|
+
* Used by `_handleDuplicate` at create-time (which additionally clones the
|
|
220
|
+
* store entry and focuses the new block) and by `_healLingeringDuplicate`
|
|
221
|
+
* at document-change time (which intentionally skips store/focus side
|
|
222
|
+
* effects so older bug-affected templates can self-repair without
|
|
223
|
+
* disturbing the user's current selection).
|
|
224
|
+
*/
|
|
225
|
+
_reassignDuplicateId(t, e) {
|
|
166
226
|
const i = this._generateNextId(), n = this._getBlockElement(t);
|
|
167
|
-
this._assignRecommendationId(t, i), n && this._reassignInstanceClass(n, e, i), c.hasConfig(t) && c.updateConfig(
|
|
227
|
+
return this._assignRecommendationId(t, i), n && this._reassignInstanceClass(n, e, i), c.hasConfig(t) && c.updateConfig(
|
|
168
228
|
this.api,
|
|
169
229
|
t,
|
|
170
230
|
{ recommendationId: i },
|
|
171
231
|
`Reassign recommendation ID on duplicate (was ${e})`
|
|
172
|
-
);
|
|
173
|
-
const o = g();
|
|
174
|
-
o.cloneBlockState(e, i), o.setCurrentBlock(i);
|
|
232
|
+
), i;
|
|
175
233
|
}
|
|
176
234
|
/**
|
|
177
235
|
* Rewrites `ins-recommendation-v3-block-{id}` on the clone — the instance
|
|
178
|
-
* class scopes per-block CSS rules
|
|
179
|
-
*
|
|
236
|
+
* class scopes per-block CSS rules in the editor and is also the key the
|
|
237
|
+
* mail render service reads to look up per-id campaign config, so leaving
|
|
238
|
+
* the source's class would both leak stylistic edits across blocks and
|
|
239
|
+
* cause the mail render to apply the source block's config to the clone.
|
|
180
240
|
*/
|
|
181
241
|
_reassignInstanceClass(t, e, i) {
|
|
182
242
|
if (!("getAttribute" in t))
|
|
183
243
|
return;
|
|
184
|
-
const n =
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const o = `ins-recommendation-v3-block-${e}`, r = `ins-recommendation-v3-block-${i}`;
|
|
188
|
-
if (!n.includes(o))
|
|
189
|
-
return;
|
|
190
|
-
const l = n.replace(o, r), d = this.api.getDocumentModifier();
|
|
191
|
-
d.modifyHtml(t).setAttribute("class", l), d.apply(new f(
|
|
192
|
-
`Reassign recommendation instance class ${o} -> ${r}`
|
|
244
|
+
const n = `ins-recommendation-v3-block-${e}`, o = `ins-recommendation-v3-block-${i}`, s = this.api.getDocumentModifier();
|
|
245
|
+
s.modifyHtml(t).removeClass(n).setClass(o), s.apply(new h(
|
|
246
|
+
`Reassign recommendation instance class ${n} -> ${o}`
|
|
193
247
|
));
|
|
194
248
|
}
|
|
195
249
|
/**
|
|
@@ -203,7 +257,7 @@ class q extends A {
|
|
|
203
257
|
if (!i)
|
|
204
258
|
return;
|
|
205
259
|
const n = this.api.getDocumentModifier();
|
|
206
|
-
n.modifyHtml(i).setAttribute(u, e.toString()), n.apply(new
|
|
260
|
+
n.modifyHtml(i).setAttribute(u, e.toString()), n.apply(new h(`Assign recommendation ID ${e}`));
|
|
207
261
|
}
|
|
208
262
|
/**
|
|
209
263
|
* Gets the recommendation-id from a block node
|
|
@@ -237,6 +291,6 @@ class q extends A {
|
|
|
237
291
|
}
|
|
238
292
|
}
|
|
239
293
|
export {
|
|
240
|
-
|
|
294
|
+
_ as BLOCK_ID,
|
|
241
295
|
q as RecommendationBlock
|
|
242
296
|
};
|
|
@@ -6,9 +6,8 @@ import { DEFAULT_CARDS_IN_ROW as F } from "../constants/layout.js";
|
|
|
6
6
|
import { EXCLUDED_ALGORITHM_IDS as D } from "../constants/defaultConfig.js";
|
|
7
7
|
import { getDefaultProducts as S } from "../templates/utils.js";
|
|
8
8
|
import { generateCompleteFilterQuery as b } from "../utils/filterUtil.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { isConfigValid as N } from "../validation/requiredFields.js";
|
|
9
|
+
import { isFilterValid as v } from "../validation/filterSchema.js";
|
|
10
|
+
import { isConfigValid as w } from "../validation/requiredFields.js";
|
|
12
11
|
const h = y();
|
|
13
12
|
let m = null, u = null, d = null;
|
|
14
13
|
function I() {
|
|
@@ -50,7 +49,7 @@ function k() {
|
|
|
50
49
|
filterSnapshot: null
|
|
51
50
|
};
|
|
52
51
|
}
|
|
53
|
-
const
|
|
52
|
+
const N = () => ({
|
|
54
53
|
recommendationCampaignUrls: {},
|
|
55
54
|
activePredictiveAlgorithms: [],
|
|
56
55
|
languages: {},
|
|
@@ -59,8 +58,8 @@ const x = () => ({
|
|
|
59
58
|
blockStates: {},
|
|
60
59
|
currentRecommendationId: null,
|
|
61
60
|
configVersion: 0
|
|
62
|
-
}),
|
|
63
|
-
state: () =>
|
|
61
|
+
}), M = P("guidoRecommendationExtension", {
|
|
62
|
+
state: () => N(),
|
|
64
63
|
getters: {
|
|
65
64
|
// ====================================================================
|
|
66
65
|
// Proxy Getters — Backward Compatible Access to Current Block State
|
|
@@ -379,7 +378,7 @@ const x = () => ({
|
|
|
379
378
|
const n = [...e.recommendationConfigs.filters];
|
|
380
379
|
n[r] = {
|
|
381
380
|
...t,
|
|
382
|
-
isValid:
|
|
381
|
+
isValid: v(t)
|
|
383
382
|
}, e.recommendationConfigs.filters = n;
|
|
384
383
|
}
|
|
385
384
|
},
|
|
@@ -425,7 +424,7 @@ const x = () => ({
|
|
|
425
424
|
* every block's recommendationConfigs across user edits.
|
|
426
425
|
*/
|
|
427
426
|
hasInvalidBlock() {
|
|
428
|
-
return Object.values(this.blockStates).some((t) => !
|
|
427
|
+
return Object.values(this.blockStates).some((t) => !w(t.recommendationConfigs, this));
|
|
429
428
|
},
|
|
430
429
|
// ====================================================================
|
|
431
430
|
// Per-Block Product Fetching
|
|
@@ -454,10 +453,7 @@ const x = () => ({
|
|
|
454
453
|
details: !0,
|
|
455
454
|
campaignId: o.variationId
|
|
456
455
|
};
|
|
457
|
-
r.strategy === "manualMerchandising" ? a.productId = r.productIds.slice(0, s).join(",") : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), c && (a.filter = c), r.shuffleProducts && (a.shuffle = !0)
|
|
458
|
-
a,
|
|
459
|
-
v(o.partnerName, r.strategy)
|
|
460
|
-
);
|
|
456
|
+
r.strategy === "manualMerchandising" ? a.productId = r.productIds.slice(0, s).join(",") : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), c && (a.filter = c), r.shuffleProducts && (a.shuffle = !0);
|
|
461
457
|
let f;
|
|
462
458
|
try {
|
|
463
459
|
f = await h.fetchRecommendationProducts(i, a);
|
|
@@ -475,5 +471,5 @@ const x = () => ({
|
|
|
475
471
|
}
|
|
476
472
|
});
|
|
477
473
|
export {
|
|
478
|
-
|
|
474
|
+
M as useRecommendationExtensionStore
|
|
479
475
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared text-block migration helpers used by both `radioButtonMigrator` and
|
|
3
|
+
* `checkboxMigrator`. Extracts a legacy v1 `.ins-title` / `.ins-description`
|
|
4
|
+
* cell into a paragraph descriptor and rebuilds it as a v2 `esd-block-text`
|
|
5
|
+
* cell — preserving every <p>, every inline tag (<u>, <a>, <br>, <strong>,
|
|
6
|
+
* <em>) and re-encoding bold/italic detection as canonical tags.
|
|
7
|
+
*/
|
|
8
|
+
export type InsCellClass = 'ins-title' | 'ins-description' | 'ins-subscribe' | 'ins-unsubscribe';
|
|
9
|
+
type ParagraphContent = {
|
|
10
|
+
innerHtml: string;
|
|
11
|
+
isBold: boolean;
|
|
12
|
+
isItalic: boolean;
|
|
13
|
+
styles: string;
|
|
14
|
+
};
|
|
15
|
+
export type TextContent = {
|
|
16
|
+
paragraphs: ParagraphContent[];
|
|
17
|
+
align: string;
|
|
18
|
+
};
|
|
19
|
+
export type ExtractedTextContent = TextContent & {
|
|
20
|
+
containerClass: string;
|
|
21
|
+
};
|
|
22
|
+
export declare function extractTextFromElement(parent: Element, className: InsCellClass): ExtractedTextContent;
|
|
23
|
+
export declare function buildTextBlock(content: TextContent, extraClass?: string): string;
|
|
24
|
+
export {};
|
|
@@ -60,14 +60,41 @@ export declare class RecommendationBlock extends Block {
|
|
|
60
60
|
* in the document and finding the maximum existing ID + 1.
|
|
61
61
|
*/
|
|
62
62
|
private _generateNextId;
|
|
63
|
+
/**
|
|
64
|
+
* Heals a duplicate that slipped past the create-time `_detectDuplicate`
|
|
65
|
+
* scan (or that was persisted by an older template before SD-142352).
|
|
66
|
+
* When two blocks share a `recommendation-id`, the first occurrence in DOM
|
|
67
|
+
* order is treated as the source and any later sibling is reassigned a
|
|
68
|
+
* fresh id. The store entry and active-block focus are intentionally not
|
|
69
|
+
* touched here: each block's persisted `esd-ext-config` carries its own
|
|
70
|
+
* truth and the regular save-time hydration (`hydrateRecommendationStore`)
|
|
71
|
+
* will seed the new id from that. Skipping `setCurrentBlock` avoids
|
|
72
|
+
* yanking the user's current selection mid-edit when the heal fires from
|
|
73
|
+
* `onDocumentChanged`.
|
|
74
|
+
*/
|
|
75
|
+
private _healLingeringDuplicate;
|
|
63
76
|
/** True when another block already holds the same id — Stripo's duplication signal. */
|
|
64
77
|
private _detectDuplicate;
|
|
65
78
|
/** Assigns a fresh id to a duplicated block and syncs DOM, node config and store. */
|
|
66
79
|
private _handleDuplicate;
|
|
80
|
+
/**
|
|
81
|
+
* Core id-reassignment for a duplicated block: rewrites the DOM
|
|
82
|
+
* `recommendation-id`, the instance class and the persisted node config to
|
|
83
|
+
* a fresh id. Returns the new id.
|
|
84
|
+
*
|
|
85
|
+
* Used by `_handleDuplicate` at create-time (which additionally clones the
|
|
86
|
+
* store entry and focuses the new block) and by `_healLingeringDuplicate`
|
|
87
|
+
* at document-change time (which intentionally skips store/focus side
|
|
88
|
+
* effects so older bug-affected templates can self-repair without
|
|
89
|
+
* disturbing the user's current selection).
|
|
90
|
+
*/
|
|
91
|
+
private _reassignDuplicateId;
|
|
67
92
|
/**
|
|
68
93
|
* Rewrites `ins-recommendation-v3-block-{id}` on the clone — the instance
|
|
69
|
-
* class scopes per-block CSS rules
|
|
70
|
-
*
|
|
94
|
+
* class scopes per-block CSS rules in the editor and is also the key the
|
|
95
|
+
* mail render service reads to look up per-id campaign config, so leaving
|
|
96
|
+
* the source's class would both leak stylistic edits across blocks and
|
|
97
|
+
* cause the mail render to apply the source block's config to the clone.
|
|
71
98
|
*/
|
|
72
99
|
private _reassignInstanceClass;
|
|
73
100
|
/**
|
|
@@ -11,6 +11,11 @@ ue-description a {
|
|
|
11
11
|
display: none;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
/* Override the rule above for the Gmail Promotions switcher docs link — remove with DT-28355. */
|
|
15
|
+
ue-lock-container.e2e-promotions-switcher ue-description a {
|
|
16
|
+
display: unset;
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
.label {
|
|
15
20
|
font-size: 13px;
|
|
16
21
|
color: var(--guido-color-gray-800);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useinsider/guido",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.1-beta.4b9dd49",
|
|
4
4
|
"description": "Guido is a Vue + TypeScript wrapper for Email Plugin. Easily embed the email editor in your Vue applications.",
|
|
5
5
|
"main": "./dist/guido.umd.cjs",
|
|
6
6
|
"module": "./dist/library.js",
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const i = [
|
|
2
|
-
"ozonebg",
|
|
3
|
-
"ozonehr",
|
|
4
|
-
"ozonero",
|
|
5
|
-
"ozoneinfo",
|
|
6
|
-
"babybg",
|
|
7
|
-
"ozongr",
|
|
8
|
-
"iboodat",
|
|
9
|
-
"iboodbe",
|
|
10
|
-
"iboodde",
|
|
11
|
-
"iboodfr",
|
|
12
|
-
"iboodnl",
|
|
13
|
-
"iboodpl"
|
|
14
|
-
], r = ["interencheres", "interencherespreprod"], d = ["lodenfrey", "lodenfreyuat"], c = "manualMerchandising";
|
|
15
|
-
function s(e, n) {
|
|
16
|
-
const o = {};
|
|
17
|
-
return i.includes(e) && (o.excludePurchaseDay = "30", o.userId = "{user_id}"), r.includes(e) && (o.hp = "1"), d.includes(e) && n === c && (o.includeOutOfStockItems = "true"), o;
|
|
18
|
-
}
|
|
19
|
-
export {
|
|
20
|
-
s as getPartnerRecommendationParams
|
|
21
|
-
};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns the extra recommendation feed query params for an account, if any.
|
|
3
|
-
* Accounts without customizations get an empty object.
|
|
4
|
-
* @param partnerName Account subdomain (`config.partner.name`)
|
|
5
|
-
* @param strategy Recommendation strategy key of the block
|
|
6
|
-
*/
|
|
7
|
-
export declare function getPartnerRecommendationParams(partnerName: string, strategy: string): Record<string, string>;
|