@useinsider/guido 3.18.1-beta.dea994d → 3.18.1-beta.e39fb14
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 -0
- package/dist/@types/config/schemas.js +28 -26
- package/dist/components/Guido.vue.js +8 -8
- package/dist/components/Guido.vue2.js +53 -51
- package/dist/components/organisms/AutoSaveController.vue2.js +9 -8
- package/dist/components/organisms/header/EditorActions.vue.js +2 -2
- package/dist/components/organisms/header/EditorActions.vue2.js +86 -56
- package/dist/components/organisms/header/LeftSlot.vue.js +5 -5
- package/dist/components/organisms/header/LeftSlot.vue2.js +16 -12
- package/dist/components/organisms/validation/ValidationErrorDrawer.vue.js +20 -0
- package/dist/components/organisms/validation/ValidationErrorDrawer.vue2.js +48 -0
- package/dist/components/wrappers/WpDrawer.vue.js +9 -7
- package/dist/components/wrappers/WpDrawer.vue2.js +1 -1
- package/dist/composables/useHtmlCompiler.js +37 -26
- package/dist/composables/useHtmlValidator.js +2 -0
- package/dist/composables/usePreviewMode.js +11 -12
- package/dist/composables/useSave.js +90 -45
- package/dist/composables/useSaveValidation.js +279 -0
- package/dist/composables/useSaveValidationRollout.js +9 -0
- package/dist/composables/validators/useCouponBlockValidator.js +24 -21
- package/dist/composables/validators/useUnsubscribeBlockValidator.js +34 -27
- package/dist/config/compiler/htmlCompilerRules.js +6 -14
- package/dist/enums/save-validation.js +4 -0
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +41 -34
- package/dist/guido.css +1 -1
- package/dist/src/@types/config/schemas.d.ts +4 -0
- package/dist/src/@types/save-validation.d.ts +19 -0
- package/dist/src/components/Guido.vue.d.ts +17 -1
- package/dist/src/components/organisms/header/EditorActions.vue.d.ts +17 -1
- package/dist/src/components/organisms/header/HeaderWrapper.vue.d.ts +17 -1
- package/dist/src/components/organisms/header/RightSlot.vue.d.ts +17 -1
- package/dist/src/components/organisms/validation/ValidationErrorDrawer.vue.d.ts +2 -0
- package/dist/src/components/wrappers/WpDrawer.vue.d.ts +4 -3
- package/dist/src/composables/useConfig.d.ts +2 -0
- package/dist/src/composables/useHtmlValidator.d.ts +21 -0
- package/dist/src/composables/useSave.d.ts +6 -1
- package/dist/src/composables/useSaveValidation.d.ts +6 -0
- package/dist/src/composables/useSaveValidationRollout.d.ts +3 -0
- package/dist/src/composables/validators/useCouponBlockValidator.d.ts +3 -0
- package/dist/src/composables/validators/useUnsubscribeBlockValidator.d.ts +10 -0
- package/dist/src/enums/save-validation.d.ts +27 -0
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +5 -0
- package/dist/src/stores/config.d.ts +30 -0
- package/dist/src/stores/save-validation.d.ts +22 -0
- package/dist/src/utils/templatePreparation.d.ts +30 -0
- package/dist/static/styles/customEditorStyle.css.js +0 -14
- package/dist/stores/config.js +39 -22
- package/dist/stores/save-validation.js +30 -0
- package/dist/utils/templatePreparation.js +28 -25
- package/package.json +1 -1
- package/dist/src/utils/appendMobileHiddenColumnCss.d.ts +0 -2
- package/dist/utils/appendMobileHiddenColumnCss.js +0 -11
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { getIgnoredRecommendationBlockIds as B } from "../config/compiler/utils/recommendationIgnoreUtils.js";
|
|
2
|
+
import { CanNotMakeAnyChangesForRunningKey as k, DISPLAY_CONDITIONS_REGEX as Y, DISPLAY_CONDITIONS_EXCEPTIONS_REGEX as x } from "../enums/html-validator.js";
|
|
3
|
+
import { SaveValidationRule as o } from "../enums/save-validation.js";
|
|
4
|
+
import { ToasterTypeOptions as r } from "../enums/toaster.js";
|
|
5
|
+
import { BLOCK_ROOT_SELECTOR as U } from "../extensions/Blocks/Checkbox/constants/selectors.js";
|
|
6
|
+
import { itemsBlockDynamicVariables as M } from "../extensions/Blocks/Items/enums/productEnums.js";
|
|
7
|
+
import { BLOCK_ROOT_SELECTOR as P } from "../extensions/Blocks/RadioButton/constants/selectors.js";
|
|
8
|
+
import { useRecommendationExtensionStore as W } from "../extensions/Blocks/Recommendation/store/recommendation.js";
|
|
9
|
+
import { RecommendationRequiredFieldsKey as G } from "../extensions/Blocks/Recommendation/validation/requiredFields.js";
|
|
10
|
+
import { useConfigStore as q } from "../stores/config.js";
|
|
11
|
+
import { useDynamicContentStore as H } from "../stores/dynamic-content.js";
|
|
12
|
+
import { useRecommendationStore as V } from "../stores/recommendation.js";
|
|
13
|
+
import { base64EncodeWithSpecialChars as T } from "../utils/base64.js";
|
|
14
|
+
import { useTemplatePreparation as X } from "../utils/templatePreparation.js";
|
|
15
|
+
import { useActionsApi as j } from "./useActionsApi.js";
|
|
16
|
+
import { useConfig as z } from "./useConfig.js";
|
|
17
|
+
import { useHtmlCompiler as $ } from "./useHtmlCompiler.js";
|
|
18
|
+
import { buildPartnerAttributeNameSet as Q, getInvalidDynamicContentTags as Z, getRecommendationBlockIds as J, findInvalidCustomFields as tt } from "./useHtmlValidator.js";
|
|
19
|
+
import { useHttp as et } from "./useHttp.js";
|
|
20
|
+
import { useTranslations as nt } from "./useTranslations.js";
|
|
21
|
+
import { findInvalidCouponBlocks as it, COUPON_TAG_MODIFIED_KEY as ot } from "./validators/useCouponBlockValidator.js";
|
|
22
|
+
import { findDuplicateUnsubPageTypes as rt, countUnsubBlocksWithoutPage as st, EMPTY_BLOCK_KEY as at } from "./validators/useUnsubscribeBlockValidator.js";
|
|
23
|
+
const ct = "newsletter.html-content-is-empty", lt = "custom-fields.missing-closing-braces", ut = "custom-fields.missing-opening-braces", I = "custom-fields.invalid-custom-fields", mt = "newsletter.display-conditions-invalid-syntax", dt = "custom-conditions.wrong-equality-operators", pt = "custom-conditions.missing-if-endif-tag", gt = "custom-conditions.no-space-after-braces", ft = "custom-conditions.no-braces-inside-if-tag", yt = "newsletter.fill-all-necessary-fields", Et = "newsletter.invalid-image-type", It = "unsubscribe-templates.select-checkbox-groups", St = "unsubscribe-templates.select-radio-button-groups", Ct = "newsletter.invalid-url-link-for-toaster", F = "journey-builder.liquid-validation-failed", _t = "/newsletter/template-library/check-template-html-body", ht = /src="[^"]*\.(svg|pst)"/gm, R = /({%(.*?)%})/g, kt = ["if", "endif", "else", "elif", "now"], Tt = (e) => !kt.includes(e.toLowerCase()), Ft = (e) => ["if", "endif"].includes(e.toLowerCase());
|
|
24
|
+
function Ot(e) {
|
|
25
|
+
return it(e).map((i) => ({
|
|
26
|
+
rule: o.CouponTagModified,
|
|
27
|
+
type: r.Warning,
|
|
28
|
+
key: ot,
|
|
29
|
+
detail: i
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
function Rt(e) {
|
|
33
|
+
return rt(e).map((i) => ({
|
|
34
|
+
rule: o.DuplicateUnsubBlock,
|
|
35
|
+
type: r.Error,
|
|
36
|
+
key: i.messageKey
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
function Lt(e) {
|
|
40
|
+
return Array.from({ length: st(e) }, () => ({
|
|
41
|
+
rule: o.UnsubBlockMissingTemplate,
|
|
42
|
+
type: r.Warning,
|
|
43
|
+
key: at
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
function Nt(e, i) {
|
|
47
|
+
const n = e.match(R);
|
|
48
|
+
if (!n)
|
|
49
|
+
return [];
|
|
50
|
+
const a = [];
|
|
51
|
+
return n.forEach((u) => {
|
|
52
|
+
const s = u.slice(2, -2).trim().match(/(".*?"|[^"\s]+)(?=\s*|\s*$)/g);
|
|
53
|
+
if (s && s.length > 0) {
|
|
54
|
+
const [m] = s;
|
|
55
|
+
Tt(m) && !i.includes(m) && a.push({
|
|
56
|
+
rule: o.CustomFieldScript,
|
|
57
|
+
type: r.Warning,
|
|
58
|
+
key: I,
|
|
59
|
+
detail: m
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}), a;
|
|
63
|
+
}
|
|
64
|
+
function bt(e) {
|
|
65
|
+
return e.length > 0 ? [] : [{ rule: o.EmptyHtml, type: r.Warning, key: ct }];
|
|
66
|
+
}
|
|
67
|
+
function At(e) {
|
|
68
|
+
const i = (e.match(/{/gm) || []).length, n = (e.match(/}/gm) || []).length;
|
|
69
|
+
return i > n ? [{
|
|
70
|
+
rule: o.MismatchedBraces,
|
|
71
|
+
type: r.Warning,
|
|
72
|
+
key: lt
|
|
73
|
+
}] : i < n ? [{
|
|
74
|
+
rule: o.MismatchedBraces,
|
|
75
|
+
type: r.Warning,
|
|
76
|
+
key: ut
|
|
77
|
+
}] : [];
|
|
78
|
+
}
|
|
79
|
+
function Dt(e) {
|
|
80
|
+
return Z(e).map((i) => ({
|
|
81
|
+
rule: o.InvalidDynamicTag,
|
|
82
|
+
type: r.Warning,
|
|
83
|
+
key: I,
|
|
84
|
+
detail: i
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
function vt(e, i, n, a) {
|
|
88
|
+
const u = J(e);
|
|
89
|
+
return tt(e, i, u, n, a).map((s) => ({
|
|
90
|
+
rule: o.InvalidCustomField,
|
|
91
|
+
type: r.Error,
|
|
92
|
+
key: I,
|
|
93
|
+
detail: s
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
function Kt(e) {
|
|
97
|
+
const i = e.match(/{%(.*?)%}/g), n = [], a = [];
|
|
98
|
+
if (i && i.forEach((u) => {
|
|
99
|
+
const s = u.match(Y), m = u.match(x), y = (s == null ? void 0 : s.join("")) || "";
|
|
100
|
+
(!s || u !== y) && !m && a.push({
|
|
101
|
+
rule: o.ConditionsSyntax,
|
|
102
|
+
type: r.Error,
|
|
103
|
+
key: mt,
|
|
104
|
+
detail: u
|
|
105
|
+
}), s && s.forEach((g) => {
|
|
106
|
+
g.trim() === "=" && a.push({
|
|
107
|
+
rule: o.WrongEqualityOperator,
|
|
108
|
+
type: r.Error,
|
|
109
|
+
key: dt
|
|
110
|
+
}), (g.match(/^[a-zA-Z]*$/g) ?? []).forEach((f) => {
|
|
111
|
+
Ft(f) && n.push(f);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}), n.length) {
|
|
115
|
+
const u = n.filter((m) => m === "if").length, s = n.filter((m) => m === "endif").length;
|
|
116
|
+
u !== s && a.push({
|
|
117
|
+
rule: o.MissingIfEndif,
|
|
118
|
+
type: r.Error,
|
|
119
|
+
key: pt
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return a;
|
|
123
|
+
}
|
|
124
|
+
function wt(e) {
|
|
125
|
+
const i = (e.match(/{% /gm) || []).length, n = (e.match(/ %}/gm) || []).length;
|
|
126
|
+
return i === n ? [] : [{
|
|
127
|
+
rule: o.ConditionTagSpacing,
|
|
128
|
+
type: r.Warning,
|
|
129
|
+
key: gt
|
|
130
|
+
}];
|
|
131
|
+
}
|
|
132
|
+
function Bt(e) {
|
|
133
|
+
return (e.match(R) || []).filter((n) => n.includes("if")).map((n) => (n.match(/{{.*}}/gm) || []).length).reduce((n, a) => n + a, 0) === 0 ? [] : [{
|
|
134
|
+
rule: o.BracesInsideIfTag,
|
|
135
|
+
type: r.Warning,
|
|
136
|
+
key: ft
|
|
137
|
+
}];
|
|
138
|
+
}
|
|
139
|
+
function Yt(e) {
|
|
140
|
+
return (e.match(ht) ?? []).map((i) => ({
|
|
141
|
+
rule: o.InvalidImageType,
|
|
142
|
+
type: r.Error,
|
|
143
|
+
key: Et,
|
|
144
|
+
detail: i
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
function O(e, i, n, a) {
|
|
148
|
+
const u = new DOMParser().parseFromString(e, "text/html");
|
|
149
|
+
return Array.from(u.querySelectorAll(i)).filter((s) => {
|
|
150
|
+
var m;
|
|
151
|
+
return !((m = s.id) != null && m.trim());
|
|
152
|
+
}).map(() => ({ rule: n, type: r.Error, key: a }));
|
|
153
|
+
}
|
|
154
|
+
const ae = () => {
|
|
155
|
+
const { config: e, isFeatureEnabled: i } = z(), n = nt(), { post: a } = et(), { getCompiledEmail: u, getTemplateData: s } = j(), { compileHtml: m } = $(), { hydrateRecommendationStore: y } = X(), g = H(), f = V(), E = W(), L = q(), N = (t) => ({
|
|
156
|
+
rule: t.rule,
|
|
157
|
+
type: t.type,
|
|
158
|
+
detail: t.detail,
|
|
159
|
+
message: "key" in t ? n(t.key) : t.message
|
|
160
|
+
}), b = async (t) => {
|
|
161
|
+
if (t.size === 0)
|
|
162
|
+
return /* @__PURE__ */ new Set();
|
|
163
|
+
try {
|
|
164
|
+
await E.fetchRecommendationFilters();
|
|
165
|
+
} catch {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
return Q(E.filterList);
|
|
169
|
+
}, A = async (t) => {
|
|
170
|
+
try {
|
|
171
|
+
const l = await a(_t, { html: T(t) }), { status: c, message: d } = l.data, p = [];
|
|
172
|
+
return c || p.push({
|
|
173
|
+
rule: o.InvalidLinks,
|
|
174
|
+
type: r.Error,
|
|
175
|
+
// status===undefined means a bare message instead of a boolean; surface it,
|
|
176
|
+
// but fall back to the canned key when it's missing so a malformed body
|
|
177
|
+
// never renders a literal 'undefined' row (SD-147430).
|
|
178
|
+
...c === void 0 && d ? { message: d } : { key: Ct }
|
|
179
|
+
}), d === n(k) && p.push({
|
|
180
|
+
rule: o.LinkCheckInProgress,
|
|
181
|
+
type: r.Error,
|
|
182
|
+
key: k
|
|
183
|
+
}), p;
|
|
184
|
+
} catch (l) {
|
|
185
|
+
return console.warn("Link-check collector failed; skipping the link rule.", l), [];
|
|
186
|
+
}
|
|
187
|
+
}, D = async (t) => {
|
|
188
|
+
try {
|
|
189
|
+
const l = await a("/newsletter/contents/validate-syntax", [{
|
|
190
|
+
identifier: "default",
|
|
191
|
+
syntax: "liquid",
|
|
192
|
+
contents: {
|
|
193
|
+
subject: null,
|
|
194
|
+
preheader: null,
|
|
195
|
+
html: T(t),
|
|
196
|
+
ampHtml: null
|
|
197
|
+
}
|
|
198
|
+
}]);
|
|
199
|
+
if (!Array.isArray(l.data)) {
|
|
200
|
+
const d = l.data;
|
|
201
|
+
return [{
|
|
202
|
+
rule: o.LiquidSyntax,
|
|
203
|
+
type: r.Warning,
|
|
204
|
+
message: d.message ?? n(F)
|
|
205
|
+
}];
|
|
206
|
+
}
|
|
207
|
+
const [c] = l.data;
|
|
208
|
+
return Object.values((c == null ? void 0 : c.errors) ?? {}).map((d) => ({
|
|
209
|
+
rule: o.LiquidSyntax,
|
|
210
|
+
type: r.Warning,
|
|
211
|
+
message: d.replace(/^line \d+:\s*/, "")
|
|
212
|
+
}));
|
|
213
|
+
} catch {
|
|
214
|
+
return [{
|
|
215
|
+
rule: o.LiquidSyntax,
|
|
216
|
+
type: r.Error,
|
|
217
|
+
message: n(F)
|
|
218
|
+
}];
|
|
219
|
+
}
|
|
220
|
+
}, v = () => {
|
|
221
|
+
const t = E.invalidBlockIds().map((c) => ({
|
|
222
|
+
rule: o.RecommendationRequiredFields,
|
|
223
|
+
type: r.Error,
|
|
224
|
+
key: G,
|
|
225
|
+
detail: c
|
|
226
|
+
})), l = (f.recommendationConfigs ?? []).filter((c) => c.filters.some((d) => d.value === "")).map(() => ({
|
|
227
|
+
rule: o.RecommendationFilters,
|
|
228
|
+
type: r.Error,
|
|
229
|
+
key: yt
|
|
230
|
+
}));
|
|
231
|
+
return [...t, ...l];
|
|
232
|
+
}, K = async (t, l) => {
|
|
233
|
+
var _, h;
|
|
234
|
+
const c = [
|
|
235
|
+
...l.map((w) => w.value),
|
|
236
|
+
...M,
|
|
237
|
+
...((h = (_ = e.value) == null ? void 0 : _.template) == null ? void 0 : h.customFieldAttributes) ?? []
|
|
238
|
+
], d = B(t), p = await b(d), { isTransactional: C } = L;
|
|
239
|
+
return [
|
|
240
|
+
...await A(t),
|
|
241
|
+
...C ? [] : Nt(t, c),
|
|
242
|
+
...bt(t),
|
|
243
|
+
...At(t),
|
|
244
|
+
...Dt(t),
|
|
245
|
+
...C ? [] : vt(t, c, d, p),
|
|
246
|
+
...Kt(t),
|
|
247
|
+
...wt(t),
|
|
248
|
+
...Bt(t),
|
|
249
|
+
...v(),
|
|
250
|
+
...Yt(t),
|
|
251
|
+
...O(
|
|
252
|
+
t,
|
|
253
|
+
U,
|
|
254
|
+
o.CheckboxUnsubGroup,
|
|
255
|
+
It
|
|
256
|
+
),
|
|
257
|
+
...O(
|
|
258
|
+
t,
|
|
259
|
+
P,
|
|
260
|
+
o.RadioButtonUnsubGroup,
|
|
261
|
+
St
|
|
262
|
+
)
|
|
263
|
+
];
|
|
264
|
+
}, S = async (t, l) => [
|
|
265
|
+
...Ot(t),
|
|
266
|
+
...Rt(t),
|
|
267
|
+
...Lt(t),
|
|
268
|
+
...i("liquidSyntax") ? await D(t) : await K(t, l)
|
|
269
|
+
].map(N);
|
|
270
|
+
return { collectSaveValidationErrors: S, validateCurrentTemplate: async () => {
|
|
271
|
+
const { html: t } = await s();
|
|
272
|
+
await y(t);
|
|
273
|
+
const { html: l } = await u({ minimize: !0, resetDataSavedFlag: !1 }), { compiledHtml: c } = m(l);
|
|
274
|
+
return S(c, g.getSelectedDynamicContentList);
|
|
275
|
+
} };
|
|
276
|
+
};
|
|
277
|
+
export {
|
|
278
|
+
ae as useSaveValidation
|
|
279
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useConfigStore as t } from "../stores/config.js";
|
|
2
|
+
import { computed as o } from "vue";
|
|
3
|
+
const n = ["newsletteruatcamp", "newsletterqacamp"], c = () => {
|
|
4
|
+
const e = t();
|
|
5
|
+
return { isEnabled: o(() => n.includes(e.partnerName)) };
|
|
6
|
+
};
|
|
7
|
+
export {
|
|
8
|
+
c as useSaveValidationRollout
|
|
9
|
+
};
|
|
@@ -1,24 +1,27 @@
|
|
|
1
|
-
import { ToasterTypeOptions as
|
|
2
|
-
import { COUPON_PLACEHOLDER_DEFAULT as
|
|
3
|
-
import { useToaster as
|
|
4
|
-
import { useTranslations as
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
]),
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
import { ToasterTypeOptions as n } from "../../enums/toaster.js";
|
|
2
|
+
import { COUPON_PLACEHOLDER_DEFAULT as s, COUPON_PLACEHOLDER_LIQUID as a } from "../../extensions/Blocks/CouponBlock/template.js";
|
|
3
|
+
import { useToaster as i } from "../useToaster.js";
|
|
4
|
+
import { useTranslations as l } from "../useTranslations.js";
|
|
5
|
+
const c = /* @__PURE__ */ new Set([
|
|
6
|
+
s,
|
|
7
|
+
a
|
|
8
|
+
]), p = "newsletter.coupon-tag-modified";
|
|
9
|
+
function u(r) {
|
|
10
|
+
const e = new DOMParser().parseFromString(r, "text/html");
|
|
11
|
+
return Array.from(e.querySelectorAll(".coupon-block")).map((o) => {
|
|
12
|
+
var t;
|
|
13
|
+
return ((t = o.textContent) == null ? void 0 : t.trim()) ?? "";
|
|
14
|
+
}).filter((o) => !c.has(o));
|
|
15
|
+
}
|
|
16
|
+
const T = () => {
|
|
17
|
+
const { showToaster: r } = i(), e = l();
|
|
18
|
+
return { validateCouponBlockTags: (t) => u(t).length > 0 ? (r({
|
|
19
|
+
type: n.Warning,
|
|
20
|
+
message: e(p)
|
|
21
|
+
}), !1) : !0 };
|
|
21
22
|
};
|
|
22
23
|
export {
|
|
23
|
-
|
|
24
|
+
p as COUPON_TAG_MODIFIED_KEY,
|
|
25
|
+
u as findInvalidCouponBlocks,
|
|
26
|
+
T as useCouponBlockValidator
|
|
24
27
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ToasterTypeOptions as
|
|
1
|
+
import { ToasterTypeOptions as c } from "../../enums/toaster.js";
|
|
2
2
|
import { PAGE_TYPES as u } from "../../enums/unsubscribe.js";
|
|
3
|
-
import { UNSUBSCRIBE_BLOCK_SELECTOR as
|
|
4
|
-
import { useToaster as
|
|
5
|
-
import { useTranslations as
|
|
3
|
+
import { UNSUBSCRIBE_BLOCK_SELECTOR as i, DATA_ATTRIBUTES as a } from "../../extensions/Blocks/Unsubscribe/utils/constants.js";
|
|
4
|
+
import { useToaster as p } from "../useToaster.js";
|
|
5
|
+
import { useTranslations as l } from "../useTranslations.js";
|
|
6
6
|
const T = [
|
|
7
7
|
{
|
|
8
8
|
pageType: u.GLOBAL_UNSUBSCRIBE,
|
|
@@ -12,30 +12,37 @@ const T = [
|
|
|
12
12
|
pageType: u.SUBSCRIPTION_PREFERENCE_CENTER,
|
|
13
13
|
messageKey: "unsubscription-preference.duplicate-pref-center"
|
|
14
14
|
}
|
|
15
|
-
], g = "unsubscription-preference.duplicate-both",
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
], g = "unsubscription-preference.duplicate-both", E = "unsubscription-preference.select-page-to-continue";
|
|
16
|
+
function m(r) {
|
|
17
|
+
const s = new DOMParser().parseFromString(r, "text/html"), t = /* @__PURE__ */ new Map();
|
|
18
|
+
return s.querySelectorAll(i).forEach((n) => {
|
|
19
|
+
const e = Number(n.getAttribute(a.PAGE_TYPE));
|
|
20
|
+
t.set(e, (t.get(e) ?? 0) + 1);
|
|
21
|
+
}), T.filter((n) => (t.get(n.pageType) ?? 0) > 1);
|
|
22
|
+
}
|
|
23
|
+
function b(r) {
|
|
24
|
+
const s = new DOMParser().parseFromString(r, "text/html");
|
|
25
|
+
return Array.from(s.querySelectorAll(i)).filter((t) => {
|
|
26
|
+
const n = t.getAttribute(a.PAGE_TYPE), e = t.getAttribute(a.PAGE_LIST);
|
|
27
|
+
return !n || !e;
|
|
28
|
+
}).length;
|
|
29
|
+
}
|
|
30
|
+
const y = () => {
|
|
31
|
+
const { showToaster: r } = p(), s = l();
|
|
32
|
+
return { validateUnsubscribeBlockUniqueness: (e) => {
|
|
33
|
+
const o = m(e);
|
|
34
|
+
return o.length ? (r({
|
|
35
|
+
type: c.Error,
|
|
36
|
+
message: s(o.length > 1 ? g : o[0].messageKey)
|
|
27
37
|
}), !1) : !0;
|
|
28
|
-
}, validateUnsubscribeBlockHasTemplate: (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return !e || !s;
|
|
33
|
-
}) ? (c({
|
|
34
|
-
type: i.Warning,
|
|
35
|
-
message: p(b)
|
|
36
|
-
}), !1) : !0;
|
|
37
|
-
} };
|
|
38
|
+
}, validateUnsubscribeBlockHasTemplate: (e) => b(e) === 0 ? !0 : (r({
|
|
39
|
+
type: c.Warning,
|
|
40
|
+
message: s(E)
|
|
41
|
+
}), !1) };
|
|
38
42
|
};
|
|
39
43
|
export {
|
|
40
|
-
|
|
44
|
+
E as EMPTY_BLOCK_KEY,
|
|
45
|
+
b as countUnsubBlocksWithoutPage,
|
|
46
|
+
m as findDuplicateUnsubPageTypes,
|
|
47
|
+
y as useUnsubscribeBlockValidator
|
|
41
48
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const g = [
|
|
1
|
+
import { stripFontTags as p } from "../../utils/stripFontTags.js";
|
|
2
|
+
const d = [
|
|
4
3
|
{
|
|
5
4
|
id: "fix-url-encoding-start",
|
|
6
5
|
description: "Replace {%22 with %7B%22 to fix URL encoding",
|
|
@@ -59,7 +58,7 @@ const g = [
|
|
|
59
58
|
id: "strip-font-tags",
|
|
60
59
|
description: 'Unwrap browser-translate-injected <font dir="auto"> tags, keeping inner content; other <font> elements are left intact.',
|
|
61
60
|
type: "custom",
|
|
62
|
-
processor: (e) =>
|
|
61
|
+
processor: (e) => p(e),
|
|
63
62
|
priority: 15
|
|
64
63
|
},
|
|
65
64
|
{
|
|
@@ -130,13 +129,6 @@ const g = [
|
|
|
130
129
|
},
|
|
131
130
|
priority: 30
|
|
132
131
|
},
|
|
133
|
-
{
|
|
134
|
-
id: "append-mobile-hidden-column-css",
|
|
135
|
-
description: "Inject media-query CSS that hides mobile-hidden columns and their gap cells",
|
|
136
|
-
type: "custom",
|
|
137
|
-
processor: (e) => c(e),
|
|
138
|
-
priority: 31
|
|
139
|
-
},
|
|
140
132
|
{
|
|
141
133
|
id: "replace-old-image-domain",
|
|
142
134
|
description: "Replacing old image domains",
|
|
@@ -165,8 +157,8 @@ const g = [
|
|
|
165
157
|
processor: (e) => {
|
|
166
158
|
const t = (i) => i.toString(16).padStart(2, "0");
|
|
167
159
|
return e.replace(/rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/gi, (i, o, n, r) => {
|
|
168
|
-
const [s, a,
|
|
169
|
-
return s > 255 || a > 255 ||
|
|
160
|
+
const [s, a, c] = [Number(o), Number(n), Number(r)];
|
|
161
|
+
return s > 255 || a > 255 || c > 255 ? i : `#${t(s)}${t(a)}${t(c)}`;
|
|
170
162
|
}).replace(/#([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3\b/gi, "#$1$2$3");
|
|
171
163
|
},
|
|
172
164
|
priority: 44
|
|
@@ -208,5 +200,5 @@ const g = [
|
|
|
208
200
|
}
|
|
209
201
|
];
|
|
210
202
|
export {
|
|
211
|
-
|
|
203
|
+
d as defaultHtmlCompilerRules
|
|
212
204
|
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var n = /* @__PURE__ */ ((s) => (s.CouponTagModified = "coupon-tag-modified", s.DuplicateUnsubBlock = "duplicate-unsub-block", s.UnsubBlockMissingTemplate = "unsub-block-missing-template", s.LiquidSyntax = "liquid-syntax", s.InvalidLinks = "invalid-links", s.LinkCheckInProgress = "link-check-in-progress", s.CustomFieldScript = "custom-field-script", s.EmptyHtml = "empty-html", s.MismatchedBraces = "mismatched-braces", s.InvalidDynamicTag = "invalid-dynamic-tag", s.InvalidCustomField = "invalid-custom-field", s.ConditionsSyntax = "conditions-syntax", s.WrongEqualityOperator = "wrong-equality-operator", s.MissingIfEndif = "missing-if-endif", s.ConditionTagSpacing = "condition-tag-spacing", s.BracesInsideIfTag = "braces-inside-if-tag", s.RecommendationRequiredFields = "recommendation-required-fields", s.RecommendationFilters = "recommendation-filters", s.InvalidImageType = "invalid-image-type", s.CheckboxUnsubGroup = "checkbox-unsub-group", s.RadioButtonUnsubGroup = "radio-button-unsub-group", s))(n || {});
|
|
2
|
+
export {
|
|
3
|
+
n as SaveValidationRule
|
|
4
|
+
};
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { getRecommendationFeedSourceMaps as b, getOperatorOptions as G, PriceAttributes as
|
|
2
|
-
import { useRecommendationApi as
|
|
3
|
-
import { useConfigStore as
|
|
4
|
-
import { defineStore as
|
|
1
|
+
import { getRecommendationFeedSourceMaps as b, getOperatorOptions as G, PriceAttributes as D } from "../../../../enums/extensions/recommendationBlock.js";
|
|
2
|
+
import { useRecommendationApi as P } from "../../../../services/recommendationApi.js";
|
|
3
|
+
import { useConfigStore as F } from "../../../../stores/config.js";
|
|
4
|
+
import { defineStore as _ } from "pinia";
|
|
5
5
|
import "../constants/selectors.js";
|
|
6
|
-
import { DEFAULT_MOBILE_CARDS_IN_ROW as
|
|
7
|
-
import { DEFAULT_NODE_CONFIG as
|
|
8
|
-
import { getDefaultProducts as
|
|
9
|
-
import { generateCompleteFilterQuery as
|
|
10
|
-
import { getPartnerRecommendationParams as
|
|
6
|
+
import { DEFAULT_MOBILE_CARDS_IN_ROW as U, DEFAULT_CARDS_IN_ROW as N } from "../constants/layout.js";
|
|
7
|
+
import { DEFAULT_NODE_CONFIG as L, EXCLUDED_ALGORITHM_IDS as x } from "../constants/defaultConfig.js";
|
|
8
|
+
import { getDefaultProducts as k } from "../templates/utils.js";
|
|
9
|
+
import { generateCompleteFilterQuery as R } from "../utils/filterUtil.js";
|
|
10
|
+
import { getPartnerRecommendationParams as B } from "../utils/partnerCustomizations.js";
|
|
11
11
|
import { sanitizeProductIds as A } from "../utils/productIds.js";
|
|
12
|
-
import { isFilterValid as
|
|
13
|
-
import { isConfigValid as
|
|
14
|
-
const u =
|
|
12
|
+
import { isFilterValid as M } from "../validation/filterSchema.js";
|
|
13
|
+
import { isConfigValid as C } from "../validation/requiredFields.js";
|
|
14
|
+
const u = P();
|
|
15
15
|
let f = null, h = null, g = null, S = null;
|
|
16
16
|
const p = /* @__PURE__ */ new Map();
|
|
17
|
-
function
|
|
17
|
+
function v() {
|
|
18
18
|
return {
|
|
19
|
-
cardsInRow:
|
|
19
|
+
cardsInRow: N,
|
|
20
20
|
currencySettings: {
|
|
21
21
|
name: "USD",
|
|
22
22
|
value: "USD",
|
|
@@ -30,7 +30,7 @@ function w() {
|
|
|
30
30
|
productIds: [],
|
|
31
31
|
id: 1,
|
|
32
32
|
language: "en_US",
|
|
33
|
-
mobileCardsInRow:
|
|
33
|
+
mobileCardsInRow: U,
|
|
34
34
|
mobileLayoutEnabled: !1,
|
|
35
35
|
orientation: "grid",
|
|
36
36
|
recommendedProducts: [],
|
|
@@ -46,9 +46,9 @@ function w() {
|
|
|
46
46
|
priceHideIfSameAsDiscounted: !1
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
-
function
|
|
49
|
+
function w() {
|
|
50
50
|
return {
|
|
51
|
-
recommendationConfigs:
|
|
51
|
+
recommendationConfigs: v(),
|
|
52
52
|
recommendationProducts: [],
|
|
53
53
|
filterStatus: !1,
|
|
54
54
|
filterSelectionDrawerStatus: !1,
|
|
@@ -59,7 +59,7 @@ function C() {
|
|
|
59
59
|
filterSnapshot: null
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
-
const
|
|
62
|
+
const O = () => ({
|
|
63
63
|
recommendationCampaignUrls: {},
|
|
64
64
|
activePredictiveAlgorithms: [],
|
|
65
65
|
languages: {},
|
|
@@ -71,8 +71,8 @@ const z = () => ({
|
|
|
71
71
|
blockStates: {},
|
|
72
72
|
currentRecommendationId: null,
|
|
73
73
|
configVersion: 0
|
|
74
|
-
}), Y =
|
|
75
|
-
state: () =>
|
|
74
|
+
}), Y = _("guidoRecommendationExtension", {
|
|
75
|
+
state: () => O(),
|
|
76
76
|
getters: {
|
|
77
77
|
// ====================================================================
|
|
78
78
|
// Proxy Getters — Backward Compatible Access to Current Block State
|
|
@@ -82,7 +82,7 @@ const z = () => ({
|
|
|
82
82
|
* This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
|
|
83
83
|
*/
|
|
84
84
|
recommendationConfigs(t) {
|
|
85
|
-
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs :
|
|
85
|
+
return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].recommendationConfigs : v();
|
|
86
86
|
},
|
|
87
87
|
/**
|
|
88
88
|
* Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
|
|
@@ -138,7 +138,7 @@ const z = () => ({
|
|
|
138
138
|
},
|
|
139
139
|
getActivePredictiveAlgorithms: (t) => {
|
|
140
140
|
const e = b(), r = [];
|
|
141
|
-
return t.activePredictiveAlgorithms.filter((n) => !
|
|
141
|
+
return t.activePredictiveAlgorithms.filter((n) => !x.includes(n)).forEach((n) => {
|
|
142
142
|
r.push(...e.filter((s) => s.id === n));
|
|
143
143
|
}), r.map((n) => ({
|
|
144
144
|
text: n.name,
|
|
@@ -156,7 +156,7 @@ const z = () => ({
|
|
|
156
156
|
getFilterList() {
|
|
157
157
|
return Object.values(this.filterList).filter((t) => t.isFilterable !== 0 && t.isFilterable !== !1).map((t) => {
|
|
158
158
|
let e;
|
|
159
|
-
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` :
|
|
159
|
+
return t.type === "productAttribute" ? e = `product_attributes.${t.attributeName}` : D.includes(t.attributeName) ? e = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : e = t.attributeName, {
|
|
160
160
|
text: t.displayName,
|
|
161
161
|
value: e,
|
|
162
162
|
type: t.attributeType
|
|
@@ -178,7 +178,7 @@ const z = () => ({
|
|
|
178
178
|
setCurrentBlock(t) {
|
|
179
179
|
this.blockStates[t] || (this.blockStates = {
|
|
180
180
|
...this.blockStates,
|
|
181
|
-
[t]:
|
|
181
|
+
[t]: w()
|
|
182
182
|
}), this.currentRecommendationId = t;
|
|
183
183
|
},
|
|
184
184
|
/**
|
|
@@ -246,7 +246,7 @@ const z = () => ({
|
|
|
246
246
|
decimalCount: String(e.currencyDecimalCount),
|
|
247
247
|
decimalSeparator: r(e.currencyDecimalSeparator, ","),
|
|
248
248
|
thousandSeparator: r(e.currencyThousandSeparator, ".")
|
|
249
|
-
}, s = !this.blockStates[t], i = s ?
|
|
249
|
+
}, s = !this.blockStates[t], i = s ? w() : this.blockStates[t];
|
|
250
250
|
i.recommendationConfigs = {
|
|
251
251
|
...i.recommendationConfigs,
|
|
252
252
|
strategy: e.strategy,
|
|
@@ -380,7 +380,7 @@ const z = () => ({
|
|
|
380
380
|
});
|
|
381
381
|
},
|
|
382
382
|
removeStrategy() {
|
|
383
|
-
this.patchCurrentBlockConfig({ strategyId: "", size:
|
|
383
|
+
this.patchCurrentBlockConfig({ strategyId: "", size: L.size });
|
|
384
384
|
},
|
|
385
385
|
// ====================================================================
|
|
386
386
|
// Shared Data Fetching (fetched once, used by all blocks)
|
|
@@ -452,7 +452,7 @@ const z = () => ({
|
|
|
452
452
|
const n = [...e.recommendationConfigs.filters];
|
|
453
453
|
n[r] = {
|
|
454
454
|
...t,
|
|
455
|
-
isValid:
|
|
455
|
+
isValid: M(t)
|
|
456
456
|
}, e.recommendationConfigs.filters = n;
|
|
457
457
|
}
|
|
458
458
|
},
|
|
@@ -490,7 +490,7 @@ const z = () => ({
|
|
|
490
490
|
}), e.recommendationConfigs.filters = r;
|
|
491
491
|
},
|
|
492
492
|
generateFilterQuery() {
|
|
493
|
-
return
|
|
493
|
+
return R(this.recommendationConfigs.filters);
|
|
494
494
|
},
|
|
495
495
|
/**
|
|
496
496
|
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
@@ -498,7 +498,14 @@ const z = () => ({
|
|
|
498
498
|
* every block's recommendationConfigs across user edits.
|
|
499
499
|
*/
|
|
500
500
|
hasInvalidBlock() {
|
|
501
|
-
return Object.values(this.blockStates).some((t) => !
|
|
501
|
+
return Object.values(this.blockStates).some((t) => !C(t.recommendationConfigs, this));
|
|
502
|
+
},
|
|
503
|
+
/**
|
|
504
|
+
* Per-instance counterpart to `hasInvalidBlock`: the ids of every block
|
|
505
|
+
* that fails required-field validation, one drawer row each (SD-147430).
|
|
506
|
+
*/
|
|
507
|
+
invalidBlockIds() {
|
|
508
|
+
return Object.entries(this.blockStates).filter(([, t]) => !C(t.recommendationConfigs, this)).map(([t]) => t);
|
|
502
509
|
},
|
|
503
510
|
// ====================================================================
|
|
504
511
|
// Per-Block Product Fetching
|
|
@@ -519,12 +526,12 @@ const z = () => ({
|
|
|
519
526
|
},
|
|
520
527
|
async _doFetchProducts() {
|
|
521
528
|
var d;
|
|
522
|
-
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n =
|
|
529
|
+
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = F();
|
|
523
530
|
if (r.strategyId && n.isFeatureEnabled("reusableRecommendationStrategy")) {
|
|
524
531
|
await this._doFetchStrategyProducts(t);
|
|
525
532
|
return;
|
|
526
533
|
}
|
|
527
|
-
const s = r.filters.filter((m) => m.isValid), i =
|
|
534
|
+
const s = r.filters.filter((m) => m.isValid), i = R(s), o = ((d = b().find((m) => m.key === r.strategy)) == null ? void 0 : d.path) || "", c = parseInt(r.size) || 6, a = {
|
|
528
535
|
locale: r.language,
|
|
529
536
|
currency: r.currencySettings.value,
|
|
530
537
|
partnerName: n.partnerName,
|
|
@@ -534,7 +541,7 @@ const z = () => ({
|
|
|
534
541
|
};
|
|
535
542
|
r.strategy === "manualMerchandising" ? a.productId = A(r.productIds) : r.strategy === "similarViewed" && (a.productId = "{itemId}"), r.strategy === "userBased" && (a.userId = "{user_id}"), i && (a.filter = i), r.shuffleProducts && (a.shuffle = !0), Object.assign(
|
|
536
543
|
a,
|
|
537
|
-
|
|
544
|
+
B(n.partnerName, r.strategy)
|
|
538
545
|
);
|
|
539
546
|
let l;
|
|
540
547
|
try {
|
|
@@ -567,10 +574,10 @@ const z = () => ({
|
|
|
567
574
|
_setBlockProducts(t, e, r) {
|
|
568
575
|
if (!this.blockStates[t])
|
|
569
576
|
return;
|
|
570
|
-
const n = e.length > 0 ? e :
|
|
577
|
+
const n = e.length > 0 ? e : k(r);
|
|
571
578
|
this.blockStates[t].recommendationProducts = [
|
|
572
579
|
...n.slice(0, r),
|
|
573
|
-
...
|
|
580
|
+
...k(Math.max(0, r - n.length))
|
|
574
581
|
];
|
|
575
582
|
}
|
|
576
583
|
}
|