@useinsider/guido 3.19.0-beta.3906ea8 → 3.19.0-beta.3abc7c5

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.
Files changed (54) hide show
  1. package/README.md +1 -0
  2. package/dist/@types/config/schemas.js +33 -31
  3. package/dist/components/Guido.vue.js +8 -8
  4. package/dist/components/Guido.vue2.js +50 -48
  5. package/dist/components/organisms/AutoSaveController.vue2.js +9 -8
  6. package/dist/components/organisms/header/EditorActions.vue.js +2 -2
  7. package/dist/components/organisms/header/EditorActions.vue2.js +85 -57
  8. package/dist/components/organisms/header/LeftSlot.vue.js +5 -5
  9. package/dist/components/organisms/header/LeftSlot.vue2.js +16 -12
  10. package/dist/components/organisms/validation/ValidationErrorDrawer.vue.js +20 -0
  11. package/dist/components/organisms/validation/ValidationErrorDrawer.vue2.js +48 -0
  12. package/dist/components/wrappers/WpDrawer.vue.js +9 -7
  13. package/dist/components/wrappers/WpDrawer.vue2.js +1 -1
  14. package/dist/composables/useActionsApi.js +52 -47
  15. package/dist/composables/useCodeEditorApi.js +23 -9
  16. package/dist/composables/useHtmlCompiler.js +37 -26
  17. package/dist/composables/useHtmlValidator.js +2 -0
  18. package/dist/composables/useSave.js +90 -45
  19. package/dist/composables/useSaveValidation.js +279 -0
  20. package/dist/composables/useSaveValidationRollout.js +9 -0
  21. package/dist/composables/useTranslations.js +3 -2
  22. package/dist/composables/useVersionHistoryApi.js +33 -24
  23. package/dist/composables/validators/useCouponBlockValidator.js +24 -21
  24. package/dist/composables/validators/useUnsubscribeBlockValidator.js +34 -27
  25. package/dist/enums/save-validation.js +4 -0
  26. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +54 -47
  27. package/dist/guido.css +1 -1
  28. package/dist/src/@types/config/schemas.d.ts +4 -0
  29. package/dist/src/@types/save-validation.d.ts +19 -0
  30. package/dist/src/components/Guido.vue.d.ts +17 -1
  31. package/dist/src/components/organisms/header/EditorActions.vue.d.ts +17 -1
  32. package/dist/src/components/organisms/header/HeaderWrapper.vue.d.ts +17 -1
  33. package/dist/src/components/organisms/header/RightSlot.vue.d.ts +17 -1
  34. package/dist/src/components/organisms/validation/ValidationErrorDrawer.vue.d.ts +2 -0
  35. package/dist/src/components/wrappers/WpDrawer.vue.d.ts +4 -3
  36. package/dist/src/composables/useConfig.d.ts +2 -0
  37. package/dist/src/composables/useHtmlValidator.d.ts +21 -0
  38. package/dist/src/composables/useSave.d.ts +6 -1
  39. package/dist/src/composables/useSaveValidation.d.ts +6 -0
  40. package/dist/src/composables/useSaveValidationRollout.d.ts +3 -0
  41. package/dist/src/composables/validators/useCouponBlockValidator.d.ts +3 -0
  42. package/dist/src/composables/validators/useUnsubscribeBlockValidator.d.ts +10 -0
  43. package/dist/src/enums/save-validation.d.ts +27 -0
  44. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +5 -0
  45. package/dist/src/stores/config.d.ts +32 -0
  46. package/dist/src/stores/save-validation.d.ts +22 -0
  47. package/dist/src/utils/stripoEditorApi.d.ts +4 -0
  48. package/dist/src/utils/templatePreparation.d.ts +30 -0
  49. package/dist/stores/config.js +84 -67
  50. package/dist/stores/save-validation.js +30 -0
  51. package/dist/stores/unsubscribe.js +3 -3
  52. package/dist/utils/stripoEditorApi.js +11 -0
  53. package/dist/utils/templatePreparation.js +39 -36
  54. package/package.json +3 -2
