@useinsider/guido 3.27.0-beta.ee85b86 → 3.27.1-beta.4ca8aae
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -10
- package/dist/components/Guido.vue.js +7 -7
- package/dist/components/Guido.vue2.js +83 -86
- package/dist/composables/useHtmlCompiler.js +8 -9
- package/dist/composables/useModuleRepair.js +32 -63
- package/dist/composables/useStripo.js +43 -44
- package/dist/config/compiler/htmlCompilerRules.js +6 -16
- package/dist/config/migrator/unsubscribeMigrator.js +112 -100
- package/dist/extensions/Blocks/Recommendation/controls/image/index.js +58 -40
- package/dist/extensions/Blocks/Unsubscribe/block.js +104 -96
- package/dist/extensions/Blocks/Unsubscribe/utils/constants.js +4 -3
- package/dist/extensions/Blocks/Unsubscribe/utils/swapMergeTagInHref.js +5 -0
- package/dist/guido.css +1 -1
- package/dist/package.json.js +3 -3
- package/dist/src/@types/generic.d.ts +0 -7
- package/dist/src/composables/useModuleRepair.d.ts +0 -6
- package/dist/src/extensions/Blocks/Recommendation/controls/image/index.d.ts +2 -0
- package/dist/src/extensions/Blocks/Unsubscribe/utils/constants.d.ts +1 -0
- package/dist/src/extensions/Blocks/Unsubscribe/utils/swapMergeTagInHref.d.ts +1 -0
- package/dist/src/utils/dynamicContentConverter.d.ts +18 -20
- package/dist/src/utils/genericUtil.d.ts +8 -4
- package/dist/static/stripo-runtime-manifest.json.js +2 -2
- package/dist/utils/dynamicContentConverter.js +27 -41
- package/dist/utils/genericUtil.js +39 -39
- package/dist/utils/templatePreparation.js +9 -9
- package/package.json +2 -2
- package/dist/components/organisms/dynamic-content/AmbiguousDynamicContentModal.vue.js +0 -24
- package/dist/components/organisms/dynamic-content/AmbiguousDynamicContentModal.vue2.js +0 -59
- package/dist/composables/useAmbiguousDynamicContent.js +0 -72
- package/dist/enums/dynamic-content.js +0 -4
- package/dist/src/components/organisms/dynamic-content/AmbiguousDynamicContentModal.vue.d.ts +0 -2
- package/dist/src/composables/useAmbiguousDynamicContent.d.ts +0 -7
- package/dist/src/enums/dynamic-content.d.ts +0 -3
- package/dist/src/stores/module-dynamic-content.d.ts +0 -30
- package/dist/src/utils/dynamicContentPendingMarker.d.ts +0 -2
- package/dist/stores/module-dynamic-content.js +0 -20
- package/dist/utils/dynamicContentPendingMarker.js +0 -6
|
@@ -1,52 +1,51 @@
|
|
|
1
|
-
import { useActionsApi as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { useConfig as G } from "./useConfig.js";
|
|
1
|
+
import { useActionsApi as N } from "./useActionsApi.js";
|
|
2
|
+
import { useBlocksConfig as j } from "./useBlocksConfig.js";
|
|
3
|
+
import { useConfig as z } from "./useConfig.js";
|
|
5
4
|
import { useCustomInterfaceAppearance as v } from "./useCustomInterfaceAppearance.js";
|
|
6
|
-
import { useFullStoryBridge as
|
|
7
|
-
import { useModuleRepair as
|
|
8
|
-
import { useStripoEventHandler as
|
|
9
|
-
import { useStripoNotifications as
|
|
10
|
-
import { useToaster as
|
|
11
|
-
import { localePatch as
|
|
5
|
+
import { useFullStoryBridge as $ } from "./useFullStoryBridge.js";
|
|
6
|
+
import { useModuleRepair as G } from "./useModuleRepair.js";
|
|
7
|
+
import { useStripoEventHandler as X } from "./useStripoEventHandler.js";
|
|
8
|
+
import { useStripoNotifications as J } from "./useStripoNotifications.js";
|
|
9
|
+
import { useToaster as K } from "./useToaster.js";
|
|
10
|
+
import { localePatch as Q } from "../config/i18n/index.js";
|
|
12
11
|
import { en as B } from "../config/i18n/en/index.js";
|
|
13
|
-
import { ToasterTypeOptions as
|
|
14
|
-
import { useStripoApi as
|
|
15
|
-
import
|
|
12
|
+
import { ToasterTypeOptions as W } from "../enums/toaster.js";
|
|
13
|
+
import { useStripoApi as Y } from "../services/stripoApi.js";
|
|
14
|
+
import Z from "../static/styles/customEditorStyle.css.js";
|
|
16
15
|
import { useEditorStore as T } from "../stores/editor.js";
|
|
17
|
-
import { buildMergeTagEntries as
|
|
18
|
-
import { getStripoRuntimeBaseUrl as
|
|
16
|
+
import { buildMergeTagEntries as ee, flattenDynamicContentList as te } from "../utils/genericUtil.js";
|
|
17
|
+
import { getStripoRuntimeBaseUrl as oe } from "../utils/stripoRuntime.js";
|
|
19
18
|
let d = null, F = !1;
|
|
20
|
-
const
|
|
21
|
-
const { features: u, template: m, isFeatureEnabled: p } =
|
|
19
|
+
const ke = (t) => {
|
|
20
|
+
const { features: u, template: m, isFeatureEnabled: p } = z(), { handleError: f, showToaster: A } = K(), { getToken: P, getCustomFonts: R, getSyncModulesStatus: U } = Y(), { handleEvent: V } = X(), { handleModuleAdd: D } = G(), { getStripoBlocksConfig: I } = j(), { getStripoNotifications: L } = J(), g = () => d || (d = new Promise((n, a) => {
|
|
22
21
|
if (document.getElementById("UiEditorScript")) {
|
|
23
22
|
n();
|
|
24
23
|
return;
|
|
25
24
|
}
|
|
26
|
-
const i =
|
|
25
|
+
const i = oe();
|
|
27
26
|
if (!i) {
|
|
28
|
-
|
|
27
|
+
a(
|
|
29
28
|
new Error("guido.stripo.version is not set in package.json. Please configure the Stripo version.")
|
|
30
29
|
);
|
|
31
30
|
return;
|
|
32
31
|
}
|
|
33
|
-
const
|
|
34
|
-
e.id = "UiEditorScript", e.type = "module", e.src =
|
|
32
|
+
const s = `${i}UIEditor.js`, e = document.createElement("script");
|
|
33
|
+
e.id = "UiEditorScript", e.type = "module", e.src = s, e.onload = () => {
|
|
35
34
|
F = !0, n();
|
|
36
35
|
}, e.onerror = () => {
|
|
37
|
-
e.remove(),
|
|
36
|
+
e.remove(), a(new Error(`Failed to load Stripo UIEditor script from S3: ${s}`));
|
|
38
37
|
}, document.body.appendChild(e);
|
|
39
38
|
}), d.catch(() => {
|
|
40
39
|
d = null;
|
|
41
|
-
}), d),
|
|
40
|
+
}), d), q = async (n, a, i, s = [], e = !1, c = !1) => {
|
|
42
41
|
var w, k, b, _;
|
|
43
|
-
const o = T(), { html: S, css: y } = n, { baseBlocks: E, extensions:
|
|
42
|
+
const o = T(), { html: S, css: y } = n, { baseBlocks: E, extensions: x } = await I();
|
|
44
43
|
t.mark("blocks_config_ready");
|
|
45
|
-
const h = ((w = u.value) == null ? void 0 : w.displayConditions) ?? !0,
|
|
44
|
+
const h = ((w = u.value) == null ? void 0 : w.displayConditions) ?? !0, O = ((k = u.value) == null ? void 0 : k.modulesDisabled) ?? !1, C = c || (((b = m.value) == null ? void 0 : b.forceRecreate) ?? !1), H = "https://email-static.useinsider.com https://edge.fullstory.com https://rs.fullstory.com";
|
|
46
45
|
t.setTemplate({ html: S, css: y, forceRecreate: C }), v().importCss(), t.mark("init_editor"), await window.UIEditor.initEditor(
|
|
47
46
|
document.querySelector("#guido-editor"),
|
|
48
47
|
{
|
|
49
|
-
metadata:
|
|
48
|
+
metadata: a,
|
|
50
49
|
html: S,
|
|
51
50
|
css: y,
|
|
52
51
|
forceRecreate: C,
|
|
@@ -59,11 +58,11 @@ const ve = (t) => {
|
|
|
59
58
|
customAppearanceMergetags: !p("liquidSyntax"),
|
|
60
59
|
customAppearanceMergetagsBorderColor: "#f1f3fe",
|
|
61
60
|
customAppearanceMergetagsBackgroundColor: "#f1f3fe",
|
|
62
|
-
customViewStyles:
|
|
61
|
+
customViewStyles: Z,
|
|
63
62
|
conditionsEnabled: h,
|
|
64
63
|
customConditionsEnabled: h,
|
|
65
64
|
enableXSSSecurity: !0,
|
|
66
|
-
modulesDisabled:
|
|
65
|
+
modulesDisabled: O,
|
|
67
66
|
syncModulesEnabled: e,
|
|
68
67
|
messageSettingsEnabled: !0,
|
|
69
68
|
displayGmailAnnotations: !0,
|
|
@@ -74,18 +73,18 @@ const ve = (t) => {
|
|
|
74
73
|
copyPasteEnabled: !1,
|
|
75
74
|
selectElementAfterDrop: !0,
|
|
76
75
|
sameFontSizeForOutlook: !0,
|
|
77
|
-
allowedScriptSourceDomains:
|
|
76
|
+
allowedScriptSourceDomains: H,
|
|
78
77
|
...E ? { baseBlocks: E } : {},
|
|
79
78
|
editorFonts: {
|
|
80
79
|
showDefaultStandardFonts: !0,
|
|
81
80
|
showDefaultNotStandardFonts: !0,
|
|
82
|
-
customFonts:
|
|
81
|
+
customFonts: s
|
|
83
82
|
},
|
|
84
83
|
mergeTags: [
|
|
85
84
|
{
|
|
86
|
-
entries:
|
|
85
|
+
entries: ee(
|
|
87
86
|
i.preselectedDynamicContentList,
|
|
88
|
-
|
|
87
|
+
te((_ = m.value) == null ? void 0 : _.dynamicContentList),
|
|
89
88
|
p("liquidSyntax")
|
|
90
89
|
)
|
|
91
90
|
}
|
|
@@ -101,8 +100,8 @@ const ve = (t) => {
|
|
|
101
100
|
},
|
|
102
101
|
onTemplateLoaded() {
|
|
103
102
|
try {
|
|
104
|
-
const { activateCustomViewStyles: r, updateTimerInClonedTemplate: l } =
|
|
105
|
-
v().importCss(), r(),
|
|
103
|
+
const { activateCustomViewStyles: r, updateTimerInClonedTemplate: l } = N(), { injectFullStory: M } = $();
|
|
104
|
+
v().importCss(), r(), M(), l(), i.onReady(), o.isStripoInitialized = !0, o.loadingStatus = !1, setTimeout(() => {
|
|
106
105
|
o.hasChanges = !1;
|
|
107
106
|
}, 1e3), t.markReady();
|
|
108
107
|
} catch (r) {
|
|
@@ -121,9 +120,9 @@ const ve = (t) => {
|
|
|
121
120
|
onDataChanged() {
|
|
122
121
|
o.hasChanges = !0, o.changeSeq += 1;
|
|
123
122
|
},
|
|
124
|
-
onEvent:
|
|
125
|
-
onModuleAdd:
|
|
126
|
-
notifications:
|
|
123
|
+
onEvent: V,
|
|
124
|
+
onModuleAdd: D,
|
|
125
|
+
notifications: L(),
|
|
127
126
|
// Stripo deselects the block on any click outside the canvas, so every surface
|
|
128
127
|
// that belongs to the block's own flow has to be listed here (SD-153273).
|
|
129
128
|
ignoreClickOutsideSelectors: [
|
|
@@ -133,23 +132,23 @@ const ve = (t) => {
|
|
|
133
132
|
".in-modal-v2-wrapper",
|
|
134
133
|
".in-toasts-wrapper"
|
|
135
134
|
],
|
|
136
|
-
extensions:
|
|
137
|
-
localePatch:
|
|
135
|
+
extensions: x,
|
|
136
|
+
localePatch: Q
|
|
138
137
|
}
|
|
139
138
|
);
|
|
140
139
|
};
|
|
141
|
-
return { initPlugin: async (n,
|
|
140
|
+
return { initPlugin: async (n, a, i, s = !1) => {
|
|
142
141
|
const e = T();
|
|
143
142
|
try {
|
|
144
143
|
t.mark("plugin_start"), t.setScriptPreloaded(F), await g(), t.mark("script_ready");
|
|
145
144
|
const [c, o] = await Promise.all([
|
|
146
145
|
R(),
|
|
147
|
-
|
|
146
|
+
U()
|
|
148
147
|
]);
|
|
149
|
-
t.mark("fonts_sync_ready"), e.syncModulesEnabled = o, await
|
|
148
|
+
t.mark("fonts_sync_ready"), e.syncModulesEnabled = o, await q(n, a, i, c, o, s);
|
|
150
149
|
} catch {
|
|
151
150
|
e.loadingStatus = !1, A({
|
|
152
|
-
type:
|
|
151
|
+
type: W.Error,
|
|
153
152
|
message: B["An error has occurred. Please report the error code to support."],
|
|
154
153
|
actionButton: {
|
|
155
154
|
text: B["Reload page"],
|
|
@@ -163,5 +162,5 @@ const ve = (t) => {
|
|
|
163
162
|
} };
|
|
164
163
|
};
|
|
165
164
|
export {
|
|
166
|
-
|
|
165
|
+
ke as useStripo
|
|
167
166
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
const y = [
|
|
1
|
+
import { stripFontTags as c } from "../../utils/stripFontTags.js";
|
|
2
|
+
import { trimHrefWhitespace as l } from "../../utils/trimHrefWhitespace.js";
|
|
3
|
+
const f = [
|
|
5
4
|
{
|
|
6
5
|
id: "fix-url-encoding-start",
|
|
7
6
|
description: "Replace {%22 with %7B%22 to fix URL encoding",
|
|
@@ -60,14 +59,14 @@ const y = [
|
|
|
60
59
|
id: "strip-font-tags",
|
|
61
60
|
description: 'Unwrap browser-translate-injected <font dir="auto"> tags, keeping inner content; other <font> elements are left intact.',
|
|
62
61
|
type: "custom",
|
|
63
|
-
processor: (e) =>
|
|
62
|
+
processor: (e) => c(e),
|
|
64
63
|
priority: 15
|
|
65
64
|
},
|
|
66
65
|
{
|
|
67
66
|
id: "trim-href-whitespace",
|
|
68
67
|
description: "Trim leading/trailing whitespace and from every href value",
|
|
69
68
|
type: "custom",
|
|
70
|
-
processor: (e) =>
|
|
69
|
+
processor: (e) => l(e),
|
|
71
70
|
priority: 16
|
|
72
71
|
},
|
|
73
72
|
{
|
|
@@ -184,15 +183,6 @@ const y = [
|
|
|
184
183
|
flags: "g",
|
|
185
184
|
priority: 45
|
|
186
185
|
},
|
|
187
|
-
{
|
|
188
|
-
id: "remove-dc-pending-marker",
|
|
189
|
-
description: "Strip the editor-only pending dynamic-content choice marker from compiled output",
|
|
190
|
-
type: "regex",
|
|
191
|
-
pattern: c,
|
|
192
|
-
replacement: "",
|
|
193
|
-
flags: "g",
|
|
194
|
-
priority: 46
|
|
195
|
-
},
|
|
196
186
|
{
|
|
197
187
|
id: "remove-script-tags",
|
|
198
188
|
// SD-145051: parity with HB HtmlCleaner.removeUnsafeHtmlTags — strip <script> from
|
|
@@ -218,5 +208,5 @@ const y = [
|
|
|
218
208
|
}
|
|
219
209
|
];
|
|
220
210
|
export {
|
|
221
|
-
|
|
211
|
+
f as defaultHtmlCompilerRules
|
|
222
212
|
};
|
|
@@ -1,146 +1,158 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { MERGE_TAGS as
|
|
5
|
-
import { UNSUBSCRIBE_BLOCK_SELECTOR as
|
|
6
|
-
import {
|
|
7
|
-
|
|
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
|
-
|
|
13
|
+
k(this, "parser");
|
|
10
14
|
this.parser = new DOMParser();
|
|
11
15
|
}
|
|
12
16
|
async migrate(e) {
|
|
13
17
|
try {
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
16
|
-
const
|
|
17
|
-
await
|
|
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
|
|
20
|
-
return !
|
|
21
|
-
} catch (
|
|
22
|
-
return console.error("UnsubscribeMigrator failed:",
|
|
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((
|
|
27
|
-
const
|
|
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:
|
|
31
|
-
pageIds:
|
|
32
|
-
paddingClass:
|
|
33
|
-
bgColor:
|
|
34
|
+
collectionType: b,
|
|
35
|
+
pageIds: u,
|
|
36
|
+
paddingClass: n,
|
|
37
|
+
bgColor: o
|
|
34
38
|
});
|
|
35
|
-
const
|
|
39
|
+
const l = this.buildUnsubscribeBlock(
|
|
36
40
|
a,
|
|
37
|
-
o,
|
|
38
41
|
b,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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(
|
|
45
|
-
|
|
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
|
|
53
|
-
let
|
|
54
|
-
return
|
|
55
|
-
const
|
|
56
|
-
if (!
|
|
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
|
|
59
|
-
if (
|
|
87
|
+
const n = i.getAttribute("href") || "";
|
|
88
|
+
if (n && n !== c.default)
|
|
60
89
|
return;
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
}),
|
|
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
|
|
67
|
-
return
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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,
|
|
111
|
-
const
|
|
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="${
|
|
121
|
-
${
|
|
134
|
+
class="${s ? `${E} ${s}` : E}"
|
|
135
|
+
${g}${m}${U}${L}
|
|
122
136
|
>
|
|
123
|
-
|
|
124
|
-
${i}
|
|
125
|
-
</p>
|
|
137
|
+
${p}
|
|
126
138
|
</td>
|
|
127
139
|
`;
|
|
128
140
|
}
|
|
129
141
|
getCollectionTypeFromMergeTag(e) {
|
|
130
|
-
return e ===
|
|
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(
|
|
145
|
+
if (Object.values(c).includes(e))
|
|
134
146
|
return e;
|
|
135
|
-
const
|
|
136
|
-
return
|
|
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
|
|
142
|
-
return new
|
|
153
|
+
async function Y(f) {
|
|
154
|
+
return new H().migrate(f);
|
|
143
155
|
}
|
|
144
156
|
export {
|
|
145
|
-
|
|
157
|
+
Y as migrateUnsubscribe
|
|
146
158
|
};
|
|
@@ -1,79 +1,97 @@
|
|
|
1
|
-
import { EditorStatePropertyType as
|
|
2
|
-
import { createImageMarginsControl as
|
|
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
|
|
5
|
-
import { BLOCK_ROOT_SELECTOR as l } from "../../constants/selectors.js";
|
|
6
|
-
import { hasGetStyle as a, hasGetAttribute as
|
|
7
|
-
const
|
|
8
|
-
function
|
|
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(
|
|
12
|
+
return t.querySelectorAll(b).some((e) => "getSelector" in e && e.getSelector() === E);
|
|
13
13
|
}
|
|
14
|
-
function
|
|
15
|
-
return a(t) && Object.entries(e).some(([o,
|
|
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
|
|
22
|
-
const
|
|
23
|
-
if (!
|
|
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
|
|
26
|
-
|
|
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
|
|
28
|
+
const L = `[esd-extension-block-id="${c.IMAGE}"]`, v = /^\d+px$/;
|
|
29
29
|
function y(t) {
|
|
30
|
-
return
|
|
30
|
+
return T(t) && Number(t.getAttribute("height")) || 0;
|
|
31
31
|
}
|
|
32
|
-
function
|
|
32
|
+
function w(t) {
|
|
33
33
|
const e = y(t), o = a(t) ? t.getStyle("max-height") ?? "" : "";
|
|
34
|
-
return
|
|
34
|
+
return v.test(o) && e > 0 && o !== `${e}px`;
|
|
35
35
|
}
|
|
36
|
-
function
|
|
37
|
-
const o = e.querySelectorAll(
|
|
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
|
|
41
|
-
o.forEach((
|
|
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
|
|
44
|
-
|
|
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.
|
|
64
|
+
if (this.isMobilePreview())
|
|
50
65
|
return;
|
|
51
|
-
const o = this.getFitStyles(),
|
|
52
|
-
if (!
|
|
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
|
|
56
|
-
const
|
|
57
|
-
Object.entries(o).forEach(([
|
|
58
|
-
|
|
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 ?
|
|
82
|
+
return (e == null ? void 0 : e.type) === "height" && e.value ? x(e.value) : _;
|
|
65
83
|
}
|
|
66
84
|
}
|
|
67
|
-
const
|
|
68
|
-
|
|
85
|
+
const N = C(
|
|
86
|
+
f.IMAGE_MARGINS,
|
|
69
87
|
c.IMAGE,
|
|
70
88
|
l
|
|
71
|
-
),
|
|
89
|
+
), j = {
|
|
72
90
|
size: D,
|
|
73
|
-
margins:
|
|
91
|
+
margins: N
|
|
74
92
|
};
|
|
75
93
|
export {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
94
|
+
j as ImageControls,
|
|
95
|
+
U as ensureMobileFitRule,
|
|
96
|
+
Z as syncHeightBound
|
|
79
97
|
};
|