@useinsider/guido 3.21.0-beta.7e166b5 → 3.21.0-beta.ab76470
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/dist/config/compiler/utils/recommendationCompilerUtils.js +1 -1
- package/dist/extensions/Blocks/Recommendation/block.js +135 -181
- package/dist/extensions/Blocks/Recommendation/controls/image/index.js +33 -16
- package/dist/extensions/Blocks/Recommendation/utils/strategyCommit.js +31 -48
- package/dist/src/extensions/Blocks/Recommendation/block.d.ts +0 -11
- package/dist/src/extensions/Blocks/Recommendation/controls/image/index.d.ts +22 -16
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyCommit.d.ts +0 -9
- package/package.json +1 -1
|
@@ -162,7 +162,7 @@ function G(t, r) {
|
|
|
162
162
|
function V(t) {
|
|
163
163
|
const r = t.getAttribute("style") || "", e = y(r, "width", 600), o = y(r, "padding", 0) * 2, c = Math.max(0, e - o);
|
|
164
164
|
c !== 0 && t.querySelectorAll("img.adapt-img").forEach((i) => {
|
|
165
|
-
if (i.hasAttribute("width"))
|
|
165
|
+
if (i.hasAttribute("width") || i.hasAttribute("height"))
|
|
166
166
|
return;
|
|
167
167
|
const n = G(i, t);
|
|
168
168
|
if (!n)
|
|
@@ -1,46 +1,43 @@
|
|
|
1
|
-
var
|
|
2
|
-
var b = (
|
|
3
|
-
var
|
|
4
|
-
import { useConfig as
|
|
5
|
-
import { BlockId as
|
|
6
|
-
import { getMigrationBannerHtml as
|
|
7
|
-
import { Block as
|
|
8
|
-
import { CURRENT_CONFIG_VERSION as
|
|
9
|
-
import { RECOMMENDATION_ID_ATTR as
|
|
1
|
+
var B = Object.defineProperty;
|
|
2
|
+
var b = (a, l, t) => l in a ? B(a, l, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[l] = t;
|
|
3
|
+
var d = (a, l, t) => b(a, typeof l != "symbol" ? l + "" : l, t);
|
|
4
|
+
import { useConfig as g } from "../../../composables/useConfig.js";
|
|
5
|
+
import { BlockId as C } from "../../../enums/block.js";
|
|
6
|
+
import { getMigrationBannerHtml as A } from "../../../utils/migrationBannerHtml.js";
|
|
7
|
+
import { Block as E, BlockCompositionType as S, ModificationDescription as p } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
8
|
+
import { CURRENT_CONFIG_VERSION as N, PRE_RRS_CONFIG_VERSION as w } from "./constants/defaultConfig.js";
|
|
9
|
+
import { RECOMMENDATION_ID_ATTR as m } from "./constants/selectors.js";
|
|
10
10
|
import { regenerateMobileProductRows as M } from "./controls/main/utils.js";
|
|
11
11
|
import { ensureMobileCssRulesExist as I, setMobileLayoutOptOut as R, hasMobileLayoutOptOut as O } from "./controls/mobileLayout/cssRules.js";
|
|
12
|
-
import { RecommendationConfigService as
|
|
13
|
-
import { useRecommendationExtensionStore as
|
|
14
|
-
import { getDefaultTemplate as
|
|
15
|
-
import { useRecommendationBlockWarning as
|
|
16
|
-
import { registerNodeConfigWriter as
|
|
17
|
-
import {
|
|
18
|
-
const
|
|
19
|
-
let
|
|
20
|
-
class
|
|
12
|
+
import { RecommendationConfigService as s } from "./services/configService.js";
|
|
13
|
+
import { useRecommendationExtensionStore as h } from "./store/recommendation.js";
|
|
14
|
+
import { getDefaultTemplate as x } from "./templates/grid/template.js";
|
|
15
|
+
import { useRecommendationBlockWarning as T } from "./useRecommendationBlockWarning.js";
|
|
16
|
+
import { registerNodeConfigWriter as H } from "./utils/nodeConfigWriter.js";
|
|
17
|
+
import { refreshDuplicatedStrategyBlocks as $ } from "./utils/strategyCommit.js";
|
|
18
|
+
const k = C.Recommendation, u = "recommendation-block-v2", D = "hide-price";
|
|
19
|
+
let y = !1;
|
|
20
|
+
class Y extends E {
|
|
21
21
|
constructor() {
|
|
22
22
|
super();
|
|
23
23
|
/**
|
|
24
24
|
* Stores the ID generated in getTemplate() so onCreated() can reuse it.
|
|
25
25
|
* This avoids generating a new (different) ID in onCreated().
|
|
26
26
|
*/
|
|
27
|
-
|
|
27
|
+
d(this, "_pendingBlockId", null);
|
|
28
28
|
/** Ids already reset under their new name, so the deferred pass skips their stale snapshot. */
|
|
29
|
-
|
|
29
|
+
d(this, "_resetSourceIds", /* @__PURE__ */ new Set());
|
|
30
30
|
/** Ids handed to duplicates the document root does not show yet: a copied module renames all its blocks at once. */
|
|
31
|
-
|
|
32
|
-
m(this, "_arrivedNodes", []);
|
|
33
|
-
/** Ids whose arrival or duplicate refresh is in flight, so a second refresh of the same block does not race it. */
|
|
34
|
-
m(this, "_refreshingIds", /* @__PURE__ */ new Set());
|
|
31
|
+
d(this, "_unsettledDuplicateIds", /* @__PURE__ */ new Set());
|
|
35
32
|
}
|
|
36
33
|
getId() {
|
|
37
|
-
return
|
|
34
|
+
return k;
|
|
38
35
|
}
|
|
39
36
|
getIcon() {
|
|
40
37
|
return "recommendation-icon";
|
|
41
38
|
}
|
|
42
39
|
getBlockCompositionType() {
|
|
43
|
-
return
|
|
40
|
+
return S.CONTAINER;
|
|
44
41
|
}
|
|
45
42
|
getName() {
|
|
46
43
|
return this.api.translate("Recommendation Block");
|
|
@@ -51,8 +48,8 @@ class Z extends S {
|
|
|
51
48
|
);
|
|
52
49
|
}
|
|
53
50
|
getSettingsPanelTitleHtml() {
|
|
54
|
-
return
|
|
55
|
-
|
|
51
|
+
return A(
|
|
52
|
+
k,
|
|
56
53
|
this.api.translate("Recommendation Block"),
|
|
57
54
|
this.api.translate("This block is switched from the Old Version to the New Version. We recommend you check the Recommendation block and test your message to ensure it works properly.")
|
|
58
55
|
);
|
|
@@ -74,8 +71,8 @@ class Z extends S {
|
|
|
74
71
|
* attribute and overwrites dynamically added classes via setAttribute.
|
|
75
72
|
*/
|
|
76
73
|
getTemplate() {
|
|
77
|
-
const
|
|
78
|
-
return this._pendingBlockId =
|
|
74
|
+
const t = this._generateNextId();
|
|
75
|
+
return this._pendingBlockId = t, x(t);
|
|
79
76
|
}
|
|
80
77
|
/**
|
|
81
78
|
* Called when a new block is dropped into the template
|
|
@@ -84,58 +81,42 @@ class Z extends S {
|
|
|
84
81
|
* and assigns the recommendation-id attribute + initializes configuration.
|
|
85
82
|
* @param node - The newly created block node
|
|
86
83
|
*/
|
|
87
|
-
onCreated(
|
|
88
|
-
const
|
|
89
|
-
if (
|
|
90
|
-
if (this._detectDuplicate(
|
|
91
|
-
this._handleDuplicate(
|
|
84
|
+
onCreated(t) {
|
|
85
|
+
const e = this._getRecommendationId(t);
|
|
86
|
+
if (e !== null && e > 0) {
|
|
87
|
+
if (this._detectDuplicate(e)) {
|
|
88
|
+
this._handleDuplicate(t, e), this._scheduleArrivalReset(t);
|
|
92
89
|
return;
|
|
93
90
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (g && this._detectDuplicate(t)) {
|
|
98
|
-
this._handleDuplicate(e, t);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
this._queueArrivalRefresh(e);
|
|
102
|
-
}
|
|
103
|
-
}, 0), this._scheduleArrivalReset(e);
|
|
91
|
+
this._pendingBlockId === null && setTimeout(() => {
|
|
92
|
+
this._getBlockElement(t) && this._detectDuplicate(e) && this._handleDuplicate(t, e);
|
|
93
|
+
}, 0), this._scheduleArrivalReset(t);
|
|
104
94
|
return;
|
|
105
95
|
}
|
|
106
96
|
const i = this._pendingBlockId ?? this._generateNextId();
|
|
107
|
-
this._pendingBlockId = null, this._assignRecommendationId(
|
|
108
|
-
const
|
|
97
|
+
this._pendingBlockId = null, this._assignRecommendationId(t, i);
|
|
98
|
+
const n = g().isFeatureEnabled("reusableRecommendationStrategy"), o = n && !s.hasConfig(t), { config: r, wasFreshDrop: c } = s.initializeConfig(
|
|
109
99
|
this.api,
|
|
110
|
-
|
|
100
|
+
t,
|
|
111
101
|
{
|
|
112
102
|
recommendationId: i,
|
|
113
|
-
configVersion:
|
|
114
|
-
...
|
|
103
|
+
configVersion: n ? N : w,
|
|
104
|
+
...o ? { partnerName: g().partnerName.value } : {},
|
|
115
105
|
// An RRS block picks a strategy, not an algorithm, and its algorithm control is
|
|
116
106
|
// hidden. Keeping the `mostPopular` default would bake a most-popular feed URL
|
|
117
107
|
// at save for a block the user never configured.
|
|
118
|
-
...
|
|
108
|
+
...o ? { strategy: "" } : {}
|
|
119
109
|
}
|
|
120
|
-
),
|
|
121
|
-
if (
|
|
110
|
+
), f = h();
|
|
111
|
+
if (f.setCurrentBlock(i), this._stampHidePrice(t, r.priceHideIfSameAsDiscounted), c) {
|
|
122
112
|
I(this.api);
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
currentNode:
|
|
113
|
+
const _ = this._getBlockElement(t);
|
|
114
|
+
_ && (R(this.api, _, !0), M({
|
|
115
|
+
currentNode: t,
|
|
126
116
|
documentModifier: this.api.getDocumentModifier()
|
|
127
117
|
}));
|
|
128
118
|
}
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
/** Refreshes every block of an opened template: Stripo restores a stored document without `onCreated`. */
|
|
132
|
-
onDocumentInit() {
|
|
133
|
-
try {
|
|
134
|
-
const e = this.api.getDocumentRoot();
|
|
135
|
-
e && "querySelectorAll" in e && e.querySelectorAll(`.${u}`).forEach((t) => this._queueArrivalRefresh(t));
|
|
136
|
-
} catch (e) {
|
|
137
|
-
console.error("[recommendation] refreshing an opened strategy failed", e);
|
|
138
|
-
}
|
|
119
|
+
f.patchCurrentBlockConfig({ language: r.language }, { triggerRefetch: !1 }), this._warnIfMultipleBlocks();
|
|
139
120
|
}
|
|
140
121
|
/**
|
|
141
122
|
* Called when the document changes or template is loaded
|
|
@@ -144,24 +125,24 @@ class Z extends S {
|
|
|
144
125
|
* and assigns recommendation-id to legacy blocks that lack one.
|
|
145
126
|
* @param node - The block node that may need migration
|
|
146
127
|
*/
|
|
147
|
-
onDocumentChanged(
|
|
148
|
-
if (!(!
|
|
149
|
-
if (!this._getRecommendationId(
|
|
150
|
-
const
|
|
151
|
-
this._assignRecommendationId(
|
|
128
|
+
onDocumentChanged(t) {
|
|
129
|
+
if (!(!t || !("getNodeConfig" in t))) {
|
|
130
|
+
if (!this._getRecommendationId(t)) {
|
|
131
|
+
const e = this._generateNextId();
|
|
132
|
+
this._assignRecommendationId(t, e), s.hasConfig(t) && s.updateConfig(
|
|
152
133
|
this.api,
|
|
153
|
-
|
|
154
|
-
{ recommendationId:
|
|
134
|
+
t,
|
|
135
|
+
{ recommendationId: e },
|
|
155
136
|
"Assign recommendation ID to legacy block"
|
|
156
137
|
);
|
|
157
138
|
}
|
|
158
|
-
this._healLingeringDuplicate(
|
|
139
|
+
this._healLingeringDuplicate(t), s.needsMigration(t) && this._migrateFromLegacy(t), this._healHidePriceAttr(t);
|
|
159
140
|
try {
|
|
160
|
-
|
|
161
|
-
const
|
|
141
|
+
y || (I(this.api), y = !0);
|
|
142
|
+
const e = s.getConfig(t), i = this._getBlockElement(t);
|
|
162
143
|
if (i) {
|
|
163
|
-
const
|
|
164
|
-
O(i) !==
|
|
144
|
+
const n = !e.mobileLayoutEnabled;
|
|
145
|
+
O(i) !== n && R(this.api, i, n);
|
|
165
146
|
}
|
|
166
147
|
} catch {
|
|
167
148
|
}
|
|
@@ -173,9 +154,9 @@ class Z extends S {
|
|
|
173
154
|
* Cleans up the per-block state from the Pinia store.
|
|
174
155
|
* @param node - The block node being deleted
|
|
175
156
|
*/
|
|
176
|
-
onDelete(
|
|
177
|
-
const
|
|
178
|
-
|
|
157
|
+
onDelete(t) {
|
|
158
|
+
const e = this._getRecommendationId(t);
|
|
159
|
+
e && h().removeBlockState(e);
|
|
179
160
|
}
|
|
180
161
|
/**
|
|
181
162
|
* Warns (dark advisory toaster) when the design holds more than one live
|
|
@@ -191,7 +172,7 @@ class Z extends S {
|
|
|
191
172
|
*/
|
|
192
173
|
_warnIfMultipleBlocks() {
|
|
193
174
|
try {
|
|
194
|
-
|
|
175
|
+
T().warnIfMultipleBlocks(this.api.getDocumentRootHtmlNode());
|
|
195
176
|
} catch {
|
|
196
177
|
}
|
|
197
178
|
}
|
|
@@ -200,21 +181,21 @@ class Z extends S {
|
|
|
200
181
|
* in the document and finding the maximum existing ID + 1.
|
|
201
182
|
*/
|
|
202
183
|
_generateNextId() {
|
|
203
|
-
let
|
|
204
|
-
const
|
|
184
|
+
let t = 0;
|
|
185
|
+
const e = /* @__PURE__ */ new Set();
|
|
205
186
|
try {
|
|
206
187
|
const i = this.api.getDocumentRoot();
|
|
207
|
-
i && "querySelectorAll" in i && i.querySelectorAll(`.${u}`).forEach((
|
|
208
|
-
if ("getAttribute" in
|
|
209
|
-
const
|
|
210
|
-
|
|
188
|
+
i && "querySelectorAll" in i && i.querySelectorAll(`.${u}`).forEach((o) => {
|
|
189
|
+
if ("getAttribute" in o) {
|
|
190
|
+
const r = o.getAttribute(m), c = r ? parseInt(r) : 0;
|
|
191
|
+
e.add(c), c > t && (t = c);
|
|
211
192
|
}
|
|
212
193
|
});
|
|
213
194
|
} catch {
|
|
214
195
|
}
|
|
215
196
|
return this._unsettledDuplicateIds.forEach((i) => {
|
|
216
|
-
|
|
217
|
-
}), Math.max(
|
|
197
|
+
e.has(i) && this._unsettledDuplicateIds.delete(i);
|
|
198
|
+
}), Math.max(t, ...this._unsettledDuplicateIds) + 1;
|
|
218
199
|
}
|
|
219
200
|
/**
|
|
220
201
|
* Drops the "already fetched" claims of a block that arrived holding a baked id
|
|
@@ -223,34 +204,12 @@ class Z extends S {
|
|
|
223
204
|
* Deferred a tick: the collision handlers rename a sibling first, and either sibling can be
|
|
224
205
|
* the renamed one depending on where the module was dropped (SD-149916).
|
|
225
206
|
*/
|
|
226
|
-
_scheduleArrivalReset(
|
|
227
|
-
|
|
228
|
-
const
|
|
229
|
-
|
|
207
|
+
_scheduleArrivalReset(t) {
|
|
208
|
+
g().isFeatureEnabled("reusableRecommendationStrategy") && setTimeout(() => {
|
|
209
|
+
const e = this._getRecommendationId(t);
|
|
210
|
+
e !== null && e > 0 && !this._resetSourceIds.delete(e) && h().resetArrivedBlock(e);
|
|
230
211
|
}, 0);
|
|
231
212
|
}
|
|
232
|
-
/**
|
|
233
|
-
* Re-reads the strategy of a block that arrived with saved cards, without waiting for a click.
|
|
234
|
-
* Blocks of one opened template or dropped module arrive in one tick and refresh together.
|
|
235
|
-
*/
|
|
236
|
-
_queueArrivalRefresh(e) {
|
|
237
|
-
d().isFeatureEnabled("reusableRecommendationStrategy") && (this._arrivedNodes.push(e) > 1 || setTimeout(() => {
|
|
238
|
-
const t = this._arrivedNodes;
|
|
239
|
-
this._arrivedNodes = [];
|
|
240
|
-
try {
|
|
241
|
-
this._refreshArrivedBlocks(t);
|
|
242
|
-
} catch (i) {
|
|
243
|
-
console.error("[recommendation] refreshing an arrived strategy failed", i);
|
|
244
|
-
}
|
|
245
|
-
}, 0));
|
|
246
|
-
}
|
|
247
|
-
_refreshArrivedBlocks(e) {
|
|
248
|
-
const t = e.flatMap((i) => {
|
|
249
|
-
const r = this._getRecommendationId(i), s = this._getBlockElement(i);
|
|
250
|
-
return !r || !s || this._refreshingIds.has(r) ? [] : (this._refreshingIds.add(r), [{ id: r, config: o.getConfig(s) }]);
|
|
251
|
-
});
|
|
252
|
-
t.length && (k(this.api), $(t).catch((i) => console.error("[recommendation] refreshing an arrived strategy failed", i)).finally(() => t.forEach(({ id: i }) => this._refreshingIds.delete(i))));
|
|
253
|
-
}
|
|
254
213
|
/**
|
|
255
214
|
* Heals a duplicate that slipped past the create-time `_detectDuplicate`
|
|
256
215
|
* scan (or that was persisted by an older template before SD-142352).
|
|
@@ -263,54 +222,49 @@ class Z extends S {
|
|
|
263
222
|
* yanking the user's current selection mid-edit when the heal fires from
|
|
264
223
|
* `onDocumentChanged`.
|
|
265
224
|
*/
|
|
266
|
-
_healLingeringDuplicate(
|
|
267
|
-
const
|
|
268
|
-
if (!(
|
|
225
|
+
_healLingeringDuplicate(t) {
|
|
226
|
+
const e = this._getRecommendationId(t);
|
|
227
|
+
if (!(e === null || e <= 0))
|
|
269
228
|
try {
|
|
270
229
|
const i = this.api.getDocumentRoot();
|
|
271
230
|
if (!i || !("querySelectorAll" in i))
|
|
272
231
|
return;
|
|
273
|
-
const
|
|
274
|
-
`.${u}[${
|
|
232
|
+
const n = i.querySelectorAll(
|
|
233
|
+
`.${u}[${m}="${e}"]`
|
|
275
234
|
);
|
|
276
|
-
if (
|
|
235
|
+
if (n.length <= 1)
|
|
277
236
|
return;
|
|
278
|
-
const
|
|
279
|
-
if (!
|
|
237
|
+
const o = this._getBlockElement(t);
|
|
238
|
+
if (!o)
|
|
280
239
|
return;
|
|
281
|
-
let
|
|
282
|
-
for (let
|
|
283
|
-
if (
|
|
284
|
-
|
|
240
|
+
let r = -1;
|
|
241
|
+
for (let c = 0; c < n.length; c++)
|
|
242
|
+
if (n[c] === o) {
|
|
243
|
+
r = c;
|
|
285
244
|
break;
|
|
286
245
|
}
|
|
287
|
-
if (
|
|
246
|
+
if (r <= 0)
|
|
288
247
|
return;
|
|
289
|
-
this._reassignDuplicateId(
|
|
248
|
+
this._reassignDuplicateId(t, e);
|
|
290
249
|
} catch {
|
|
291
250
|
}
|
|
292
251
|
}
|
|
293
252
|
/** True when another block already holds the same id — Stripo's duplication signal. */
|
|
294
|
-
_detectDuplicate(
|
|
253
|
+
_detectDuplicate(t) {
|
|
295
254
|
try {
|
|
296
|
-
const
|
|
297
|
-
if (
|
|
298
|
-
return
|
|
299
|
-
`.${u}[${
|
|
255
|
+
const e = this.api.getDocumentRoot();
|
|
256
|
+
if (e && "querySelectorAll" in e)
|
|
257
|
+
return e.querySelectorAll(
|
|
258
|
+
`.${u}[${m}="${t}"]`
|
|
300
259
|
).length > 1;
|
|
301
260
|
} catch {
|
|
302
261
|
}
|
|
303
262
|
return !1;
|
|
304
263
|
}
|
|
305
264
|
/** Assigns a fresh id to a duplicated block and syncs DOM, node config and store. */
|
|
306
|
-
_handleDuplicate(
|
|
307
|
-
const i = this._reassignDuplicateId(
|
|
308
|
-
|
|
309
|
-
this._resetSourceIds.add(t), k(this.api);
|
|
310
|
-
const s = [t, i].filter((n) => !this._refreshingIds.has(n));
|
|
311
|
-
s.forEach((n) => this._refreshingIds.add(n)), H(t, i, o.getConfig(e)).catch((n) => console.error("[recommendation] refreshing a duplicated strategy failed", n)).finally(() => s.forEach((n) => this._refreshingIds.delete(n)));
|
|
312
|
-
}
|
|
313
|
-
this._warnIfMultipleBlocks();
|
|
265
|
+
_handleDuplicate(t, e) {
|
|
266
|
+
const i = this._reassignDuplicateId(t, e), n = h();
|
|
267
|
+
n.cloneBlockState(e, i), n.setCurrentBlock(i), g().isFeatureEnabled("reusableRecommendationStrategy") && (this._resetSourceIds.add(e), H(this.api), $(e, i, s.getConfig(t)).catch((o) => console.error("[recommendation] refreshing a duplicated strategy failed", o))), this._warnIfMultipleBlocks();
|
|
314
268
|
}
|
|
315
269
|
/**
|
|
316
270
|
* Core id-reassignment for a duplicated block: rewrites the DOM
|
|
@@ -323,13 +277,13 @@ class Z extends S {
|
|
|
323
277
|
* effects so older bug-affected templates can self-repair without
|
|
324
278
|
* disturbing the user's current selection).
|
|
325
279
|
*/
|
|
326
|
-
_reassignDuplicateId(
|
|
327
|
-
const i = this._generateNextId(),
|
|
328
|
-
return this._unsettledDuplicateIds.add(i), this._assignRecommendationId(
|
|
280
|
+
_reassignDuplicateId(t, e) {
|
|
281
|
+
const i = this._generateNextId(), n = this._getBlockElement(t);
|
|
282
|
+
return this._unsettledDuplicateIds.add(i), this._assignRecommendationId(t, i), n && this._reassignInstanceClass(n, e, i), s.hasConfig(t) && s.updateConfig(
|
|
329
283
|
this.api,
|
|
330
|
-
|
|
284
|
+
t,
|
|
331
285
|
{ recommendationId: i },
|
|
332
|
-
`Reassign recommendation ID on duplicate (was ${
|
|
286
|
+
`Reassign recommendation ID on duplicate (was ${e})`
|
|
333
287
|
), i;
|
|
334
288
|
}
|
|
335
289
|
/**
|
|
@@ -339,12 +293,12 @@ class Z extends S {
|
|
|
339
293
|
* the source's class would both leak stylistic edits across blocks and
|
|
340
294
|
* cause the mail render to apply the source block's config to the clone.
|
|
341
295
|
*/
|
|
342
|
-
_reassignInstanceClass(
|
|
343
|
-
if (!("getAttribute" in
|
|
296
|
+
_reassignInstanceClass(t, e, i) {
|
|
297
|
+
if (!("getAttribute" in t))
|
|
344
298
|
return;
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
`Reassign recommendation instance class ${
|
|
299
|
+
const n = `ins-recommendation-v3-block-${e}`, o = `ins-recommendation-v3-block-${i}`, r = this.api.getDocumentModifier();
|
|
300
|
+
r.modifyHtml(t).removeClass(n).setClass(o), r.apply(new p(
|
|
301
|
+
`Reassign recommendation instance class ${n} -> ${o}`
|
|
348
302
|
));
|
|
349
303
|
}
|
|
350
304
|
/**
|
|
@@ -353,64 +307,64 @@ class Z extends S {
|
|
|
353
307
|
* HTML by getTemplate(), since Stripo's Angular rendering overwrites dynamically
|
|
354
308
|
* added classes via setAttribute.
|
|
355
309
|
*/
|
|
356
|
-
_assignRecommendationId(
|
|
357
|
-
const i = this._getBlockElement(
|
|
310
|
+
_assignRecommendationId(t, e) {
|
|
311
|
+
const i = this._getBlockElement(t);
|
|
358
312
|
if (!i)
|
|
359
313
|
return;
|
|
360
|
-
const
|
|
361
|
-
|
|
314
|
+
const n = this.api.getDocumentModifier();
|
|
315
|
+
n.modifyHtml(i).setAttribute(m, e.toString()), n.apply(new p(`Assign recommendation ID ${e}`));
|
|
362
316
|
}
|
|
363
317
|
/**
|
|
364
318
|
* Stamps the `hide-price` attribute (read by email-service at send time) on
|
|
365
319
|
* the block element from the config flag.
|
|
366
320
|
*/
|
|
367
|
-
_stampHidePrice(
|
|
368
|
-
const i = this._getBlockElement(
|
|
369
|
-
i && this.api.getDocumentModifier().modifyHtml(i).setAttribute(
|
|
321
|
+
_stampHidePrice(t, e) {
|
|
322
|
+
const i = this._getBlockElement(t);
|
|
323
|
+
i && this.api.getDocumentModifier().modifyHtml(i).setAttribute(D, String(e)).apply(new p("Stamp hide-price"));
|
|
370
324
|
}
|
|
371
325
|
/**
|
|
372
326
|
* Stamps `hide-price` from config only when the block lacks the attribute —
|
|
373
327
|
* heals templates saved before this feature without dirtying current ones.
|
|
374
328
|
*/
|
|
375
|
-
_healHidePriceAttr(
|
|
376
|
-
const
|
|
377
|
-
if (!
|
|
329
|
+
_healHidePriceAttr(t) {
|
|
330
|
+
const e = this._getBlockElement(t);
|
|
331
|
+
if (!e || !("getAttribute" in e) || e.getAttribute(D) !== null)
|
|
378
332
|
return;
|
|
379
|
-
const { priceHideIfSameAsDiscounted: i } =
|
|
380
|
-
this._stampHidePrice(
|
|
333
|
+
const { priceHideIfSameAsDiscounted: i } = s.getConfig(t);
|
|
334
|
+
this._stampHidePrice(t, i);
|
|
381
335
|
}
|
|
382
336
|
/**
|
|
383
337
|
* Gets the recommendation-id from a block node
|
|
384
338
|
*/
|
|
385
|
-
_getRecommendationId(
|
|
386
|
-
const
|
|
387
|
-
if (!
|
|
339
|
+
_getRecommendationId(t) {
|
|
340
|
+
const e = this._getBlockElement(t);
|
|
341
|
+
if (!e || !("getAttribute" in e))
|
|
388
342
|
return null;
|
|
389
|
-
const i =
|
|
343
|
+
const i = e.getAttribute(m);
|
|
390
344
|
if (!i)
|
|
391
345
|
return null;
|
|
392
|
-
const
|
|
393
|
-
return Number.isNaN(
|
|
346
|
+
const n = parseInt(i);
|
|
347
|
+
return Number.isNaN(n) ? null : n;
|
|
394
348
|
}
|
|
395
349
|
/**
|
|
396
350
|
* Gets the block element (the element with BLOCK_CLASS)
|
|
397
351
|
*/
|
|
398
|
-
_getBlockElement(
|
|
399
|
-
if ("getAttribute" in
|
|
400
|
-
const
|
|
401
|
-
if (
|
|
402
|
-
return
|
|
352
|
+
_getBlockElement(t) {
|
|
353
|
+
if ("getAttribute" in t) {
|
|
354
|
+
const e = t.getAttribute("class");
|
|
355
|
+
if (e && e.includes(u))
|
|
356
|
+
return t;
|
|
403
357
|
}
|
|
404
|
-
return "querySelector" in
|
|
358
|
+
return "querySelector" in t ? t.querySelector(`.${u}`) ?? null : null;
|
|
405
359
|
}
|
|
406
360
|
/**
|
|
407
361
|
* Migrate configuration from legacy format
|
|
408
362
|
*/
|
|
409
|
-
_migrateFromLegacy(
|
|
410
|
-
|
|
363
|
+
_migrateFromLegacy(t) {
|
|
364
|
+
s.migrateFromDataAttributes(this.api, t);
|
|
411
365
|
}
|
|
412
366
|
}
|
|
413
367
|
export {
|
|
414
|
-
|
|
415
|
-
|
|
368
|
+
k as BLOCK_ID,
|
|
369
|
+
Y as RecommendationBlock
|
|
416
370
|
};
|
|
@@ -1,19 +1,36 @@
|
|
|
1
|
-
import { createImageMarginsControl as
|
|
2
|
-
import { RecommendationBlockId as
|
|
3
|
-
import { RecommendationControlId as
|
|
4
|
-
import { BLOCK_ROOT_SELECTOR as
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
t
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { createImageMarginsControl as I, createImageSizeControl as d } from "../../../controlFactories.js";
|
|
2
|
+
import { RecommendationBlockId as n } from "../../constants/blockIds.js";
|
|
3
|
+
import { RecommendationControlId as m } from "../../constants/controlIds.js";
|
|
4
|
+
import { BLOCK_ROOT_SELECTOR as a } from "../../constants/selectors.js";
|
|
5
|
+
import { hasGetStyle as f } from "../../utils/tagName.js";
|
|
6
|
+
const s = ["width", "height"];
|
|
7
|
+
function g(t) {
|
|
8
|
+
return f(t) && s.some((e) => !!t.getStyle(e));
|
|
9
|
+
}
|
|
10
|
+
class S extends d(
|
|
11
|
+
m.IMAGE_SIZE,
|
|
12
|
+
n.IMAGE,
|
|
13
|
+
a
|
|
14
|
+
) {
|
|
15
|
+
getAdditionalModifications(e) {
|
|
16
|
+
const r = this.getTargetNodes(e).map((o) => o.querySelector("img")).filter((o) => !!o && g(o));
|
|
17
|
+
if (!r.length)
|
|
18
|
+
return;
|
|
19
|
+
const i = this.api.getDocumentModifier();
|
|
20
|
+
return r.forEach((o) => {
|
|
21
|
+
const l = i.modifyHtml(o);
|
|
22
|
+
s.forEach((c) => l.removeStyle(c));
|
|
23
|
+
}), i;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const h = I(
|
|
27
|
+
m.IMAGE_MARGINS,
|
|
28
|
+
n.IMAGE,
|
|
29
|
+
a
|
|
30
|
+
), A = {
|
|
31
|
+
size: S,
|
|
32
|
+
margins: h
|
|
16
33
|
};
|
|
17
34
|
export {
|
|
18
|
-
|
|
35
|
+
A as ImageControls
|
|
19
36
|
};
|
|
@@ -1,60 +1,43 @@
|
|
|
1
|
-
import { useRecommendationExtensionStore as
|
|
2
|
-
import { refreshBlockOutsidePanel as
|
|
3
|
-
import { toBlockUrlConfig as
|
|
4
|
-
import { commitBlockChangeOutsidePanel as
|
|
5
|
-
function
|
|
6
|
-
const r = JSON.stringify(
|
|
7
|
-
return
|
|
1
|
+
import { useRecommendationExtensionStore as g } from "../store/recommendation.js";
|
|
2
|
+
import { refreshBlockOutsidePanel as y } from "./blockRefresh.js";
|
|
3
|
+
import { toBlockUrlConfig as a } from "./blockUrlConfig.js";
|
|
4
|
+
import { commitBlockChangeOutsidePanel as l, readBlockNodeConfigs as S } from "./nodeConfigWriter.js";
|
|
5
|
+
function d(e, t) {
|
|
6
|
+
const r = JSON.stringify(a(t));
|
|
7
|
+
return S(e).find((o) => JSON.stringify(a(o)) !== r) ?? t;
|
|
8
8
|
}
|
|
9
|
-
async function
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
async function p(e, t, r) {
|
|
10
|
+
const o = g(), s = [e, t];
|
|
11
|
+
(/* @__PURE__ */ new Map([[e, d(e, r)], [t, r]])).forEach((n, i) => {
|
|
12
|
+
var m;
|
|
13
|
+
(!!n.strategyId || i === t) && ((m = o.blockStates[i]) == null ? void 0 : m.recommendationConfigs.strategyId) !== n.strategyId && o.seedBlockUrlConfig(i, a(n));
|
|
14
|
+
}), o.resetArrivedBlock(t), await Promise.all(s.map(async (n) => {
|
|
15
|
+
if (!await o.refreshStrategyBlock(n))
|
|
13
16
|
return;
|
|
14
|
-
const { recommendationConfigs:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{ size:
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const { recommendationConfigs: i, recommendationProducts: f } = o.blockStates[n];
|
|
18
|
+
l(
|
|
19
|
+
n,
|
|
20
|
+
{ size: i.size },
|
|
21
|
+
f,
|
|
22
|
+
"Refresh duplicated recommendation strategy"
|
|
20
23
|
);
|
|
21
24
|
}));
|
|
22
25
|
}
|
|
23
|
-
async function
|
|
24
|
-
|
|
25
|
-
(/* @__PURE__ */ new Map([[o, S(o, r)], [t, r]])).forEach((a, f) => {
|
|
26
|
-
var g;
|
|
27
|
-
(!!a.strategyId || f === t) && ((g = n.blockStates[f]) == null ? void 0 : g.recommendationConfigs.strategyId) !== a.strategyId && n.seedBlockUrlConfig(f, i(a));
|
|
28
|
-
}), n.resetArrivedBlock(t), await m(e, "Refresh duplicated recommendation strategy");
|
|
29
|
-
}
|
|
30
|
-
async function k(o) {
|
|
31
|
-
const t = c(), r = o.filter(({ config: e }) => !!e.strategyId);
|
|
32
|
-
if (!r.length)
|
|
33
|
-
return;
|
|
34
|
-
r.forEach(({ id: e, config: s }) => t.seedBlockUrlConfig(e, i(s))), t.invalidateStrategies();
|
|
35
|
-
const n = new Map(r.map(({ id: e, config: s }) => [e, s.size]));
|
|
36
|
-
await m(
|
|
37
|
-
r.map(({ id: e }) => e),
|
|
38
|
-
"Refresh recommendation strategy",
|
|
39
|
-
(e, s) => s !== n.get(e)
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
async function O(o, t) {
|
|
43
|
-
if (!c().blockStates[o])
|
|
26
|
+
async function k(e, t) {
|
|
27
|
+
if (!g().blockStates[e])
|
|
44
28
|
return !1;
|
|
45
|
-
const r = await
|
|
46
|
-
pickUpdates: ({ strategyId:
|
|
47
|
-
strategyId:
|
|
48
|
-
strategy:
|
|
49
|
-
size:
|
|
50
|
-
configVersion:
|
|
29
|
+
const r = await y(e, {
|
|
30
|
+
pickUpdates: ({ strategyId: o, strategy: s, size: c, nodeConfigVersion: n }) => ({
|
|
31
|
+
strategyId: o,
|
|
32
|
+
strategy: s,
|
|
33
|
+
size: c,
|
|
34
|
+
configVersion: n
|
|
51
35
|
}),
|
|
52
36
|
description: t
|
|
53
37
|
});
|
|
54
|
-
return r || console.error("[recommendation] strategy change did not reach a node", { blockId:
|
|
38
|
+
return r || console.error("[recommendation] strategy change did not reach a node", { blockId: e }), r;
|
|
55
39
|
}
|
|
56
40
|
export {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
C as refreshDuplicatedStrategyBlocks
|
|
41
|
+
k as commitStrategyChange,
|
|
42
|
+
p as refreshDuplicatedStrategyBlocks
|
|
60
43
|
};
|
|
@@ -19,9 +19,6 @@ export declare class RecommendationBlock extends Block {
|
|
|
19
19
|
private _resetSourceIds;
|
|
20
20
|
/** Ids handed to duplicates the document root does not show yet: a copied module renames all its blocks at once. */
|
|
21
21
|
private _unsettledDuplicateIds;
|
|
22
|
-
private _arrivedNodes;
|
|
23
|
-
/** Ids whose arrival or duplicate refresh is in flight, so a second refresh of the same block does not race it. */
|
|
24
|
-
private _refreshingIds;
|
|
25
22
|
constructor();
|
|
26
23
|
getId(): string;
|
|
27
24
|
getIcon(): string;
|
|
@@ -47,8 +44,6 @@ export declare class RecommendationBlock extends Block {
|
|
|
47
44
|
* @param node - The newly created block node
|
|
48
45
|
*/
|
|
49
46
|
onCreated(node: ImmutableHtmlNode): void;
|
|
50
|
-
/** Refreshes every block of an opened template: Stripo restores a stored document without `onCreated`. */
|
|
51
|
-
onDocumentInit(): void;
|
|
52
47
|
/**
|
|
53
48
|
* Called when the document changes or template is loaded
|
|
54
49
|
*
|
|
@@ -90,12 +85,6 @@ export declare class RecommendationBlock extends Block {
|
|
|
90
85
|
* the renamed one depending on where the module was dropped (SD-149916).
|
|
91
86
|
*/
|
|
92
87
|
private _scheduleArrivalReset;
|
|
93
|
-
/**
|
|
94
|
-
* Re-reads the strategy of a block that arrived with saved cards, without waiting for a click.
|
|
95
|
-
* Blocks of one opened template or dropped module arrive in one tick and refresh together.
|
|
96
|
-
*/
|
|
97
|
-
private _queueArrivalRefresh;
|
|
98
|
-
private _refreshArrivedBlocks;
|
|
99
88
|
/**
|
|
100
89
|
* Heals a duplicate that slipped past the create-time `_detectDuplicate`
|
|
101
90
|
* scan (or that was persisted by an older template before SD-142352).
|
|
@@ -3,35 +3,41 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Controls for styling the product image element in recommendation cards.
|
|
5
5
|
*/
|
|
6
|
+
import type { ImmutableHtmlNode } from '@stripoinc/ui-editor-extensions';
|
|
7
|
+
declare const SizeControl_base: {
|
|
8
|
+
new (): {
|
|
9
|
+
getId(): string;
|
|
10
|
+
getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
|
|
11
|
+
getParentControlId(): string;
|
|
12
|
+
api: import("@stripoinc/ui-editor-extensions").ControlApi;
|
|
13
|
+
getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
|
|
14
|
+
getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
|
|
15
|
+
getAdditionalModifications(_root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
|
|
16
|
+
isVisible(_node: ImmutableHtmlNode): boolean;
|
|
17
|
+
getElementLockCategory(): import("@stripoinc/ui-editor-extensions").ElementLockCategory | undefined;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
declare class SizeControl extends SizeControl_base {
|
|
21
|
+
getAdditionalModifications(root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
|
|
22
|
+
}
|
|
6
23
|
/**
|
|
7
24
|
* Grouped Image Controls
|
|
8
25
|
* Use this object for cleaner imports in extension.ts
|
|
9
26
|
*/
|
|
10
27
|
export declare const ImageControls: {
|
|
11
|
-
readonly size:
|
|
12
|
-
new (): {
|
|
13
|
-
getId(): string;
|
|
14
|
-
getTargetNodes(root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode[];
|
|
15
|
-
getParentControlId(): string;
|
|
16
|
-
api: import("@stripoinc/ui-editor-extensions").ControlApi;
|
|
17
|
-
getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
|
|
18
|
-
getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
|
|
19
|
-
getAdditionalModifications(_root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
|
|
20
|
-
isVisible(_node: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): boolean;
|
|
21
|
-
getElementLockCategory(): import("@stripoinc/ui-editor-extensions").ElementLockCategory | undefined;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
28
|
+
readonly size: typeof SizeControl;
|
|
24
29
|
readonly margins: {
|
|
25
30
|
new (): {
|
|
26
31
|
getId(): string;
|
|
27
|
-
getTargetNodes(root:
|
|
32
|
+
getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
|
|
28
33
|
getParentControlId(): string;
|
|
29
34
|
api: import("@stripoinc/ui-editor-extensions").ControlApi;
|
|
30
35
|
getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
|
|
31
36
|
getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
|
|
32
|
-
getAdditionalModifications(_root:
|
|
33
|
-
isVisible(_node:
|
|
37
|
+
getAdditionalModifications(_root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
|
|
38
|
+
isVisible(_node: ImmutableHtmlNode): boolean;
|
|
34
39
|
getElementLockCategory(): import("@stripoinc/ui-editor-extensions").ElementLockCategory | undefined;
|
|
35
40
|
};
|
|
36
41
|
};
|
|
37
42
|
};
|
|
43
|
+
export {};
|
|
@@ -5,15 +5,6 @@ import type { RecommendationNodeConfig } from '../types/nodeConfig';
|
|
|
5
5
|
* @param config - the arriving block's persisted config; seeds either block its store entry does not match
|
|
6
6
|
*/
|
|
7
7
|
export declare function refreshDuplicatedStrategyBlocks(sourceId: number, duplicateId: number, config: RecommendationNodeConfig): Promise<void>;
|
|
8
|
-
/**
|
|
9
|
-
* Re-reads the strategy of blocks that arrived from a saved template or module, so the panel and
|
|
10
|
-
* preview show a strategy edited since the design was saved without selecting the block.
|
|
11
|
-
* @param blocks - each block's id with its persisted config, the truth its store entry is seeded from
|
|
12
|
-
*/
|
|
13
|
-
export declare function refreshArrivedStrategyBlocks(blocks: {
|
|
14
|
-
id: number;
|
|
15
|
-
config: RecommendationNodeConfig;
|
|
16
|
-
}[]): Promise<void>;
|
|
17
8
|
/**
|
|
18
9
|
* Writes a strategy change and its products straight to the document, without the settings panel.
|
|
19
10
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useinsider/guido",
|
|
3
|
-
"version": "3.21.0-beta.
|
|
3
|
+
"version": "3.21.0-beta.ab76470",
|
|
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",
|