@@ -1,55 +1,100 @@
1
- import { useActionsApi as T } from "./useActionsApi.js";
1
+ import { useActionsApi as W } from "./useActionsApi.js";
2
2
  import { useConfig as q } from "./useConfig.js";
3
- import { useEditorLock as C } from "./useEditorLock.js";
4
- import { useSaveStart as L, useSaveComplete as M } from "./useGuidoActions.js";
5
- import { useSyncModuleExtractor as D } from "./useSyncModuleExtractor.js";
6
- import { ToasterTypeOptions as P } from "../enums/toaster.js";
7
- import { useStripoApi as U } from "../services/stripoApi.js";
8
- import { useTemplatePreparation as A } from "../utils/templatePreparation.js";
9
- import { useAllowlist as h } from "./useAllowlist.js";
10
- import { useHtmlValidator as F } from "./useHtmlValidator.js";
11
- import { useToaster as O } from "./useToaster.js";
12
- import { useCouponBlockValidator as W } from "./validators/useCouponBlockValidator.js";
13
- import { useLiquidValidator as j } from "./validators/useLiquidValidator.js";
14
- import { useSyncModuleBlockValidator as z } from "./validators/useSyncModuleBlockValidator.js";
15
- import { useUnsubscribeBlockValidator as G } from "./validators/useUnsubscribeBlockValidator.js";
16
- const rt = () => {
17
- const n = L(), c = M(), { validateHtml: d } = F(), { validateLiquidSyntax: m } = j(), { validateCouponBlockTags: u } = W(), { validateUnsubscribeBlockUniqueness: p, validateUnsubscribeBlockHasTemplate: f } = G(), { validateSyncModuleBlocks: v } = z(), { callbacks: s, isFeatureEnabled: r } = q(), { extractSyncModuleData: S } = D(), { setSyncModuleUnsubscriptionPages: b } = U(), { editorSave: w } = T(), { showToaster: V } = O(), { getBlockedDomains: y, resolveToast: k } = h(), { runExclusive: x } = C(), H = async (a, o) => {
18
- var l;
19
- n();
20
- const { prepareTemplateDetails: B } = A(), t = await B();
21
- if (!v(t.rawHtml, o) || !u(t.compiledHtml) || !p(t.compiledHtml) || !f(t.compiledHtml))
22
- return;
23
- if (r("liquidSyntax")) {
24
- if (!await m(t.compiledHtml))
25
- return;
26
- } else if (!await d(t.compiledHtml, t.dynamicContentList, !0))
27
- return;
28
- if ((l = s.value) != null && l.externalValidation && !await s.value.externalValidation(t))
3
+ import { useEditorLock as O } from "./useEditorLock.js";
4
+ import { useSaveStart as D, useSaveComplete as F } from "./useGuidoActions.js";
5
+ import { useSaveValidation as j } from "./useSaveValidation.js";
6
+ import { useSaveValidationRollout as z } from "./useSaveValidationRollout.js";
7
+ import { useSyncModuleExtractor as G } from "./useSyncModuleExtractor.js";
8
+ import { ToasterTypeOptions as I } from "../enums/toaster.js";
9
+ import { useStripoApi as J } from "../services/stripoApi.js";
10
+ import { useConfigStore as K } from "../stores/config.js";
11
+ import { useDynamicContentStore as N } from "../stores/dynamic-content.js";
12
+ import { useSaveValidationStore as Q } from "../stores/save-validation.js";
13
+ import { useTemplatePreparation as X, getHtmlReferencedUnsubscribePages as Y } from "../utils/templatePreparation.js";
14
+ import { useAllowlist as Z } from "./useAllowlist.js";
15
+ import { useHtmlValidator as _ } from "./useHtmlValidator.js";
16
+ import { useToaster as $ } from "./useToaster.js";
17
+ import { useCouponBlockValidator as tt } from "./validators/useCouponBlockValidator.js";
18
+ import { useLiquidValidator as et } from "./validators/useLiquidValidator.js";
19
+ import { useSyncModuleBlockValidator as ot } from "./validators/useSyncModuleBlockValidator.js";
20
+ import { useUnsubscribeBlockValidator as st } from "./validators/useUnsubscribeBlockValidator.js";
21
+ const Bt = () => {
22
+ const r = D(), f = F(), { validateHtml: p } = _(), { validateLiquidSyntax: v } = et(), { validateCouponBlockTags: y } = tt(), { validateUnsubscribeBlockUniqueness: S, validateUnsubscribeBlockHasTemplate: w } = st(), { validateSyncModuleBlocks: u } = ot(), { callbacks: a, isFeatureEnabled: m } = q(), { extractSyncModuleData: b } = G(), { setSyncModuleUnsubscriptionPages: g } = J(), { editorSave: E, getTemplateData: H } = W(), { showToaster: V } = $(), { getBlockedDomains: x, resolveToast: k } = Z(), { prepareTemplateDetails: d } = X(), { collectSaveValidationErrors: C } = j(), { isEnabled: B } = z(), T = Q(), h = N(), P = K(), { runExclusive: n } = O(), l = async (t, e, o) => {
23
+ if (!m("allowlistEnabled"))
24
+ return !1;
25
+ const i = await x(t, e);
26
+ if (!i.length)
27
+ return !1;
28
+ if (!o) {
29
+ const s = await k(i);
30
+ s != null && s.message && V({
31
+ type: I.Warning,
32
+ message: s.message,
33
+ actionButton: s.actionButton
34
+ });
35
+ }
36
+ return !0;
37
+ }, L = async (t) => !y(t.compiledHtml) || !S(t.compiledHtml) || !w(t.compiledHtml) ? !1 : m("liquidSyntax") ? v(t.compiledHtml) : p(t.compiledHtml, t.dynamicContentList, !0), c = async (t, e) => {
38
+ if (!await E())
29
39
  return;
30
- if (r("allowlistEnabled")) {
31
- const i = await y(t.compiledHtml, t.css);
32
- if (i.length) {
33
- if (!o) {
34
- const e = await k(i);
35
- e != null && e.message && V({
36
- type: P.Warning,
37
- message: e.message,
38
- actionButton: e.actionButton
39
- });
40
+ const { unsubscribePayload: i, stripoModules: s } = b(t.rawHtml);
41
+ if (await g(i), t.modules = s, !e.suppress) {
42
+ const R = e.blankCompiled ? { compiledHtml: "", ampHtml: "" } : {};
43
+ f({ ...t, ...R, silent: e.silent });
44
+ }
45
+ return t;
46
+ }, U = async (t, e) => {
47
+ var i;
48
+ r();
49
+ const o = await d();
50
+ if (u(o.rawHtml, e)) {
51
+ if (B.value && !e) {
52
+ const s = await C(
53
+ o.compiledHtml,
54
+ o.dynamicContentList
55
+ );
56
+ if (s.length) {
57
+ T.open(s, "save");
58
+ return;
40
59
  }
60
+ } else if (!await L(o))
41
61
  return;
42
- }
62
+ if (!((i = a.value) != null && i.externalValidation && !await a.value.externalValidation(o)) && !await l(o.compiledHtml, o.css, e))
63
+ return c(o, { silent: e, suppress: t });
43
64
  }
44
- if (!await w())
65
+ }, A = async () => {
66
+ var e;
67
+ if (!P.allowSaveWithErrors)
45
68
  return;
46
- const { unsubscribePayload: E, stripoModules: g } = S(t.rawHtml);
47
- return await b(E), t.modules = g, a || c({ ...t, silent: o }), t;
69
+ r();
70
+ const t = await d();
71
+ if (!((e = a.value) != null && e.externalValidation && !await a.value.externalValidation(t)) && !await l(t.compiledHtml, t.css, !1))
72
+ return c(t, { silent: !1, blankCompiled: !0 });
73
+ }, M = async () => {
74
+ r();
75
+ const { html: t, css: e } = await H();
76
+ if (!u(t, !0) || await l(t, e, !0))
77
+ return;
78
+ const o = Y(t), i = {
79
+ dynamicContentList: h.getSelectedDynamicContentList,
80
+ compiledHtml: "",
81
+ rawHtml: t,
82
+ css: e,
83
+ ampHtml: "",
84
+ ampErrors: [],
85
+ modules: [],
86
+ recommendation: { campaignUrls: {}, configs: {} },
87
+ unsubscribe: {
88
+ status: o.length > 0,
89
+ config: o
90
+ }
91
+ };
92
+ return c(i, { silent: !0 });
48
93
  };
49
- return { save: (a = !1, o = !1) => x(
50
- () => H(a, o)
51
- ) };
94
+ return { save: (t = !1, e = !1) => n(
95
+ () => U(t, e)
96
+ ), saveWithErrors: () => n(A), saveRawOnly: () => n(M) };
52
97
  };
53
98
  export {
54
- rt as useSave
99
+ Bt as useSave
55
100
  };
@@ -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
+ };
@@ -6,9 +6,10 @@ import { useConfig } from "./useConfig.js";
6
6
  const useTranslations = () => {
7
7
  var o, e;
8
8
  const { config } = useConfig(), translationsPath = ((e = (o = config.value) == null ? void 0 : o.editor) == null ? void 0 : e.translationsPath) || DEFAULT_EDITOR.translationsPath, translations = ref(eval(translationsPath)), trans = (t, n) => {
9
- const r = translations.value[t];
9
+ var s;
10
+ const r = (s = translations.value) == null ? void 0 : s[t];
10
11
  return r ? n ? Object.entries(n).reduce(
11
- (s, [i, a]) => s.replace(new RegExp(`{${i}}`, "g"), String(a)),
12
+ (i, [a, l]) => i.replace(new RegExp(`{${a}}`, "g"), String(l)),
12
13
  r
13
14
  ) : r : (console.warn(`Translation key not found: ${t}`), t);
14
15
  };
@@ -1,54 +1,63 @@
1
1
  import { ToasterTypeOptions as t } from "../enums/toaster.js";
2
- import { useVersionHistoryStore as c } from "../stores/version-history.js";
3
- import { useToaster as w } from "./useToaster.js";
4
- const S = () => {
5
- const i = c(), { showToaster: s } = w(), n = (e) => {
6
- i.$reset(), i.updateState(e);
7
- }, p = () => {
8
- i.$reset();
2
+ import { useVersionHistoryStore as m } from "../stores/version-history.js";
3
+ import { findEditorApi as w, EDITOR_NOT_READY_MESSAGE as y } from "../utils/stripoEditorApi.js";
4
+ import { useToaster as V } from "./useToaster.js";
5
+ const d = () => {
6
+ const n = m(), { showToaster: i } = V(), o = (e) => {
7
+ var s;
8
+ const r = (s = w()) == null ? void 0 : s.versionHistoryApi;
9
+ if (!r) {
10
+ i({ type: t.Error, message: y });
11
+ return;
12
+ }
13
+ e(r);
14
+ }, p = (e) => {
15
+ n.$reset(), n.updateState(e);
16
+ }, a = () => {
17
+ n.$reset();
9
18
  };
10
19
  return {
11
20
  openVersionHistory: () => {
12
- window.StripoEditorApi.versionHistoryApi.openVersionHistory(n, p);
21
+ o((e) => e.openVersionHistory(p, a));
13
22
  },
14
23
  closeVersionHistory: () => {
15
- window.StripoEditorApi.versionHistoryApi.closeVersionHistory();
24
+ o((e) => e.closeVersionHistory());
16
25
  },
17
26
  switchToDesktopPreview: () => {
18
- window.StripoEditorApi.versionHistoryApi.switchToDesktopPreview();
27
+ o((e) => e.switchToDesktopPreview());
19
28
  },
20
29
  switchToMobilePreview: () => {
21
- window.StripoEditorApi.versionHistoryApi.switchToMobilePreview();
30
+ o((e) => e.switchToMobilePreview());
22
31
  },
23
32
  previewVersion: (e) => {
24
- window.StripoEditorApi.versionHistoryApi.previewVersion(e, (o) => {
25
- const r = o instanceof Error ? o.message : String(o);
26
- s({
33
+ o((r) => r.previewVersion(e, (s) => {
34
+ const c = s instanceof Error ? s.message : String(s);
35
+ i({
27
36
  type: t.Error,
28
- message: `Error compiling email: ${r}`
37
+ message: `Error compiling email: ${c}`
29
38
  });
30
- });
39
+ }));
31
40
  },
32
41
  restoreVersion: (e) => {
33
- window.StripoEditorApi.versionHistoryApi.restoreVersion(
42
+ o((r) => r.restoreVersion(
34
43
  e,
35
44
  () => {
36
- s({
45
+ i({
37
46
  type: t.Success,
38
47
  message: "Your version has been restored successfully."
39
48
  });
40
49
  },
41
- (o) => {
42
- const r = o instanceof Error ? o.message : String(o);
43
- s({
50
+ (s) => {
51
+ const c = s instanceof Error ? s.message : String(s);
52
+ i({
44
53
  type: t.Error,
45
- message: `Error compiling email: ${r}`
54
+ message: `Error compiling email: ${c}`
46
55
  });
47
56
  }
48
- );
57
+ ));
49
58
  }
50
59
  };
51
60
  };
52
61
  export {
53
- S as useVersionHistoryApi
62
+ d as useVersionHistoryApi
54
63
  };
@@ -1,24 +1,27 @@
1
- import { ToasterTypeOptions as c } from "../../enums/toaster.js";
2
- import { COUPON_PLACEHOLDER_DEFAULT as i, COUPON_PLACEHOLDER_LIQUID as l } from "../../extensions/Blocks/CouponBlock/template.js";
3
- import { useToaster as m } from "../useToaster.js";
4
- import { useTranslations as p } from "../useTranslations.js";
5
- const u = /* @__PURE__ */ new Set([
6
- i,
7
- l
8
- ]), A = () => {
9
- const { showToaster: t } = m(), r = p();
10
- return { validateCouponBlockTags: (e) => {
11
- const n = new DOMParser().parseFromString(e, "text/html");
12
- return Array.from(n.querySelectorAll(".coupon-block")).find((s) => {
13
- var o;
14
- const a = ((o = s.textContent) == null ? void 0 : o.trim()) ?? "";
15
- return !u.has(a);
16
- }) ? (t({
17
- type: c.Warning,
18
- message: r("newsletter.coupon-tag-modified")
19
- }), !1) : !0;
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
- A as useCouponBlockValidator
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 i } from "../../enums/toaster.js";
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 l, DATA_ATTRIBUTES as a } from "../../extensions/Blocks/Unsubscribe/utils/constants.js";
4
- import { useToaster as E } from "../useToaster.js";
5
- import { useTranslations as m } from "../useTranslations.js";
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", b = "unsubscription-preference.select-page-to-continue", P = () => {
16
- const { showToaster: c } = E(), p = m();
17
- return { validateUnsubscribeBlockUniqueness: (n) => {
18
- const o = new DOMParser().parseFromString(n, "text/html"), r = /* @__PURE__ */ new Map();
19
- o.querySelectorAll(l).forEach((e) => {
20
- const s = Number(e.getAttribute(a.PAGE_TYPE));
21
- r.set(s, (r.get(s) ?? 0) + 1);
22
- });
23
- const t = T.filter((e) => (r.get(e.pageType) ?? 0) > 1).map((e) => e.messageKey);
24
- return t.length ? (c({
25
- type: i.Error,
26
- message: p(t.length > 1 ? g : t[0])
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: (n) => {
29
- const o = new DOMParser().parseFromString(n, "text/html");
30
- return Array.from(o.querySelectorAll(l)).some((t) => {
31
- const e = t.getAttribute(a.PAGE_TYPE), s = t.getAttribute(a.PAGE_LIST);
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
- P as useUnsubscribeBlockValidator
44
+ E as EMPTY_BLOCK_KEY,
45
+ b as countUnsubBlocksWithoutPage,
46
+ m as findDuplicateUnsubPageTypes,
47
+ y as useUnsubscribeBlockValidator
41
48
  };