@useinsider/guido 3.17.0-beta.dc7f4d2 → 3.17.0-beta.ddd4dde

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 (52) hide show
  1. package/README.md +5 -5
  2. package/dist/components/Guido.vue.js +8 -8
  3. package/dist/components/Guido.vue2.js +76 -78
  4. package/dist/components/organisms/AutoSaveController.vue2.js +8 -9
  5. package/dist/components/organisms/header/EditorActions.vue.js +2 -2
  6. package/dist/components/organisms/header/EditorActions.vue2.js +43 -74
  7. package/dist/components/organisms/header/LeftSlot.vue.js +5 -5
  8. package/dist/components/organisms/header/LeftSlot.vue2.js +23 -46
  9. package/dist/components/wrappers/WpDrawer.vue.js +7 -9
  10. package/dist/components/wrappers/WpDrawer.vue2.js +1 -1
  11. package/dist/composables/useHtmlCompiler.js +26 -37
  12. package/dist/composables/useHtmlValidator.js +0 -2
  13. package/dist/composables/useSave.js +41 -84
  14. package/dist/composables/validators/useCouponBlockValidator.js +21 -24
  15. package/dist/composables/validators/useUnsubscribeBlockValidator.js +27 -34
  16. package/dist/extensions/Blocks/Items/block.js +98 -49
  17. package/dist/extensions/Blocks/Items/constants/currency.js +11 -0
  18. package/dist/extensions/Blocks/Items/controls/price/currencyLocation.js +25 -24
  19. package/dist/extensions/Blocks/Items/controls/price/currencySymbol.js +12 -11
  20. package/dist/extensions/Blocks/Items/template.js +153 -152
  21. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +26 -33
  22. package/dist/guido.css +1 -1
  23. package/dist/src/components/Guido.vue.d.ts +1 -17
  24. package/dist/src/components/organisms/header/EditorActions.vue.d.ts +1 -17
  25. package/dist/src/components/organisms/header/HeaderWrapper.vue.d.ts +1 -17
  26. package/dist/src/components/organisms/header/RightSlot.vue.d.ts +1 -17
  27. package/dist/src/components/wrappers/WpDrawer.vue.d.ts +3 -4
  28. package/dist/src/composables/useHtmlValidator.d.ts +0 -21
  29. package/dist/src/composables/useSave.d.ts +1 -6
  30. package/dist/src/composables/validators/useCouponBlockValidator.d.ts +0 -3
  31. package/dist/src/composables/validators/useUnsubscribeBlockValidator.d.ts +0 -10
  32. package/dist/src/extensions/Blocks/Items/block.d.ts +21 -0
  33. package/dist/src/extensions/Blocks/Items/constants/currency.d.ts +19 -0
  34. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +0 -5
  35. package/dist/src/stores/config.d.ts +0 -5
  36. package/dist/src/utils/templatePreparation.d.ts +0 -30
  37. package/dist/stores/config.js +6 -13
  38. package/dist/utils/pairProductVariables.js +60 -59
  39. package/dist/utils/templatePreparation.js +25 -28
  40. package/package.json +2 -2
  41. package/dist/components/organisms/validation/ValidationErrorDrawer.vue.js +0 -20
  42. package/dist/components/organisms/validation/ValidationErrorDrawer.vue2.js +0 -48
  43. package/dist/composables/useSaveValidation.js +0 -279
  44. package/dist/composables/useSaveValidationRollout.js +0 -9
  45. package/dist/enums/save-validation.js +0 -4
  46. package/dist/src/@types/save-validation.d.ts +0 -19
  47. package/dist/src/components/organisms/validation/ValidationErrorDrawer.vue.d.ts +0 -2
  48. package/dist/src/composables/useSaveValidation.d.ts +0 -6
  49. package/dist/src/composables/useSaveValidationRollout.d.ts +0 -3
  50. package/dist/src/enums/save-validation.d.ts +0 -27
  51. package/dist/src/stores/save-validation.d.ts +0 -22
  52. package/dist/stores/save-validation.js +0 -30
