@useinsider/guido 3.7.0-beta.fc2a9d1 → 3.7.1-beta.05a2232

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 (30) hide show
  1. package/dist/components/organisms/unsubscribe/UnsubscribePageSelection.vue.js +2 -2
  2. package/dist/components/organisms/unsubscribe/UnsubscribePageSelection.vue2.js +24 -22
  3. package/dist/composables/useHtmlValidator.js +79 -73
  4. package/dist/composables/useSave.js +17 -16
  5. package/dist/composables/validators/useUnsubscribeBlockValidator.js +32 -0
  6. package/dist/enums/html-validator.js +13 -5
  7. package/dist/enums/toaster.js +1 -1
  8. package/dist/extensions/Blocks/Recommendation/block.js +35 -16
  9. package/dist/extensions/Blocks/Recommendation/useRecommendationBlockWarning.js +16 -0
  10. package/dist/extensions/Blocks/Recommendation/utils/recommendationBlockCount.js +9 -0
  11. package/dist/extensions/Blocks/Unsubscribe/block.js +123 -73
  12. package/dist/extensions/Blocks/Unsubscribe/control.js +33 -26
  13. package/dist/extensions/Blocks/Unsubscribe/template.js +4 -4
  14. package/dist/extensions/Blocks/Unsubscribe/utils/constants.js +4 -3
  15. package/dist/guido.css +1 -1
  16. package/dist/src/composables/validators/useUnsubscribeBlockValidator.d.ts +3 -0
  17. package/dist/src/composables/validators/useUnsubscribeBlockValidator.test.d.ts +1 -0
  18. package/dist/src/enums/html-validator.d.ts +4 -0
  19. package/dist/src/enums/toaster.d.ts +2 -1
  20. package/dist/src/extensions/Blocks/Recommendation/block.d.ts +13 -0
  21. package/dist/src/extensions/Blocks/Recommendation/block.test.d.ts +1 -0
  22. package/dist/src/extensions/Blocks/Recommendation/useRecommendationBlockWarning.d.ts +12 -0
  23. package/dist/src/extensions/Blocks/Recommendation/utils/recommendationBlockCount.d.ts +28 -0
  24. package/dist/src/extensions/Blocks/Recommendation/utils/recommendationBlockCount.test.d.ts +1 -0
  25. package/dist/src/extensions/Blocks/Unsubscribe/block.d.ts +9 -0
  26. package/dist/src/extensions/Blocks/Unsubscribe/control.d.ts +1 -0
  27. package/dist/src/extensions/Blocks/Unsubscribe/utils/constants.d.ts +1 -0
  28. package/dist/static/styles/components/base-input.css.js +5 -0
  29. package/dist/stores/autosave.js +6 -6
  30. package/package.json +1 -1
@@ -3,7 +3,7 @@ import a from "./UnsubscribePageSelection.vue2.js";
3
3
  import n from "../../../_virtual/_plugin-vue2_normalizer.js";
