@useinsider/guido 3.27.0-beta.c63ada9 → 3.27.0-beta.ee85b86
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 +10 -5
- package/dist/components/Guido.vue.js +7 -7
- package/dist/components/Guido.vue2.js +86 -83
- package/dist/components/organisms/dynamic-content/AmbiguousDynamicContentModal.vue.js +24 -0
- package/dist/components/organisms/dynamic-content/AmbiguousDynamicContentModal.vue2.js +59 -0
- package/dist/composables/useAmbiguousDynamicContent.js +72 -0
- package/dist/composables/useHtmlCompiler.js +9 -8
- package/dist/composables/useModuleRepair.js +63 -32
- package/dist/composables/useStripo.js +44 -43
- package/dist/config/compiler/htmlCompilerRules.js +16 -6
- package/dist/enums/dynamic-content.js +4 -0
- package/dist/guido.css +1 -1
- package/dist/package.json.js +4 -4
- package/dist/src/@types/generic.d.ts +7 -0
- package/dist/src/components/organisms/dynamic-content/AmbiguousDynamicContentModal.vue.d.ts +2 -0
- package/dist/src/composables/useAmbiguousDynamicContent.d.ts +7 -0
- package/dist/src/composables/useModuleRepair.d.ts +6 -0
- package/dist/src/enums/dynamic-content.d.ts +3 -0
- package/dist/src/stores/module-dynamic-content.d.ts +30 -0
- package/dist/src/utils/dynamicContentConverter.d.ts +20 -18
- package/dist/src/utils/dynamicContentPendingMarker.d.ts +2 -0
- package/dist/src/utils/genericUtil.d.ts +4 -8
- package/dist/stores/module-dynamic-content.js +20 -0
- package/dist/utils/dynamicContentConverter.js +41 -27
- package/dist/utils/dynamicContentPendingMarker.js +6 -0
- package/dist/utils/genericUtil.js +39 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -119,7 +119,8 @@ const config: GuidoConfigInput = {
|
|
|
119
119
|
// { [partnerName]: [{ text, value, children }] } (architect is multi-partner).
|
|
120
120
|
// Guido flattens the active (first) partner's leaf attributes and uses them to
|
|
121
121
|
// repair label-form tokens (`{{ Phone Number }}` -> `{{phone_number}}`) in
|
|
122
|
-
// dropped saved modules;
|
|
122
|
+
// dropped saved modules; a label shared by several attributes opens a picker
|
|
123
|
+
// modal (see "Saved-module token repair"); an unresolvable token raises a single warning toaster
|
|
123
124
|
// (translation key `dynamic-content.unresolved-attributes-on-drop`, registered
|
|
124
125
|
// host-side). Omit it and the repair is a silent no-op. Default: {}.
|
|
125
126
|
dynamicContentList?: DynamicContentList,
|
|
@@ -691,18 +692,22 @@ const closeModal = () => {
|
|
|
691
692
|
|
|
692
693
|
### Saved-module token repair
|
|
693
694
|
|
|
694
|
-
Legacy **saved modules** may
|
|
695
|
+
Legacy or hand-written **saved modules** may carry tokens by display label
|
|
695
696
|
(`{{ Phone Number }}`) instead of the canonical token (`{{phone_number}}`), which the
|
|
696
697
|
backend can't resolve. When such a module is dropped or copied into the editor, Guido
|
|
697
698
|
repairs these automatically using the `template.dynamicContentList` catalog (see
|
|
698
699
|
[Configuration](#configuration)):
|
|
699
700
|
|
|
700
|
-
- **
|
|
701
|
-
-
|
|
701
|
+
- **Off under `features.liquidSyntax`**: Liquid templates keep every token exactly as written — no rewrite, no modal, no toaster. The Items currency and legacy-unsubscribe repairs still run.
|
|
702
|
+
- **Label match with one attribute** → canonical value: `{{ Phone Number }}` → `{{phone_number}}` (any author `| default:` / format tail is preserved). A label matches a leaf's `text` or its `tag_text` (e.g. `Wishlist Item (8) Name`), case-insensitively.
|
|
703
|
+
- **Valid tokens are never rewritten**: an exact catalog value, an Items block variable, or an exact entry of `template.customFieldAttributes` (e.g. the host's long-form aliases `name`, `surname`), stays as written — so `{{name | downcase | capitalize}}` survives a drop.
|
|
704
|
+
- **Catalog attributes the module ends up using are registered** for Save's allow-list, the same way the picker registers them, so a repaired or chosen token does not fail Save as an invalid custom field.
|
|
705
|
+
- **Label match with several attributes** (e.g. a bare `Name` shared by a default attribute and a commerce field) is not guessed: the token is left in place and a modal asks the user to pick an attribute per label, showing each option as `category › label`. Applying the choice is one undo step; closing the modal keeps the tokens and shows the warning toaster below. A module whose choice was still open when the design was saved asks again when the design is reopened. Register these keys host-side: `email-editor.ambiguous-dynamic-content-title`, `email-editor.ambiguous-dynamic-content-message` and `email-editor.ambiguous-dynamic-content-apply` (Cancel reuses `action-builder.cancel`).
|
|
706
|
+
- Liquid nested tokens (`coupon.code`), recommendation-block variables (`123_0_price`), allowed system tokens, and `data-*` product tags are left untouched.
|
|
702
707
|
- An **unresolvable** token is left in place and raises a single **warning toaster** (translation key `dynamic-content.unresolved-attributes-on-drop`; register the copy host-side).
|
|
703
708
|
|
|
704
709
|
Pass `template.dynamicContentList` as a **partner-keyed** tree
|
|
705
|
-
(`{ [partnerName]: DynamicContentNode[] }`, where a node is `{ text, value, children? }`).
|
|
710
|
+
(`{ [partnerName]: DynamicContentNode[] }`, where a node is `{ text, tag_text?, value, children? }`).
|
|
706
711
|
Guido flattens the **active (first) partner's** leaf attributes. Products that manage
|
|
707
712
|
multiple partners (e.g. architect) should key by partner and place the active partner
|
|
708
713
|
first. Omit the prop and the repair is a safe no-op — nothing is rewritten and no
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import o from "./Guido.vue2.js";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import i from "../_virtual/_plugin-vue2_normalizer.js";
|
|
4
|
-
var
|
|
4
|
+
var n = function() {
|
|
5
5
|
var a = this, r = a._self._c, e = a._self._setupProxy;
|
|
6
|
-
return r("div", { ref: "wrapperRef", staticClass: "guido-editor__wrapper", class: { "guido-editor__no-header": e.noHeader } }, [r(e.HeaderWrapper), r(e.AutoSaveController, { ref: "autoSaveControllerRef" }), e.editorStore.isPreviewModeOpen ? r(e.PreviewContainer) : a._e(), r("div", { directives: [{ name: "show", rawName: "v-show", value: !e.previewStore.isLoaded, expression: "!previewStore.isLoaded" }], staticClass: "guido-editor__container", class: { "guido-editor__no-header": e.noHeader }, attrs: { id: "guido-editor" } }), r(e.Toaster), r(e.AuthErrorModal), r(e.FilterSelectionDrawer), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.AssignStrategyDrawer) : a._e(), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.RemoveStrategyModal) : a._e(), e.isRrsEnabled ? r(e.LegacyStrategyUpdatedModal) : a._e(), e.isLegacyUnsubscribeConversionEnabled ? r(e.LegacyUnsubscribeConvertedModal) : a._e(), r(e.SaveAsTemplateDrawer), e.isSaveValidationEnabled ? r(e.ValidationErrorDrawer) : a._e(), e.isExternalDisplayConditionsEnabled ? r(e.DisplayConditionsHost) : a._e(), e.isTestPartner() ? a._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(l) {
|
|
6
|
+
return r("div", { ref: "wrapperRef", staticClass: "guido-editor__wrapper", class: { "guido-editor__no-header": e.noHeader } }, [r(e.HeaderWrapper), r(e.AutoSaveController, { ref: "autoSaveControllerRef" }), e.editorStore.isPreviewModeOpen ? r(e.PreviewContainer) : a._e(), r("div", { directives: [{ name: "show", rawName: "v-show", value: !e.previewStore.isLoaded, expression: "!previewStore.isLoaded" }], staticClass: "guido-editor__container", class: { "guido-editor__no-header": e.noHeader }, attrs: { id: "guido-editor" } }), r(e.Toaster), r(e.AuthErrorModal), r(e.FilterSelectionDrawer), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.AssignStrategyDrawer) : a._e(), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.RemoveStrategyModal) : a._e(), e.isRrsEnabled ? r(e.LegacyStrategyUpdatedModal) : a._e(), e.isLegacyUnsubscribeConversionEnabled ? r(e.LegacyUnsubscribeConvertedModal) : a._e(), e.moduleDynamicContentStore.queue.length > 0 ? r(e.AmbiguousDynamicContentModal) : a._e(), r(e.SaveAsTemplateDrawer), e.isSaveValidationEnabled ? r(e.ValidationErrorDrawer) : a._e(), e.isExternalDisplayConditionsEnabled ? r(e.DisplayConditionsHost) : a._e(), e.isTestPartner() ? a._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(l) {
|
|
7
7
|
return e.emit("onboarding:finished");
|
|
8
8
|
} } }), r(e.UnsubscribeWrapper), r(e.LoadingWrapper)], 1);
|
|
9
|
-
}, t = [],
|
|
9
|
+
}, t = [], s = /* @__PURE__ */ i(
|
|
10
10
|
o,
|
|
11
|
-
|
|
11
|
+
n,
|
|
12
12
|
t,
|
|
13
13
|
!1,
|
|
14
14
|
null,
|
|
15
|
-
"
|
|
15
|
+
"0c5f11a1"
|
|
16
16
|
);
|
|
17
|
-
const
|
|
17
|
+
const u = s.exports;
|
|
18
18
|
export {
|
|
19
|
-
|
|
19
|
+
u as default
|
|
20
20
|
};
|
|
@@ -1,79 +1,82 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
import { useCortexBlueprintBridge as
|
|
3
|
-
import { useEditorLock as
|
|
4
|
-
import { startEditorOpenMetrics as
|
|
5
|
-
import { provideGuidoActions as
|
|
6
|
-
import { useGuidoStateBridge as
|
|
7
|
-
import { usePartner as
|
|
8
|
-
import { useSaveValidationRollout as
|
|
9
|
-
import { useStripo as
|
|
10
|
-
import { useTimerClone as
|
|
11
|
-
import { useToaster as
|
|
12
|
-
import { useTranslations as
|
|
13
|
-
import { migrate as
|
|
14
|
-
import { ModuleFolderDefaults as
|
|
15
|
-
import { RIBBON_SELECTOR as
|
|
16
|
-
import { ToasterTypeOptions as
|
|
17
|
-
import { useRecommendationExtensionStore as z, disposeStrategyPageReturnListeners as
|
|
18
|
-
import { disposeUnsubscribeListeners as
|
|
19
|
-
import { disposeDisplayConditionRequest as
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
import
|
|
29
|
-
import { useStripoApi as
|
|
30
|
-
import { useConfigStore as
|
|
31
|
-
import { useDynamicContentStore as
|
|
1
|
+
import { defineComponent as Se, defineAsyncComponent as a, ref as W, computed as l, watch as $, onMounted as he, onUnmounted as Ee } from "vue";
|
|
2
|
+
import { useCortexBlueprintBridge as Ce } from "../composables/useCortexBlueprintBridge.js";
|
|
3
|
+
import { useEditorLock as De } from "../composables/useEditorLock.js";
|
|
4
|
+
import { startEditorOpenMetrics as we } from "../composables/useEditorOpenMetrics.js";
|
|
5
|
+
import { provideGuidoActions as Te } from "../composables/useGuidoActions.js";
|
|
6
|
+
import { useGuidoStateBridge as ke } from "../composables/useGuidoStateBridge.js";
|
|
7
|
+
import { usePartner as Fe } from "../composables/usePartner.js";
|
|
8
|
+
import { useSaveValidationRollout as Me } from "../composables/useSaveValidationRollout.js";
|
|
9
|
+
import { useStripo as Ie } from "../composables/useStripo.js";
|
|
10
|
+
import { useTimerClone as Le } from "../composables/useTimerClone.js";
|
|
11
|
+
import { useToaster as Re } from "../composables/useToaster.js";
|
|
12
|
+
import { useTranslations as Oe } from "../composables/useTranslations.js";
|
|
13
|
+
import { migrate as Ue } from "../config/migrator/index.js";
|
|
14
|
+
import { ModuleFolderDefaults as G } from "../enums/defaults.js";
|
|
15
|
+
import { RIBBON_SELECTOR as Ae } from "../enums/onboarding.js";
|
|
16
|
+
import { ToasterTypeOptions as Ne } from "../enums/toaster.js";
|
|
17
|
+
import { useRecommendationExtensionStore as z, disposeStrategyPageReturnListeners as _e } from "../extensions/Blocks/Recommendation/store/recommendation.js";
|
|
18
|
+
import { disposeUnsubscribeListeners as Pe } from "../extensions/Blocks/Unsubscribe/block.js";
|
|
19
|
+
import { disposeDisplayConditionRequest as xe } from "../extensions/DisplayConditions/bridge.js";
|
|
20
|
+
import Be from "./organisms/AutoSaveController.vue.js";
|
|
21
|
+
import He from "./organisms/base/AuthErrorModal.vue.js";
|
|
22
|
+
import Ve from "./organisms/base/Toaster.vue.js";
|
|
23
|
+
import We from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
|
|
24
|
+
import $e from "./organisms/header/HeaderWrapper.vue.js";
|
|
25
|
+
import Ge from "./organisms/LoadingWrapper.vue.js";
|
|
26
|
+
import ze from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
|
|
27
|
+
import qe from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
|
|
28
|
+
import Ke from "./organisms/validation/ValidationErrorDrawer.vue.js";
|
|
29
|
+
import { useStripoApi as je } from "../services/stripoApi.js";
|
|
30
|
+
import { useConfigStore as Je } from "../stores/config.js";
|
|
31
|
+
import { useDynamicContentStore as Qe } from "../stores/dynamic-content.js";
|
|
32
32
|
import { useEditorStore as C } from "../stores/editor.js";
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
|
|
33
|
+
import { useModuleDynamicContentStore as q } from "../stores/module-dynamic-content.js";
|
|
34
|
+
import { useOnboardingStore as Xe } from "../stores/onboarding.js";
|
|
35
|
+
import { usePreviewStore as Ye } from "../stores/preview.js";
|
|
36
|
+
import { useSaveValidationStore as Ze } from "../stores/save-validation.js";
|
|
37
|
+
import { useTemplateStore as et } from "../stores/template.js";
|
|
38
|
+
import { useUnsubscribeStore as tt } from "../stores/unsubscribe.js";
|
|
39
|
+
import { readTrackFloor as K } from "../utils/linkTrackingIds.js";
|
|
40
|
+
const Vt = /* @__PURE__ */ Se({
|
|
40
41
|
__name: "Guido",
|
|
41
42
|
props: {
|
|
42
43
|
config: null,
|
|
43
44
|
ready: { type: Boolean, default: !0 }
|
|
44
45
|
},
|
|
45
46
|
emits: ["dynamic-content:open", "back", "save:start", "save:complete", "on-change", "ready", "onboarding:finished", "test-email:click"],
|
|
46
|
-
setup(
|
|
47
|
-
const c =
|
|
47
|
+
setup(j, { expose: J, emit: i }) {
|
|
48
|
+
const c = j, r = we(), Q = a(
|
|
48
49
|
() => import("./organisms/email-preview/PreviewContainer.vue.js")
|
|
49
|
-
), Q = a(
|
|
50
|
-
() => import("./organisms/onboarding/OnboardingWrapper.vue.js")
|
|
51
50
|
), X = a(
|
|
52
|
-
() => import("./organisms/
|
|
51
|
+
() => import("./organisms/onboarding/OnboardingWrapper.vue.js")
|
|
53
52
|
), Y = a(
|
|
54
|
-
() => import("./organisms/extensions/recommendation/
|
|
53
|
+
() => import("./organisms/extensions/recommendation/AssignStrategyDrawer.vue.js")
|
|
55
54
|
), Z = a(
|
|
55
|
+
() => import("./organisms/extensions/recommendation/RemoveStrategyModal.vue.js")
|
|
56
|
+
), ee = a(
|
|
56
57
|
() => import("./organisms/display-conditions/DisplayConditionsHost.vue.js")
|
|
57
|
-
), D = W(),
|
|
58
|
+
), D = W(), te = a(
|
|
58
59
|
() => import("./organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.js")
|
|
59
|
-
),
|
|
60
|
+
), oe = a(
|
|
60
61
|
() => import("./organisms/unsubscribe/LegacyUnsubscribeConvertedModal.vue.js")
|
|
61
|
-
),
|
|
62
|
+
), ne = a(
|
|
63
|
+
() => import("./organisms/dynamic-content/AmbiguousDynamicContentModal.vue.js")
|
|
64
|
+
), y = W(), g = Qe(), w = tt(), re = q(), o = Je();
|
|
62
65
|
c.ready && o.init(c.config);
|
|
63
|
-
const d = C(),
|
|
66
|
+
const d = C(), ie = Ye(), p = l(() => d.hasChanges), { isTestPartner: se } = Fe(), { isEnabled: ae, loadRollout: T } = Me(), { showToaster: k } = Re(), F = Oe(), M = () => {
|
|
64
67
|
var t;
|
|
65
68
|
if (d.isVersionHistoryOpen) {
|
|
66
69
|
console.debug("guido:save:silent:blocked", { isVersionHistoryOpen: !0 }), k({
|
|
67
|
-
type:
|
|
70
|
+
type: Ne.Warning,
|
|
68
71
|
message: F("email-editor.save-blocked-outside-editor")
|
|
69
72
|
});
|
|
70
73
|
return;
|
|
71
74
|
}
|
|
72
75
|
return (t = D.value) == null ? void 0 : t.saveSilent();
|
|
73
|
-
},
|
|
76
|
+
}, I = (t) => {
|
|
74
77
|
d.loadingStatus = t;
|
|
75
78
|
};
|
|
76
|
-
|
|
79
|
+
Ce(), ke();
|
|
77
80
|
const b = () => {
|
|
78
81
|
var t, e;
|
|
79
82
|
return {
|
|
@@ -81,20 +84,20 @@ const Pt = /* @__PURE__ */ ye({
|
|
|
81
84
|
userId: o.userId,
|
|
82
85
|
username: o.username,
|
|
83
86
|
partnerName: o.partnerName,
|
|
84
|
-
savedModulesFolderName: ((t = o.editor) == null ? void 0 : t.savedModulesFolderName) ||
|
|
85
|
-
defaultModulesFolderName: ((e = o.editor) == null ? void 0 : e.defaultModulesFolderName) ||
|
|
87
|
+
savedModulesFolderName: ((t = o.editor) == null ? void 0 : t.savedModulesFolderName) || G.SAVED_MODULES,
|
|
88
|
+
defaultModulesFolderName: ((e = o.editor) == null ? void 0 : e.defaultModulesFolderName) || G.DEFAULT_MODULES
|
|
86
89
|
};
|
|
87
|
-
}, { initPlugin:
|
|
90
|
+
}, { initPlugin: L, preloadRuntime: R } = Ie(r), { runExclusive: O, beginMount: U, isCurrentMount: v } = De();
|
|
88
91
|
let f = 0;
|
|
89
|
-
const { getDefaultTemplate:
|
|
92
|
+
const { getDefaultTemplate: A } = je(), { cloneTimersOnSave: N, hasTimerBlocks: _ } = Le(), ce = l(() => {
|
|
90
93
|
var t;
|
|
91
94
|
return !((t = o.ui) != null && t.showHeader);
|
|
92
|
-
}),
|
|
95
|
+
}), de = l(() => o.isFeatureEnabled("reusableRecommendationStrategy")), me = l(() => o.externalDisplayConditions), le = l(
|
|
93
96
|
() => o.isFeatureEnabled("legacyUnsubscribeConversion")
|
|
94
|
-
),
|
|
97
|
+
), ue = l(
|
|
95
98
|
() => !!z().recommendationConfigs.strategyId
|
|
96
99
|
);
|
|
97
|
-
|
|
100
|
+
Te({
|
|
98
101
|
onBack: () => {
|
|
99
102
|
console.debug("guido:back"), i("back");
|
|
100
103
|
},
|
|
@@ -110,11 +113,11 @@ const Pt = /* @__PURE__ */ ye({
|
|
|
110
113
|
}
|
|
111
114
|
});
|
|
112
115
|
const P = (t) => {
|
|
113
|
-
console.debug("dynamic-content:close", t),
|
|
116
|
+
console.debug("dynamic-content:close", t), g.setSelectedDynamicContent(t), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: t }));
|
|
114
117
|
}, x = () => {
|
|
115
118
|
console.debug("dynamic-content:close", "Without Data"), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: { text: "", value: "" } }));
|
|
116
119
|
};
|
|
117
|
-
|
|
120
|
+
$(() => p.value, () => {
|
|
118
121
|
i("on-change", p.value);
|
|
119
122
|
});
|
|
120
123
|
const S = (t) => {
|
|
@@ -124,8 +127,8 @@ const Pt = /* @__PURE__ */ ye({
|
|
|
124
127
|
let m = null;
|
|
125
128
|
const h = () => {
|
|
126
129
|
var e;
|
|
127
|
-
const t = document.querySelector(
|
|
128
|
-
(e =
|
|
130
|
+
const t = document.querySelector(Ae);
|
|
131
|
+
(e = y.value) == null || e.style.setProperty("--ribbon-offset", `${(t == null ? void 0 : t.offsetHeight) ?? 0}px`);
|
|
129
132
|
}, E = async () => {
|
|
130
133
|
var t;
|
|
131
134
|
r.mark("host_ready");
|
|
@@ -138,49 +141,49 @@ const Pt = /* @__PURE__ */ ye({
|
|
|
138
141
|
});
|
|
139
142
|
const e = o.template, s = (e == null ? void 0 : e.html) || "", u = (e == null ? void 0 : e.css) || "", B = (e == null ? void 0 : e.preselectedDynamicContent) || [];
|
|
140
143
|
w.selectedUnsubscribePages = (e == null ? void 0 : e.selectedUnsubscribePages) || [];
|
|
141
|
-
const
|
|
144
|
+
const pe = ((t = e == null ? void 0 : e.migration) == null ? void 0 : t.recommendationConfigs) ?? {}, H = o.isFeatureEnabled("linkTrackingIds"), fe = {
|
|
142
145
|
partnerName: o.partnerName,
|
|
143
146
|
campaignUrls: e == null ? void 0 : e.recommendationCampaignUrls,
|
|
144
147
|
rrsEnabled: o.isFeatureEnabled("reusableRecommendationStrategy")
|
|
145
|
-
},
|
|
148
|
+
}, ye = {
|
|
146
149
|
itemsPriceFormatting: o.isFeatureEnabled("itemsPriceFormatting")
|
|
147
|
-
}, V = (
|
|
150
|
+
}, V = (ve) => r.timed(
|
|
148
151
|
"migration",
|
|
149
|
-
() =>
|
|
152
|
+
() => Ue(ve, pe, fe, ye)
|
|
150
153
|
);
|
|
151
154
|
let n = {
|
|
152
155
|
html: s && await V(s),
|
|
153
156
|
css: u
|
|
154
157
|
};
|
|
155
|
-
n.html || (n = await r.timed("default_template", () =>
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
const
|
|
158
|
+
n.html || (n = await r.timed("default_template", () => A()), n.html = await V(n.html));
|
|
159
|
+
const ge = H ? K(n.html, (e == null ? void 0 : e.trackIdCounter) || 0) : 0;
|
|
160
|
+
_(n.html) && (n.html = await r.timed("timer_clone", () => N(n.html))), H && (d.trackIdSessionFloor = Math.max(ge, K(n.html)));
|
|
161
|
+
const be = {
|
|
159
162
|
preselectedDynamicContentList: B,
|
|
160
163
|
onReady: () => {
|
|
161
164
|
console.debug("guido:ready"), i("ready");
|
|
162
165
|
}
|
|
163
166
|
};
|
|
164
|
-
f = U(), await
|
|
167
|
+
f = U(), await L(n, b(), be, n.html !== s), g.selectedDynamicContentList = B;
|
|
165
168
|
} catch (e) {
|
|
166
169
|
console.error("Failed to initialize Stripo editor:", e), r.markFailed();
|
|
167
170
|
}
|
|
168
171
|
};
|
|
169
|
-
return
|
|
172
|
+
return he(async () => {
|
|
170
173
|
var e;
|
|
171
|
-
console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), z().$reset(), C().$reset(),
|
|
172
|
-
const t = (e =
|
|
174
|
+
console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), z().$reset(), C().$reset(), et().$reset(), Ze().$reset(), q().$reset(), Xe().resetOnboarding("recommendationLegacyStrategyOnboarding"), T(), h();
|
|
175
|
+
const t = (e = y.value) == null ? void 0 : e.parentElement;
|
|
173
176
|
if (t && (m = new ResizeObserver(h), m.observe(t)), R(), c.ready)
|
|
174
177
|
await E();
|
|
175
178
|
else {
|
|
176
|
-
const s =
|
|
179
|
+
const s = $(() => c.ready, (u) => {
|
|
177
180
|
u && (s(), E());
|
|
178
181
|
});
|
|
179
182
|
}
|
|
180
183
|
document.addEventListener("dynamic-content:open", S);
|
|
181
|
-
}),
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
+
}), Ee(() => {
|
|
185
|
+
if (Pe(), _e(), r.dispose(), m == null || m.disconnect(), document.removeEventListener("dynamic-content:open", S), v(f)) {
|
|
186
|
+
xe();
|
|
184
187
|
try {
|
|
185
188
|
const t = C();
|
|
186
189
|
t.isStripoInitialized = !1, t.isAccessibilityTestingOpen = !1, t.imagesHidden = !1, t.colorVisionDeficiency = "";
|
|
@@ -196,17 +199,17 @@ const Pt = /* @__PURE__ */ ye({
|
|
|
196
199
|
console.debug("Failed to remove Stripo editor: No editor found");
|
|
197
200
|
}
|
|
198
201
|
}), o.reset();
|
|
199
|
-
}),
|
|
202
|
+
}), J({
|
|
200
203
|
dynamicContent: {
|
|
201
204
|
insert: P,
|
|
202
205
|
close: x
|
|
203
206
|
},
|
|
204
207
|
hasChanges: p,
|
|
205
|
-
saveSilent:
|
|
206
|
-
setLoading:
|
|
207
|
-
}), { __sfc: !0, openMetrics: r, PreviewContainer:
|
|
208
|
+
saveSilent: M,
|
|
209
|
+
setLoading: I
|
|
210
|
+
}), { __sfc: !0, openMetrics: r, PreviewContainer: Q, OnboardingWrapper: X, AssignStrategyDrawer: Y, RemoveStrategyModal: Z, DisplayConditionsHost: ee, autoSaveControllerRef: D, LegacyStrategyUpdatedModal: te, LegacyUnsubscribeConvertedModal: oe, AmbiguousDynamicContentModal: ne, wrapperRef: y, dynamicContentStore: g, unsubscribeStore: w, moduleDynamicContentStore: re, props: c, configStore: o, editorStore: d, previewStore: ie, hasChanges: p, isTestPartner: se, isSaveValidationEnabled: ae, loadRollout: T, showToaster: k, trans: F, saveSilent: M, setLoading: I, emit: i, buildMetadata: b, initPlugin: L, preloadRuntime: R, runExclusive: O, beginMount: U, isCurrentMount: v, mountGeneration: f, getDefaultTemplate: A, cloneTimersOnSave: N, hasTimerBlocks: _, noHeader: ce, isRrsEnabled: de, isExternalDisplayConditionsEnabled: me, isLegacyUnsubscribeConversionEnabled: le, hasAssignedStrategy: ue, insertDynamicContent: P, closeDynamicContent: x, handleDynamicContentOpen: S, ribbonObserver: m, updateRibbonOffset: h, startEditor: E, AutoSaveController: Be, AuthErrorModal: He, Toaster: Ve, FilterSelectionDrawer: We, HeaderWrapper: $e, LoadingWrapper: Ge, SaveAsTemplateDrawer: ze, UnsubscribeWrapper: qe, ValidationErrorDrawer: Ke };
|
|
208
211
|
}
|
|
209
212
|
});
|
|
210
213
|
export {
|
|
211
|
-
|
|
214
|
+
Vt as default
|
|
212
215
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import i from "./AmbiguousDynamicContentModal.vue2.js";
|
|
2
|
+
/* empty css */
|
|
3
|
+
import l from "../../../_virtual/_plugin-vue2_normalizer.js";
|
|
4
|
+
var c = function() {
|
|
5
|
+
var n = this, a = n._self._c, t = n._self._setupProxy;
|
|
6
|
+
return t.current ? a(t.WpModal, { attrs: { id: "guido__ambiguous-dynamic-content-modal", size: "medium", "close-on-outside-click": !1, "footer-button-options": t.footerButtonOptions, title: t.trans("email-editor.ambiguous-dynamic-content-title") }, on: { close: t.cancel, "primary-action": t.apply } }, [a("div", { staticClass: "ambiguous-dynamic-content-modal__content" }, [a("p", { staticClass: "mb-3" }, [n._v(" " + n._s(t.trans("email-editor.ambiguous-dynamic-content-message")) + " ")]), n._l(t.rows, function(e, s) {
|
|
7
|
+
return a(t.InSelect, { key: e.label, staticClass: "mb-2", attrs: { id: `guido__ambiguous-dynamic-content-select-${s}`, "search-status": "", "button-status": !1, "label-text": `{{ ${e.label} }}`, options: e.options, "placeholder-text": t.trans("email-editor.ambiguous-dynamic-content-placeholder"), state: e.isInvalid ? "error" : "default", "state-message": t.trans("email-editor.ambiguous-dynamic-content-validation"), value: e.selected }, on: { close: function(o) {
|
|
8
|
+
return t.touch(e.label);
|
|
9
|
+
}, select: function(o) {
|
|
10
|
+
return t.select(e.label, o);
|
|
11
|
+
} } });
|
|
12
|
+
})], 2)]) : n._e();
|
|
13
|
+
}, r = [], u = /* @__PURE__ */ l(
|
|
14
|
+
i,
|
|
15
|
+
c,
|
|
16
|
+
r,
|
|
17
|
+
!1,
|
|
18
|
+
null,
|
|
19
|
+
"2643213c"
|
|
20
|
+
);
|
|
21
|
+
const f = u.exports;
|
|
22
|
+
export {
|
|
23
|
+
f as default
|
|
24
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { defineComponent as h, ref as y, computed as u, watch as _ } from "vue";
|
|
2
|
+
import x from "../../wrappers/WpModal.vue.js";
|
|
3
|
+
import { useAmbiguousDynamicContent as S } from "../../../composables/useAmbiguousDynamicContent.js";
|
|
4
|
+
import { useTranslations as T } from "../../../composables/useTranslations.js";
|
|
5
|
+
import { useEditorStore as C } from "../../../stores/editor.js";
|
|
6
|
+
import { useModuleDynamicContentStore as B } from "../../../stores/module-dynamic-content.js";
|
|
7
|
+
import { InSelect as D } from "@useinsider/design-system-vue";
|
|
8
|
+
const G = /* @__PURE__ */ h({
|
|
9
|
+
__name: "AmbiguousDynamicContentModal",
|
|
10
|
+
setup(I) {
|
|
11
|
+
const s = T(), i = C(), c = B(), { resolve: r, dismiss: p } = S(), o = y({}), l = y([]), t = u(() => i.isStripoInitialized ? c.current : null);
|
|
12
|
+
_(() => {
|
|
13
|
+
var e;
|
|
14
|
+
return (e = t.value) == null ? void 0 : e.id;
|
|
15
|
+
}, () => {
|
|
16
|
+
o.value = {}, l.value = [];
|
|
17
|
+
});
|
|
18
|
+
const m = (e) => ({
|
|
19
|
+
text: [...e.path, e.tagText].join(" › "),
|
|
20
|
+
value: e.value
|
|
21
|
+
}), v = u(() => {
|
|
22
|
+
var e;
|
|
23
|
+
return (((e = t.value) == null ? void 0 : e.items) ?? []).map((a) => {
|
|
24
|
+
const d = a.candidates.map(m), f = d.filter((g) => g.value === o.value[a.label]);
|
|
25
|
+
return {
|
|
26
|
+
label: a.label,
|
|
27
|
+
options: d,
|
|
28
|
+
selected: f,
|
|
29
|
+
isInvalid: f.length === 0 && l.value.includes(a.label)
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
}), n = u(() => v.value.every((e) => e.selected.length > 0)), b = u(() => ({
|
|
33
|
+
cancelOrBackButton: {
|
|
34
|
+
type: "secondary",
|
|
35
|
+
labelText: s("action-builder.cancel"),
|
|
36
|
+
styling: "ghost"
|
|
37
|
+
},
|
|
38
|
+
primaryButton: {
|
|
39
|
+
type: "primary",
|
|
40
|
+
labelText: s("email-editor.ambiguous-dynamic-content-apply"),
|
|
41
|
+
disabledStatus: !n.value,
|
|
42
|
+
isTooltip: !n.value,
|
|
43
|
+
tooltipText: n.value ? "" : s("email-editor.ambiguous-dynamic-content-apply-tooltip")
|
|
44
|
+
}
|
|
45
|
+
}));
|
|
46
|
+
return { __sfc: !0, trans: s, editorStore: i, store: c, resolve: r, dismiss: p, selections: o, touched: l, current: t, toOption: m, rows: v, isComplete: n, footerButtonOptions: b, select: (e, { value: a }) => {
|
|
47
|
+
o.value = { ...o.value, [e]: a };
|
|
48
|
+
}, touch: (e) => {
|
|
49
|
+
l.value.includes(e) || (l.value = [...l.value, e]);
|
|
50
|
+
}, apply: () => {
|
|
51
|
+
t.value && n.value && r(t.value, o.value);
|
|
52
|
+
}, cancel: () => {
|
|
53
|
+
t.value && p(t.value.id);
|
|
54
|
+
}, WpModal: x, InSelect: D };
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
export {
|
|
58
|
+
G as default
|
|
59
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useModuleRepair as A, UNRESOLVED_DYNAMIC_CONTENT_ON_DROP_KEY as D, registerUsedAttributes as C } from "./useModuleRepair.js";
|
|
2
|
+
import { useToaster as v } from "./useToaster.js";
|
|
3
|
+
import { useTranslations as R } from "./useTranslations.js";
|
|
4
|
+
import { ModuleDynamicContentAttribute as b } from "../enums/dynamic-content.js";
|
|
5
|
+
import { ToasterTypeOptions as h } from "../enums/toaster.js";
|
|
6
|
+
import { useModuleDynamicContentStore as O } from "../stores/module-dynamic-content.js";
|
|
7
|
+
import { applyDynamicContentChoices as H } from "../utils/dynamicContentConverter.js";
|
|
8
|
+
import { stripPendingMarker as _ } from "../utils/dynamicContentPendingMarker.js";
|
|
9
|
+
import { getEditorApi as w, EDITOR_NOT_READY_MESSAGE as N } from "../utils/stripoEditorApi.js";
|
|
10
|
+
import { ModificationDescription as u } from "../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
11
|
+
const c = b.Pending, M = () => {
|
|
12
|
+
const { editorCopilotApi: t } = w();
|
|
13
|
+
if (!t)
|
|
14
|
+
throw new Error(N);
|
|
15
|
+
return { api: t, root: t.getDocumentRootHtmlNode() };
|
|
16
|
+
}, E = (t) => {
|
|
17
|
+
const { api: p, root: a } = M(), m = a.querySelector(`[${c}="${t}"]`);
|
|
18
|
+
return { api: p, node: m };
|
|
19
|
+
}, G = () => {
|
|
20
|
+
const t = O(), { convertDynamicContent: p } = A(), { showToaster: a, handleError: m } = v(), f = R();
|
|
21
|
+
return { resolve: ({ id: o, items: r }, i) => {
|
|
22
|
+
try {
|
|
23
|
+
const { api: e, node: n } = E(o);
|
|
24
|
+
if (n) {
|
|
25
|
+
const s = /* @__PURE__ */ new Map();
|
|
26
|
+
r.forEach((l) => {
|
|
27
|
+
const g = i[l.label];
|
|
28
|
+
g && l.spellings.forEach((T) => s.set(T, g));
|
|
29
|
+
});
|
|
30
|
+
const d = _(H(n.getOuterHTML(), s)), y = e.getTemplateModifier();
|
|
31
|
+
y.modifyHtml(n).replaceWith(d), y.apply(new u("Resolved dynamic content")), C(d, r.flatMap((l) => l.candidates)), a({
|
|
32
|
+
type: h.Success,
|
|
33
|
+
message: f("email-editor.ambiguous-dynamic-content-success")
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
t.remove(o);
|
|
37
|
+
} catch (e) {
|
|
38
|
+
m(e, "Failed to apply the dynamic content choice");
|
|
39
|
+
}
|
|
40
|
+
}, dismiss: (o) => {
|
|
41
|
+
try {
|
|
42
|
+
const { api: r, node: i } = E(o);
|
|
43
|
+
if (i) {
|
|
44
|
+
const e = r.getTemplateModifier();
|
|
45
|
+
e.modifyHtml(i).removeAttribute(c), e.apply(new u("Cleared pending dynamic content").asHidden()), a({
|
|
46
|
+
type: h.Warning,
|
|
47
|
+
message: f(D)
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
} catch (r) {
|
|
51
|
+
m(r, "Failed to dismiss the dynamic content choice");
|
|
52
|
+
} finally {
|
|
53
|
+
t.remove(o);
|
|
54
|
+
}
|
|
55
|
+
}, restorePending: () => {
|
|
56
|
+
try {
|
|
57
|
+
const { api: o, root: r } = M(), i = [];
|
|
58
|
+
if (r.querySelectorAll(`[${c}]`).forEach((e) => {
|
|
59
|
+
const n = e.getAttribute(c), { ambiguous: s } = p(e.getOuterHTML());
|
|
60
|
+
!n || s.length === 0 ? i.push(e) : t.queue.some((d) => d.id === n) || t.enqueue({ id: n, items: s });
|
|
61
|
+
}), i.length > 0) {
|
|
62
|
+
const e = o.getTemplateModifier();
|
|
63
|
+
i.forEach((n) => e.modifyHtml(n).removeAttribute(c)), e.apply(new u("Cleared pending dynamic content").asHidden());
|
|
64
|
+
}
|
|
65
|
+
} catch (o) {
|
|
66
|
+
console.error("Failed to restore pending dynamic content:", o);
|
|
67
|
+
}
|
|
68
|
+
} };
|
|
69
|
+
};
|
|
70
|
+
export {
|
|
71
|
+
G as useAmbiguousDynamicContent
|
|
72
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { defaultHtmlCompilerRules as d } from "../config/compiler/htmlCompilerRules.js";
|
|
2
2
|
import { itemsCompilerRules as f } from "../config/compiler/itemsCompilerRules.js";
|
|
3
3
|
import { liquidCompilerRules as g } from "../config/compiler/liquidCompilerRules.js";
|
|
4
|
-
import { outlookCompilerRules as
|
|
5
|
-
import { recommendationCompilerRules as
|
|
4
|
+
import { outlookCompilerRules as v } from "../config/compiler/outlookCompilerRules.js";
|
|
5
|
+
import { recommendationCompilerRules as R } from "../config/compiler/recommendationCompilerRules.js";
|
|
6
6
|
import { socialCompilerRules as H } from "../config/compiler/socialCompilerRules.js";
|
|
7
7
|
import { unsubscribeCompilerRules as b } from "../config/compiler/unsubscribeCompilerRules.js";
|
|
8
8
|
import { createHtmlCompiler as n } from "../utils/htmlCompiler.js";
|
|
@@ -32,19 +32,20 @@ const x = /* @__PURE__ */ new Set([
|
|
|
32
32
|
"liquid-coupon-code",
|
|
33
33
|
// Editor-only attribute strip — AMP4EMAIL has no `contenteditable`, so leaving
|
|
34
34
|
// it in narrows/breaks rendering. Pure attribute removal, emits nothing.
|
|
35
|
-
"remove-contenteditable"
|
|
35
|
+
"remove-contenteditable",
|
|
36
|
+
"remove-dc-pending-marker"
|
|
36
37
|
]), I = () => {
|
|
37
|
-
const { compiler: i, isFeatureEnabled:
|
|
38
|
+
const { compiler: i, isFeatureEnabled: a, partner: u } = C(), c = p(() => {
|
|
38
39
|
var m, l;
|
|
39
40
|
const e = ((m = i.value) == null ? void 0 : m.customRules) || [];
|
|
40
41
|
return [
|
|
41
42
|
...!!((l = i.value) != null && l.ignoreDefaultRules) ? [] : d,
|
|
42
|
-
...
|
|
43
|
+
...R,
|
|
43
44
|
...b,
|
|
44
45
|
...f,
|
|
45
|
-
...
|
|
46
|
+
...v,
|
|
46
47
|
...H,
|
|
47
|
-
...
|
|
48
|
+
...a("liquidSyntax") ? g : [],
|
|
48
49
|
...e.map((t, o) => ({
|
|
49
50
|
...t,
|
|
50
51
|
priority: t.priority + 1e3 + o
|
|
@@ -53,7 +54,7 @@ const x = /* @__PURE__ */ new Set([
|
|
|
53
54
|
];
|
|
54
55
|
}), r = p(() => {
|
|
55
56
|
var t;
|
|
56
|
-
const e = c.value, s = n(e), m = n(e.filter((o) => x.has(o.id))), l = (t =
|
|
57
|
+
const e = c.value, s = n(e), m = n(e.filter((o) => x.has(o.id))), l = (t = u.value) == null ? void 0 : t.fallbackFont;
|
|
57
58
|
return {
|
|
58
59
|
compileHtml: (o) => s.compile(o, void 0, l),
|
|
59
60
|
compileAmpHtml: (o) => m.compile(o, void 0, l)
|