@@ -1,19 +1,17 @@
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, 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) {
4
+ var t = this, n = t._self._c, e = t._self._setupProxy;
5
+ return n(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(o) {
6
6
  return e.emit("cancelOrBackButtonEvent");
7
- }, onCloseEvent: function(n) {
7
+ }, onCloseEvent: function(o) {
8
8
  return e.emit("onCloseEvent");
9
- }, primaryButtonEvent: function(n) {
9
+ }, primaryButtonEvent: function(o) {
10
10
  return e.emit("primaryButtonEvent");
11
- }, secondaryButtonEvent: function(n) {
12
- return e.emit("secondaryButtonEvent");
13
11
  } }, scopedSlots: t._u([t.$slots.headerBottomSlot ? { key: "headerBottomSlot", fn: function() {
14
12
  return [t._t("headerBottomSlot")];
15
13
  }, proxy: !0 } : null, { key: "contentSlot", fn: function() {
16
- return [o("div", [t._t("default")], 2)];
14
+ return [n("div", [t._t("default")], 2)];
17
15
  }, proxy: !0 }], null, !0) });
18
16
  }, i = [], c = /* @__PURE__ */ s(
19
17
  r,
@@ -23,7 +21,7 @@ var u = function() {
23
21
  null,
24
22
  null
25
23
  );
26
- const p = c.exports;
24
+ const f = c.exports;
27
25
  export {
28
- p as default
26
+ f as default
29
27
  };
@@ -13,7 +13,7 @@ const r = /* @__PURE__ */ e({
13
13
  status: { type: Boolean },
14
14
  titleText: null
15
15
  },
16
- emits: ["cancelOrBackButtonEvent", "onCloseEvent", "primaryButtonEvent", "secondaryButtonEvent"],
16
+ emits: ["cancelOrBackButtonEvent", "onCloseEvent", "primaryButtonEvent"],
17
17
  setup(n, { emit: t }) {
18
18
  return { __sfc: !0, emit: t, InDrawer: o };
19
19
  }
@@ -1,14 +1,13 @@
1
- import { defaultHtmlCompilerRules as d } from "../config/compiler/htmlCompilerRules.js";
2
- import { itemsCompilerRules as f } from "../config/compiler/itemsCompilerRules.js";
3
- import { liquidCompilerRules as g } from "../config/compiler/liquidCompilerRules.js";
4
- import { outlookCompilerRules as R } from "../config/compiler/outlookCompilerRules.js";
1
+ import { defaultHtmlCompilerRules as R } from "../config/compiler/htmlCompilerRules.js";
2
+ import { itemsCompilerRules as g } from "../config/compiler/itemsCompilerRules.js";
3
+ import { liquidCompilerRules as C } from "../config/compiler/liquidCompilerRules.js";
4
+ import { outlookCompilerRules as b } from "../config/compiler/outlookCompilerRules.js";
5
5
  import { recommendationCompilerRules as v } from "../config/compiler/recommendationCompilerRules.js";
6
6
  import { socialCompilerRules as H } from "../config/compiler/socialCompilerRules.js";
7
- import { unsubscribeCompilerRules as b } from "../config/compiler/unsubscribeCompilerRules.js";
8
- import { createHtmlCompiler as n } from "../utils/htmlCompiler.js";
9
- import { computed as p } from "vue";
10
- import { useConfig as C } from "./useConfig.js";
11
- const x = /* @__PURE__ */ new Set([
7
+ import { unsubscribeCompilerRules as x } from "../config/compiler/unsubscribeCompilerRules.js";
8
+ import { createHtmlCompiler as s } from "../utils/htmlCompiler.js";
9
+ import { useConfig as k } from "./useConfig.js";
10
+ const y = /* @__PURE__ */ new Set([
12
11
  // URL/tag encoding fixes — keep merge-tag and placeholder integrity intact.
13
12
  "fix-url-encoding-start",
14
13
  "fix-url-encoding-end",
@@ -31,34 +30,24 @@ const x = /* @__PURE__ */ new Set([
31
30
  // Editor-only attribute strip — AMP4EMAIL has no `contenteditable`, so leaving
32
31
  // it in narrows/breaks rendering. Pure attribute removal, emits nothing.
33
32
  "remove-contenteditable"
34
- ]), I = () => {
35
- const { compiler: i, isFeatureEnabled: u, partner: a } = C(), c = p(() => {
36
- var m, l;
37
- const e = ((m = i.value) == null ? void 0 : m.customRules) || [];
38
- return [
39
- ...!!((l = i.value) != null && l.ignoreDefaultRules) ? [] : d,
40
- ...v,
41
- ...b,
42
- ...f,
43
- ...R,
44
- ...H,
45
- ...u("liquidSyntax") ? g : [],
46
- ...e.map((t, o) => ({
47
- ...t,
48
- priority: t.priority + 1e3 + o
49
- // Ensure additional rules run after default rules
50
- }))
51
- ];
52
- }), r = p(() => {
53
- var t;
54
- const e = c.value, s = n(e), m = n(e.filter((o) => x.has(o.id))), l = (t = a.value) == null ? void 0 : t.fallbackFont;
55
- return {
56
- compileHtml: (o) => s.compile(o, void 0, l),
57
- compileAmpHtml: (o) => m.compile(o, void 0, l)
58
- };
59
- });
60
- return { compileHtml: (e) => r.value.compileHtml(e), compileAmpHtml: (e) => r.value.compileAmpHtml(e) };
33
+ ]), M = () => {
34
+ var i, m, r;
35
+ const { compiler: o, isFeatureEnabled: n, partner: a } = k(), p = ((i = o.value) == null ? void 0 : i.customRules) || [], l = [
36
+ ...!!((m = o.value) != null && m.ignoreDefaultRules) ? [] : R,
37
+ ...v,
38
+ ...x,
39
+ ...g,
40
+ ...b,
41
+ ...H,
42
+ ...n("liquidSyntax") ? C : [],
43
+ ...p.map((e, f) => ({
44
+ ...e,
45
+ priority: e.priority + 1e3 + f
46
+ // Ensure additional rules run after default rules
47
+ }))
48
+ ], u = s(l), c = l.filter((e) => y.has(e.id)), d = s(c), t = (r = a.value) == null ? void 0 : r.fallbackFont;
49
+ return { compileHtml: (e) => u.compile(e, void 0, t), compileAmpHtml: (e) => d.compile(e, void 0, t) };
61
50
  };
62
51
  export {
63
- I as useHtmlCompiler
52
+ M as useHtmlCompiler
64
53
  };
@@ -221,8 +221,6 @@ const De = () => {
221
221
  export {
222
222
  de as buildPartnerAttributeNameSet,
223
223
  fe as findInvalidCustomFields,
224
- pe as getInvalidDynamicContentTags,
225
- ce as getRecommendationBlockIds,
226
224
  ue as parseRecommendationVariable,
227
225
  De as useHtmlValidator
228
226
  };
@@ -1,94 +1,51 @@
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";
1
+ import { useActionsApi as T } from "./useActionsApi.js";
2
+ import { useConfig as k } from "./useConfig.js";
3
+ import { useSaveStart as B, useSaveComplete as E } from "./useGuidoActions.js";
4
+ import { useSyncModuleExtractor as q } from "./useSyncModuleExtractor.js";
5
+ import { ToasterTypeOptions as C } from "../enums/toaster.js";
8
6
  import { useStripoApi as D } from "../services/stripoApi.js";
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())
37
- return;
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;
7
+ import { useTemplatePreparation as L } from "../utils/templatePreparation.js";
8
+ import { useAllowlist as P } from "./useAllowlist.js";
9
+ import { useHtmlValidator as U } from "./useHtmlValidator.js";
10
+ import { useToaster as A } from "./useToaster.js";
11
+ import { useCouponBlockValidator as M } from "./validators/useCouponBlockValidator.js";
12
+ import { useLiquidValidator as h } from "./validators/useLiquidValidator.js";
13
+ import { useUnsubscribeBlockValidator as F } from "./validators/useUnsubscribeBlockValidator.js";
14
+ const $ = () => {
15
+ const n = B(), l = E(), { validateHtml: c } = U(), { validateLiquidSyntax: d } = h(), { validateCouponBlockTags: m } = M(), { validateUnsubscribeBlockUniqueness: u, validateUnsubscribeBlockHasTemplate: p } = F(), { callbacks: e, isFeatureEnabled: a } = k(), { extractSyncModuleData: f } = q(), { setSyncModuleUnsubscriptionPages: v } = D(), { editorSave: S } = T(), { showToaster: b } = A(), { getBlockedDomains: w, resolveToast: V } = P();
16
+ return { save: async (y = !1, s = !1) => {
17
+ var r;
47
18
  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");
19
+ const { prepareTemplateDetails: H } = L(), t = await H();
20
+ if (!m(t.compiledHtml) || !u(t.compiledHtml) || !p(t.compiledHtml))
21
+ return;
22
+ if (a("liquidSyntax")) {
23
+ if (!await d(t.compiledHtml))
56
24
  return;
57
- }
58
- } else if (!await P(o))
25
+ } else if (!await c(t.compiledHtml, t.dynamicContentList, !0))
59
26
  return;
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)
27
+ if ((r = e.value) != null && r.externalValidation && !await e.value.externalValidation(t))
65
28
  return;
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))
74
- return;
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
29
+ if (a("allowlistEnabled")) {
30
+ const i = await w(t.compiledHtml, t.css);
31
+ if (i.length) {
32
+ if (!s) {
33
+ const o = await V(i);
34
+ o != null && o.message && b({
35
+ type: C.Warning,
36
+ message: o.message,
37
+ actionButton: o.actionButton
38
+ });
39
+ }
40
+ return;
87
41
  }
88
- };
89
- return l(i, { silent: !0 });
42
+ }
43
+ if (!await S())
44
+ return;
45
+ const { unsubscribePayload: g, stripoModules: x } = f(t.rawHtml);
46
+ return await v(g), t.modules = x, y || l({ ...t, silent: s }), t;
90
47
  } };