4
4
  var o = function() {
5
5
  var r = this, e = r._self._c, t = r._self._setupProxy;
6
- return e(t.WpDrawer, { attrs: { id: "unsubscribe-modal", "description-status": "", size: "large", "footer-button-group-options": t.footerButtonGroupOptions, status: t.unsubscribeStore.pageSelectionDrawerStatus, "title-text": t.trans("newsletter.select-a-template") }, on: { cancelOrBackButtonEvent: t.handleBack, onCloseEvent: t.closeModal, primaryButtonEvent: t.handleSave }, scopedSlots: r._u([{ key: "headerBottomSlot", fn: function() {
6
+ return e(t.WpDrawer, { attrs: { id: "unsubscribe-modal", "description-status": "", size: "large", "footer-button-group-options": t.footerButtonGroupOptions, status: t.unsubscribeStore.pageSelectionDrawerStatus, "title-text": t.trans("newsletter.select-a-template") }, on: { cancelOrBackButtonEvent: t.handleBack, onCloseEvent: t.handleClose, primaryButtonEvent: t.handleSave }, scopedSlots: r._u([{ key: "headerBottomSlot", fn: function() {
7
7
  return [e(t.UnsubscribeBreadcrumb, { staticClass: "px-5 py-3" })];
8
8
  }, proxy: !0 }]) }, [e("div", { staticClass: "d-g templates-wrapper" }, r._l(t.unsubscribeStore.getTemplatesByActiveType, function(s) {
9
9
  return e("div", { key: s.id, staticClass: "template-wrapper", on: { click: function(u) {
@@ -16,7 +16,7 @@ var o = function() {
16
16
  i,
17
17
  !1,
18
18
  null,
19
- "df672485"
19
+ "f6a8cb4c"
20
20
  );
21
21
  const _ = c.exports;
22
22
  export {
@@ -1,15 +1,15 @@
1
- import { defineComponent as g, ref as y, computed as n, watch as S } from "vue";
2
- import T from "../../wrappers/WpDrawer.vue.js";
3
- import { useToaster as v } from "../../../composables/useToaster.js";
1
+ import { defineComponent as y, ref as S, computed as a, watch as T } from "vue";
2
+ import v from "../../wrappers/WpDrawer.vue.js";
3
+ import { useToaster as C } from "../../../composables/useToaster.js";
4
4
  import { useTranslations as B } from "../../../composables/useTranslations.js";
5
- import { ToasterTypeOptions as C } from "../../../enums/toaster.js";
6
- import { useUnsubscribeStore as w } from "../../../stores/unsubscribe.js";
7
- import { InContainer as h } from "@useinsider/design-system-vue";
8
- import U from "./UnsubscribeBreadcrumb.vue.js";
9
- const F = /* @__PURE__ */ g({
5
+ import { ToasterTypeOptions as w } from "../../../enums/toaster.js";
6
+ import { useUnsubscribeStore as h } from "../../../stores/unsubscribe.js";
7
+ import { InContainer as U } from "@useinsider/design-system-vue";
8
+ import P from "./UnsubscribeBreadcrumb.vue.js";
9
+ const L = /* @__PURE__ */ y({
10
10
  __name: "UnsubscribePageSelection",
11
- setup(P) {
12
- const s = B(), e = w(), { showToaster: a } = v(), o = y(!1), c = n(() => e.isActiveTypeLastInCollection ? o.value ? s("unsubscription-preference.applying-changes") : s("statistics.apply") : s("products.select-and-continue")), i = n(() => e.pageSelectionUpdateStatus && e.isActiveTypeFirstInCollection ? s("products.cancel") : s("newsletter.back")), u = n(() => ({
11
+ setup(_) {
12
+ const s = B(), e = h(), { showToaster: r } = C(), o = S(!1), c = a(() => e.isActiveTypeLastInCollection ? o.value ? s("unsubscription-preference.applying-changes") : s("statistics.apply") : s("products.select-and-continue")), i = a(() => e.pageSelectionUpdateStatus && e.isActiveTypeFirstInCollection ? s("products.cancel") : s("newsletter.back")), u = a(() => ({
13
13
  primaryButton: {
14
14
  styling: "solid",
15
15
  type: "primary",
@@ -23,42 +23,44 @@ const F = /* @__PURE__ */ g({
23
23
  labelText: i.value,
24
24
  disabledStatus: o.value
25
25
  }
26
- })), p = (t) => e.getSelectedTemplateByActiveType === t ? "bor-w-3 bor-s-s bor-c-7" : "bor-w-1 bor-s-s bor-c-6", r = (t) => {
26
+ })), p = (t) => e.getSelectedTemplateByActiveType === t ? "bor-w-3 bor-s-s bor-c-7" : "bor-w-1 bor-s-s bor-c-6", n = (t) => {
27
27
  e.pageSelectionDrawerStatus = !1, t && setTimeout(() => {
28
28
  t();
29
29
  }, 500);
30
30
  }, d = () => {
31
+ n(), e.pageSelectionUpdateStatus || document.dispatchEvent(new CustomEvent("unsubscribe:cancel"));
32
+ }, m = () => {
31
33
  if (e.isActiveTypeFirstInCollection) {
32
- r(), e.pageSelectionUpdateStatus || (e.typeSelectionDrawerStatus = !0);
34
+ n(), e.pageSelectionUpdateStatus || (e.typeSelectionDrawerStatus = !0);
33
35
  return;
34
36
  }
35
37
  e.setPreviousType();
36
- }, m = () => {
38
+ }, b = () => {
37
39
  if (e.isActiveTypeLastInCollection) {
38
40
  o.value = !0;
39
- const t = e.selectedCollectionType, l = e.getSelectedTemplatesByCollection(t), f = e.getSelectedUnsubscribePagesByCollection(t);
40
- e.removeUnsubscribePages(f), e.addUnsubscribePages(l), document.dispatchEvent(new CustomEvent("unsubscribe:select", {
41
+ const t = e.selectedCollectionType, l = e.getSelectedTemplatesByCollection(t), g = e.getSelectedUnsubscribePagesByCollection(t);
42
+ e.removeUnsubscribePages(g), e.addUnsubscribePages(l), document.dispatchEvent(new CustomEvent("unsubscribe:select", {
41
43
  detail: {
42
44
  collectionType: t,
43
45
  selectedPages: l
44
46
  }
45
- })), r(() => {
46
- o.value = !1, a({
47
- type: C.Success,
47
+ })), n(() => {
48
+ o.value = !1, r({
49
+ type: w.Success,
48
50
  message: s("global-unsubscribe.pages-were-attached")
49
51
  });
50
52
  });
51
53
  return;
52
54
  }
53
55
  e.setNextType();
54
- }, b = (t) => {
56
+ }, f = (t) => {
55
57
  e.setSelectedTemplate(t);
56
58
  };
57
- return S(() => e.pageSelectionDrawerStatus, (t) => {
59
+ return T(() => e.pageSelectionDrawerStatus, (t) => {
58
60
  t && e.pageSelectionUpdateStatus && e.fetchTemplates();
59
- }), { __sfc: !0, trans: s, unsubscribeStore: e, showToaster: a, isApplying: o, getPrimaryButtonText: c, getCancelOrBackButtonText: i, footerButtonGroupOptions: u, getBorderClass: p, closeModal: r, handleBack: d, handleSave: m, selectTemplate: b, WpDrawer: T, InContainer: h, UnsubscribeBreadcrumb: U };
61
+ }), { __sfc: !0, trans: s, unsubscribeStore: e, showToaster: r, isApplying: o, getPrimaryButtonText: c, getCancelOrBackButtonText: i, footerButtonGroupOptions: u, getBorderClass: p, closeModal: n, handleClose: d, handleBack: m, handleSave: b, selectTemplate: f, WpDrawer: v, InContainer: U, UnsubscribeBreadcrumb: P };
60
62
  }
61
63
  });
62
64
  export {
63
- F as default
65
+ L as default
64
66
  };
@@ -1,86 +1,92 @@
1
- import { useConfig as _ } from "./useConfig.js";
2
- import { TemplateTypes as H } from "../enums/defaults.js";
3
- import { DISPLAY_CONDITIONS_REGEX as P, DISPLAY_CONDITIONS_EXCEPTIONS_REGEX as G, CampaignCouldNotBeSavedKey as M, CanNotMakeAnyChangesForRunningKey as $ } from "../enums/html-validator.js";
1
+ import { useConfig as V } from "./useConfig.js";
2
+ import { TemplateTypes as G } from "../enums/defaults.js";
3
+ import { DISPLAY_CONDITIONS_REGEX as H, DISPLAY_CONDITIONS_EXCEPTIONS_REGEX as M, CampaignCouldNotBeSavedKey as X, CanNotMakeAnyChangesForRunningKey as P, DATA_ATTRIBUTE_REGEX as Y, DYNAMIC_CONTENT_TAG_REGEX as $, ALLOWED_DYNAMIC_SYSTEM_TOKENS as q, VALID_DYNAMIC_VARIABLE_REGEX as K } from "../enums/html-validator.js";
4
4
  import { ToasterTypeOptions as c } from "../enums/toaster.js";
5
- import { itemsBlockDynamicVariables as q } from "../extensions/Blocks/Items/enums/productEnums.js";
6
- import { useRecommendationExtensionStore as X } from "../extensions/Blocks/Recommendation/store/recommendation.js";
7
- import { RecommendationRequiredFieldsKey as j } from "../extensions/Blocks/Recommendation/validation/requiredFields.js";
8
- import { useRecommendationStore as K } from "../stores/recommendation.js";
9
- import { base64EncodeWithSpecialChars as z } from "../utils/base64.js";
10
- import { useHttp as U } from "./useHttp.js";
11
- import { useToaster as Y } from "./useToaster.js";
12
- import { useTranslations as Z } from "./useTranslations.js";
13
- const J = /recommendation-id="(\d+)"/g;
14
- function Q(a) {
15
- return [...a.matchAll(J)].map((u) => u[1]);
5
+ import { itemsBlockDynamicVariables as j } from "../extensions/Blocks/Items/enums/productEnums.js";
6
+ import { useRecommendationExtensionStore as U } from "../extensions/Blocks/Recommendation/store/recommendation.js";
7
+ import { RecommendationRequiredFieldsKey as z } from "../extensions/Blocks/Recommendation/validation/requiredFields.js";
8
+ import { useRecommendationStore as Z } from "../stores/recommendation.js";
9
+ import { base64EncodeWithSpecialChars as J } from "../utils/base64.js";
10
+ import { useHttp as Q } from "./useHttp.js";
11
+ import { useToaster as ee } from "./useToaster.js";
12
+ import { useTranslations as te } from "./useTranslations.js";
13
+ const se = /recommendation-id="(\d+)"/g;
14
+ function ne(i) {
15
+ return [...i.matchAll(se)].map((d) => d[1]);
16
16
  }
17
- function ee(a, u) {
18
- return u.some((d) => a.startsWith(`${d}_`));
17
+ function ie(i, d) {
18
+ return d.some((g) => i.startsWith(`${g}_`));
19
19
  }
20
- const ge = () => {
21
- var y, h;
22
- const { showToaster: a } = Y(), { post: u } = U(), { config: d } = _(), r = Z(), g = K(), S = X(), p = ((h = (y = d.value) == null ? void 0 : y.partner) == null ? void 0 : h.messageType) === H.transactional, b = async (e) => {
23
- const t = await u(
20
+ function oe(i) {
21
+ return (i.replace(Y, "$1").match($) ?? []).filter((r) => {
22
+ const u = r.slice(2, -2), f = u.indexOf("|"), p = (f === -1 ? u : u.slice(0, f)).trim();
23
+ return q.includes(p) ? !1 : K.test(p) ? f !== -1 && u.slice(f + 1).trim() === "" : !0;
24
+ });
25
+ }
26
+ const Ce = () => {
27
+ var h, v;
28
+ const { showToaster: i } = ee(), { post: d } = Q(), { config: g } = V(), r = te(), u = Z(), f = U(), p = ((v = (h = g.value) == null ? void 0 : h.partner) == null ? void 0 : v.messageType) === G.transactional, A = async (e) => {
29
+ const t = await d(
24
30
  "/newsletter/template-library/check-template-html-body",
25
- { html: z(e) }
31
+ { html: J(e) }
26
32
  ), { status: n, message: l } = t.data;
27
- return n || a({
33
+ return n || i({
28
34
  type: c.Alert,
29
35
  message: n === void 0 ? l : r("newsletter.invalid-url-link-for-toaster")
30
- }), r(M), l === r($) && a({
36
+ }), r(X), l === r(P) && i({
31
37
  type: c.Alert,
32
38
  message: r("newsletter.already-in-progress")
33
39
  }), n;
34
- }, w = (e) => !["if", "endif", "else", "elif", "now"].includes(e.toLowerCase()), E = (e) => ["if", "endif"].includes(e.toLowerCase()), A = (e, s) => {
40
+ }, S = (e) => !["if", "endif", "else", "elif", "now"].includes(e.toLowerCase()), b = (e) => ["if", "endif"].includes(e.toLowerCase()), I = (e, s) => {
35
41
  const t = e.match(/({%(.*?)%})/g);
36
42
  let n = !0;
37
43
  return t !== null && !p && t.forEach((l) => {
38
44
  const o = l.slice(2, -2).trim().match(/(".*?"|[^"\s]+)(?=\s*|\s*$)/g);
39
45
  if (o && o.length > 0) {
40
- const [i] = o;
41
- w(i) && !s.includes(i) && (a({
46
+ const [a] = o;
47
+ S(a) && !s.includes(a) && (i({
42
48
  type: c.Warning,
43
49
  message: r("custom-fields.invalid-custom-fields")
44
50
  }), n = !1);
45
51
  }
46
52
  }), n;
47
- }, k = async (e, s, t) => {
48
- const n = t ? await b(e) : !0;
49
- return A(e, s) && n;
50
- }, x = (e) => e.length > 0 ? !0 : (a({
53
+ }, T = async (e, s, t) => {
54
+ const n = t ? await A(e) : !0;
55
+ return I(e, s) && n;
56
+ }, w = (e) => e.length > 0 ? !0 : (i({
51
57
  type: c.Warning,
52
58
  message: r("newsletter.html-content-is-empty")
53
- }), !1), I = (e) => {
59
+ }), !1), x = (e) => {
54
60
  const s = (e.match(/{/gm) || []).length, t = (e.match(/}/gm) || []).length;
55
- return s > t && a({
61
+ return s > t && i({
56
62
  type: c.Warning,
57
63
  message: r("custom-fields.missing-closing-braces")
58
- }), s < t && a({
64
+ }), s < t && i({
59
65
  type: c.Warning,
60
66
  message: r("custom-fields.missing-opening-braces")
61
67
  }), s === t;
62
- }, F = (e) => {
63
- const s = e.match(/{{\s*(\w+\s+((\w+\|\w+)|(\w+)))\s*}}/gm) === null;
64
- return s || a({
68
+ }, _ = (e) => {
69
+ const s = oe(e).length === 0;
70
+ return s || i({
65
71
  type: c.Warning,
66
72
  message: r("custom-fields.invalid-custom-fields")
67
73
  }), s;
68
- }, T = (e, s) => {
74
+ }, k = (e, s) => {
69
75
  const t = e.match(/{{([a-zA-Z0-9_\s]*)}}/gm);
70
76
  if (t && !p) {
71
- const n = new Set(s.map((i) => i.toLowerCase())), l = Q(e), o = [];
72
- if (t.forEach((i) => {
73
- const m = i.slice(2, -2).trim().toLowerCase();
74
- (!n.has(m) || m === "") && !ee(m, l) && o.push(m);
77
+ const n = new Set(s.map((a) => a.toLowerCase())), l = ne(e), o = [];
78
+ if (t.forEach((a) => {
79
+ const m = a.slice(2, -2).trim().toLowerCase();
80
+ (!n.has(m) || m === "") && !ie(m, l) && o.push(m);
75
81
  }), o.length > 0) {
76
- const i = `
82
+ const a = `
77
83
  <ul>
78
84
  ${o.map((m) => `<li>${m}</li>`).join("")}
79
85
  </ul>
80
86
  `;
81
- return a({
87
+ return i({
82
88
  type: c.Alert,
83
- message: r("custom-fields.invalid-custom-fields") + i
89
+ message: r("custom-fields.invalid-custom-fields") + a
84
90
  }), !1;
85
91
  }
86
92
  }
@@ -89,78 +95,78 @@ const ge = () => {
89
95
  const s = e.match(/{%(.*?)%}/g), t = [];
90
96
  let n = !0;
91
97
  if (s && s.forEach((l) => {
92
- const o = l.match(P), i = l.match(G), m = (o == null ? void 0 : o.join("")) || "";
93
- (!o || l !== m) && !i && (a({
98
+ const o = l.match(H), a = l.match(M), m = (o == null ? void 0 : o.join("")) || "";
99
+ (!o || l !== m) && !a && (i({
94
100
  type: c.Alert,
95
101
  message: r("newsletter.display-conditions-invalid-syntax")
96
- }), n = !1), o && o.forEach((f) => {
97
- f.trim() === "=" && (a({
102
+ }), n = !1), o && o.forEach((y) => {
103
+ y.trim() === "=" && (i({
98
104
  type: c.Alert,
99
105
  message: r("custom-conditions.wrong-equality-operators")
100
106
  }), n = !1);
101
- const v = f.match(/^[a-zA-Z]*$/g);
102
- v && v.forEach((C) => {
103
- E(C) && t.push(C);
107
+ const C = y.match(/^[a-zA-Z]*$/g);
108
+ C && C.forEach((E) => {
109
+ b(E) && t.push(E);
104
110
  });
105
111
  });
106
112
  }), t.length) {
107
- const l = t.filter((i) => i === "if"), o = t.filter((i) => i === "endif");
108
- l.length !== o.length && (a({
113
+ const l = t.filter((a) => a === "if"), o = t.filter((a) => a === "endif");
114
+ l.length !== o.length && (i({
109
115
  type: c.Alert,
110
116
  message: r("custom-conditions.missing-if-endif-tag")
111
117
  }), n = !1);
112
118
  }
113
119
  return n;
114
- }, B = (e) => {
120
+ }, N = (e) => {
115
121
  const s = (e.match(/{% /gm) || []).length, t = (e.match(/ %}/gm) || []).length, n = s === t;
116
- return n || a({
122
+ return n || i({
117
123
  type: c.Warning,
118
124
  message: r("custom-conditions.no-space-after-braces")
119
125
  }), n;
120
- }, W = (e) => (e.match(/({%(.*?)%})/g) || []).filter((t) => t.includes("if")).map((t) => (t.match(/{{.*}}/gm) || []).length).reduce((t, n) => t + n, 0) > 0 ? (a({
126
+ }, D = (e) => (e.match(/({%(.*?)%})/g) || []).filter((t) => t.includes("if")).map((t) => (t.match(/{{.*}}/gm) || []).length).reduce((t, n) => t + n, 0) > 0 ? (i({
121
127
  type: c.Warning,
122
128
  message: r("custom-conditions.no-braces-inside-if-tag")
123
- }), !1) : !0, N = () => S.hasInvalidBlock() ? (a({
129
+ }), !1) : !0, F = () => f.hasInvalidBlock() ? (i({
124
130
  type: c.Alert,
125
- message: r(j)
126
- }), !1) : !0, O = () => g.recommendationConfigs && Object.values(g.recommendationConfigs).find((s) => s.filters.find((t) => t.value === "")) !== void 0 ? (a({
131
+ message: r(z)
132
+ }), !1) : !0, O = () => u.recommendationConfigs && Object.values(u.recommendationConfigs).find((s) => s.filters.find((t) => t.value === "")) !== void 0 ? (i({
127
133
  type: c.Alert,
128
134
  message: r("newsletter.fill-all-necessary-fields")
129
- }), !1) : !0, D = (e) => {
135
+ }), !1) : !0, B = (e) => {
130
136
  const s = /src="[^"]*\.(svg|pst)"/gm;
131
- return e.match(s) === null ? !0 : (a({
137
+ return e.match(s) === null ? !0 : (i({
132
138
  type: c.Alert,
133
139
  message: r("newsletter.invalid-image-type")
134
140
  }), !1);
135
141
  }, L = (e) => {
136
142
  const n = new DOMParser().parseFromString(e, "text/html").querySelectorAll(".checkbox-block-v2");
137
143
  return Array.from(n).find((o) => {
138
- var i;
139
- return !((i = o.id) != null && i.trim());
140
- }) ? (a({
144
+ var a;
145
+ return !((a = o.id) != null && a.trim());
146
+ }) ? (i({
141
147
  type: c.Alert,
142
148
  message: r("unsubscribe-templates.select-checkbox-groups")
143
149
  }), !1) : !0;
144
- }, V = (e) => {
150
+ }, W = (e) => {
145
151
  const n = new DOMParser().parseFromString(e, "text/html").querySelectorAll(".radio-button-v2");
146
152
  return Array.from(n).find((o) => {
147
- var i;
148
- return !((i = o.id) != null && i.trim());
149
- }) ? (a({
153
+ var a;
154
+ return !((a = o.id) != null && a.trim());
155
+ }) ? (i({
150
156
  type: c.Alert,
151
157
  message: r("unsubscribe-templates.select-radio-button-groups")
152
158
  }), !1) : !0;
153
159
  };
154
160
  return { validateHtml: async (e, s, t = !1) => {
155
- var o, i;
161
+ var o, a;
156
162
  const n = [
157
163
  ...s.map((m) => m.value),
158
- ...q,
159
- ...((i = (o = d.value) == null ? void 0 : o.template) == null ? void 0 : i.customFieldAttributes) ?? []
164
+ ...j,
165
+ ...((a = (o = g.value) == null ? void 0 : o.template) == null ? void 0 : a.customFieldAttributes) ?? []
160
166
  ];
161
- return await k(e, n, t) && x(e) && I(e) && F(e) && T(e, n) && R(e) && B(e) && W(e) && N() && O() && D(e) && L(e) && V(e);
167
+ return await T(e, n, t) && w(e) && x(e) && _(e) && k(e, n) && R(e) && N(e) && D(e) && F() && O() && B(e) && L(e) && W(e);
162
168
  } };
163
169
  };
164
170
  export {
165
- ge as useHtmlValidator
171
+ Ce as useHtmlValidator
166
172
  };
@@ -1,31 +1,32 @@
1
1
  import { useActionsApi as x } from "./useActionsApi.js";
2
2
  import { useConfig as y } from "./useConfig.js";
3
- import { useSaveStart as w, useSaveComplete as C } from "./useGuidoActions.js";
4
- import { useSyncModuleExtractor as E } from "./useSyncModuleExtractor.js";
5
- import { useStripoApi as H } from "../services/stripoApi.js";
6
- import { useTemplatePreparation as b } from "../utils/templatePreparation.js";
7
- import { useHtmlValidator as q } from "./useHtmlValidator.js";
3
+ import { useSaveStart as w, useSaveComplete as H } from "./useGuidoActions.js";
4
+ import { useSyncModuleExtractor as q } from "./useSyncModuleExtractor.js";
5
+ import { useStripoApi as C } from "../services/stripoApi.js";
6
+ import { useTemplatePreparation as E } from "../utils/templatePreparation.js";
7
+ import { useHtmlValidator as k } from "./useHtmlValidator.js";
8
8
  import { useCouponBlockValidator as L } from "./validators/useCouponBlockValidator.js";
9
9
  import { useLiquidValidator as P } from "./validators/useLiquidValidator.js";
10
- const z = () => {
11
- const o = w(), s = C(), { validateHtml: r } = q(), { validateLiquidSyntax: n } = P(), { validateCouponBlockTags: l } = L(), { callbacks: a, isFeatureEnabled: d } = y(), { extractSyncModuleData: u } = E(), { setSyncModuleUnsubscriptionPages: c } = H(), { editorSave: m } = x();
12
- return { save: async (p = !1, f = !1) => {
13
- var i;
10
+ import { useUnsubscribeBlockValidator as B } from "./validators/useUnsubscribeBlockValidator.js";
11
+ const J = () => {
12
+ const o = w(), s = H(), { validateHtml: r } = k(), { validateLiquidSyntax: n } = P(), { validateCouponBlockTags: l } = L(), { validateUnsubscribeBlockUniqueness: d } = B(), { callbacks: i, isFeatureEnabled: u } = y(), { extractSyncModuleData: c } = q(), { setSyncModuleUnsubscriptionPages: m } = C(), { editorSave: p } = x();
13
+ return { save: async (f = !1, v = !1) => {
14
+ var a;
14
15
  o();
15
- const { prepareTemplateDetails: v } = b(), t = await v();
16
- if (!l(t.compiledHtml))
16
+ const { prepareTemplateDetails: S } = E(), t = await S();
17
+ if (!l(t.compiledHtml) || !d(t.compiledHtml))
17
18
  return;
18
- if (d("liquidSyntax")) {
19
+ if (u("liquidSyntax")) {
19
20
  if (!await n(t.compiledHtml))
20
21
  return;
21
22
  } else if (!await r(t.compiledHtml, t.dynamicContentList, !0))
22
23
  return;
23
- if ((i = a.value) != null && i.externalValidation && !await a.value.externalValidation(t) || !await m())
24
+ if ((a = i.value) != null && a.externalValidation && !await i.value.externalValidation(t) || !await p())
24
25
  return;
25
- const { unsubscribePayload: S, stripoModules: V } = u(t.rawHtml);
26
- return await c(S), t.modules = V, p || s({ ...t, silent: f }), t;
26
+ const { unsubscribePayload: V, stripoModules: b } = c(t.rawHtml);
27
+ return await m(V), t.modules = b, f || s({ ...t, silent: v }), t;
27
28
  } };
28
29
  };
29
30
  export {
30
- z as useSave
31
+ J as useSave
31
32
  };
@@ -0,0 +1,32 @@
1
+ import { ToasterTypeOptions as i } from "../../enums/toaster.js";
2
+ import { PAGE_TYPES as n } from "../../enums/unsubscribe.js";
3
+ import { UNSUBSCRIBE_BLOCK_SELECTOR as u, DATA_ATTRIBUTES as l } from "../../extensions/Blocks/Unsubscribe/utils/constants.js";
4
+ import { useToaster as T } from "../useToaster.js";
5
+ import { useTranslations as E } from "../useTranslations.js";
6
+ const m = [
7
+ {
8
+ pageType: n.GLOBAL_UNSUBSCRIBE,
9
+ messageKey: "unsubscription-preference.duplicate-global-unsub"
10
+ },
11
+ {
12
+ pageType: n.SUBSCRIPTION_PREFERENCE_CENTER,
13
+ messageKey: "unsubscription-preference.duplicate-pref-center"
14
+ }
15
+ ], g = "unsubscription-preference.duplicate-both", y = () => {
16
+ const { showToaster: o } = T(), a = E();
17
+ return { validateUnsubscribeBlockUniqueness: (c) => {
18
+ const p = new DOMParser().parseFromString(c, "text/html"), t = /* @__PURE__ */ new Map();
19
+ p.querySelectorAll(u).forEach((e) => {
20
+ const r = Number(e.getAttribute(l.PAGE_TYPE));
21
+ t.set(r, (t.get(r) ?? 0) + 1);
22
+ });
23
+ const s = m.filter((e) => (t.get(e.pageType) ?? 0) > 1).map((e) => e.messageKey);
24
+ return s.length ? (o({
25
+ type: i.Alert,
26
+ message: a(s.length > 1 ? g : s[0])
27
+ }), !1) : !0;
28
+ } };
29
+ };
30
+ export {
31
+ y as useUnsubscribeBlockValidator
32
+ };
@@ -1,7 +1,15 @@
1
- const e = "newsletter.already-in-progress", n = "newsletter.campaign-could-not-be-saved", o = / (==|<=|>=|!=|>|<|in) | (if|elif|endif|else|and|or) |("[\S ]+")|('[\S ]+')|([^”\s\n]+)|(({%)|( %}))/gm, a = /{%( )*now( )(".*")( )*%}/gm;
1
+ const n = "newsletter.already-in-progress", e = "newsletter.campaign-could-not-be-saved", s = / (==|<=|>=|!=|>|<|in) | (if|elif|endif|else|and|or) |("[\S ]+")|('[\S ]+')|([^”\s\n]+)|(({%)|( %}))/gm, o = /{%( )*now( )(".*")( )*%}/gm, E = /\{\{[^{}]+\}\}/g, i = /(\s)data-[\w-]+=(?:"[^"]*"|'[^']*')/g, t = /^[A-Za-z0-9_.]+$/, _ = [
2
+ "ins-unsubscribe-link",
3
+ "ins-global-unsubscribe-link",
4
+ "ins-preferences-unsubscribe-link"
5
+ ];
2
6
  export {
3
- n as CampaignCouldNotBeSavedKey,
4
- e as CanNotMakeAnyChangesForRunningKey,
5
- a as DISPLAY_CONDITIONS_EXCEPTIONS_REGEX,
6
- o as DISPLAY_CONDITIONS_REGEX
7
+ _ as ALLOWED_DYNAMIC_SYSTEM_TOKENS,
8
+ e as CampaignCouldNotBeSavedKey,
9
+ n as CanNotMakeAnyChangesForRunningKey,
10
+ i as DATA_ATTRIBUTE_REGEX,
11
+ o as DISPLAY_CONDITIONS_EXCEPTIONS_REGEX,
12
+ s as DISPLAY_CONDITIONS_REGEX,
13
+ E as DYNAMIC_CONTENT_TAG_REGEX,
14
+ t as VALID_DYNAMIC_VARIABLE_REGEX
7
15
  };
@@ -1,4 +1,4 @@
1
- var c = /* @__PURE__ */ ((r) => (r.Success = "success", r.Warning = "warning", r.Alert = "alert", r))(c || {});
1
+ var c = /* @__PURE__ */ ((r) => (r.Success = "success", r.Warning = "warning", r.Alert = "alert", r.Dark = "dark", r))(c || {});
2
2
  export {
3
3
  c as ToasterTypeOptions
4
4
  };
@@ -1,17 +1,18 @@
1
1
  var k = Object.defineProperty;
2
- var y = (a, r, t) => r in a ? k(a, r, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[r] = t;
3
- var d = (a, r, t) => y(a, typeof r != "symbol" ? r + "" : r, t);
4
- import { BlockId as B } from "../../../enums/block.js";
5
- import { getMigrationBannerHtml as D } from "../../../utils/migrationBannerHtml.js";
6
- import { Block as R, BlockCompositionType as C, ModificationDescription as h } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
+ var B = (a, r, t) => r in a ? k(a, r, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[r] = t;
3
+ var d = (a, r, t) => B(a, typeof r != "symbol" ? r + "" : r, t);
4
+ import { BlockId as R } from "../../../enums/block.js";
5
+ import { getMigrationBannerHtml as y } from "../../../utils/migrationBannerHtml.js";
6
+ import { Block as D, BlockCompositionType as C, ModificationDescription as h } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
7
7
  import { regenerateMobileProductRows as b } from "./controls/main/utils.js";
8
8
  import { ensureMobileCssRulesExist as p, setMobileLayoutOptOut as f, hasMobileLayoutOptOut as A } from "./controls/mobileLayout/cssRules.js";
9
9
  import { RecommendationConfigService as c } from "./services/configService.js";
10
10
  import { useRecommendationExtensionStore as g } from "./store/recommendation.js";
11
11
  import { getDefaultTemplate as E } from "./templates/grid/template.js";
12
- const _ = B.Recommendation, m = "recommendation-block-v2", u = "recommendation-id";
13
- let I = !1;
14
- class q extends R {
12
+ import { useRecommendationBlockWarning as M } from "./useRecommendationBlockWarning.js";
13
+ const I = R.Recommendation, m = "recommendation-block-v2", u = "recommendation-id";
14
+ let _ = !1;
15
+ class H extends D {
15
16
  constructor() {
16
17
  super();
17
18
  /**
@@ -21,7 +22,7 @@ class q extends R {
21
22
  d(this, "_pendingBlockId", null);
22
23
  }
23
24
  getId() {
24
- return _;
25
+ return I;
25
26
  }
26
27
  getIcon() {
27
28
  return "recommendation-icon";
@@ -38,8 +39,8 @@ class q extends R {
38
39
  );
39
40
  }
40
41
  getSettingsPanelTitleHtml() {
41
- return D(
42
- _,
42
+ return y(
43
+ I,
43
44
  this.api.translate("Recommendation Block"),
44
45
  this.api.translate("This block is switched from the Old Version to the New Version. We recommend you check the Recommendation block and test your message to ensure it works properly.")
45
46
  );
@@ -95,7 +96,7 @@ class q extends R {
95
96
  documentModifier: this.api.getDocumentModifier()
96
97
  }));
97
98
  }
98
- s.patchCurrentBlockConfig({ language: n.language }, { triggerRefetch: !1 });
99
+ s.patchCurrentBlockConfig({ language: n.language }, { triggerRefetch: !1 }), this._warnIfMultipleBlocks();
99
100
  }
100
101
  /**
101
102
  * Called when the document changes or template is loaded
@@ -117,7 +118,7 @@ class q extends R {
117
118
  }
118
119
  this._healLingeringDuplicate(t), c.needsMigration(t) && this._migrateFromLegacy(t);
119
120
  try {
120
- I || (p(this.api), I = !0);
121
+ _ || (p(this.api), _ = !0);
121
122
  const e = c.getConfig(t), i = this._getBlockElement(t);
122
123
  if (i) {
123
124
  const n = !e.mobileLayoutEnabled;
@@ -137,6 +138,24 @@ class q extends R {
137
138
  const e = this._getRecommendationId(t);
138
139
  e && g().removeBlockState(e);
139
140
  }
141
+ /**
142
+ * Warns (dark advisory toaster) when the design holds more than one live
143
+ * recommendation block. Triggered from the user-add paths only (fresh drop
144
+ * and duplicate) — never from document-load/migration, so opening a template
145
+ * that already has multiple blocks does not fire it. `onCreated` also runs
146
+ * for a reco block that arrives inside a saved structure (SD-143028), so this
147
+ * covers that case too — no separate `module_dropped` handling is needed.
148
+ *
149
+ * Counting lives in `useRecommendationBlockWarning`, whose DOM-based logic
150
+ * ignores the empty shells deletions leave behind (SD-143028). Wrapped in
151
+ * try/catch because the document root may be unavailable during initial load.
152
+ */
153
+ _warnIfMultipleBlocks() {
154
+ try {
155
+ M().warnIfMultipleBlocks(this.api.getDocumentRootHtmlNode());
156
+ } catch {
157
+ }
158
+ }
140
159
  /**
141
160
  * Generates the next unique recommendation ID by scanning all existing blocks
142
161
  * in the document and finding the maximum existing ID + 1.
@@ -209,7 +228,7 @@ class q extends R {
209
228
  /** Assigns a fresh id to a duplicated block and syncs DOM, node config and store. */
210
229
  _handleDuplicate(t, e) {
211
230
  const i = this._reassignDuplicateId(t, e), n = g();
212
- n.cloneBlockState(e, i), n.setCurrentBlock(i);
231
+ n.cloneBlockState(e, i), n.setCurrentBlock(i), this._warnIfMultipleBlocks();
213
232
  }
214
233
  /**
215
234
  * Core id-reassignment for a duplicated block: rewrites the DOM
@@ -291,6 +310,6 @@ class q extends R {
291
310
  }
292
311
  }
293
312
  export {
294
- _ as BLOCK_ID,
295
- q as RecommendationBlock
313
+ I as BLOCK_ID,
314
+ H as RecommendationBlock
296
315
  };
@@ -0,0 +1,16 @@
1
+ import { useToaster as r } from "../../../composables/useToaster.js";
2
+ import { useTranslations as s } from "../../../composables/useTranslations.js";
3
+ import { ToasterTypeOptions as n } from "../../../enums/toaster.js";
4
+ import { countLiveRecommendationBlocks as i } from "./utils/recommendationBlockCount.js";
5
+ const a = "newsletter.multiple-reco-blocks-warning", f = () => {
6
+ const { showToaster: o } = r(), t = s();
7
+ return { warnIfMultipleBlocks: (e) => {
8
+ i(e) > 1 && o({
9
+ type: n.Dark,
10
+ message: t(a)
11
+ });
12
+ } };
13
+ };
14
+ export {
15
+ f as useRecommendationBlockWarning
16
+ };
@@ -0,0 +1,9 @@
1
+ const r = ".recommendation-block-v2", t = ".recommendation-product-row";
2
+ function n(o) {
3
+ return Array.from(o.querySelectorAll(r)).filter((e) => e.querySelector(t)).length;
4
+ }
5
+ export {
6
+ r as RECOMMENDATION_BLOCK_SELECTOR,
7
+ t as RECOMMENDATION_PRODUCT_ROW_SELECTOR,
8
+ n as countLiveRecommendationBlocks
9
+ };