@useinsider/guido 3.27.0 → 3.27.1-beta.842075e

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.
@@ -3,9 +3,9 @@ import { MinDeviceViewport as C, DefaultPadding as R } from "../enums/recommenda
3
3
  import { useRecommendationExtensionStore as g } from "../extensions/Blocks/Recommendation/store/recommendation.js";
4
4
  import { generateCompleteFilterQuery as b } from "../extensions/Blocks/Recommendation/utils/filterUtil.js";
5
5
  import { getPartnerRecommendationParams as h } from "../extensions/Blocks/Recommendation/utils/partnerCustomizations.js";
6
- import { sanitizeProductIds as x } from "../extensions/Blocks/Recommendation/utils/productIds.js";
7
- import { useConfigStore as P } from "../stores/config.js";
8
- const B = () => ({
6
+ import { sanitizeProductIds as P } from "../extensions/Blocks/Recommendation/utils/productIds.js";
7
+ import { useConfigStore as S } from "../stores/config.js";
8
+ const M = () => ({
9
9
  calculateCardWidth: ({
10
10
  mobileLeftPadding: s,
11
11
  mobileRightPadding: c,
@@ -24,11 +24,7 @@ const B = () => ({
24
24
  mobileLeftPadding: 0,
25
25
  mobileRightPadding: 0,
26
26
  cardsInRow: 2,
27
- unresponsive: !1,
28
- priceBeforeTextValue: "",
29
- priceAfterTextValue: "",
30
- discountBeforeTextValue: "",
31
- discountAfterTextValue: ""
27
+ unresponsive: !1
32
28
  };
33
29
  const { recommendationConfigs: i } = a, e = i.orientation === "grid" ? "vertical" : "horizontal";
34
30
  return {
@@ -37,16 +33,12 @@ const B = () => ({
37
33
  mobileLeftPadding: 0,
38
34
  mobileRightPadding: 0,
39
35
  cardsInRow: i.cardsInRow,
40
- unresponsive: i.unresponsive,
41
- priceBeforeTextValue: "",
42
- priceAfterTextValue: "",
43
- discountBeforeTextValue: "",
44
- discountAfterTextValue: ""
36
+ unresponsive: i.unresponsive
45
37
  };
46
38
  },
47
39
  buildCampaignUrl: (s, c) => {
48
40
  var l;
49
- const o = g(), a = P(), i = Number(s);
41
+ const o = g(), a = S(), i = Number(s);
50
42
  let e;
51
43
  if (c)
52
44
  e = c;
@@ -78,7 +70,7 @@ const B = () => ({
78
70
  return delete r[s], o.recommendationCampaignUrls = r, "";
79
71
  }
80
72
  const t = new URLSearchParams();
81
- t.set("locale", e.language), t.set("currency", e.currencyCode), t.set("partnerName", a.partnerName), t.set("size", e.size), t.set("details", "true"), t.set("campaignId", a.variationId), e.strategy === "manualMerchandising" ? t.set("productId", x(e.productIds)) : e.strategy === "similarViewed" && t.set("productId", "{itemId}"), e.strategy === "userBased" && t.set("userId", "{user_id}");
73
+ t.set("locale", e.language), t.set("currency", e.currencyCode), t.set("partnerName", a.partnerName), t.set("size", e.size), t.set("details", "true"), t.set("campaignId", a.variationId), e.strategy === "manualMerchandising" ? t.set("productId", P(e.productIds)) : e.strategy === "similarViewed" && t.set("productId", "{itemId}"), e.strategy === "userBased" && t.set("userId", "{user_id}");
82
74
  const f = e.filters.filter((r) => r.isValid), m = b(f);
83
75
  m && t.set("filter", m), e.shuffleProducts && t.set("shuffle", "true"), Object.entries(h(a.partnerName, e.strategy)).forEach(([r, n]) => t.set(r, n));
84
76
  const p = decodeURIComponent(t.toString()), u = `${I.RECOMMENDATION_API_URL}/v2/${d}?${p}`;
@@ -86,5 +78,5 @@ const B = () => ({
86
78
  }
87
79
  });
88
80
  export {
89
- B as useRecommendation
81
+ M as useRecommendation
90
82
  };
@@ -1,14 +1,14 @@
1
- import { useRecommendation as N } from "../../composables/useRecommendation.js";
2
- import { DUMMY_IMAGE_MAPPINGS as h, REGEX as d, VerticalOrientation as $, CSS as n, ATTRIBUTES as p, CONDITIONS as A, HTML as g } from "../../enums/recommendation.js";
3
- import { prepareRecommendationBlocks as O } from "./utils/recommendationCompilerUtils.js";
4
- const H = [
1
+ import { useRecommendation as R } from "../../composables/useRecommendation.js";
2
+ import { DUMMY_IMAGE_MAPPINGS as A, REGEX as m, VerticalOrientation as y, CSS as n, CONDITIONS as u, ATTRIBUTES as l, HTML as I } from "../../enums/recommendation.js";
3
+ import { prepareRecommendationBlocks as S } from "./utils/recommendationCompilerUtils.js";
4
+ const f = [
5
5
  {
6
6
  id: "replace-images-with-variable-names",
7
7
  description: "Replacing dummy images with variable names in recommendation module",
8
8
  type: "custom",
9
9
  processor: (t) => {
10
10
  let e = t;
11
- return Object.entries(h).forEach(([, r]) => {
11
+ return Object.entries(A).forEach(([, r]) => {
12
12
  Object.entries(r).forEach(([o, i]) => {
13
13
  e = e.replaceAll(i, `{{${o}}}`);
14
14
  });
@@ -42,17 +42,17 @@ const H = [
42
42
  description: "Adding recommendation unresponsive css",
43
43
  type: "custom",
44
44
  processor: (t) => {
45
- const { calculateCardWidth: e, getRecommendationCampaignData: r } = N();
45
+ const { calculateCardWidth: e, getRecommendationCampaignData: r } = R();
46
46
  let o = t;
47
- const i = o.match(d.ID);
47
+ const i = o.match(m.ID);
48
48
  if (i) {
49
- const s = [];
50
- if (i.forEach((c) => {
51
- const m = /recommendation-id="(.*?)"/i.exec(c), E = m ? m[1].trim() : "", u = r(E);
52
- u.textTrimming && u.orientation === $ && s.push(e(u));
53
- }), s.length) {
54
- const c = `width:${Math.min(...s)}px!important;`;
55
- o = o.replace(n.REGULAR_NAME_HEIGHT, `${n.TRIMMED_NAME_HEIGHT} ${c} ${n.ELLIPSIS}`).replace(n.REGULAR_NAME_CONTAINER_HEIGHT, n.TRIMMED_NAME_CONTAINER_CSS).replace(n.RESPONSIVE_NAME_SIZE, `${n.RESPONSIVE_NAME_HEIGHT} ${c} ${n.ELLIPSIS}`).replace(n.RESPONSIVE_NAME_CONTAINER_HEIGHT, n.TRIMMED_RESPONSIVE_NAME_CONTAINER_CSS);
49
+ const c = [];
50
+ if (i.forEach((s) => {
51
+ const a = /recommendation-id="(.*?)"/i.exec(s), d = a ? a[1].trim() : "", p = r(d);
52
+ p.textTrimming && p.orientation === y && c.push(e(p));
53
+ }), c.length) {
54
+ const s = `width:${Math.min(...c)}px!important;`;
55
+ o = o.replace(n.REGULAR_NAME_HEIGHT, `${n.TRIMMED_NAME_HEIGHT} ${s} ${n.ELLIPSIS}`).replace(n.REGULAR_NAME_CONTAINER_HEIGHT, n.TRIMMED_NAME_CONTAINER_CSS).replace(n.RESPONSIVE_NAME_SIZE, `${n.RESPONSIVE_NAME_HEIGHT} ${s} ${n.ELLIPSIS}`).replace(n.RESPONSIVE_NAME_CONTAINER_HEIGHT, n.TRIMMED_RESPONSIVE_NAME_CONTAINER_CSS);
56
56
  }
57
57
  }
58
58
  return o;
@@ -63,36 +63,24 @@ const H = [
63
63
  id: "prepare-recommendations",
64
64
  description: "Replacing product data with template variables in recommendation blocks",
65
65
  type: "custom",
66
- processor: (t) => O(t),
66
+ processor: (t) => S(t),
67
67
  priority: 48
68
68
  },
69
69
  {
70
70
  id: "add-discount-conditions",
71
71
  description: "Adding discount conditions to the recommendation block",
72
72
  type: "custom",
73
- processor: (t) => {
74
- let e = t;
75
- const r = e.match(d.ATTRIBUTE_PARAGRAPH), { getRecommendationCampaignData: o } = N();
76
- return r !== null && r.forEach((i) => {
77
- const s = i.match(d.CUSTOM_FIELD);
78
- if (!s)
79
- return;
80
- const [c] = s, m = c.match(d.CUSTOM_FIELD_INDEXES_PART), E = c.match(d.CUSTOM_FIELD_NAME_PART), u = i.match(d.ATTRIBUTE_PARAGRAPH_START_TAG);
81
- if (!m || !E || !u)
82
- return;
83
- const [T] = m, [I] = E, [_] = u, b = I.substring(1, I.length - 2), S = _.match(d.COMPOSITION) !== null;
84
- let a = c;
85
- if (S) {
86
- const y = T.substring(2, T.length - 3), l = o(y);
87
- b === p.OMNIBUS_PRICE && (l.priceBeforeTextValue && (a = `${l.priceBeforeTextValue}${a}`), l.priceAfterTextValue && (a = `${a}${l.priceAfterTextValue}`)), b === p.OMNIBUS_DISCOUNT && (l.discountBeforeTextValue && (a = `${l.discountBeforeTextValue}${a}`), l.discountAfterTextValue && (a = `${a}${l.discountAfterTextValue}`));
88
- }
89
- const R = T.substring(2);
90
- let f = "";
91
- b in A.IF && (f = A.IF[b].replaceAll(`{${p.DISCOUNT}}`, `${R}${p.DISCOUNT}`).replaceAll(`{${p.OMNIBUS_DISCOUNT}}`, `${R}${p.OMNIBUS_DISCOUNT}`).replaceAll(`{${p.OMNIBUS_PRICE}}`, `${R}${p.OMNIBUS_PRICE}`));
92
- const M = `${_}${a}${g.PARAGRAPH_END_TAG}`, C = `${f}${S ? M : i}${A.ELSE}${_}${g.PARAGRAPH_END_TAG}${A.END_IF}`;
93
- e = e.replace(i, C);
94
- }), e;
95
- },
73
+ processor: (t) => t.replace(m.ATTRIBUTE_PARAGRAPH, (e) => {
74
+ const r = e.match(m.CUSTOM_FIELD);
75
+ if (!r)
76
+ return e;
77
+ const [o] = r, i = o.match(m.CUSTOM_FIELD_INDEXES_PART), c = o.match(m.CUSTOM_FIELD_NAME_PART), s = e.match(m.ATTRIBUTE_PARAGRAPH_START_TAG);
78
+ if (!i || !c || !s)
79
+ return e;
80
+ const [a] = i, [d] = c, [p] = s, b = d.substring(1, d.length - 2), E = a.substring(2);
81
+ let _ = "";
82
+ return b in u.IF && (_ = u.IF[b].replaceAll(`{${l.DISCOUNT}}`, `${E}${l.DISCOUNT}`).replaceAll(`{${l.OMNIBUS_DISCOUNT}}`, `${E}${l.OMNIBUS_DISCOUNT}`).replaceAll(`{${l.OMNIBUS_PRICE}}`, `${E}${l.OMNIBUS_PRICE}`)), `${_}${e}${u.ELSE}${p}${I.PARAGRAPH_END_TAG}${u.END_IF}`;
83
+ }),
96
84
  priority: 53
97
85
  },
98
86
  {
@@ -147,8 +135,8 @@ const H = [
147
135
  ), e = e.replace(
148
136
  /@media[^{]*max-width\s*:\s*480px[^{]*\{((?:[^{}]*\{[^{}]*\})*[^{}]*)\}/g,
149
137
  (r, o) => {
150
- const i = o.match(/[^{}]+\{[^{}]*\}/g) || [], s = /ins-recommendation|product-image-cell|button-cell|product-info-cell/;
151
- return i.every((m) => s.test(m)) ? "" : r;
138
+ const i = o.match(/[^{}]+\{[^{}]*\}/g) || [], c = /ins-recommendation|product-image-cell|button-cell|product-info-cell/;
139
+ return i.every((a) => c.test(a)) ? "" : r;
152
140
  }
153
141
  )), e;
154
142
  },
@@ -208,5 +196,5 @@ const H = [
208
196
  }
209
197
  ];
210
198
  export {
211
- H as recommendationCompilerRules
199
+ f as recommendationCompilerRules
212
200
  };
@@ -1,146 +1,158 @@
1
- var x = Object.defineProperty;
2
- var B = (c, e, r) => e in c ? x(c, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : c[e] = r;
3
- var A = (c, e, r) => B(c, typeof e != "symbol" ? e + "" : e, r);
4
- import { MERGE_TAGS as f, PAGE_TYPES as p } from "../../enums/unsubscribe.js";
5
- import { UNSUBSCRIBE_BLOCK_SELECTOR as h, DATA_ATTRIBUTES as k } from "../../extensions/Blocks/Unsubscribe/utils/constants.js";
6
- import { useUnsubscribeStore as C } from "../../stores/unsubscribe.js";
7
- class $ {
1
+ var _ = Object.defineProperty;
2
+ var $ = (f, e, t) => e in f ? _(f, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : f[e] = t;
3
+ var k = (f, e, t) => $(f, typeof e != "symbol" ? e + "" : e, t);
4
+ import { MERGE_TAGS as c, PAGE_TYPES as T } from "../../enums/unsubscribe.js";
5
+ import { UNSUBSCRIBE_BLOCK_SELECTOR as y, DATA_ATTRIBUTES as d, UNSUBSCRIBE_MERGE_TAG_REGEX as h } from "../../extensions/Blocks/Unsubscribe/utils/constants.js";
6
+ import { swapMergeTagInHref as B } from "../../extensions/Blocks/Unsubscribe/utils/swapMergeTagInHref.js";
7
+ import { parsePageList as P } from "../../extensions/Blocks/Unsubscribe/utils/utils.js";
8
+ import { useUnsubscribeStore as M } from "../../stores/unsubscribe.js";
9
+ import { escapeHtml as A } from "../../utils/htmlEscape.js";
10
+ const S = "unsubscribe", N = "You can ", R = " from our emails, if you need to.", C = "{-{-UNSUBSCRIBE-LINK-}-}";
11
+ class H {
8
12
  constructor() {
9
- A(this, "parser");
13
+ k(this, "parser");
10
14
  this.parser = new DOMParser();
11
15
  }
12
16
  async migrate(e) {
13
17
  try {
14
- const r = this.parser.parseFromString(e, "text/html"), t = r.querySelectorAll("td.unsubscribe-block");
15
- if (t.length) {
16
- const s = C();
17
- await s.fetchTemplates(), this.migrateLegacyBlocks(t, s);
18
+ const t = this.parser.parseFromString(e, "text/html"), r = t.querySelectorAll("td.unsubscribe-block");
19
+ if (r.length) {
20
+ const i = M();
21
+ await i.fetchTemplates(), this.migrateLegacyBlocks(r, i, this.collectBlockTags(t, i));
18
22
  }
19
- const n = this.repairUnsubscribeLinks(r);
20
- return !t.length && !n ? e : r.documentElement.outerHTML;
21
- } catch (r) {
22
- return console.error("UnsubscribeMigrator failed:", r), e;
23
+ const s = this.repairUnsubscribeLinks(t);
24
+ return !r.length && !s ? e : t.documentElement.outerHTML;
25
+ } catch (t) {
26
+ return console.error("UnsubscribeMigrator failed:", t), e;
23
27
  }
24
28
  }
25
- migrateLegacyBlocks(e, r) {
26
- e.forEach((t) => {
27
- const n = t.getAttribute("id"), s = this.extractPaddingClass(t), l = t.getAttribute("bgcolor") || "", a = this.extractUnsubscribeContent(t), o = this.getCollectionTypeFromMergeTag(a.linkHref), b = r.getSelectedUnsubscribePagesByCollection(o);
29
+ migrateLegacyBlocks(e, t, r) {
30
+ e.forEach((s) => {
31
+ const i = s.getAttribute("id"), n = this.extractPaddingClass(s), o = s.getAttribute("bgcolor") || "", a = this.extractUnsubscribeContent(s, r), b = this.getCollectionTypeFromMergeTag(a.linkHref), u = t.getSelectedUnsubscribePagesByCollection(b);
28
32
  console.debug("[UnsubscribeMigrator]", {
29
33
  mergeTag: a.linkHref,
30
- collectionType: o,
31
- pageIds: b,
32
- paddingClass: s,
33
- bgColor: l
34
+ collectionType: b,
35
+ pageIds: u,
36
+ paddingClass: n,
37
+ bgColor: o
34
38
  });
35
- const u = this.buildUnsubscribeBlock(
39
+ const l = this.buildUnsubscribeBlock(
36
40
  a,
37
- o,
38
41
  b,
39
- s,
40
- l
41
- ), i = this.parser.parseFromString(
42
- `<table id="tempDoc"><tbody><tr>${u}</tr></tbody></table>`,
42
+ u,
43
+ n,
44
+ o
45
+ ), g = this.parser.parseFromString(
46
+ `<table id="tempDoc"><tbody><tr>${l}</tr></tbody></table>`,
43
47
  "text/html"
44
- ).querySelector(h);
45
- i && t.parentNode && (i.setAttribute("id", n || ""), t.parentNode.replaceChild(i, t));
48
+ ).querySelector(y);
49
+ g && s.parentNode && (g.setAttribute("id", i || ""), s.parentNode.replaceChild(g, s));
46
50
  });
47
51
  }
52
+ // The compiler resolves a typed tag only through a block that lists pages, so a page-less block carries no tag.
53
+ collectBlockTags(e, t) {
54
+ const r = /* @__PURE__ */ new Set();
55
+ return e.querySelectorAll(y).forEach((s) => {
56
+ var a, b, u;
57
+ if (!P(s.getAttribute(d.PAGE_LIST) || "").length)
58
+ return;
59
+ const i = Number(s.getAttribute(d.PAGE_TYPE)), n = c[i];
60
+ if (n) {
61
+ r.add(n);
62
+ return;
63
+ }
64
+ const o = (u = (b = (a = this.findLinkCandidates(s).primary) == null ? void 0 : a.getAttribute("href")) == null ? void 0 : b.match(h)) == null ? void 0 : u[0];
65
+ o && r.add(c[this.getCollectionTypeFromMergeTag(o)]);
66
+ }), e.querySelectorAll("td.unsubscribe-block").forEach((s) => {
67
+ const i = this.getCollectionTypeFromMergeTag(this.getLegacyLinkTag(s));
68
+ t.getSelectedUnsubscribePagesByCollection(i).length && r.add(c[i]);
69
+ }), r;
70
+ }
71
+ // Mirrors extractUnsubscribeContent: without a <p> the block migrates on the default tag.
72
+ getLegacyLinkTag(e) {
73
+ var r, s;
74
+ const { primary: t } = this.findLinkCandidates(e);
75
+ return !t || !(t.closest("p") || e.querySelector("p")) ? c.default : ((s = (r = t.getAttribute("href")) == null ? void 0 : r.match(h)) == null ? void 0 : s[0]) ?? c.default;
76
+ }
48
77
  // Re-derives the typed merge tag from data-unsubscribe-page-type for any v2
49
78
  // block whose anchor href is missing or the legacy default. Returns true when
50
79
  // at least one href was rewritten. Typed tags and custom URLs are left intact.
51
80
  repairUnsubscribeLinks(e) {
52
- const r = e.querySelectorAll(`${h}[${k.PAGE_TYPE}]`);
53
- let t = !1;
54
- return r.forEach((n) => {
55
- const s = n.querySelector('a[data-unsubscribe-link="true"], a.unsubscribe-link');
56
- if (!s)
81
+ const t = e.querySelectorAll(`${y}[${d.PAGE_TYPE}]`);
82
+ let r = !1;
83
+ return t.forEach((s) => {
84
+ const i = s.querySelector('a[data-unsubscribe-link="true"], a.unsubscribe-link');
85
+ if (!i)
57
86
  return;
58
- const l = s.getAttribute("href") || "";
59
- if (l && l !== f.default)
87
+ const n = i.getAttribute("href") || "";
88
+ if (n && n !== c.default)
60
89
  return;
61
- const a = Number(n.getAttribute(k.PAGE_TYPE)), o = f[a];
62
- o && (s.setAttribute("href", o), t = !0);
63
- }), t;
90
+ const o = Number(s.getAttribute(d.PAGE_TYPE)), a = c[o];
91
+ a && (i.setAttribute("href", a), r = !0);
92
+ }), r;
64
93
  }
65
94
  extractPaddingClass(e) {
66
- const t = (e.getAttribute("class") || "").match(/\bes-p\d+\b/);
67
- return t ? t[0] : "";
95
+ const r = (e.getAttribute("class") || "").match(/\bes-p\d+\b/);
96
+ return r ? r[0] : "";
97
+ }
98
+ hasVisibleContent(e) {
99
+ var t;
100
+ return !!((t = e.textContent) != null && t.trim() || e.querySelector("img"));
101
+ }
102
+ findLinkCandidates(e) {
103
+ const t = Array.from(/* @__PURE__ */ new Set([
104
+ ...Array.from(e.querySelectorAll("a.unsubscribe-link")),
105
+ ...Array.from(e.querySelectorAll('a[href*="unsubscribe"]'))
106
+ ])), r = (n) => h.test(n.getAttribute("href") || ""), s = (n) => this.hasVisibleContent(n), i = t.find((n) => s(n) && r(n)) ?? t.find((n) => s(n) && n.classList.contains("unsubscribe-link")) ?? t.find(r) ?? t.find(s) ?? t[0];
107
+ return { candidates: t, primary: i };
68
108
  }
69
- extractUnsubscribeContent(e) {
70
- var d;
71
- const r = e.querySelector("a.unsubscribe-link") || e.querySelector('a[href*="unsubscribe"]'), t = (r == null ? void 0 : r.closest("p")) || e.querySelector("p");
72
- if (!t)
73
- return {
74
- textBefore: "You can ",
75
- linkText: "unsubscribe",
76
- linkHref: "{{ins-unsubscribe-link}}",
77
- linkStyle: "",
78
- textAfter: " from our emails, if you need to.",
79
- isBold: !1,
80
- isItalic: !1,
81
- align: "center",
82
- paragraphStyle: ""
83
- };
84
- const n = e.getAttribute("align") || t.getAttribute("align") || "center", s = t.getAttribute("style") || "";
85
- if (!r)
86
- return {
87
- textBefore: "You can ",
88
- linkText: "unsubscribe",
89
- linkHref: "{{ins-unsubscribe-link}}",
90
- linkStyle: "",
91
- textAfter: " from our emails, if you need to.",
92
- isBold: !1,
93
- isItalic: !1,
94
- align: n,
95
- paragraphStyle: s
96
- };
97
- const l = ((d = r.textContent) == null ? void 0 : d.trim()) || "unsubscribe", a = r.getAttribute("href") || "{{ins-unsubscribe-link}}", o = r.getAttribute("style") || "", b = t.textContent || "", u = b.indexOf(l), g = u >= 0 ? b.substring(0, u).trim() : "You can ", i = u >= 0 ? b.substring(u + l.length).trim() : " from our emails, if you need to.", m = !!t.querySelector("b, strong"), y = !!t.querySelector("i, em");
98
- return {
99
- textBefore: g,
100
- linkText: l,
101
- linkHref: this.normalizeUnsubscribeHref(a),
102
- linkStyle: o,
103
- textAfter: i,
104
- isBold: m,
105
- isItalic: y,
106
- align: n,
107
- paragraphStyle: s
109
+ extractUnsubscribeContent(e, t) {
110
+ const r = e.cloneNode(!0), { candidates: s, primary: i } = this.findLinkCandidates(r), n = (i == null ? void 0 : i.closest("p")) ?? null, o = n || r.querySelector("p"), a = {
111
+ footerHtml: "",
112
+ linkText: S,
113
+ linkHref: c.default,
114
+ linkStyle: "",
115
+ align: "center",
116
+ paragraphStyle: ""
108
117
  };
118
+ if (!o || (a.align = e.getAttribute("align") || o.getAttribute("align") || "center", n || (a.paragraphStyle = o.getAttribute("style") || ""), !i))
119
+ return a;
120
+ a.linkText = this.hasVisibleContent(i) ? i.innerHTML.trim() : S, a.linkHref = this.normalizeUnsubscribeHref(i.getAttribute("href") || c.default), a.linkStyle = i.getAttribute("style") || "";
121
+ const b = this.getCollectionTypeFromMergeTag(a.linkHref), u = c[b];
122
+ return r.querySelectorAll("a[href]").forEach((l) => {
123
+ var m;
124
+ const p = l.getAttribute("href") || "", g = (m = p.match(h)) == null ? void 0 : m[0];
125
+ g && l.setAttribute("href", B(p, t.has(g) ? g : u));
126
+ }), s.filter((l) => l !== i && !this.hasVisibleContent(l)).forEach((l) => l.replaceWith(...Array.from(l.childNodes))), i.replaceWith(r.ownerDocument.createTextNode(C)), a.footerHtml = r.innerHTML.trim(), a;
109
127
  }
110
- buildUnsubscribeBlock(e, r, t, n, s) {
111
- const l = e.linkStyle ? ` style="${e.linkStyle}"` : "", u = `<a ${`href="${Object.values(f).includes(e.linkHref) ? f[r] : e.linkHref}" class="unsubscribe-link" target="_blank" data-unsubscribe-link="true"`}${l}>${e.linkText}</a>`, g = [];
112
- e.textBefore && g.push(e.textBefore), g.push(u), e.textAfter && g.push(e.textAfter);
113
- let i = g.join(" ");
114
- e.isBold && e.isItalic ? i = `<strong path="1,0"><em path="1,0,0">${i}</em></strong>` : e.isBold ? i = `<strong path="1,0">${i}</strong>` : e.isItalic && (i = `<em path="1,0">${i}</em>`);
115
- const m = e.align ? ` align="${e.align}"` : "", y = s ? ` bgcolor="${s}"` : "", d = e.paragraphStyle ? ` style="${e.paragraphStyle}"` : "", T = t.length > 0 ? ` ${k.PAGE_LIST}="${t.join(",")}"` : "", E = ` ${k.PAGE_TYPE}="${r}"`, S = "esd-block-text unsubscribe-block-v2 esd-block-unsubscribe esd-unsubscribe-block esd-extension-block";
128
+ buildUnsubscribeBlock(e, t, r, s, i) {
129
+ const n = e.linkStyle ? ` style="${A(e.linkStyle)}"` : "", a = Object.values(c).includes(e.linkHref) ? c[t] : e.linkHref, u = `<a ${`href="${A(a)}" class="unsubscribe-link" target="_blank" data-unsubscribe-link="true"`}${n}>${e.linkText}</a>`, l = e.paragraphStyle ? ` style="${A(e.paragraphStyle)}"` : "", p = e.footerHtml ? e.footerHtml.replace(C, () => u) : `<p path="1"${l}>${N}${u}${R}</p>`, g = e.align ? ` align="${e.align}"` : "", m = i ? ` bgcolor="${i}"` : "", L = r.length > 0 ? ` ${d.PAGE_LIST}="${r.join(",")}"` : "", U = ` ${d.PAGE_TYPE}="${t}"`, E = "esd-block-text unsubscribe-block-v2 esd-block-unsubscribe esd-unsubscribe-block esd-extension-block";
116
130
  return `
117
131
  <td
118
132
  data-migration="true"
119
133
  esd-extension-block-id="unsubscribe-block"
120
- class="${n ? `${S} ${n}` : S}"
121
- ${m}${y}${E}${T}
134
+ class="${s ? `${E} ${s}` : E}"
135
+ ${g}${m}${U}${L}
122
136
  >
123
- <p path="1"${d}>
124
- ${i}
125
- </p>
137
+ ${p}
126
138
  </td>
127
139
  `;
128
140
  }
129
141
  getCollectionTypeFromMergeTag(e) {
130
- return e === f[p.SUBSCRIPTION_PREFERENCE_CENTER] ? p.SUBSCRIPTION_PREFERENCE_CENTER : e === f[p.GLOBAL_UNSUBSCRIBE] ? p.GLOBAL_UNSUBSCRIBE : p.GLOBAL_UNSUBSCRIBE;
142
+ return e === c[T.SUBSCRIPTION_PREFERENCE_CENTER] ? T.SUBSCRIPTION_PREFERENCE_CENTER : e === c[T.GLOBAL_UNSUBSCRIBE] ? T.GLOBAL_UNSUBSCRIBE : T.GLOBAL_UNSUBSCRIBE;
131
143
  }
132
144
  normalizeUnsubscribeHref(e) {
133
- if (Object.values(f).includes(e))
145
+ if (Object.values(c).includes(e))
134
146
  return e;
135
- const t = e.match(/{{ins-(?:global-)?(?:preferences-)?unsubscribe-link}}/);
136
- return t ? t[0] : e.includes("unsubscribe") || e.includes("unsub") ? (console.warn(
147
+ const r = e.match(/{{ins-(?:global-)?(?:preferences-)?unsubscribe-link}}/);
148
+ return r ? r[0] : e.includes("unsubscribe") || e.includes("unsub") ? (console.warn(
137
149
  `[UnsubscribeMigrator] Unrecognized unsubscribe href format: "${e}". Defaulting to {{ins-unsubscribe-link}}`
138
150
  ), "{{ins-unsubscribe-link}}") : e;
139
151
  }
140
152
  }
141
- async function M(c) {
142
- return new $().migrate(c);
153
+ async function Y(f) {
154
+ return new H().migrate(f);
143
155
  }
144
156
  export {
145
- M as migrateUnsubscribe
157
+ Y as migrateUnsubscribe
146
158
  };
@@ -27,13 +27,12 @@ const e = 20, t = 320, s = "vertical", m = {
27
27
  ID: /recommendation-id="(.*?)"/gi,
28
28
  ATTRIBUTE_PARAGRAPH: /<p[^>]*?product-attr="(discount|omnibus_discount|omnibus_price)"[^>]*>[\S\s]*?<\/p>/gm,
29
29
  ATTRIBUTE_PARAGRAPH_START_TAG: /<p[^>]*?product-attr="(discount|omnibus_discount|omnibus_price)"[^>]*>/gm,
30
- COMPOSITION: /composition="true"/gm,
31
30
  CUSTOM_FIELD: /{{(?:reco_)?[0-9]+_[0-8]_(discount|omnibus_discount|omnibus_price)}}/gm,
32
31
  CUSTOM_FIELD_INDEXES_PART: /{{(?:reco_)?[0-9]+_[0-8]_/gm,
33
32
  CUSTOM_FIELD_NAME_PART: /_(discount|omnibus_discount|omnibus_price)}}/gm
34
- }, o = {
35
- PARAGRAPH_END_TAG: "</p>"
36
33
  }, a = {
34
+ PARAGRAPH_END_TAG: "</p>"
35
+ }, o = {
37
36
  REGULAR_NAME_HEIGHT: ".ext-product-name.ins-vertical p { height:90px!important;",
38
37
  TRIMMED_NAME_HEIGHT: ".ext-product-name.ins-vertical p { height:18px!important;",
39
38
  ELLIPSIS: "text-overflow:ellipsis!important; white-space:nowrap!important;",
@@ -47,10 +46,10 @@ const e = 20, t = 320, s = "vertical", m = {
47
46
  export {
48
47
  i as ATTRIBUTES,
49
48
  _ as CONDITIONS,
50
- a as CSS,
49
+ o as CSS,
51
50
  m as DUMMY_IMAGE_MAPPINGS,
52
51
  e as DefaultPadding,
53
- o as HTML,
52
+ a as HTML,
54
53
  t as MinDeviceViewport,
55
54
  n as REGEX,
56
55
  s as VerticalOrientation
@@ -1,79 +1,97 @@
1
- import { EditorStatePropertyType as E, PreviewDeviceMode as I, ModificationDescription as h } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
- import { createImageMarginsControl as M, createImageSizeControl as C } from "../../../controlFactories.js";
1
+ import { EditorStatePropertyType as M, PreviewDeviceMode as I, ModificationDescription as g } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
+ import { createImageMarginsControl as C, createImageSizeControl as O } from "../../../controlFactories.js";
3
3
  import { RecommendationBlockId as c } from "../../constants/blockIds.js";
4
- import { RecommendationControlId as g } from "../../constants/controlIds.js";
5
- import { BLOCK_ROOT_SELECTOR as l } from "../../constants/selectors.js";
6
- import { hasGetStyle as a, hasGetAttribute as O } from "../../utils/tagName.js";
7
- const R = { width: "", height: "auto", "max-height": "" }, f = `${l} img.adapt-img`, x = `*${l.slice(1)}`, p = `@media only screen and (max-width: 600px) { ${f} { max-height: none !important; } }`;
8
- function _(t) {
4
+ import { RecommendationControlId as f } from "../../constants/controlIds.js";
5
+ import { BLOCK_ROOT_SELECTOR as l, MOBILE_CONTAINER_SELECTOR as R } from "../../constants/selectors.js";
6
+ import { hasGetStyle as a, hasGetAttribute as T } from "../../utils/tagName.js";
7
+ const _ = { width: "", height: "auto", "max-height": "" }, E = `${l} img.adapt-img`, b = `*${l.slice(1)}`, p = `@media only screen and (max-width: 600px) { ${E} { max-height: none !important; } }`;
8
+ function x(t) {
9
9
  return { width: "auto", height: "auto", "max-height": `${t}px` };
10
10
  }
11
11
  function A(t) {
12
- return t.querySelectorAll(x).some((e) => "getSelector" in e && e.getSelector() === f);
12
+ return t.querySelectorAll(b).some((e) => "getSelector" in e && e.getSelector() === E);
13
13
  }
14
- function T(t, e) {
15
- return a(t) && Object.entries(e).some(([o, n]) => (t.getStyle(o) ?? "") !== n);
14
+ function B(t, e) {
15
+ return a(t) && Object.entries(e).some(([o, i]) => (t.getStyle(o) ?? "") !== i);
16
16
  }
17
17
  function S(t) {
18
18
  const e = t.getDocumentRootCssNode();
19
19
  return e && !A(e) ? e : null;
20
20
  }
21
- function H(t, e) {
22
- const n = e.querySelectorAll("img").some((r) => a(r) && !!r.getStyle("max-height")) ? S(t) : null;
23
- if (!n)
21
+ function U(t, e) {
22
+ const i = e.querySelectorAll("img").some((r) => a(r) && !!r.getStyle("max-height")) ? S(t) : null;
23
+ if (!i)
24
24
  return;
25
- const i = t.getDocumentModifier();
26
- i.modifyCss(n).appendRule(p), i.apply(new h("Add the reco image mobile fit rule"));
25
+ const n = t.getDocumentModifier();
26
+ n.modifyCss(i).appendRule(p), n.apply(new g("Add the reco image mobile fit rule"));
27
27
  }
28
- const B = `[esd-extension-block-id="${c.IMAGE}"]`, L = /^\d+px$/;
28
+ const L = `[esd-extension-block-id="${c.IMAGE}"]`, v = /^\d+px$/;
29
29
  function y(t) {
30
- return O(t) && Number(t.getAttribute("height")) || 0;
30
+ return T(t) && Number(t.getAttribute("height")) || 0;
31
31
  }
32
- function b(t) {
32
+ function w(t) {
33
33
  const e = y(t), o = a(t) ? t.getStyle("max-height") ?? "" : "";
34
- return L.test(o) && e > 0 && o !== `${e}px`;
34
+ return v.test(o) && e > 0 && o !== `${e}px`;
35
35
  }
36
- function U(t, e) {
37
- const o = e.querySelectorAll(B).map((i) => i.querySelector("img")).filter(b);
36
+ function Z(t, e) {
37
+ const o = e.querySelectorAll(L).map((n) => n.querySelector("img")).filter(w);
38
38
  if (!o.length)
39
39
  return;
40
- const n = t.getDocumentModifier();
41
- o.forEach((i) => n.modifyHtml(i).setStyle("max-height", `${y(i)}px`)), n.apply(new h("Sync the reco image height bound").asHidden());
40
+ const i = t.getDocumentModifier();
41
+ o.forEach((n) => i.modifyHtml(n).setStyle("max-height", `${y(n)}px`)), i.apply(new g("Sync the reco image height bound").asHidden());
42
+ }
43
+ function h(t) {
44
+ try {
45
+ return !!t.closest(R);
46
+ } catch {
47
+ return null;
48
+ }
42
49
  }
43
- class D extends C(
44
- g.IMAGE_SIZE,
50
+ class D extends O(
51
+ f.IMAGE_SIZE,
45
52
  c.IMAGE,
46
53
  l
47
54
  ) {
55
+ // Stripo derives the mobile size from rendered targets, and the container hidden in mobile preview renders 0px.
56
+ getTargetNodes(e) {
57
+ const o = super.getTargetNodes(e);
58
+ if (!this.isMobilePreview())
59
+ return o;
60
+ const i = h(e);
61
+ return i === null ? [] : o.filter((n) => h(n) === i);
62
+ }
48
63
  getAdditionalModifications(e) {
49
- if (this.api.getEditorState()[E.previewDeviceMode] === I.MOBILE)
64
+ if (this.isMobilePreview())
50
65
  return;
51
- const o = this.getFitStyles(), n = this.getTargetNodes(e).map((s) => s.querySelector("img")).filter((s) => T(s, o)), i = o["max-height"] ? S(this.api) : null;
52
- if (!n.length && !i)
66
+ const o = this.getFitStyles(), i = this.getTargetNodes(e).map((s) => s.querySelector("img")).filter((s) => B(s, o)), n = o["max-height"] ? S(this.api) : null;
67
+ if (!i.length && !n)
53
68
  return;
54
69
  const r = this.api.getDocumentModifier();
55
- return i && r.modifyCss(i).appendRule(p), n.forEach((s) => {
56
- const m = r.modifyHtml(s);
57
- Object.entries(o).forEach(([u, d]) => {
58
- d ? m.setStyle(u, d) : m.removeStyle(u);
70
+ return n && r.modifyCss(n).appendRule(p), i.forEach((s) => {
71
+ const u = r.modifyHtml(s);
72
+ Object.entries(o).forEach(([d, m]) => {
73
+ m ? u.setStyle(d, m) : u.removeStyle(d);
59
74
  });
60
75
  }), r;
61
76
  }
77
+ isMobilePreview() {
78
+ return this.api.getEditorState()[M.previewDeviceMode] === I.MOBILE;
79
+ }
62
80
  getFitStyles() {
63
81
  const { size: e } = this.api.getValues();
64
- return (e == null ? void 0 : e.type) === "height" && e.value ? _(e.value) : R;
82
+ return (e == null ? void 0 : e.type) === "height" && e.value ? x(e.value) : _;
65
83
  }
66
84
  }
67
- const F = M(
68
- g.IMAGE_MARGINS,
85
+ const N = C(
86
+ f.IMAGE_MARGINS,
69
87
  c.IMAGE,
70
88
  l
71
- ), P = {
89
+ ), j = {
72
90
  size: D,
73
- margins: F
91
+ margins: N
74
92
  };
75
93
  export {
76
- P as ImageControls,
77
- H as ensureMobileFitRule,
78
- U as syncHeightBound
94
+ j as ImageControls,
95
+ U as ensureMobileFitRule,
96
+ Z as syncHeightBound
79
97
  };
@@ -1,48 +1,49 @@
1
- var y = Object.defineProperty;
2
- var I = (c, o, e) => o in c ? y(c, o, { enumerable: !0, configurable: !0, writable: !0, value: e }) : c[o] = e;
3
- var g = (c, o, e) => I(c, typeof o != "symbol" ? o + "" : o, e);
4
- import { useToaster as L } from "../../../composables/useToaster.js";
5
- import { ToasterTypeOptions as C } from "../../../enums/toaster.js";
6
- import { PAGE_TYPES as m } from "../../../enums/unsubscribe.js";
7
- import { useEditorStore as N } from "../../../stores/editor.js";
8
- import { useUnsubscribeStore as a } from "../../../stores/unsubscribe.js";
9
- import { Block as U, BlockCompositionType as R, ContextActionType as f, ModificationDescription as u, BlockType as v } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
10
- import { getDefaultTemplate as D } from "./template.js";
11
- import { UNSUBSCRIBE_BLOCK_SELECTOR as B, DATA_ATTRIBUTES as n, UNSUBSCRIBE_EVENTS as h } from "./utils/constants.js";
12
- import { parsePageList as S } from "./utils/utils.js";
13
- const w = "unsubscribe-block", E = 'a[data-unsubscribe-link="true"]', P = "{{ins-unsubscribe-link}}", x = "https://academy.insiderone.com/docs/adding-unsubscribe-pages-into-emails", G = "Removing the unsubscribe text leaves an empty block, but an active unsubscribe link is required. Undo your last action to restore the text, or delete the unsubscribe block entirely.", M = {
14
- [m.GLOBAL_UNSUBSCRIBE]: "{{ins-global-unsubscribe-link}}",
15
- [m.SUBSCRIPTION_PREFERENCE_CENTER]: "{{ins-preferences-unsubscribe-link}}"
16
- }, O = 3;
17
- let d = null, p = null;
18
- const A = () => {
19
- d && (document.removeEventListener(h.SELECT, d), d = null);
20
- }, T = () => {
21
- p && (document.removeEventListener(h.CANCEL, p), p = null);
22
- }, q = () => {
23
- A(), T();
1
+ var R = Object.defineProperty;
2
+ var v = (l, c, e) => c in l ? R(l, c, { enumerable: !0, configurable: !0, writable: !0, value: e }) : l[c] = e;
3
+ var h = (l, c, e) => v(l, typeof c != "symbol" ? c + "" : c, e);
4
+ import { useToaster as D } from "../../../composables/useToaster.js";
5
+ import { ToasterTypeOptions as w } from "../../../enums/toaster.js";
6
+ import { PAGE_TYPES as B } from "../../../enums/unsubscribe.js";
7
+ import { useEditorStore as G } from "../../../stores/editor.js";
8
+ import { useUnsubscribeStore as u } from "../../../stores/unsubscribe.js";
9
+ import { Block as P, BlockCompositionType as x, ContextActionType as y, ModificationDescription as k, BlockType as M } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
10
+ import { getDefaultTemplate as O } from "./template.js";
11
+ import { UNSUBSCRIBE_BLOCK_SELECTOR as f, DATA_ATTRIBUTES as o, UNSUBSCRIBE_EVENTS as E, UNSUBSCRIBE_MERGE_TAG_REGEX as I } from "./utils/constants.js";
12
+ import { swapMergeTagInHref as q } from "./utils/swapMergeTagInHref.js";
13
+ import { parsePageList as L } from "./utils/utils.js";
14
+ const F = "unsubscribe-block", _ = 'a[data-unsubscribe-link="true"]', C = "{{ins-unsubscribe-link}}", K = "https://academy.insiderone.com/docs/adding-unsubscribe-pages-into-emails", H = "Removing the unsubscribe text leaves an empty block, but an active unsubscribe link is required. Undo your last action to restore the text, or delete the unsubscribe block entirely.", Y = {
15
+ [B.GLOBAL_UNSUBSCRIBE]: "{{ins-global-unsubscribe-link}}",
16
+ [B.SUBSCRIPTION_PREFERENCE_CENTER]: "{{ins-preferences-unsubscribe-link}}"
17
+ }, V = 3;
18
+ let d = null, b = null;
19
+ const N = () => {
20
+ d && (document.removeEventListener(E.SELECT, d), d = null);
21
+ }, U = () => {
22
+ b && (document.removeEventListener(E.CANCEL, b), b = null);
23
+ }, W = () => {
24
+ N(), U();
24
25
  };
25
- class J extends U {
26
+ class se extends P {
26
27
  constructor() {
27
28
  super();
28
- g(this, "currentNode");
29
+ h(this, "currentNode");
29
30
  // Per-block "did this instance have a link last time we saw it?" tracking.
30
31
  // Keyed by the stable `data-unsubscribe-block-id` we assign, because
31
32
  // ImmutableHtmlNode instances are recreated on every document mutation and
32
33
  // can't be used as Map keys directly. A singleton boolean here would be
33
34
  // polluted across blocks since Stripo fires onDocumentChanged per-instance.
34
- g(this, "linkStateByBlockId", /* @__PURE__ */ new Map());
35
+ h(this, "linkStateByBlockId", /* @__PURE__ */ new Map());
35
36
  // Per-block prepend retry counter for the leading text guard (SD-143097).
36
- g(this, "guardAttemptsByBlockId", /* @__PURE__ */ new Map());
37
+ h(this, "guardAttemptsByBlockId", /* @__PURE__ */ new Map());
37
38
  }
38
39
  getId() {
39
- return w;
40
+ return F;
40
41
  }
41
42
  getIcon() {
42
43
  return "unsubscribe-icon";
43
44
  }
44
45
  getBlockCompositionType() {
45
- return R.BLOCK;
46
+ return x.BLOCK;
46
47
  }
47
48
  getName() {
48
49
  return this.api.translate("Unsubscribe Block");
@@ -51,16 +52,16 @@ class J extends U {
51
52
  return this.api.translate("Unsubscribe Block Description");
52
53
  }
53
54
  getTemplate() {
54
- return D();
55
+ return O();
55
56
  }
56
57
  getContextActionsIds() {
57
- return [f.MOVE, f.REMOVE];
58
+ return [y.MOVE, y.REMOVE];
58
59
  }
59
60
  onSelect(e) {
60
- if (this.currentNode = e, N().isPreviewModeOpen)
61
+ if (this.currentNode = e, G().isPreviewModeOpen)
61
62
  return;
62
63
  const t = this._getOrAssignBlockId(e);
63
- t && this.linkStateByBlockId.set(t, this._hasUnsubscribeLink(e)), this._setupSelectEventListener(), this._setupCancelEventListener(t), !("getAttribute" in e && e.getAttribute("data-migration")) && (this._resetStoreState(), t && (a().pendingBlockId = t), this._loadBlockState(e), this._checkExistingBlocks(), this._openDrawer());
64
+ t && this.linkStateByBlockId.set(t, this._hasUnsubscribeLink(e)), this._setupSelectEventListener(), this._setupCancelEventListener(t), !("getAttribute" in e && e.getAttribute("data-migration")) && (this._resetStoreState(), t && (u().pendingBlockId = t), this._loadBlockState(e), this._checkExistingBlocks(), this._openDrawer());
64
65
  }
65
66
  onCreated(e) {
66
67
  this._ensureLeadingTextGuard(e);
@@ -68,7 +69,7 @@ class J extends U {
68
69
  onDocumentInit() {
69
70
  try {
70
71
  const e = this.api.getDocumentRoot();
71
- e && "querySelectorAll" in e && e.querySelectorAll(B).forEach((t) => {
72
+ e && "querySelectorAll" in e && e.querySelectorAll(f).forEach((t) => {
72
73
  this._ensureLeadingTextGuard(t);
73
74
  });
74
75
  } catch {
@@ -79,11 +80,11 @@ class J extends U {
79
80
  const t = this._getOrAssignBlockId(e);
80
81
  if (!t)
81
82
  return;
82
- const s = this._hasUnsubscribeLink(e);
83
- this.linkStateByBlockId.get(t) === !0 && !s && this._warnLinkRemoved(), this.linkStateByBlockId.set(t, s);
83
+ const i = this._hasUnsubscribeLink(e);
84
+ this.linkStateByBlockId.get(t) === !0 && !i && this._warnLinkRemoved(), this.linkStateByBlockId.set(t, i);
84
85
  }
85
86
  onDelete(e) {
86
- q(), this._removeBlockTemplatesFromStore(e), this._resetStoreState();
87
+ W(), this._removeBlockTemplatesFromStore(e), this._resetStoreState();
87
88
  const t = this._readBlockId(e);
88
89
  t && (this.linkStateByBlockId.delete(t), this.guardAttemptsByBlockId.delete(t));
89
90
  }
@@ -95,38 +96,38 @@ class J extends U {
95
96
  _ensureLeadingTextGuard(e) {
96
97
  if (!("querySelector" in e))
97
98
  return;
98
- const t = e.querySelector(E);
99
+ const t = e.querySelector(_);
99
100
  if (!t)
100
101
  return;
101
- let s = t, r = s.parent();
102
+ let i = t, r = i.parent();
102
103
  for (; r && "getTagName" in r && r.getTagName().toLowerCase() !== "p"; )
103
- s = r, r = r.parent();
104
+ i = r, r = r.parent();
104
105
  if (!r || !("getTagName" in r) || r.getTagName().toLowerCase() !== "p")
105
106
  return;
106
- const i = s.previousSibling();
107
- if (!!(i && i.getType() === "text" && i.getTextContent())) {
108
- const b = this._readBlockId(e);
109
- b && this.guardAttemptsByBlockId.delete(b);
107
+ const s = i.previousSibling();
108
+ if (!!(s && s.getType() === "text" && s.getTextContent())) {
109
+ const a = this._readBlockId(e);
110
+ a && this.guardAttemptsByBlockId.delete(a);
110
111
  return;
111
112
  }
112
- const k = this._getOrAssignBlockId(e);
113
- if (!k)
113
+ const g = this._getOrAssignBlockId(e);
114
+ if (!g)
114
115
  return;
115
- const _ = this.guardAttemptsByBlockId.get(k) ?? 0;
116
- if (!(_ >= O)) {
117
- this.guardAttemptsByBlockId.set(k, _ + 1);
116
+ const p = this.guardAttemptsByBlockId.get(g) ?? 0;
117
+ if (!(p >= V)) {
118
+ this.guardAttemptsByBlockId.set(g, p + 1);
118
119
  try {
119
- this.api.getDocumentModifier().modifyHtml(r).prepend("&nbsp;").apply(new u("Ensure unsubscribe link text guard"));
120
- } catch (b) {
121
- console.warn("[UnsubscribeBlock] Failed to ensure link text guard:", b);
120
+ this.api.getDocumentModifier().modifyHtml(r).prepend("&nbsp;").apply(new k("Ensure unsubscribe link text guard"));
121
+ } catch (a) {
122
+ console.warn("[UnsubscribeBlock] Failed to ensure link text guard:", a);
122
123
  }
123
124
  }
124
125
  }
125
126
  _hasUnsubscribeLink(e) {
126
- return "querySelector" in e ? !!e.querySelector(E) : !1;
127
+ return "querySelector" in e ? !!e.querySelector(_) : !1;
127
128
  }
128
129
  _readBlockId(e) {
129
- return "getAttribute" in e ? e.getAttribute(n.BLOCK_ID) : null;
130
+ return "getAttribute" in e ? e.getAttribute(o.BLOCK_ID) : null;
130
131
  }
131
132
  /**
132
133
  * Returns the block's stable id, assigning one via the document modifier if
@@ -140,13 +141,13 @@ class J extends U {
140
141
  return t;
141
142
  if (!("getAttribute" in e))
142
143
  return null;
143
- const s = this._generateNextBlockId();
144
+ const i = this._generateNextBlockId();
144
145
  try {
145
- this.api.getDocumentModifier().modifyHtml(e).setAttribute(n.BLOCK_ID, s).apply(new u(`Assign unsubscribe block id ${s}`));
146
+ this.api.getDocumentModifier().modifyHtml(e).setAttribute(o.BLOCK_ID, i).apply(new k(`Assign unsubscribe block id ${i}`));
146
147
  } catch (r) {
147
148
  return console.warn("[UnsubscribeBlock] Failed to assign block id:", r), null;
148
149
  }
149
- return s;
150
+ return i;
150
151
  }
151
152
  /**
152
153
  * Generates a unique id by scanning the document for the highest existing
@@ -157,10 +158,10 @@ class J extends U {
157
158
  let e = 0;
158
159
  try {
159
160
  const t = this.api.getDocumentRoot();
160
- t && "querySelectorAll" in t && t.querySelectorAll(B).forEach((r) => {
161
+ t && "querySelectorAll" in t && t.querySelectorAll(f).forEach((r) => {
161
162
  if ("getAttribute" in r) {
162
- const i = r.getAttribute(n.BLOCK_ID), l = i ? parseInt(i) : 0;
163
- l > e && (e = l);
163
+ const s = r.getAttribute(o.BLOCK_ID), n = s ? parseInt(s) : 0;
164
+ n > e && (e = n);
164
165
  }
165
166
  });
166
167
  } catch {
@@ -169,14 +170,14 @@ class J extends U {
169
170
  }
170
171
  _warnLinkRemoved() {
171
172
  try {
172
- const { showToaster: e } = L();
173
+ const { showToaster: e } = D();
173
174
  e({
174
- type: C.Warning,
175
- message: this.api.translate(G),
175
+ type: w.Warning,
176
+ message: this.api.translate(H),
176
177
  actionButton: {
177
178
  text: this.api.translate("Visit Academy"),
178
179
  onClick: () => {
179
- window.open(x, "_blank", "noopener,noreferrer");
180
+ window.open(K, "_blank", "noopener,noreferrer");
180
181
  }
181
182
  }
182
183
  });
@@ -185,55 +186,62 @@ class J extends U {
185
186
  }
186
187
  }
187
188
  _setupSelectEventListener() {
188
- A(), d = (e) => {
189
- const t = e, { collectionType: s, selectedPages: r } = t.detail;
190
- this._updateBlock(s, r.join(","));
191
- }, document.addEventListener(h.SELECT, d);
189
+ N(), d = (e) => {
190
+ const t = e, { collectionType: i, selectedPages: r } = t.detail;
191
+ this._updateBlock(i, r.join(","));
192
+ }, document.addEventListener(E.SELECT, d);
192
193
  }
193
194
  _setupCancelEventListener(e) {
194
- T(), p = (t) => {
195
- const { detail: s } = t;
196
- ((s == null ? void 0 : s.blockId) ?? null) === e && this._handleCancel();
197
- }, document.addEventListener(h.CANCEL, p);
195
+ U(), b = (t) => {
196
+ const { detail: i } = t;
197
+ ((i == null ? void 0 : i.blockId) ?? null) === e && this._handleCancel();
198
+ }, document.addEventListener(E.CANCEL, b);
198
199
  }
199
200
  _handleCancel() {
200
201
  try {
201
202
  if (!this.currentNode)
202
203
  return;
203
- this.api.getDocumentModifier().modifyHtml(this.currentNode).replaceWith(`<${v.EMPTY_CONTAINER}/>`).apply(new u("Removed unsubscribe block due to cancel"));
204
+ this.api.getDocumentModifier().modifyHtml(this.currentNode).replaceWith(`<${M.EMPTY_CONTAINER}/>`).apply(new k("Removed unsubscribe block due to cancel"));
204
205
  } catch (e) {
205
206
  console.warn("[UnsubscribeBlock] Failed to remove unsubscribe block:", e);
206
207
  }
207
208
  }
208
209
  _updateBlock(e, t) {
210
+ var a;
209
211
  if (!this.currentNode || !("querySelector" in this.currentNode))
210
212
  return;
211
- const s = this.currentNode.querySelector(E);
212
- if (!s)
213
+ const i = this.currentNode.querySelector(_);
214
+ if (!i)
213
215
  return;
214
- const r = this._getMergeTag(e);
215
- this.api.getDocumentModifier().modifyHtml(s).setAttribute("href", r).apply(new u(`Updated unsubscribe link to ${r}`)), this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute(n.PAGE_TYPE, e.toString()).setAttribute(n.PAGE_LIST, t).apply(new u("Updated unsubscribe block metadata"));
216
+ const r = this._getMergeTag(e), s = this.api.getDocumentModifier(), n = "getAttribute" in i ? i.getAttribute("href") : null, p = [(a = n == null ? void 0 : n.match(I)) == null ? void 0 : a[0], C];
217
+ s.modifyHtml(i).setAttribute("href", r), this.currentNode.querySelectorAll("a[href]").forEach((m) => {
218
+ var T;
219
+ if (!("getAttribute" in m) || m.getAttribute("data-unsubscribe-link") === "true")
220
+ return;
221
+ const S = m.getAttribute("href") ?? "", A = (T = S.match(I)) == null ? void 0 : T[0];
222
+ A && p.includes(A) && s.modifyHtml(m).setAttribute("href", q(S, r));
223
+ }), s.modifyHtml(this.currentNode).setAttribute(o.PAGE_TYPE, e.toString()).setAttribute(o.PAGE_LIST, t), s.apply(new k(`Updated unsubscribe link to ${r}`));
216
224
  }
217
225
  _getMergeTag(e) {
218
- return M[e] ?? P;
226
+ return Y[e] ?? C;
219
227
  }
220
228
  _openDrawer() {
221
229
  if (!(this.currentNode && this.currentNode.getAttribute("data-unsubscribe-page-type")))
222
230
  try {
223
- const e = a();
231
+ const e = u();
224
232
  e.typeSelectionDrawerStatus = !0;
225
233
  } catch (e) {
226
234
  console.error("[UnsubscribeBlock] Failed to open drawer:", e);
227
235
  }
228
236
  }
229
237
  _checkExistingBlocks() {
230
- const e = a();
231
- e.isGlobalUnsubscribeDisabled = !1, e.isSubscriptionPreferencesCenterDisabled = !1, this.api.getDocumentRoot().querySelectorAll(B).forEach((s) => {
232
- if ("getAttribute" in s) {
233
- const r = s.getAttribute(n.PAGE_TYPE);
238
+ const e = u();
239
+ e.isGlobalUnsubscribeDisabled = !1, e.isSubscriptionPreferencesCenterDisabled = !1, this.api.getDocumentRoot().querySelectorAll(f).forEach((i) => {
240
+ if ("getAttribute" in i) {
241
+ const r = i.getAttribute(o.PAGE_TYPE);
234
242
  if (r) {
235
- const i = Number(r);
236
- i === m.GLOBAL_UNSUBSCRIBE ? e.isGlobalUnsubscribeDisabled = !0 : i === m.SUBSCRIPTION_PREFERENCE_CENTER && (e.isSubscriptionPreferencesCenterDisabled = !0);
243
+ const s = Number(r);
244
+ s === B.GLOBAL_UNSUBSCRIBE ? e.isGlobalUnsubscribeDisabled = !0 : s === B.SUBSCRIPTION_PREFERENCE_CENTER && (e.isSubscriptionPreferencesCenterDisabled = !0);
237
245
  }
238
246
  }
239
247
  });
@@ -241,27 +249,27 @@ class J extends U {
241
249
  async _loadBlockState(e) {
242
250
  if (!("getAttribute" in e))
243
251
  return;
244
- const t = e.getAttribute(n.PAGE_TYPE), s = e.getAttribute(n.PAGE_LIST);
245
- if (!t || !s)
252
+ const t = e.getAttribute(o.PAGE_TYPE), i = e.getAttribute(o.PAGE_LIST);
253
+ if (!t || !i)
246
254
  return;
247
- const r = a(), i = Number(t), l = S(s);
248
- await r.fetchTemplates(), r.setCollectionWithoutAutoSelection(i), r.loadSelectedTemplates(l);
255
+ const r = u(), s = Number(t), n = L(i);
256
+ await r.fetchTemplates(), r.setCollectionWithoutAutoSelection(s), r.loadSelectedTemplates(n);
249
257
  }
250
258
  _resetStoreState() {
251
- a().$reset();
259
+ u().$reset();
252
260
  }
253
261
  _removeBlockTemplatesFromStore(e) {
254
262
  if (!("getAttribute" in e))
255
263
  return;
256
- const t = e.getAttribute(n.PAGE_LIST);
264
+ const t = e.getAttribute(o.PAGE_LIST);
257
265
  if (!t)
258
266
  return;
259
- const s = a(), r = S(t);
260
- s.removeUnsubscribePages(r);
267
+ const i = u(), r = L(t);
268
+ i.removeUnsubscribePages(r);
261
269
  }
262
270
  }
263
271
  export {
264
- w as UNSUBSCRIBE_BLOCK_ID,
265
- J as UnsubscribeBlock,
266
- q as disposeUnsubscribeListeners
272
+ F as UNSUBSCRIBE_BLOCK_ID,
273
+ se as UnsubscribeBlock,
274
+ W as disposeUnsubscribeListeners
267
275
  };
@@ -5,10 +5,11 @@ const s = {
5
5
  PAGE_TYPE: "data-unsubscribe-page-type",
6
6
  PAGE_LIST: "data-unsubscribe-page-list",
7
7
  BLOCK_ID: "data-unsubscribe-block-id"
8
- }, c = ".unsubscribe-block-v2", u = 'a[data-unsubscribe-link="true"], a.unsubscribe-link';
8
+ }, e = ".unsubscribe-block-v2", E = /{{ins-(?:global-)?(?:preferences-)?unsubscribe-link}}/, c = 'a[data-unsubscribe-link="true"], a.unsubscribe-link';
9
9
  export {
10
10
  b as DATA_ATTRIBUTES,
11
- c as UNSUBSCRIBE_BLOCK_SELECTOR,
11
+ e as UNSUBSCRIBE_BLOCK_SELECTOR,
12
12
  s as UNSUBSCRIBE_EVENTS,
13
- u as UNSUBSCRIBE_LINK_SELECTOR
13
+ c as UNSUBSCRIBE_LINK_SELECTOR,
14
+ E as UNSUBSCRIBE_MERGE_TAG_REGEX
14
15
  };
@@ -0,0 +1,5 @@
1
+ import { UNSUBSCRIBE_MERGE_TAG_REGEX as E } from "./constants.js";
2
+ const o = (r, p) => r.replace(E, () => p).replace(`${p}?`, () => `${p}&`);
3
+ export {
4
+ o as swapMergeTagInHref
5
+ };
@@ -1,9 +1,9 @@
1
- const o = "3.27.0", s = { stripo: { version: "2.83.1" } }, n = {
1
+ const o = "3.27.1-beta.842075e", s = { stripo: { version: "2.86.1" } }, e = {
2
2
  version: o,
3
3
  guido: s
4
4
  };
5
5
  export {
6
- n as default,
6
+ e as default,
7
7
  s as guido,
8
8
  o as version
9
9
  };
@@ -8,10 +8,6 @@ type CardWidthParams = {
8
8
  interface CampaignData extends CardWidthParams {
9
9
  textTrimming: boolean;
10
10
  orientation: string;
11
- priceBeforeTextValue: string;
12
- priceAfterTextValue: string;
13
- discountBeforeTextValue: string;
14
- discountAfterTextValue: string;
15
11
  }
16
12
  export declare const useRecommendation: () => {
17
13
  calculateCardWidth: ({ mobileLeftPadding, mobileRightPadding, cardsInRow, unresponsive, }: CardWidthParams) => number;
@@ -33,7 +33,6 @@ export declare const REGEX: {
33
33
  ID: RegExp;
34
34
  ATTRIBUTE_PARAGRAPH: RegExp;
35
35
  ATTRIBUTE_PARAGRAPH_START_TAG: RegExp;
36
- COMPOSITION: RegExp;
37
36
  CUSTOM_FIELD: RegExp;
38
37
  CUSTOM_FIELD_INDEXES_PART: RegExp;
39
38
  CUSTOM_FIELD_NAME_PART: RegExp;
@@ -25,7 +25,9 @@ declare const SizeControl_base: {
25
25
  };
26
26
  };
27
27
  declare class SizeControl extends SizeControl_base {
28
+ getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
28
29
  getAdditionalModifications(root: ImmutableHtmlNode): TemplateModifier<HtmlNodeModifier, CssNodeModifier> | undefined;
30
+ private isMobilePreview;
29
31
  private getFitStyles;
30
32
  }
31
33
  /**
@@ -9,4 +9,5 @@ export declare const DATA_ATTRIBUTES: {
9
9
  readonly BLOCK_ID: "data-unsubscribe-block-id";
10
10
  };
11
11
  export declare const UNSUBSCRIBE_BLOCK_SELECTOR = ".unsubscribe-block-v2";
12
+ export declare const UNSUBSCRIBE_MERGE_TAG_REGEX: RegExp;
12
13
  export declare const UNSUBSCRIBE_LINK_SELECTOR = "a[data-unsubscribe-link=\"true\"], a.unsubscribe-link";
@@ -0,0 +1 @@
1
+ export declare const swapMergeTagInHref: (href: string, mergeTag: string) => string;
@@ -1,9 +1,9 @@
1
- const s = "2.83.1", n = ["UIEditor.js", "zone.js", "styles-BWH3PMR4.css", "polyfills-FF3RLU5F.js", "main-OTN2PYRT.js", "chunk-62K3AMOD.js", "chunk-6RGJBGUG.js", "chunk-6W43DTQG.js", "chunk-EC4WGEOZ.js", "chunk-GLBBUJ54.js", "chunk-GPJLJCMF.js", "chunk-MDCDEJUH.js", "chunk-P7HQTFJV.js", "chunk-PA4WGBC4.js", "chunk-QMDAV6OU.js", "chunk-R2F3ADM2.js", "chunk-YSKQ2TWF.js", "chunk-ZU5ASRKR.js", "assets/css/uiEditor.css", "assets/i18n/en.json", "assets/icons/ui-editor-icons.sprite.svg", "assets/icons/ui-editor-icons.map.json", "assets/imageeditor/scripts.min.js", "assets/imageeditor/assets/icons/merged.svg"], i = {
1
+ const s = "2.86.1", n = ["UIEditor.js", "zone.js", "styles-BWH3PMR4.css", "polyfills-FF3RLU5F.js", "main-QEKXZ3YR.js", "chunk-5T7CEBI5.js", "chunk-62K3AMOD.js", "chunk-66LFOY5U.js", "chunk-AMCKJHBC.js", "chunk-BOERNIOQ.js", "chunk-BVZUBVXH.js", "chunk-I2DLD5I4.js", "chunk-IEC5XOV2.js", "chunk-ILRQX7FO.js", "chunk-LBYVYY25.js", "chunk-LC3XAPU2.js", "chunk-OZSNTS6D.js", "chunk-PBUSX63H.js", "chunk-PYISBD2D.js", "assets/css/uiEditor.css", "assets/i18n/en.json", "assets/icons/ui-editor-icons.sprite.svg", "assets/icons/ui-editor-icons.map.json", "assets/imageeditor/scripts.min.js", "assets/imageeditor/assets/icons/merged.svg"], c = {
2
2
  version: s,
3
3
  files: n
4
4
  };
5
5
  export {
6
- i as default,
6
+ c as default,
7
7
  n as files,
8
8
  s as version
9
9
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "3.27.0",
3
+ "version": "3.27.1-beta.842075e",
4
4
  "description": "Guido is a Vue + TypeScript wrapper for Email Plugin. Easily embed the email editor in your Vue applications.",
5
5
  "main": "./dist/guido.umd.cjs",
6
6
  "module": "./dist/library.js",
@@ -136,7 +136,7 @@
136
136
  },
137
137
  "guido": {
138
138
  "stripo": {
139
- "version": "2.83.1"
139
+ "version": "2.86.1"
140
140
  }
141
141
  }
142
142
  }