91
48
  };
92
49
  export {
93
- bt as useSave
50
+ $ as useSave
94
51
  };
@@ -1,27 +1,24 @@
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 };
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
+ } };
22
21
  };
23
22
  export {
24
- p as COUPON_TAG_MODIFIED_KEY,
25
- u as findInvalidCouponBlocks,
26
- T as useCouponBlockValidator
23
+ A as useCouponBlockValidator
27
24
  };
@@ -1,8 +1,8 @@
1
- import { ToasterTypeOptions as c } from "../../enums/toaster.js";
1
+ import { ToasterTypeOptions as i } from "../../enums/toaster.js";
2
2
  import { PAGE_TYPES as u } from "../../enums/unsubscribe.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";
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";
6
6
  const T = [
7
7
  {
8
8
  pageType: u.GLOBAL_UNSUBSCRIBE,
@@ -12,37 +12,30 @@ 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", 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)
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])
37
27
  }), !1) : !0;
38
- }, validateUnsubscribeBlockHasTemplate: (e) => b(e) === 0 ? !0 : (r({
39
- type: c.Warning,
40
- message: s(E)
41
- }), !1) };
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
+ } };
42
38
  };
43
39
  export {
44
- E as EMPTY_BLOCK_KEY,
45
- b as countUnsubBlocksWithoutPage,
46
- m as findDuplicateUnsubPageTypes,
47
- y as useUnsubscribeBlockValidator
40
+ P as useUnsubscribeBlockValidator
48
41
  };
