@useinsider/guido 3.16.0-beta.ca26c4e → 3.16.0-beta.efbb91f
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/components/Guido.vue.js +8 -8
- package/dist/components/Guido.vue2.js +78 -76
- 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 +74 -43
- package/dist/components/organisms/header/LeftSlot.vue.js +5 -5
- package/dist/components/organisms/header/LeftSlot.vue2.js +45 -23
- package/dist/components/organisms/validation/ValidationErrorDrawer.vue.js +20 -0
- package/dist/components/organisms/validation/ValidationErrorDrawer.vue2.js +61 -0
- package/dist/components/wrappers/WpDrawer.vue.js +9 -7
- package/dist/components/wrappers/WpDrawer.vue2.js +1 -1
- package/dist/composables/useHtmlValidator.js +1 -0
- package/dist/composables/useSave.js +84 -41
- package/dist/composables/useSaveValidation.js +276 -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/migrator/itemsBlockMigrator.js +1 -1
- package/dist/enums/recommendation.js +17 -17
- package/dist/enums/save-validation.js +4 -0
- package/dist/extensions/Blocks/Items/enums/productEnums.js +45 -45
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +31 -24
- package/dist/guido.css +1 -1
- 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/useHtmlValidator.d.ts +14 -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 +5 -0
- package/dist/src/stores/save-validation.d.ts +22 -0
- package/dist/src/utils/templatePreparation.d.ts +30 -0
- package/dist/stores/config.js +13 -6
- package/dist/stores/save-validation.js +30 -0
- package/dist/utils/templatePreparation.js +28 -25
- package/package.json +1 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { defineComponent as S, ref as v, computed as a } from "vue";
|
|
2
|
+
import g from "../../wrappers/WpDrawer.vue.js";
|
|
3
|
+
import { useBack as h } from "../../../composables/useGuidoActions.js";
|
|
4
|
+
import { useSave as _ } from "../../../composables/useSave.js";
|
|
5
|
+
import { useTranslations as b } from "../../../composables/useTranslations.js";
|
|
6
|
+
import { useConfigStore as w } from "../../../stores/config.js";
|
|
7
|
+
import { useEditorStore as B } from "../../../stores/editor.js";
|
|
8
|
+
import { useSaveValidationStore as T } from "../../../stores/save-validation.js";
|
|
9
|
+
import { InIcons as x } from "@useinsider/design-system-vue";
|
|
10
|
+
const L = /* @__PURE__ */ S({
|
|
11
|
+
__name: "ValidationErrorDrawer",
|
|
12
|
+
setup(C) {
|
|
13
|
+
const o = b(), t = T(), n = B(), s = w(), { saveWithErrors: i } = _(), l = h(), r = v(!1), d = a(() => `${o("email-editor.validation-errors")} (${t.errorCount})`), m = a(() => {
|
|
14
|
+
const e = {
|
|
15
|
+
primaryButton: {
|
|
16
|
+
styling: "solid",
|
|
17
|
+
type: "primary",
|
|
18
|
+
labelText: o("email-editor.update-design")
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return t.intent === "back" ? e.secondaryButton = {
|
|
22
|
+
styling: "solid",
|
|
23
|
+
type: "subtle-primary",
|
|
24
|
+
labelText: o("email-editor.leave-without-saving")
|
|
25
|
+
} : !s.isTransactional && t.intent !== "test" && (e.secondaryButton = {
|
|
26
|
+
styling: "solid",
|
|
27
|
+
type: "subtle-primary",
|
|
28
|
+
labelText: o("email-editor.save-and-continue"),
|
|
29
|
+
loadingStatus: r.value
|
|
30
|
+
}), e;
|
|
31
|
+
}), p = a(() => t.errors.map((e) => {
|
|
32
|
+
const y = e.detail ? ` (${e.detail})` : "";
|
|
33
|
+
return `${e.message}${y}`;
|
|
34
|
+
})), f = () => {
|
|
35
|
+
t.isDrawerOpen && t.close();
|
|
36
|
+
}, c = async () => {
|
|
37
|
+
if (!r.value) {
|
|
38
|
+
r.value = !0, n.loadingStatus = !0;
|
|
39
|
+
try {
|
|
40
|
+
await i() ? t.close() : n.loadingStatus = !1;
|
|
41
|
+
} catch {
|
|
42
|
+
n.loadingStatus = !1;
|
|
43
|
+
} finally {
|
|
44
|
+
r.value = !1;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}, u = () => {
|
|
48
|
+
t.close(), l();
|
|
49
|
+
};
|
|
50
|
+
return { __sfc: !0, trans: o, store: t, editorStore: n, configStore: s, saveWithErrors: i, handleBack: l, isSaving: r, titleText: d, footerButtonGroupOptions: m, rows: p, handleClose: f, handleSaveAndContinue: c, handleDiscardAndLeave: u, handleSecondary: () => {
|
|
51
|
+
if (t.intent === "back") {
|
|
52
|
+
u();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
c();
|
|
56
|
+
}, WpDrawer: g, InIcons: x };
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
export {
|
|
60
|
+
L as default
|
|
61
|
+
};
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import r from "./WpDrawer.vue2.js";
|
|
2
2
|
import s from "../../_virtual/_plugin-vue2_normalizer.js";
|
|
3
3
|
var u = function() {
|
|
4
|
-
var t = this,
|
|
5
|
-
return
|
|
4
|
+
var t = this, o = t._self._c, e = t._self._setupProxy;
|
|
5
|
+
return o(e.InDrawer, { class: t.className, attrs: { id: t.id, "footer-status": "", "close-on-outside-click": t.closeOnOutsideClick, "description-status": t.descriptionStatus, "description-text": t.descriptionText, "footer-button-group-options": t.footerButtonGroupOptions, size: t.size, status: t.status, "title-text": t.titleText }, on: { cancelOrBackButtonEvent: function(n) {
|
|
6
6
|
return e.emit("cancelOrBackButtonEvent");
|
|
7
|
-
}, onCloseEvent: function(
|
|
7
|
+
}, onCloseEvent: function(n) {
|
|
8
8
|
return e.emit("onCloseEvent");
|
|
9
|
-
}, primaryButtonEvent: function(
|
|
9
|
+
}, primaryButtonEvent: function(n) {
|
|
10
10
|
return e.emit("primaryButtonEvent");
|
|
11
|
+
}, secondaryButtonEvent: function(n) {
|
|
12
|
+
return e.emit("secondaryButtonEvent");
|
|
11
13
|
} }, scopedSlots: t._u([t.$slots.headerBottomSlot ? { key: "headerBottomSlot", fn: function() {
|
|
12
14
|
return [t._t("headerBottomSlot")];
|
|
13
15
|
}, proxy: !0 } : null, { key: "contentSlot", fn: function() {
|
|
14
|
-
return [
|
|
16
|
+
return [o("div", [t._t("default")], 2)];
|
|
15
17
|
}, proxy: !0 }], null, !0) });
|
|
16
18
|
}, i = [], c = /* @__PURE__ */ s(
|
|
17
19
|
r,
|
|
@@ -21,7 +23,7 @@ var u = function() {
|
|
|
21
23
|
null,
|
|
22
24
|
null
|
|
23
25
|
);
|
|
24
|
-
const
|
|
26
|
+
const p = c.exports;
|
|
25
27
|
export {
|
|
26
|
-
|
|
28
|
+
p as default
|
|
27
29
|
};
|
|
@@ -13,7 +13,7 @@ const r = /* @__PURE__ */ e({
|
|
|
13
13
|
status: { type: Boolean },
|
|
14
14
|
titleText: null
|
|
15
15
|
},
|
|
16
|
-
emits: ["cancelOrBackButtonEvent", "onCloseEvent", "primaryButtonEvent"],
|
|
16
|
+
emits: ["cancelOrBackButtonEvent", "onCloseEvent", "primaryButtonEvent", "secondaryButtonEvent"],
|
|
17
17
|
setup(n, { emit: t }) {
|
|
18
18
|
return { __sfc: !0, emit: t, InDrawer: o };
|
|
19
19
|
}
|
|
@@ -1,51 +1,94 @@
|
|
|
1
|
-
import { useActionsApi as
|
|
2
|
-
import { useConfig as
|
|
3
|
-
import { useSaveStart as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { useActionsApi as h } from "./useActionsApi.js";
|
|
2
|
+
import { useConfig as L } from "./useConfig.js";
|
|
3
|
+
import { useSaveStart as A, useSaveComplete as q } from "./useGuidoActions.js";
|
|
4
|
+
import { useSaveValidation as M } from "./useSaveValidation.js";
|
|
5
|
+
import { useSaveValidationRollout as R } from "./useSaveValidationRollout.js";
|
|
6
|
+
import { useSyncModuleExtractor as O } from "./useSyncModuleExtractor.js";
|
|
7
|
+
import { ToasterTypeOptions as W } from "../enums/toaster.js";
|
|
6
8
|
import { useStripoApi as D } from "../services/stripoApi.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
import { useConfigStore as F } from "../stores/config.js";
|
|
10
|
+
import { useDynamicContentStore as j } from "../stores/dynamic-content.js";
|
|
11
|
+
import { useSaveValidationStore as z } from "../stores/save-validation.js";
|
|
12
|
+
import { useTemplatePreparation as G, getHtmlReferencedUnsubscribePages as I } from "../utils/templatePreparation.js";
|
|
13
|
+
import { useAllowlist as J } from "./useAllowlist.js";
|
|
14
|
+
import { useHtmlValidator as K } from "./useHtmlValidator.js";
|
|
15
|
+
import { useToaster as N } from "./useToaster.js";
|
|
16
|
+
import { useCouponBlockValidator as Q } from "./validators/useCouponBlockValidator.js";
|
|
17
|
+
import { useLiquidValidator as X } from "./validators/useLiquidValidator.js";
|
|
18
|
+
import { useUnsubscribeBlockValidator as Y } from "./validators/useUnsubscribeBlockValidator.js";
|
|
19
|
+
const bt = () => {
|
|
20
|
+
const n = A(), d = q(), { validateHtml: u } = K(), { validateLiquidSyntax: f } = X(), { validateCouponBlockTags: p } = Q(), { validateUnsubscribeBlockUniqueness: v, validateUnsubscribeBlockHasTemplate: y } = Y(), { callbacks: a, isFeatureEnabled: c } = L(), { extractSyncModuleData: S } = O(), { setSyncModuleUnsubscriptionPages: b } = D(), { editorSave: g, getTemplateData: w } = h(), { showToaster: H } = N(), { getBlockedDomains: V, resolveToast: C } = J(), { prepareTemplateDetails: m } = G(), { collectSaveValidationErrors: E } = M(), { isEnabled: x } = R(), k = z(), T = j(), B = F(), r = async (t, e, o) => {
|
|
21
|
+
if (!c("allowlistEnabled"))
|
|
22
|
+
return !1;
|
|
23
|
+
const i = await V(t, e);
|
|
24
|
+
if (!i.length)
|
|
25
|
+
return !1;
|
|
26
|
+
if (!o) {
|
|
27
|
+
const s = await C(i);
|
|
28
|
+
s != null && s.message && H({
|
|
29
|
+
type: W.Warning,
|
|
30
|
+
message: s.message,
|
|
31
|
+
actionButton: s.actionButton
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return !0;
|
|
35
|
+
}, P = async (t) => !p(t.compiledHtml) || !v(t.compiledHtml) || !y(t.compiledHtml) ? !1 : c("liquidSyntax") ? f(t.compiledHtml) : u(t.compiledHtml, t.dynamicContentList, !0), l = async (t, e) => {
|
|
36
|
+
if (!await g())
|
|
21
37
|
return;
|
|
22
|
-
|
|
23
|
-
|
|
38
|
+
const { unsubscribePayload: i, stripoModules: s } = S(t.rawHtml);
|
|
39
|
+
if (await b(i), t.modules = s, !e.suppress) {
|
|
40
|
+
const U = e.blankCompiled ? { compiledHtml: "", ampHtml: "" } : {};
|
|
41
|
+
d({ ...t, ...U, silent: e.silent });
|
|
42
|
+
}
|
|
43
|
+
return t;
|
|
44
|
+
};
|
|
45
|
+
return { save: async (t = !1, e = !1) => {
|
|
46
|
+
var i;
|
|
47
|
+
n();
|
|
48
|
+
const o = await m();
|
|
49
|
+
if (x.value && !t && !e) {
|
|
50
|
+
const s = await E(
|
|
51
|
+
o.compiledHtml,
|
|
52
|
+
o.dynamicContentList
|
|
53
|
+
);
|
|
54
|
+
if (s.length) {
|
|
55
|
+
k.open(s, "save");
|
|
24
56
|
return;
|
|
25
|
-
|
|
57
|
+
}
|
|
58
|
+
} else if (!await P(o))
|
|
26
59
|
return;
|
|
27
|
-
if ((
|
|
60
|
+
if (!((i = a.value) != null && i.externalValidation && !await a.value.externalValidation(o)) && !await r(o.compiledHtml, o.css, e))
|
|
61
|
+
return l(o, { silent: e, suppress: t });
|
|
62
|
+
}, saveWithErrors: async () => {
|
|
63
|
+
var e;
|
|
64
|
+
if (B.isTransactional)
|
|
28
65
|
return;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
actionButton: o.actionButton
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
if (!await S())
|
|
66
|
+
n();
|
|
67
|
+
const t = await m();
|
|
68
|
+
if (!((e = a.value) != null && e.externalValidation && !await a.value.externalValidation(t)) && !await r(t.compiledHtml, t.css, !1))
|
|
69
|
+
return l(t, { silent: !1, blankCompiled: !0 });
|
|
70
|
+
}, saveRawOnly: async () => {
|
|
71
|
+
n();
|
|
72
|
+
const { html: t, css: e } = await w();
|
|
73
|
+
if (await r(t, e, !0))
|
|
44
74
|
return;
|
|
45
|
-
const
|
|
46
|
-
|
|
75
|
+
const o = I(t), i = {
|
|
76
|
+
dynamicContentList: T.getSelectedDynamicContentList,
|
|
77
|
+
compiledHtml: "",
|
|
78
|
+
rawHtml: t,
|
|
79
|
+
css: e,
|
|
80
|
+
ampHtml: "",
|
|
81
|
+
ampErrors: [],
|
|
82
|
+
modules: [],
|
|
83
|
+
recommendation: { campaignUrls: {}, configs: {} },
|
|
84
|
+
unsubscribe: {
|
|
85
|
+
status: o.length > 0,
|
|
86
|
+
config: o
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
return l(i, { silent: !0 });
|
|
47
90
|
} };
|
|
48
91
|
};
|
|
49
92
|
export {
|
|
50
|
-
|
|
93
|
+
bt as useSave
|
|
51
94
|
};
|
|
@@ -0,0 +1,276 @@
|
|
|
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, findInvalidCustomFields as J } from "./useHtmlValidator.js";
|
|
19
|
+
import { useHttp as tt } from "./useHttp.js";
|
|
20
|
+
import { useTranslations as et } from "./useTranslations.js";
|
|
21
|
+
import { findInvalidCouponBlocks as nt, COUPON_TAG_MODIFIED_KEY as it } from "./validators/useCouponBlockValidator.js";
|
|
22
|
+
import { findDuplicateUnsubPageTypes as ot, countUnsubBlocksWithoutPage as rt, EMPTY_BLOCK_KEY as st } from "./validators/useUnsubscribeBlockValidator.js";
|
|
23
|
+
const at = "newsletter.html-content-is-empty", ct = "custom-fields.missing-closing-braces", lt = "custom-fields.missing-opening-braces", I = "custom-fields.invalid-custom-fields", ut = "newsletter.display-conditions-invalid-syntax", mt = "custom-conditions.wrong-equality-operators", dt = "custom-conditions.missing-if-endif-tag", pt = "custom-conditions.no-space-after-braces", gt = "custom-conditions.no-braces-inside-if-tag", ft = "newsletter.fill-all-necessary-fields", yt = "newsletter.invalid-image-type", Et = "unsubscribe-templates.select-checkbox-groups", It = "unsubscribe-templates.select-radio-button-groups", St = "newsletter.invalid-url-link-for-toaster", F = "journey-builder.liquid-validation-failed", Ct = "/newsletter/template-library/check-template-html-body", _t = /src="[^"]*\.(svg|pst)"/gm, L = /({%(.*?)%})/g, ht = ["if", "endif", "else", "elif", "now"], kt = (e) => !ht.includes(e.toLowerCase()), Tt = (e) => ["if", "endif"].includes(e.toLowerCase());
|
|
24
|
+
function Ft(e) {
|
|
25
|
+
return nt(e).map((i) => ({
|
|
26
|
+
rule: o.CouponTagModified,
|
|
27
|
+
type: r.Warning,
|
|
28
|
+
key: it,
|
|
29
|
+
detail: i
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
function Ot(e) {
|
|
33
|
+
return ot(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: rt(e) }, () => ({
|
|
41
|
+
rule: o.UnsubBlockMissingTemplate,
|
|
42
|
+
type: r.Warning,
|
|
43
|
+
key: st
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
function Nt(e, i) {
|
|
47
|
+
const n = e.match(L);
|
|
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
|
+
kt(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 Rt(e) {
|
|
65
|
+
return e.length > 0 ? [] : [{ rule: o.EmptyHtml, type: r.Warning, key: at }];
|
|
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: ct
|
|
73
|
+
}] : i < n ? [{
|
|
74
|
+
rule: o.MismatchedBraces,
|
|
75
|
+
type: r.Warning,
|
|
76
|
+
key: lt
|
|
77
|
+
}] : [];
|
|
78
|
+
}
|
|
79
|
+
function bt(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 Dt(e, i, n, a) {
|
|
88
|
+
const u = [...e.matchAll(/recommendation-id="(\d+)"/g)].map((s) => s[1]);
|
|
89
|
+
return J(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 vt(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: ut,
|
|
104
|
+
detail: u
|
|
105
|
+
}), s && s.forEach((g) => {
|
|
106
|
+
g.trim() === "=" && a.push({
|
|
107
|
+
rule: o.WrongEqualityOperator,
|
|
108
|
+
type: r.Error,
|
|
109
|
+
key: mt
|
|
110
|
+
}), (g.match(/^[a-zA-Z]*$/g) ?? []).forEach((f) => {
|
|
111
|
+
Tt(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: dt
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return a;
|
|
123
|
+
}
|
|
124
|
+
function Kt(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: pt
|
|
130
|
+
}];
|
|
131
|
+
}
|
|
132
|
+
function wt(e) {
|
|
133
|
+
return (e.match(L) || []).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: gt
|
|
137
|
+
}];
|
|
138
|
+
}
|
|
139
|
+
function Bt(e) {
|
|
140
|
+
return (e.match(_t) ?? []).map((i) => ({
|
|
141
|
+
rule: o.InvalidImageType,
|
|
142
|
+
type: r.Error,
|
|
143
|
+
key: yt,
|
|
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 se = () => {
|
|
155
|
+
const { config: e, isFeatureEnabled: i } = z(), n = et(), { post: a } = tt(), { getCompiledEmail: u, getTemplateData: s } = j(), { compileHtml: m } = $(), { hydrateRecommendationStore: y } = X(), g = H(), f = V(), E = W(), N = q(), R = (t) => ({
|
|
156
|
+
rule: t.rule,
|
|
157
|
+
type: t.type,
|
|
158
|
+
detail: t.detail,
|
|
159
|
+
message: "key" in t ? n(t.key) : t.message
|
|
160
|
+
}), A = 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
|
+
}, b = async (t) => {
|
|
170
|
+
try {
|
|
171
|
+
const l = await a(Ct, { html: T(t) }), { status: c, message: d } = l.data, p = [];
|
|
172
|
+
return c || p.push({
|
|
173
|
+
rule: o.InvalidLinks,
|
|
174
|
+
type: r.Error,
|
|
175
|
+
...c === void 0 ? { message: d } : { key: St }
|
|
176
|
+
}), d === n(k) && p.push({
|
|
177
|
+
rule: o.LinkCheckInProgress,
|
|
178
|
+
type: r.Error,
|
|
179
|
+
key: k
|
|
180
|
+
}), p;
|
|
181
|
+
} catch (l) {
|
|
182
|
+
return console.warn("Link-check collector failed; skipping the link rule.", l), [];
|
|
183
|
+
}
|
|
184
|
+
}, D = async (t) => {
|
|
185
|
+
try {
|
|
186
|
+
const l = await a("/newsletter/contents/validate-syntax", [{
|
|
187
|
+
identifier: "default",
|
|
188
|
+
syntax: "liquid",
|
|
189
|
+
contents: {
|
|
190
|
+
subject: null,
|
|
191
|
+
preheader: null,
|
|
192
|
+
html: T(t),
|
|
193
|
+
ampHtml: null
|
|
194
|
+
}
|
|
195
|
+
}]);
|
|
196
|
+
if (!Array.isArray(l.data)) {
|
|
197
|
+
const d = l.data;
|
|
198
|
+
return [{
|
|
199
|
+
rule: o.LiquidSyntax,
|
|
200
|
+
type: r.Warning,
|
|
201
|
+
message: d.message ?? n(F)
|
|
202
|
+
}];
|
|
203
|
+
}
|
|
204
|
+
const [c] = l.data;
|
|
205
|
+
return Object.values((c == null ? void 0 : c.errors) ?? {}).map((d) => ({
|
|
206
|
+
rule: o.LiquidSyntax,
|
|
207
|
+
type: r.Warning,
|
|
208
|
+
message: d.replace(/^line \d+:\s*/, "")
|
|
209
|
+
}));
|
|
210
|
+
} catch {
|
|
211
|
+
return [{
|
|
212
|
+
rule: o.LiquidSyntax,
|
|
213
|
+
type: r.Error,
|
|
214
|
+
message: n(F)
|
|
215
|
+
}];
|
|
216
|
+
}
|
|
217
|
+
}, v = () => {
|
|
218
|
+
const t = E.invalidBlockIds().map((c) => ({
|
|
219
|
+
rule: o.RecommendationRequiredFields,
|
|
220
|
+
type: r.Error,
|
|
221
|
+
key: G,
|
|
222
|
+
detail: c
|
|
223
|
+
})), l = (f.recommendationConfigs ?? []).filter((c) => c.filters.some((d) => d.value === "")).map(() => ({
|
|
224
|
+
rule: o.RecommendationFilters,
|
|
225
|
+
type: r.Error,
|
|
226
|
+
key: ft
|
|
227
|
+
}));
|
|
228
|
+
return [...t, ...l];
|
|
229
|
+
}, K = async (t, l) => {
|
|
230
|
+
var _, h;
|
|
231
|
+
const c = [
|
|
232
|
+
...l.map((w) => w.value),
|
|
233
|
+
...M,
|
|
234
|
+
...((h = (_ = e.value) == null ? void 0 : _.template) == null ? void 0 : h.customFieldAttributes) ?? []
|
|
235
|
+
], d = B(t), p = await A(d), { isTransactional: C } = N;
|
|
236
|
+
return [
|
|
237
|
+
...await b(t),
|
|
238
|
+
...C ? [] : Nt(t, c),
|
|
239
|
+
...Rt(t),
|
|
240
|
+
...At(t),
|
|
241
|
+
...bt(t),
|
|
242
|
+
...C ? [] : Dt(t, c, d, p),
|
|
243
|
+
...vt(t),
|
|
244
|
+
...Kt(t),
|
|
245
|
+
...wt(t),
|
|
246
|
+
...v(),
|
|
247
|
+
...Bt(t),
|
|
248
|
+
...O(
|
|
249
|
+
t,
|
|
250
|
+
U,
|
|
251
|
+
o.CheckboxUnsubGroup,
|
|
252
|
+
Et
|
|
253
|
+
),
|
|
254
|
+
...O(
|
|
255
|
+
t,
|
|
256
|
+
P,
|
|
257
|
+
o.RadioButtonUnsubGroup,
|
|
258
|
+
It
|
|
259
|
+
)
|
|
260
|
+
];
|
|
261
|
+
}, S = async (t, l) => [
|
|
262
|
+
...Ft(t),
|
|
263
|
+
...Ot(t),
|
|
264
|
+
...Lt(t),
|
|
265
|
+
...i("liquidSyntax") ? await D(t) : await K(t, l)
|
|
266
|
+
].map(R);
|
|
267
|
+
return { collectSaveValidationErrors: S, validateCurrentTemplate: async () => {
|
|
268
|
+
const { html: t } = await s();
|
|
269
|
+
await y(t);
|
|
270
|
+
const { html: l } = await u({ minimize: !0, resetDataSavedFlag: !1 }), { compiledHtml: c } = m(l);
|
|
271
|
+
return S(c, g.getSelectedDynamicContentList);
|
|
272
|
+
} };
|
|
273
|
+
};
|
|
274
|
+
export {
|
|
275
|
+
se as useSaveValidation
|
|
276
|
+
};
|
|
@@ -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
|
};
|