@@ -1,20 +1,30 @@
1
- import { BlockId as g } from "../../../enums/block.js";
2
- import { useOnboardingStore as y } from "../../../stores/onboarding.js";
3
- import { getMigrationBannerHtml as I } from "../../../utils/migrationBannerHtml.js";
4
- import { Block as C, BlockCompositionType as b, ModificationDescription as c } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
- import { SETTINGS_ENUMS as l, DefaultConfigValues as d } from "./enums/settingsEnums.js";
6
- import { getDefaultTemplate as h } from "./template.js";
7
- import { getItemsBlockContainer as u, getItemsBlockConfig as f, deriveItemNumber as D, getDefaultItemsBlockConfig as N } from "./utils/nodeConfigUtils.js";
8
- const p = g.Items;
9
- class E extends C {
1
+ var D = Object.defineProperty;
2
+ var k = (l, a, t) => a in l ? D(l, a, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[a] = t;
3
+ var I = (l, a, t) => k(l, typeof a != "symbol" ? a + "" : a, t);
4
+ import { BlockId as N } from "../../../enums/block.js";
5
+ import { useOnboardingStore as T } from "../../../stores/onboarding.js";
6
+ import { getMigrationBannerHtml as _ } from "../../../utils/migrationBannerHtml.js";
7
+ import { Block as A, BlockCompositionType as M, ModificationDescription as m } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
8
+ import { currencyPositionFromLocation as O, ITEMS_CURRENCY_ATTR as d } from "./constants/currency.js";
9
+ import { ItemsBlockId as R } from "./enums/controlEnums.js";
10
+ import { SETTINGS_ENUMS as b, DefaultConfigValues as f } from "./enums/settingsEnums.js";
11
+ import { getDefaultTemplate as E } from "./template.js";
12
+ import { getItemsBlockContainer as h, getItemsBlockConfig as C, deriveItemNumber as H, getDefaultItemsBlockConfig as B } from "./utils/nodeConfigUtils.js";
13
+ const S = N.Items, P = "Reconcile Items currency DOM attributes";
14
+ class G extends A {
15
+ constructor() {
16
+ super(...arguments);
17
+ /** Block instances whose currency attrs were already self-healed this session (SD-147588 — undo-safe). */
18
+ I(this, "_currencyHealed", /* @__PURE__ */ new Set());
19
+ }
10
20
  getId() {
11
- return p;
21
+ return S;
12
22
  }
13
23
  getIcon() {
14
24
  return "items-icon";
15
25
  }
16
26
  getBlockCompositionType() {
17
- return b.CONTAINER;
27
+ return M.CONTAINER;
18
28
  }
19
29
  getName() {
20
30
  return this.api.translate("Items");
@@ -23,20 +33,20 @@ class E extends C {
23
33
  return this.api.translate("Items lets you display personalized products based on user behavior.");
24
34
  }
25
35
  getSettingsPanelTitleHtml() {
26
- return I(
27
- p,
36
+ return _(
37
+ S,
28
38
  this.api.translate("Items"),
29
39
  this.api.translate("This block is switched from the Old Version to the New Version. We recommend you check the Items block and test your message to ensure it works properly.")
30
40
  );
31
41
  }
32
42
  getTemplate() {
33
- return h({
34
- orientation: l.ORIENTATION.VERTICAL,
35
- itemsType: l.ITEMS_TYPE.CART_ITEMS,
43
+ return E({
44
+ orientation: b.ORIENTATION.VERTICAL,
45
+ itemsType: b.ITEMS_TYPE.CART_ITEMS,
36
46
  itemId: "{{Abandoned Cart Item (1) Url}}",
37
- currencySymbol: d.productPriceCurrencySymbolControlValue,
38
- currencyLocation: d.productPriceCurrencyLocationControlValue,
39
- formattedPrice: d.productPriceFormattedControlValue === "1"
47
+ currencySymbol: f.productPriceCurrencySymbolControlValue,
48
+ currencyLocation: f.productPriceCurrencyLocationControlValue,
49
+ formattedPrice: f.productPriceFormattedControlValue === "1"
40
50
  });
41
51
  }
42
52
  allowInnerBlocksDND() {
@@ -45,24 +55,27 @@ class E extends C {
45
55
  canBeSavedAsModule() {
46
56
  return !0;
47
57
  }
48
- onCreated(n) {
49
- const t = this.api.getDocumentModifier(), a = this.api.getDocumentRootCssNode();
50
- a.querySelector('[product-attr="imageSrc"] img') || t.modifyCss(a).appendRule('[product-attr="imageSrc"] img {object-fit: contain;}');
51
- const e = u(n);
52
- if (!e)
58
+ onCreated(t) {
59
+ const o = this.api.getDocumentModifier(), s = this.api.getDocumentRootCssNode();
60
+ s.querySelector('[product-attr="imageSrc"] img') || o.modifyCss(s).appendRule('[product-attr="imageSrc"] img {object-fit: contain;}');
61
+ const r = h(t);
62
+ if (!r)
53
63
  return;
54
- const o = e.getNodeConfig(), r = o && Object.keys(o).length > 0, i = f(n);
55
- if (i != null && i.initialized)
56
- if (r)
57
- i.blockInstanceId || this.api.getDocumentModifier().modifyHtml(e).setNodeConfig({ ...i, blockInstanceId: String(Date.now()) }).apply(new c("Assign block instance ID to block"));
58
- else {
59
- const s = this.api.getDocumentModifier();
60
- s.modifyHtml(e).setNodeConfig(i), this._stampProductTdDomAttributes(e, i, s), s.apply(new c("Migrate legacy config to nodeConfig"));
64
+ const i = r.getNodeConfig(), c = i && Object.keys(i).length > 0, e = C(t);
65
+ if (e != null && e.initialized) {
66
+ if (!c) {
67
+ const u = this.api.getDocumentModifier();
68
+ u.modifyHtml(r).setNodeConfig(e), this._stampProductTdDomAttributes(r, e, u), u.apply(new m("Migrate legacy config to nodeConfig"));
69
+ return;
61
70
  }
62
- else {
63
- const s = N(), m = this.api.getDocumentModifier();
64
- m.modifyHtml(e).setNodeConfig(s), this._stampProductTdDomAttributes(e, s, m, !0), m.apply(new c("Initialize Items block with default configuration")), y().startOnboarding("itemsOnboarding");
71
+ } else {
72
+ const u = B(), g = this.api.getDocumentModifier();
73
+ g.modifyHtml(r).setNodeConfig(u), this._stampProductTdDomAttributes(r, u, g, !0), g.apply(new m("Initialize Items block with default configuration")), T().startOnboarding("itemsOnboarding");
74
+ return;
65
75
  }
76
+ const n = e.blockInstanceId || String(Date.now()), p = this.api.getDocumentModifier();
77
+ let y = !1;
78
+ e.blockInstanceId || (p.modifyHtml(r).setNodeConfig({ ...e, blockInstanceId: n }), y = !0), this._shouldReconcileCurrency(e) && this._reconcileCurrencyDomAttributes(r, e, p) && (y = !0), y && p.apply(new m("Assign Items block instance ID and reconcile currency")), this._markCurrencyHealed(n);
66
79
  }
67
80
  /**
68
81
  * Re-seeds nodeConfig from the persisted esd-ext-config when a saved module
@@ -70,18 +83,24 @@ class E extends C {
70
83
  * into nodeConfig, so without this a reused module would reset to defaults.
71
84
  * Guarded to the nodeConfig-empty case so it runs once and never loops.
72
85
  */
73
- onDocumentChanged(n) {
74
- const t = u(n);
75
- if (!t)
86
+ onDocumentChanged(t) {
87
+ const o = h(t);
88
+ if (!o)
76
89
  return;
77
- const a = t.getNodeConfig();
78
- if (a && Object.keys(a).length > 0)
90
+ const s = o.getNodeConfig();
91
+ if (s && Object.keys(s).length > 0) {
92
+ const e = C(t);
93
+ if (e != null && e.initialized && this._shouldReconcileCurrency(e)) {
94
+ const n = this.api.getDocumentModifier();
95
+ this._reconcileCurrencyDomAttributes(o, e, n) && n.apply(new m(P)), this._markCurrencyHealed(e.blockInstanceId);
96
+ }
79
97
  return;
80
- const o = f(n);
81
- if (!(o != null && o.initialized))
98
+ }
99
+ const i = C(t);
100
+ if (!(i != null && i.initialized))
82
101
  return;
83
- const r = this.api.getDocumentModifier();
84
- r.modifyHtml(t).setNodeConfig(o), this._stampProductTdDomAttributes(t, o, r), r.apply(new c("Recover Items block config from saved module"));
102
+ const c = this.api.getDocumentModifier();
103
+ c.modifyHtml(o).setNodeConfig(i), this._stampProductTdDomAttributes(o, i, c), c.apply(new m("Recover Items block config from saved module"));
85
104
  }
86
105
  /**
87
106
  * Bakes the compiler-read DOM attributes (`data-type`, `data-number`, `data-nodup`) onto the
@@ -91,14 +110,44 @@ class E extends C {
91
110
  * restored before export. The name `<a>` carries no data-type/data-number of its own and
92
111
  * relies on this td-level fallback in pairProductVariables.
93
112
  */
94
- _stampProductTdDomAttributes(n, t, a, e = !1) {
95
- const o = D(t.itemsSelectValue, t.type), r = (i, s) => {
96
- e && n.getAttribute(i) || a.modifyHtml(n).setAttribute(i, s);
113
+ _stampProductTdDomAttributes(t, o, s, r = !1) {
114
+ const i = H(o.itemsSelectValue, o.type), c = (e, n) => {
115
+ r && t.getAttribute(e) || s.modifyHtml(t).setAttribute(e, n);
97
116
  };
98
- r("data-type", t.type), r("data-number", o), r("data-nodup", String(t.priceHideDiscount));
117
+ c("data-type", o.type), c("data-number", i), c("data-nodup", String(o.priceHideDiscount));
118
+ }
119
+ /**
120
+ * Whether the currency self-heal should run for this block. Two guards (SD-147588):
121
+ * 1. Config is only authoritative when the symbol was actually customized — a symbol still at
122
+ * the 'USD' sentinel may be a migrator default, so we trust the DOM's real value over a
123
+ * defaulted config and never overwrite it.
124
+ * 2. Heal each instance at most once per session, so the auto-fix can't fight undo (undo
125
+ * re-drifts the attr, which would otherwise re-trigger the heal forever).
126
+ */
127
+ _shouldReconcileCurrency(t) {
128
+ const o = (t.priceCurrencySymbol ?? "").trim();
129
+ return !o || o === f.productPriceCurrencySymbolControlValue ? !1 : !t.blockInstanceId || !this._currencyHealed.has(t.blockInstanceId);
130
+ }
131
+ /** Marks a block instance's currency as reconciled so it is not healed again (undo-safe). */
132
+ _markCurrencyHealed(t) {
133
+ t && this._currencyHealed.add(t);
134
+ }
135
+ /**
136
+ * Stamps the export-read currency attrs onto every price `<p>` from config, so a template whose
137
+ * attrs drifted (e.g. a location toggle before the sync fix) self-heals to match the editor.
138
+ * Config is the source of truth — never derive from visible text. Callers gate this with
139
+ * `_shouldReconcileCurrency`. Returns true only when an attr actually changed, so the caller can
140
+ * skip an empty apply that would otherwise re-trigger onDocumentChanged and loop (SD-147588).
141
+ */
142
+ _reconcileCurrencyDomAttributes(t, o, s) {
143
+ const r = O(o.priceCurrencyLocation), i = (o.priceCurrencySymbol ?? "").trim(), c = t.querySelectorAll(`.${R.PRICE} p`);
144
+ let e = !1;
145
+ return c.forEach((n) => {
146
+ n.getAttribute(d.POSITION) !== r && (s.modifyHtml(n).setAttribute(d.POSITION, r), e = !0), i && n.getAttribute(d.SYMBOL) !== i && (s.modifyHtml(n).setAttribute(d.SYMBOL, i), e = !0);
147
+ }), e;
99
148
  }
100
149
  }
101
150
  export {
102
- p as BLOCK_ID,
103
- E as ItemsBlock
151
+ S as BLOCK_ID,
152
+ G as ItemsBlock
104
153
  };
@@ -0,0 +1,11 @@
1
+ const o = {
2
+ POSITION: "data-curency",
3
+ SYMBOL: "data-currency_symbol"
4
+ };
5
+ function c(r) {
6
+ return r === "1" ? "after" : "before";
7
+ }
8
+ export {
9
+ o as ITEMS_CURRENCY_ATTR,
10
+ c as currencyPositionFromLocation
11
+ };