@useinsider/guido 3.15.0 → 3.16.0-beta.0faee0c
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/@types/config/schemas.js +108 -92
- package/dist/components/Guido.vue.js +1 -1
- package/dist/components/Guido.vue2.js +78 -75
- package/dist/composables/useActionsApi.js +30 -22
- package/dist/composables/useEmailTemplateApplier.js +25 -23
- package/dist/composables/useHtmlValidator.js +108 -106
- package/dist/composables/useStripo.js +30 -29
- package/dist/composables/useTimerClone.js +21 -19
- package/dist/config/i18n/en/labels.json.js +7 -3
- package/dist/config/migrator/checkboxMigrator.js +20 -19
- package/dist/config/migrator/radioButtonMigrator.js +26 -25
- package/dist/config/migrator/recommendation/compositionMapper.js +26 -23
- package/dist/config/migrator/recommendation/htmlBuilder.js +156 -155
- package/dist/extensions/Blocks/Checkbox/constants/controlIds.js +4 -0
- package/dist/extensions/Blocks/Checkbox/constants/selectors.js +6 -0
- package/dist/extensions/Blocks/Checkbox/controls/blockBackground/index.js +10 -0
- package/dist/extensions/Blocks/Checkbox/extension.js +6 -5
- package/dist/extensions/Blocks/Checkbox/settingsPanel.js +15 -14
- package/dist/extensions/Blocks/Checkbox/template.js +10 -9
- package/dist/extensions/Blocks/Items/block.js +44 -42
- package/dist/extensions/Blocks/Items/template.js +86 -86
- package/dist/extensions/Blocks/RadioButton/constants/controlIds.js +4 -0
- package/dist/extensions/Blocks/RadioButton/constants/selectors.js +6 -0
- package/dist/extensions/Blocks/RadioButton/controls/blockBackground/index.js +10 -0
- package/dist/extensions/Blocks/RadioButton/extension.js +5 -4
- package/dist/extensions/Blocks/RadioButton/settingsPanel.js +12 -11
- package/dist/extensions/Blocks/RadioButton/template.js +16 -9
- package/dist/extensions/Blocks/Recommendation/constants/selectors.js +18 -15
- package/dist/extensions/Blocks/Recommendation/controls/cardBackground/index.js +5 -9
- package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +363 -322
- package/dist/extensions/Blocks/Recommendation/controls/main/layoutOrientation.js +8 -8
- package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +271 -231
- package/dist/extensions/Blocks/Recommendation/controls/spacing/index.js +98 -113
- package/dist/extensions/Blocks/Recommendation/recommendation.css.js +21 -0
- package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +16 -16
- package/dist/extensions/Blocks/Recommendation/templates/list/template.js +16 -16
- package/dist/extensions/Blocks/Recommendation/templates/utils.js +120 -120
- package/dist/extensions/Blocks/Recommendation/utils/captureStyleTemplates.js +55 -54
- package/dist/extensions/Blocks/Recommendation/utils/compositionKeys.js +89 -0
- package/dist/extensions/Blocks/common-control.js +42 -35
- package/dist/extensions/Blocks/controlFactories.js +117 -115
- package/dist/guido.css +1 -1
- package/dist/library.js +11 -7
- package/dist/node_modules/valibot/dist/index.js +230 -216
- package/dist/public/trackingIds.js +8 -0
- package/dist/src/@types/config/schemas.d.ts +20 -0
- package/dist/src/composables/useActionsApi.d.ts +1 -1
- package/dist/src/composables/useConfig.d.ts +4 -0
- package/dist/src/composables/useHtmlValidator.d.ts +3 -2
- package/dist/src/config/migrator/recommendation/types.d.ts +1 -0
- package/dist/src/extensions/Blocks/Checkbox/constants/controlIds.d.ts +7 -0
- package/dist/src/extensions/Blocks/Checkbox/constants/index.d.ts +10 -0
- package/dist/src/extensions/Blocks/Checkbox/constants/selectors.d.ts +16 -0
- package/dist/src/extensions/Blocks/Checkbox/controls/blockBackground/index.d.ts +14 -0
- package/dist/src/extensions/Blocks/RadioButton/constants/controlIds.d.ts +7 -0
- package/dist/src/extensions/Blocks/RadioButton/constants/index.d.ts +10 -0
- package/dist/src/extensions/Blocks/RadioButton/constants/selectors.d.ts +16 -0
- package/dist/src/extensions/Blocks/RadioButton/controls/blockBackground/index.d.ts +14 -0
- package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +1 -1
- package/dist/src/extensions/Blocks/Recommendation/constants/selectors.d.ts +6 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/cardComposition/index.d.ts +27 -5
- package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +4 -2
- package/dist/src/extensions/Blocks/Recommendation/controls/spacing/index.d.ts +5 -0
- package/dist/src/extensions/Blocks/Recommendation/templates/utils.d.ts +12 -11
- package/dist/src/extensions/Blocks/Recommendation/utils/compositionKeys.d.ts +47 -0
- package/dist/src/extensions/Blocks/_Boilerplate/constants/controlIds.d.ts +7 -0
- package/dist/src/extensions/Blocks/_Boilerplate/constants/index.d.ts +10 -0
- package/dist/src/extensions/Blocks/_Boilerplate/constants/selectors.d.ts +16 -0
- package/dist/src/extensions/Blocks/_Boilerplate/controls/blockBackground/index.d.ts +14 -0
- package/dist/src/extensions/Blocks/common-control.d.ts +3 -1
- package/dist/src/library.d.ts +1 -0
- package/dist/src/public/trackingIds.d.ts +9 -0
- package/dist/src/stores/config.d.ts +36 -0
- package/dist/src/stores/editor.d.ts +25 -0
- package/dist/src/utils/linkTrackingIds.d.ts +30 -0
- package/dist/stores/editor.js +4 -1
- package/dist/stores/onboarding.js +11 -7
- package/dist/utils/linkTrackingIds.js +56 -0
- package/dist/utils/pairProductVariables.js +105 -99
- package/dist/utils/templatePreparation.js +72 -61
- package/package.json +5 -1
|
@@ -1,103 +1,106 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { UIElementType as
|
|
5
|
-
import { CommonControl as
|
|
6
|
-
import { ATTR_PRODUCT_IMAGE as
|
|
7
|
-
import { DEFAULT_COMPOSITION as
|
|
8
|
-
import { RecommendationConfigService as
|
|
9
|
-
import { useRecommendationExtensionStore as
|
|
10
|
-
import { ATTRIBUTE_CELL_CLASS as
|
|
11
|
-
import { listElementRenderer as
|
|
12
|
-
import { resolveInlinePriceOrder as
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
1
|
+
var ot = Object.defineProperty;
|
|
2
|
+
var st = (h, p, t) => p in h ? ot(h, p, { enumerable: !0, configurable: !0, writable: !0, value: t }) : h[p] = t;
|
|
3
|
+
var $ = (h, p, t) => st(h, typeof p != "symbol" ? p + "" : p, t);
|
|
4
|
+
import { UIElementType as g, UEAttr as N, ModificationDescription as A } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
5
|
+
import { CommonControl as nt } from "../../../common-control.js";
|
|
6
|
+
import { ATTR_PRODUCT_IMAGE as B, ATTR_PRODUCT_NAME as lt, ATTR_PRODUCT_PRICE as C, ATTR_PRODUCT_OLD_PRICE as v, ATTR_PRODUCT_OMNIBUS_PRICE as at, ATTR_PRODUCT_OMNIBUS_DISCOUNT as ct, ATTR_PRODUCT_BUTTON as q, ATTR_DATA_CARD_COMPOSITION as V, ATTR_DATA_CUSTOM_ATTRIBUTES as j, ATTR_CUSTOM_PREFIX as I, SELECTOR_ATTRIBUTE_ROW as R, ATTR_DATA_ATTRIBUTE_TYPE as E, BUILT_IN_DEFAULT_ATTRIBUTES as dt } from "../../constants/selectors.js";
|
|
7
|
+
import { DEFAULT_COMPOSITION as K, DEFAULT_VISIBILITY as W } from "../../constants/defaultConfig.js";
|
|
8
|
+
import { RecommendationConfigService as _ } from "../../services/configService.js";
|
|
9
|
+
import { useRecommendationExtensionStore as ut } from "../../store/recommendation.js";
|
|
10
|
+
import { ATTRIBUTE_CELL_CLASS as mt, gridElementRenderer as ht, DEFAULT_CELL_PADDING as pt, buildFillerCell as gt } from "../../templates/grid/elementRenderer.js";
|
|
11
|
+
import { listElementRenderer as bt } from "../../templates/list/elementRenderer.js";
|
|
12
|
+
import { resolveInlinePriceOrder as ft, toDisplayName as _t, toDisplayableAttributeValue as yt, buildElementRenderer as z } from "../../templates/utils.js";
|
|
13
|
+
import { normalizeCompositionKeys as Ct, normalizeCustomAttrValues as St, compositionKeyToProductAttr as w, resolveRowCompositionKey as At, filterToProductAttrValue as y, findAttributeRow as Tt, rewriteLegacyRowKeyHtml as G, bareAttributeName as D, isDefaultProductAttr as $t, productAttrToCompositionKey as k } from "../../utils/compositionKeys.js";
|
|
14
|
+
import { getTableDisplayValue as It } from "../../utils/tagName.js";
|
|
15
|
+
import { isPartnerManagedBlock as vt, regenerateProductRowsWithStyles as Nt, getCurrentLayout as Rt } from "../main/utils.js";
|
|
16
|
+
const Et = "ui-elements-recommendation-card-composition", U = ".product-card-wrapper > tbody", Y = ".product-info-cell > table > tbody", O = "data-visibility", X = {
|
|
16
17
|
ADD_ATTRIBUTE: "addAttribute"
|
|
17
|
-
},
|
|
18
|
-
{ key:
|
|
19
|
-
{ key:
|
|
20
|
-
{ key:
|
|
21
|
-
{ key:
|
|
22
|
-
{ key:
|
|
23
|
-
{ key:
|
|
24
|
-
{ key:
|
|
25
|
-
],
|
|
26
|
-
class
|
|
18
|
+
}, b = 5, L = "reorderIcon_", Dt = '<svg width="14" height="10" viewBox="0 0 14 10" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><circle cx="2" cy="2.5" r="1.2"/><circle cx="7" cy="2.5" r="1.2"/><circle cx="12" cy="2.5" r="1.2"/><circle cx="2" cy="7.5" r="1.2"/><circle cx="7" cy="7.5" r="1.2"/><circle cx="12" cy="7.5" r="1.2"/></svg>', m = [
|
|
19
|
+
{ key: B, label: "Product Image" },
|
|
20
|
+
{ key: lt, label: "Product Name" },
|
|
21
|
+
{ key: C, label: "Product Price" },
|
|
22
|
+
{ key: v, label: "Product Original Price" },
|
|
23
|
+
{ key: at, label: "Omnibus Price" },
|
|
24
|
+
{ key: ct, label: "Omnibus Discount" },
|
|
25
|
+
{ key: q, label: "Product Button" }
|
|
26
|
+
], Ot = new Set(m.map((h) => h.key)), T = "customAttr_", P = "deleteAttr_";
|
|
27
|
+
class Wt extends nt {
|
|
27
28
|
constructor() {
|
|
28
29
|
super(...arguments);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
$(this, "store", ut());
|
|
31
|
+
$(this, "unsubscribeStore", null);
|
|
32
|
+
$(this, "eventController", null);
|
|
32
33
|
/**
|
|
33
34
|
* Guard flag: when true, onTemplateNodeUpdated skips _initializeComposition.
|
|
34
35
|
* Used during _onReorder to prevent multiple intermediate rebuilds.
|
|
35
36
|
*/
|
|
36
|
-
|
|
37
|
+
$(this, "reorderInProgress", !1);
|
|
37
38
|
}
|
|
38
39
|
getId() {
|
|
39
|
-
return
|
|
40
|
+
return Et;
|
|
40
41
|
}
|
|
41
42
|
// ========================================================================
|
|
42
43
|
// Lifecycle
|
|
43
44
|
// ========================================================================
|
|
44
45
|
getTemplate() {
|
|
45
|
-
const t =
|
|
46
|
-
<div data-toggle-key="${
|
|
47
|
-
${this._GuToggle(`visibility_${
|
|
46
|
+
const t = m.map((d) => `
|
|
47
|
+
<div data-toggle-key="${d.key}" style="display: none;">
|
|
48
|
+
${this._GuToggle(`visibility_${d.key}`)}
|
|
48
49
|
</div>
|
|
49
50
|
`).join(""), e = Array.from(
|
|
50
|
-
{ length:
|
|
51
|
-
(
|
|
52
|
-
<div data-custom-select-key="${
|
|
51
|
+
{ length: b },
|
|
52
|
+
(d, c) => `
|
|
53
|
+
<div data-custom-select-key="${T}${c}" style="display: none;">
|
|
53
54
|
${this._GuSelect({
|
|
54
|
-
name: `${
|
|
55
|
+
name: `${T}${c}`,
|
|
55
56
|
placeholder: this.api.translate("Select Attribute"),
|
|
56
|
-
options: []
|
|
57
|
+
options: [],
|
|
58
|
+
// A partner's attribute list runs long; search beats scrolling.
|
|
59
|
+
searchable: !0
|
|
57
60
|
})}
|
|
58
61
|
</div>
|
|
59
62
|
`
|
|
60
|
-
).join(""), r =
|
|
63
|
+
).join(""), r = m.length + b, i = Array.from(
|
|
61
64
|
{ length: r },
|
|
62
|
-
(
|
|
63
|
-
<div data-reorder-icon-key="${
|
|
64
|
-
<${
|
|
65
|
+
(d, c) => `
|
|
66
|
+
<div data-reorder-icon-key="${L}${c}" style="display: none;">
|
|
67
|
+
<${g.BUTTON}
|
|
65
68
|
class="drag-handle-btn flat-inline flat-white"
|
|
66
|
-
${
|
|
69
|
+
${N.BUTTON.name}="${L}${c}"
|
|
67
70
|
>
|
|
68
|
-
<${
|
|
71
|
+
<${g.ICON}
|
|
69
72
|
src="reorder"
|
|
70
73
|
class="icon-button"
|
|
71
|
-
></${
|
|
72
|
-
</${
|
|
74
|
+
></${g.ICON}>
|
|
75
|
+
</${g.BUTTON}>
|
|
73
76
|
</div>
|
|
74
77
|
`
|
|
75
|
-
).join(""),
|
|
76
|
-
{ length:
|
|
77
|
-
(
|
|
78
|
-
<div data-custom-delete-key="${
|
|
79
|
-
<${
|
|
78
|
+
).join(""), o = Array.from(
|
|
79
|
+
{ length: b },
|
|
80
|
+
(d, c) => `
|
|
81
|
+
<div data-custom-delete-key="${P}${c}" style="display: none;">
|
|
82
|
+
<${g.BUTTON}
|
|
80
83
|
class="custom-attr-delete flat-inline flat-white"
|
|
81
|
-
${
|
|
84
|
+
${N.BUTTON.name}="${P}${c}"
|
|
82
85
|
>
|
|
83
|
-
<${
|
|
86
|
+
<${g.ICON}
|
|
84
87
|
src="delete"
|
|
85
88
|
class="icon-button"
|
|
86
|
-
></${
|
|
87
|
-
</${
|
|
89
|
+
></${g.ICON}>
|
|
90
|
+
</${g.BUTTON}>
|
|
88
91
|
</div>
|
|
89
92
|
`
|
|
90
93
|
).join(""), s = "https://academy.insiderone.com/docs/new-editor-email-recommendation-block", n = this.api.translate(
|
|
91
94
|
"Drag and drop the card elements to reorder them, adjust their visibility or add new attributes up to 5."
|
|
92
|
-
),
|
|
95
|
+
), l = this.api.translate("For more information, you can"), a = this.api.translate("visit Academy");
|
|
93
96
|
return `
|
|
94
97
|
<div class="recommendation-controls-container" data-card-composition-control>
|
|
95
98
|
<div class="container">
|
|
96
99
|
<p class="card-composition-description">
|
|
97
100
|
${n}
|
|
98
|
-
${
|
|
101
|
+
${l}
|
|
99
102
|
<!-- cspell:disable-next-line -->
|
|
100
|
-
<a href="${s}" target="_blank" rel="noopener noreferrer">${
|
|
103
|
+
<a href="${s}" target="_blank" rel="noopener noreferrer">${a}</a>.
|
|
101
104
|
</p>
|
|
102
105
|
</div>
|
|
103
106
|
|
|
@@ -110,17 +113,17 @@ class qt extends rt {
|
|
|
110
113
|
</div>
|
|
111
114
|
|
|
112
115
|
<div class="custom-delete-store" style="display: none;">
|
|
113
|
-
${
|
|
116
|
+
${o}
|
|
114
117
|
</div>
|
|
115
118
|
|
|
116
119
|
<div class="reorder-icon-store" style="display: none;">
|
|
117
|
-
${
|
|
120
|
+
${i}
|
|
118
121
|
</div>
|
|
119
122
|
|
|
120
123
|
<div class="orderable-list" data-composition-list></div>
|
|
121
124
|
|
|
122
125
|
${this._GuButton({
|
|
123
|
-
name:
|
|
126
|
+
name: X.ADD_ATTRIBUTE,
|
|
124
127
|
label: this.api.translate("Add Attribute"),
|
|
125
128
|
id: "guido__btn-add-attribute"
|
|
126
129
|
})}
|
|
@@ -141,7 +144,7 @@ class qt extends rt {
|
|
|
141
144
|
const t = (r = this.getContainer()) == null ? void 0 : r.querySelector("[data-card-composition-control]");
|
|
142
145
|
if (!t)
|
|
143
146
|
return;
|
|
144
|
-
const e =
|
|
147
|
+
const e = vt(this.currentNode);
|
|
145
148
|
t.style.pointerEvents = e ? "none" : "", t.style.opacity = e ? "0.5" : "";
|
|
146
149
|
}
|
|
147
150
|
onTemplateNodeUpdated(t) {
|
|
@@ -154,19 +157,19 @@ class qt extends rt {
|
|
|
154
157
|
// Initialization
|
|
155
158
|
// ========================================================================
|
|
156
159
|
_initializeComposition() {
|
|
157
|
-
const t = this._readCompositionFromNode(), e = this._readCustomAttributesFromNode(), r = this._readVisibilityFromRows(),
|
|
158
|
-
this.api.updateValues(
|
|
160
|
+
const t = this._readCompositionFromNode(), e = this._readCustomAttributesFromNode(), r = this._readVisibilityFromRows(), i = this._renderOrderableItems(t, e), o = this._buildVisibilityValues(r);
|
|
161
|
+
this.api.updateValues(o), i && this._initializeCustomSelects(e), this._updateAddButtonState();
|
|
159
162
|
}
|
|
160
163
|
_registerValueChangeListeners() {
|
|
161
|
-
|
|
164
|
+
m.forEach((t) => {
|
|
162
165
|
this.api.onValueChanged(`visibility_${t.key}`, (e) => {
|
|
163
166
|
this._applyVisibilityToBlock(t.key, e);
|
|
164
167
|
});
|
|
165
168
|
});
|
|
166
|
-
for (let t = 0; t <
|
|
167
|
-
const e = `${
|
|
168
|
-
this.api.onValueChanged(e, (
|
|
169
|
-
this._onCustomAttributeChanged(r,
|
|
169
|
+
for (let t = 0; t < b; t++) {
|
|
170
|
+
const e = `${T}${t}`, r = t;
|
|
171
|
+
this.api.onValueChanged(e, (i) => {
|
|
172
|
+
this._onCustomAttributeChanged(r, i);
|
|
170
173
|
});
|
|
171
174
|
}
|
|
172
175
|
}
|
|
@@ -175,56 +178,64 @@ class qt extends rt {
|
|
|
175
178
|
// ========================================================================
|
|
176
179
|
_readCompositionFromNode() {
|
|
177
180
|
if (!this.currentNode || !("getAttribute" in this.currentNode))
|
|
178
|
-
return [...
|
|
179
|
-
const t = this.currentNode.getAttribute(
|
|
181
|
+
return [...K];
|
|
182
|
+
const t = this.currentNode.getAttribute(V);
|
|
180
183
|
if (t)
|
|
181
|
-
return t.split(",").filter(Boolean);
|
|
182
|
-
const { composition: e } =
|
|
183
|
-
return e != null && e.length ? [...e] : [...
|
|
184
|
+
return this._normalizeComposition(t.split(",").filter(Boolean));
|
|
185
|
+
const { composition: e } = _.getConfig(this.currentNode);
|
|
186
|
+
return e != null && e.length ? this._normalizeComposition([...e]) : [...K];
|
|
187
|
+
}
|
|
188
|
+
/** Upgrades legacy bare-name custom keys to the canonical form. (SD-147101) */
|
|
189
|
+
_normalizeComposition(t) {
|
|
190
|
+
return Ct(t, this.currentNode, this.store.filterList);
|
|
184
191
|
}
|
|
185
192
|
_readCustomAttributesFromNode() {
|
|
186
193
|
if (!this.currentNode || !("getAttribute" in this.currentNode))
|
|
187
194
|
return [];
|
|
188
|
-
const t = this.currentNode.getAttribute(
|
|
195
|
+
const t = this.currentNode.getAttribute(j);
|
|
189
196
|
if (t)
|
|
190
197
|
try {
|
|
191
|
-
return
|
|
198
|
+
return St(
|
|
199
|
+
JSON.parse(t).map((e) => String(e)),
|
|
200
|
+
this.currentNode,
|
|
201
|
+
this.store.filterList
|
|
202
|
+
);
|
|
192
203
|
} catch {
|
|
193
204
|
return [];
|
|
194
205
|
}
|
|
195
|
-
return this._readCompositionFromNode().filter((e) => e.startsWith(
|
|
206
|
+
return this._readCompositionFromNode().filter((e) => e.startsWith(I)).map(w);
|
|
196
207
|
}
|
|
197
208
|
_readVisibilityFromRows() {
|
|
198
209
|
if (!this.currentNode)
|
|
199
210
|
return this._getDefaultVisibilities();
|
|
200
|
-
const t = Array.from(this.currentNode.querySelectorAll(
|
|
211
|
+
const t = Array.from(this.currentNode.querySelectorAll(R)), e = this._extractVisibilityFromRows(t);
|
|
201
212
|
if (Object.keys(e).length > 0)
|
|
202
213
|
return this._mergeWithDefaults(e);
|
|
203
|
-
const r =
|
|
214
|
+
const r = _.getConfig(this.currentNode).visibility;
|
|
204
215
|
return this._mergeWithDefaults({ ...r });
|
|
205
216
|
}
|
|
206
217
|
_getDefaultVisibilities() {
|
|
207
|
-
return { ...
|
|
218
|
+
return { ...W };
|
|
208
219
|
}
|
|
209
220
|
_extractVisibilityFromRows(t) {
|
|
210
221
|
const e = {};
|
|
211
222
|
return t.forEach((r) => {
|
|
212
223
|
if (!("getAttribute" in r))
|
|
213
224
|
return;
|
|
214
|
-
const
|
|
215
|
-
|
|
225
|
+
const i = At(r), o = r.getAttribute(O);
|
|
226
|
+
i && o !== null && (e[i] = this._parseVisibilityValue(o));
|
|
216
227
|
}), e;
|
|
217
228
|
}
|
|
218
229
|
_parseVisibilityValue(t) {
|
|
219
230
|
return t === "1" || t === "true";
|
|
220
231
|
}
|
|
221
232
|
_mergeWithDefaults(t) {
|
|
222
|
-
return Object.entries(
|
|
233
|
+
return Object.entries(W).forEach(([e, r]) => {
|
|
223
234
|
e in t || (t[e] = r);
|
|
224
235
|
}), t;
|
|
225
236
|
}
|
|
226
237
|
_buildVisibilityValues(t) {
|
|
227
|
-
return
|
|
238
|
+
return m.reduce((e, r) => (e[`visibility_${r.key}`] = t[r.key] ?? !0, e), {});
|
|
228
239
|
}
|
|
229
240
|
// ========================================================================
|
|
230
241
|
// UI Rendering (Orderable List)
|
|
@@ -238,30 +249,30 @@ class qt extends rt {
|
|
|
238
249
|
const r = this._getControlContainer();
|
|
239
250
|
if (!r)
|
|
240
251
|
return !1;
|
|
241
|
-
const
|
|
242
|
-
if (!
|
|
252
|
+
const i = r.querySelector("[data-composition-list]");
|
|
253
|
+
if (!i)
|
|
243
254
|
return !1;
|
|
244
|
-
const
|
|
245
|
-
if (!(
|
|
255
|
+
const o = !_.getConfig(this.currentNode).priceMovedToNextLine;
|
|
256
|
+
if (!(i.dataset.inlinePrices !== String(o)) && this._tryReorderInPlace(i, t))
|
|
246
257
|
return !1;
|
|
247
|
-
|
|
248
|
-
const n = new Set(e),
|
|
249
|
-
let
|
|
250
|
-
const
|
|
251
|
-
if (
|
|
252
|
-
return u ===
|
|
253
|
-
if (
|
|
254
|
-
const
|
|
255
|
-
return this._createBuiltInItemHtml(
|
|
258
|
+
i.dataset.inlinePrices = String(o);
|
|
259
|
+
const n = new Set(e), l = ft(t);
|
|
260
|
+
let a = 0, d = 0;
|
|
261
|
+
const c = t.map((u) => {
|
|
262
|
+
if (o && (u === C || u === v))
|
|
263
|
+
return u === l.anchor ? this._createPriceGroupItemHtml(d++, l.originalFirst) : "";
|
|
264
|
+
if (Ot.has(u)) {
|
|
265
|
+
const f = m.find((S) => S.key === u);
|
|
266
|
+
return this._createBuiltInItemHtml(f, d++);
|
|
256
267
|
}
|
|
257
|
-
if (u.startsWith(
|
|
258
|
-
const
|
|
259
|
-
if (n.has(
|
|
260
|
-
return this._createCustomItemHtml(u,
|
|
268
|
+
if (u.startsWith(I)) {
|
|
269
|
+
const f = w(u);
|
|
270
|
+
if (n.has(f))
|
|
271
|
+
return this._createCustomItemHtml(u, a++, d++);
|
|
261
272
|
}
|
|
262
273
|
return "";
|
|
263
274
|
}).join("");
|
|
264
|
-
return this._rescueTogglesToStore(r), this._rescueSelectsToStore(r), this._rescueDeleteButtonsToStore(r), this._rescueReorderIconsToStore(r),
|
|
275
|
+
return this._rescueTogglesToStore(r), this._rescueSelectsToStore(r), this._rescueDeleteButtonsToStore(r), this._rescueReorderIconsToStore(r), i.innerHTML = c, this._moveTogglesIntoItems(r), this._moveSelectsIntoItems(r, e.length), this._moveDeleteButtonsIntoItems(r, e.length), this._moveReorderIconsIntoItems(r, d), !0;
|
|
265
276
|
}
|
|
266
277
|
/**
|
|
267
278
|
* Attempts to reorder existing orderable-item elements to match the composition order.
|
|
@@ -273,27 +284,27 @@ class qt extends rt {
|
|
|
273
284
|
const r = Array.from(t.querySelectorAll(".orderable-item"));
|
|
274
285
|
if (r.length !== e.length)
|
|
275
286
|
return !1;
|
|
276
|
-
const
|
|
277
|
-
if (
|
|
287
|
+
const i = r.map((a) => a.dataset.key).filter(Boolean);
|
|
288
|
+
if (i.length !== e.length)
|
|
278
289
|
return !1;
|
|
279
|
-
const
|
|
280
|
-
if (
|
|
290
|
+
const o = [...i].sort().join(","), s = [...e].sort().join(",");
|
|
291
|
+
if (o !== s || e.some((a) => a.startsWith(I)))
|
|
281
292
|
return !1;
|
|
282
293
|
const n = /* @__PURE__ */ new Map();
|
|
283
|
-
r.forEach((
|
|
284
|
-
const { key:
|
|
285
|
-
if (
|
|
286
|
-
const
|
|
287
|
-
|
|
294
|
+
r.forEach((a) => {
|
|
295
|
+
const { key: d } = a.dataset;
|
|
296
|
+
if (d) {
|
|
297
|
+
const c = n.get(d) || [];
|
|
298
|
+
c.push(a), n.set(d, c);
|
|
288
299
|
}
|
|
289
300
|
});
|
|
290
|
-
const
|
|
291
|
-
return e.forEach((
|
|
292
|
-
const
|
|
293
|
-
if (!
|
|
301
|
+
const l = /* @__PURE__ */ new Map();
|
|
302
|
+
return e.forEach((a) => {
|
|
303
|
+
const d = n.get(a);
|
|
304
|
+
if (!d)
|
|
294
305
|
return;
|
|
295
|
-
const
|
|
296
|
-
|
|
306
|
+
const c = l.get(a) || 0;
|
|
307
|
+
l.set(a, c + 1), d[c] && t.appendChild(d[c]);
|
|
297
308
|
}), !0;
|
|
298
309
|
}
|
|
299
310
|
_createBuiltInItemHtml(t, e) {
|
|
@@ -314,19 +325,19 @@ class qt extends rt {
|
|
|
314
325
|
* plain drag handle (no UE button → untouched by the reorder-icon rescue).
|
|
315
326
|
*/
|
|
316
327
|
_createPriceGroupItemHtml(t, e) {
|
|
317
|
-
var n,
|
|
318
|
-
const r = ((n =
|
|
319
|
-
<div class="price-suborderable-item" draggable="true" data-subkey="${
|
|
320
|
-
<span class="sub-drag-handle">${
|
|
321
|
-
<span class="item-label">${this.api.translate(
|
|
322
|
-
</div>`, s = e ?
|
|
328
|
+
var n, l;
|
|
329
|
+
const r = ((n = m.find((a) => a.key === C)) == null ? void 0 : n.label) ?? "Product Price", i = ((l = m.find((a) => a.key === v)) == null ? void 0 : l.label) ?? "Product Original Price", o = (a, d) => `
|
|
330
|
+
<div class="price-suborderable-item" draggable="true" data-subkey="${a}">
|
|
331
|
+
<span class="sub-drag-handle">${Dt}</span>
|
|
332
|
+
<span class="item-label">${this.api.translate(d)}</span>
|
|
333
|
+
</div>`, s = e ? o(v, i) + o(C, r) : o(C, r) + o(v, i);
|
|
323
334
|
return `
|
|
324
335
|
<div class="orderable-item price-group-item" draggable="true"
|
|
325
|
-
data-key="${
|
|
336
|
+
data-key="${C}" data-group="prices">
|
|
326
337
|
<div class="price-group-header">
|
|
327
338
|
<span class="drag-handle" data-reorder-icon-slot="${t}"></span>
|
|
328
339
|
<span class="item-label">${this.api.translate("Product Prices")}</span>
|
|
329
|
-
<div class="item-action" data-action-for="${
|
|
340
|
+
<div class="item-action" data-action-for="${C}"></div>
|
|
330
341
|
</div>
|
|
331
342
|
<div class="price-suborderable-list">${s}</div>
|
|
332
343
|
</div>
|
|
@@ -346,19 +357,34 @@ class qt extends rt {
|
|
|
346
357
|
`;
|
|
347
358
|
}
|
|
348
359
|
/**
|
|
349
|
-
*
|
|
360
|
+
* Dropdown label of an attribute. A partner can own a default and a custom
|
|
361
|
+
* attribute under the same name; the type is spelled out only then, so partners
|
|
362
|
+
* without a collision keep clean labels. (SD-147101)
|
|
363
|
+
*/
|
|
364
|
+
_toOptionLabel(t, e, r) {
|
|
365
|
+
return r ? `${t} (${this.api.translate(e ? "Default" : "Custom")})` : t;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Builds select options from the store's filterList. Option values are
|
|
369
|
+
* `product-attr` values, so a default attribute and a same-named custom one
|
|
370
|
+
* never collapse onto a single option. (SD-147101)
|
|
350
371
|
* Falls back to a single option for the currently selected attribute.
|
|
351
372
|
*/
|
|
352
373
|
_getSelectOptions(t, e = []) {
|
|
353
374
|
const r = this._getAddableFilters();
|
|
354
|
-
if (r.length
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
375
|
+
if (r.length === 0)
|
|
376
|
+
return [{ text: this._getDisplayNameForAttribute(t), value: t }];
|
|
377
|
+
const i = /* @__PURE__ */ new Map();
|
|
378
|
+
r.forEach((s) => i.set(s.attributeName, (i.get(s.attributeName) ?? 0) + 1));
|
|
379
|
+
const o = new Set(e);
|
|
380
|
+
return o.delete(t), r.filter((s) => !o.has(y(s))).map((s) => ({
|
|
381
|
+
text: this._toOptionLabel(
|
|
382
|
+
s.displayName,
|
|
383
|
+
s.type === "defaultAttribute",
|
|
384
|
+
(i.get(s.attributeName) ?? 0) > 1
|
|
385
|
+
),
|
|
386
|
+
value: y(s)
|
|
387
|
+
}));
|
|
362
388
|
}
|
|
363
389
|
/**
|
|
364
390
|
* Initializes custom attribute selects: sets their options and current value.
|
|
@@ -368,8 +394,8 @@ class qt extends rt {
|
|
|
368
394
|
_initializeCustomSelects(t) {
|
|
369
395
|
t.length !== 0 && setTimeout(() => {
|
|
370
396
|
t.forEach((e, r) => {
|
|
371
|
-
const
|
|
372
|
-
this.api.setUIEAttribute(
|
|
397
|
+
const i = `${T}${r}`, o = this._getSelectOptions(e, t);
|
|
398
|
+
this.api.setUIEAttribute(i, N.SELECTPICKER.items, o), this.api.updateValues({ [i]: e });
|
|
373
399
|
});
|
|
374
400
|
}, 0);
|
|
375
401
|
}
|
|
@@ -378,11 +404,11 @@ class qt extends rt {
|
|
|
378
404
|
* Stripo initializes toggles at template parse time; moving the DOM node preserves bindings.
|
|
379
405
|
*/
|
|
380
406
|
_moveTogglesIntoItems(t) {
|
|
381
|
-
|
|
382
|
-
const r = t.querySelector(`[data-toggle-key="${e.key}"]`),
|
|
383
|
-
if (r &&
|
|
384
|
-
const
|
|
385
|
-
|
|
407
|
+
m.forEach((e) => {
|
|
408
|
+
const r = t.querySelector(`[data-toggle-key="${e.key}"]`), i = t.querySelector(`[data-action-for="${e.key}"]`);
|
|
409
|
+
if (r && i) {
|
|
410
|
+
const o = r.querySelector("ue-switcher");
|
|
411
|
+
o && i.appendChild(o);
|
|
386
412
|
}
|
|
387
413
|
});
|
|
388
414
|
}
|
|
@@ -392,9 +418,9 @@ class qt extends rt {
|
|
|
392
418
|
*/
|
|
393
419
|
_moveSelectsIntoItems(t, e) {
|
|
394
420
|
for (let r = 0; r < e; r++) {
|
|
395
|
-
const
|
|
396
|
-
if (
|
|
397
|
-
const n =
|
|
421
|
+
const i = `${T}${r}`, o = t.querySelector(`[data-custom-select-key="${i}"]`), s = t.querySelector(`[data-custom-select-slot="${r}"]`);
|
|
422
|
+
if (o && s) {
|
|
423
|
+
const n = o.querySelector("ue-select");
|
|
398
424
|
n && s.appendChild(n);
|
|
399
425
|
}
|
|
400
426
|
}
|
|
@@ -406,11 +432,11 @@ class qt extends rt {
|
|
|
406
432
|
* previously-moved toggles, making them permanently lost.
|
|
407
433
|
*/
|
|
408
434
|
_rescueTogglesToStore(t) {
|
|
409
|
-
|
|
410
|
-
const r = t.querySelector(`[data-toggle-key="${e.key}"]`),
|
|
411
|
-
if (
|
|
412
|
-
const
|
|
413
|
-
|
|
435
|
+
m.forEach((e) => {
|
|
436
|
+
const r = t.querySelector(`[data-toggle-key="${e.key}"]`), i = t.querySelector(`[data-action-for="${e.key}"]`);
|
|
437
|
+
if (i) {
|
|
438
|
+
const o = i.querySelector("ue-switcher");
|
|
439
|
+
o && r && r.appendChild(o);
|
|
414
440
|
}
|
|
415
441
|
});
|
|
416
442
|
}
|
|
@@ -419,11 +445,11 @@ class qt extends rt {
|
|
|
419
445
|
* Same rescue pattern as _rescueTogglesToStore — prevents innerHTML from destroying them.
|
|
420
446
|
*/
|
|
421
447
|
_rescueSelectsToStore(t) {
|
|
422
|
-
for (let e = 0; e <
|
|
423
|
-
const r = `${
|
|
424
|
-
if (
|
|
425
|
-
const s =
|
|
426
|
-
s &&
|
|
448
|
+
for (let e = 0; e < b; e++) {
|
|
449
|
+
const r = `${T}${e}`, i = t.querySelector(`[data-custom-select-key="${r}"]`), o = t.querySelector(`[data-custom-select-slot="${e}"]`);
|
|
450
|
+
if (o) {
|
|
451
|
+
const s = o.querySelector("ue-select");
|
|
452
|
+
s && i && i.appendChild(s);
|
|
427
453
|
}
|
|
428
454
|
}
|
|
429
455
|
}
|
|
@@ -433,9 +459,9 @@ class qt extends rt {
|
|
|
433
459
|
*/
|
|
434
460
|
_moveDeleteButtonsIntoItems(t, e) {
|
|
435
461
|
for (let r = 0; r < e; r++) {
|
|
436
|
-
const
|
|
437
|
-
if (
|
|
438
|
-
const n =
|
|
462
|
+
const i = `${P}${r}`, o = t.querySelector(`[data-custom-delete-key="${i}"]`), s = t.querySelector(`[data-custom-delete-slot="${r}"]`);
|
|
463
|
+
if (o && s) {
|
|
464
|
+
const n = o.querySelector("ue-button");
|
|
439
465
|
n && s.appendChild(n);
|
|
440
466
|
}
|
|
441
467
|
}
|
|
@@ -445,11 +471,11 @@ class qt extends rt {
|
|
|
445
471
|
* Same rescue pattern as _rescueSelectsToStore — prevents innerHTML from destroying them.
|
|
446
472
|
*/
|
|
447
473
|
_rescueDeleteButtonsToStore(t) {
|
|
448
|
-
for (let e = 0; e <
|
|
449
|
-
const r = `${
|
|
450
|
-
if (
|
|
451
|
-
const s =
|
|
452
|
-
s &&
|
|
474
|
+
for (let e = 0; e < b; e++) {
|
|
475
|
+
const r = `${P}${e}`, i = t.querySelector(`[data-custom-delete-key="${r}"]`), o = t.querySelector(`[data-custom-delete-slot="${e}"]`);
|
|
476
|
+
if (o) {
|
|
477
|
+
const s = o.querySelector("ue-button");
|
|
478
|
+
s && i && i.appendChild(s);
|
|
453
479
|
}
|
|
454
480
|
}
|
|
455
481
|
}
|
|
@@ -459,9 +485,9 @@ class qt extends rt {
|
|
|
459
485
|
*/
|
|
460
486
|
_moveReorderIconsIntoItems(t, e) {
|
|
461
487
|
for (let r = 0; r < e; r++) {
|
|
462
|
-
const
|
|
463
|
-
if (
|
|
464
|
-
const n =
|
|
488
|
+
const i = `${L}${r}`, o = t.querySelector(`[data-reorder-icon-key="${i}"]`), s = t.querySelector(`[data-reorder-icon-slot="${r}"]`);
|
|
489
|
+
if (o && s) {
|
|
490
|
+
const n = o.querySelector("ue-button");
|
|
465
491
|
n && s.appendChild(n);
|
|
466
492
|
}
|
|
467
493
|
}
|
|
@@ -471,12 +497,12 @@ class qt extends rt {
|
|
|
471
497
|
* Same rescue pattern as _rescueDeleteButtonsToStore — prevents innerHTML from destroying them.
|
|
472
498
|
*/
|
|
473
499
|
_rescueReorderIconsToStore(t) {
|
|
474
|
-
const e =
|
|
500
|
+
const e = m.length + b;
|
|
475
501
|
for (let r = 0; r < e; r++) {
|
|
476
|
-
const
|
|
502
|
+
const i = `${L}${r}`, o = t.querySelector(`[data-reorder-icon-key="${i}"]`), s = t.querySelector(`[data-reorder-icon-slot="${r}"]`);
|
|
477
503
|
if (s) {
|
|
478
504
|
const n = s.querySelector("ue-button");
|
|
479
|
-
n &&
|
|
505
|
+
n && o && o.appendChild(n);
|
|
480
506
|
}
|
|
481
507
|
}
|
|
482
508
|
}
|
|
@@ -488,10 +514,10 @@ class qt extends rt {
|
|
|
488
514
|
const { signal: t } = this.eventController, e = this._getControlContainer();
|
|
489
515
|
if (!e)
|
|
490
516
|
return;
|
|
491
|
-
const r = e.querySelector("[data-composition-list]"),
|
|
492
|
-
r && (this._setupDragAndDrop(r, t), this._setupDeleteHandler(r, t)),
|
|
493
|
-
const
|
|
494
|
-
s && this._onAddAttribute(s
|
|
517
|
+
const r = e.querySelector("[data-composition-list]"), i = e.querySelector("#guido__btn-add-attribute");
|
|
518
|
+
r && (this._setupDragAndDrop(r, t), this._setupDeleteHandler(r, t)), i && i.addEventListener("click", () => {
|
|
519
|
+
const o = new Set(this._readCustomAttributesFromNode()), s = this._getAddableFilters().find((n) => !o.has(y(n)));
|
|
520
|
+
s && this._onAddAttribute(y(s), s.displayName);
|
|
495
521
|
}, { signal: t });
|
|
496
522
|
}
|
|
497
523
|
/**
|
|
@@ -502,11 +528,11 @@ class qt extends rt {
|
|
|
502
528
|
_extractCompositionOrder(t) {
|
|
503
529
|
const e = [];
|
|
504
530
|
return t.querySelectorAll(".orderable-item").forEach((r) => {
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
const s =
|
|
531
|
+
const i = r;
|
|
532
|
+
i.dataset.group === "prices" ? i.querySelectorAll(".price-suborderable-item").forEach((o) => {
|
|
533
|
+
const s = o.dataset.subkey;
|
|
508
534
|
s && e.push(s);
|
|
509
|
-
}) :
|
|
535
|
+
}) : i.dataset.key && e.push(i.dataset.key);
|
|
510
536
|
}), e;
|
|
511
537
|
}
|
|
512
538
|
_setupDragAndDrop(t, e) {
|
|
@@ -529,42 +555,42 @@ class qt extends rt {
|
|
|
529
555
|
* identically.
|
|
530
556
|
*/
|
|
531
557
|
_registerDragHandlers(t, e, r) {
|
|
532
|
-
let
|
|
558
|
+
let i = null, o = null;
|
|
533
559
|
const s = (n) => n.target.closest(r.itemSelector);
|
|
534
560
|
t.addEventListener("dragstart", (n) => {
|
|
535
|
-
var
|
|
536
|
-
const
|
|
537
|
-
if (r.ignoreSelector &&
|
|
561
|
+
var d;
|
|
562
|
+
const l = n.target;
|
|
563
|
+
if (r.ignoreSelector && l.closest(r.ignoreSelector))
|
|
538
564
|
return;
|
|
539
|
-
const
|
|
540
|
-
|
|
565
|
+
const a = s(n);
|
|
566
|
+
a && (i = a, a.classList.add("dragging"), (d = n.dataTransfer) == null || d.setData("text/plain", a.dataset.key ?? a.dataset.subkey ?? ""));
|
|
541
567
|
}, { signal: e }), t.addEventListener("dragend", () => {
|
|
542
|
-
|
|
568
|
+
i == null || i.classList.remove("dragging"), o == null || o.classList.remove("drag-over"), i = null, o = null;
|
|
543
569
|
}, { signal: e }), t.addEventListener("dragover", (n) => {
|
|
544
|
-
if (!
|
|
570
|
+
if (!i)
|
|
545
571
|
return;
|
|
546
|
-
const
|
|
547
|
-
if (!
|
|
572
|
+
const l = s(n);
|
|
573
|
+
if (!l)
|
|
548
574
|
return;
|
|
549
575
|
n.preventDefault();
|
|
550
|
-
const
|
|
551
|
-
|
|
576
|
+
const a = l !== i ? l : null;
|
|
577
|
+
a !== o && (o == null || o.classList.remove("drag-over"), o = a, o == null || o.classList.add("drag-over"));
|
|
552
578
|
}, { signal: e }), t.addEventListener("drop", (n) => {
|
|
553
|
-
var
|
|
554
|
-
const
|
|
555
|
-
if (!
|
|
579
|
+
var c;
|
|
580
|
+
const l = i && s(n);
|
|
581
|
+
if (!i || !l || l === i)
|
|
556
582
|
return;
|
|
557
583
|
n.preventDefault();
|
|
558
|
-
const
|
|
559
|
-
(
|
|
584
|
+
const a = l.getBoundingClientRect(), d = n.clientY < a.top + a.height / 2;
|
|
585
|
+
(c = r.getDropParent(l)) == null || c.insertBefore(i, d ? l : l.nextSibling), o == null || o.classList.remove("drag-over"), i.classList.remove("dragging"), i = null, o = null, this._onReorder(this._extractCompositionOrder(t));
|
|
560
586
|
}, { signal: e });
|
|
561
587
|
}
|
|
562
588
|
_setupDeleteHandler(t, e) {
|
|
563
589
|
t.addEventListener("click", (r) => {
|
|
564
|
-
const
|
|
565
|
-
if (!
|
|
590
|
+
const o = r.target.closest(".custom-attr-delete");
|
|
591
|
+
if (!o)
|
|
566
592
|
return;
|
|
567
|
-
const s =
|
|
593
|
+
const s = o.closest("[data-custom-index]"), n = s == null ? void 0 : s.dataset.customIndex;
|
|
568
594
|
n !== void 0 && this._onDeleteCustomAttribute(Number(n));
|
|
569
595
|
}, { signal: e });
|
|
570
596
|
}
|
|
@@ -572,10 +598,10 @@ class qt extends rt {
|
|
|
572
598
|
// Actions (Add, Delete, Reorder)
|
|
573
599
|
// ========================================================================
|
|
574
600
|
_onAddAttribute(t, e) {
|
|
575
|
-
const r =
|
|
576
|
-
|
|
577
|
-
const
|
|
578
|
-
this._updateBothAttributes(
|
|
601
|
+
const r = k(t), i = this._readCompositionFromNode();
|
|
602
|
+
i.push(r);
|
|
603
|
+
const o = [...this._readCustomAttributesFromNode(), t];
|
|
604
|
+
this._updateBothAttributes(i, o), this._injectCustomAttributeHtml(t, e, r, i), this._renderOrderableItems(i, o), this._initializeCustomSelects(o), this._updateAddButtonState();
|
|
579
605
|
}
|
|
580
606
|
/**
|
|
581
607
|
* Removes a single custom attribute by its index in the customAttrs array.
|
|
@@ -585,7 +611,7 @@ class qt extends rt {
|
|
|
585
611
|
const e = this._readCustomAttributesFromNode();
|
|
586
612
|
if (e[t] === void 0)
|
|
587
613
|
return;
|
|
588
|
-
const
|
|
614
|
+
const i = this._readCompositionFromNode(), o = this._findNthCustomKeyIndex(i, t), s = i.filter((l, a) => a !== o), n = e.filter((l, a) => a !== t);
|
|
589
615
|
this._updateBothAttributes(s, n), this._removeCustomAttributeHtml(s), this._renderOrderableItems(s, n), this._initializeCustomSelects(n), this._updateAddButtonState();
|
|
590
616
|
}
|
|
591
617
|
/**
|
|
@@ -593,21 +619,21 @@ class qt extends rt {
|
|
|
593
619
|
* Uses the customIndex to target only the specific instance, supporting duplicates.
|
|
594
620
|
*/
|
|
595
621
|
_onCustomAttributeChanged(t, e) {
|
|
596
|
-
const r = this._readCustomAttributesFromNode(),
|
|
597
|
-
if (
|
|
622
|
+
const r = this._readCustomAttributesFromNode(), i = r[t];
|
|
623
|
+
if (i === void 0 || i === e)
|
|
598
624
|
return;
|
|
599
|
-
const
|
|
600
|
-
n !== -1 && (s[n] =
|
|
601
|
-
const
|
|
602
|
-
this._updateBothAttributes(s, r), this._injectCustomAttributeHtml(e,
|
|
625
|
+
const o = k(e), s = this._readCompositionFromNode(), n = this._findNthCustomKeyIndex(s, t);
|
|
626
|
+
n !== -1 && (s[n] = o), r[t] = e;
|
|
627
|
+
const l = this._getDisplayNameForAttribute(e);
|
|
628
|
+
this._updateBothAttributes(s, r), this._injectCustomAttributeHtml(e, l, o, s), this._renderOrderableItems(s, r), this._initializeCustomSelects(r);
|
|
603
629
|
}
|
|
604
630
|
_onReorder(t) {
|
|
605
|
-
const e = t.filter((r) => r.startsWith(
|
|
631
|
+
const e = t.filter((r) => r.startsWith(I)).map(w);
|
|
606
632
|
this.reorderInProgress = !0;
|
|
607
633
|
try {
|
|
608
634
|
this._updateBothAttributes(t, e);
|
|
609
|
-
const r = !
|
|
610
|
-
this._getCurrentLayout() === "grid" && !r ? this._reorderProductAttributes(t) : this.currentNode &&
|
|
635
|
+
const r = !_.getConfig(this.currentNode).priceMovedToNextLine;
|
|
636
|
+
this._getCurrentLayout() === "grid" && !r ? this._reorderProductAttributes(t) : this.currentNode && Nt({
|
|
611
637
|
currentNode: this.currentNode,
|
|
612
638
|
documentModifier: this.api.getDocumentModifier()
|
|
613
639
|
});
|
|
@@ -619,67 +645,75 @@ class qt extends rt {
|
|
|
619
645
|
// ========================================================================
|
|
620
646
|
// HTML Injection / Removal (Product Card DOM)
|
|
621
647
|
// ========================================================================
|
|
622
|
-
|
|
648
|
+
/**
|
|
649
|
+
* Outer HTML of an existing attribute row, rewritten to the canonical key when
|
|
650
|
+
* the row still carries a legacy bare-name one. Copying rows this way lets the
|
|
651
|
+
* DOM converge on the next composition change without writing on open.
|
|
652
|
+
*/
|
|
653
|
+
_getExistingRowHtml(t, e) {
|
|
654
|
+
const r = Tt(t, e);
|
|
655
|
+
if (r && "getOuterHTML" in r)
|
|
656
|
+
return G(r.getOuterHTML(), e);
|
|
657
|
+
const i = t.querySelector(
|
|
658
|
+
`${R}[${E}="${e}"]`
|
|
659
|
+
);
|
|
660
|
+
return i && "getOuterHTML" in i ? G(i.getOuterHTML(), e) : "";
|
|
661
|
+
}
|
|
662
|
+
_injectCustomAttributeHtml(t, e, r, i) {
|
|
623
663
|
if (!this.currentNode)
|
|
624
664
|
return;
|
|
625
|
-
this._getCurrentLayout() === "grid" ? this._injectGridAttributeRow(t, e, r,
|
|
665
|
+
this._getCurrentLayout() === "grid" ? this._injectGridAttributeRow(t, e, r, i) : this._injectListAttributeRow(t, e, r, i);
|
|
626
666
|
}
|
|
627
|
-
_injectGridAttributeRow(t, e, r,
|
|
628
|
-
const
|
|
629
|
-
if (!(
|
|
667
|
+
_injectGridAttributeRow(t, e, r, i) {
|
|
668
|
+
const o = this.currentNode.querySelectorAll(U);
|
|
669
|
+
if (!(o != null && o.length))
|
|
630
670
|
return;
|
|
631
|
-
const s =
|
|
632
|
-
let
|
|
633
|
-
|
|
634
|
-
var
|
|
635
|
-
const
|
|
636
|
-
if (
|
|
637
|
-
const
|
|
638
|
-
{ length:
|
|
639
|
-
(
|
|
640
|
-
const
|
|
671
|
+
const s = _.getConfig(this.currentNode), l = `0 ${Math.floor(s.columnSpacing / 2)}px`, a = this.api.getDocumentModifier(), d = this.store.recommendationProducts.length;
|
|
672
|
+
let c = 0;
|
|
673
|
+
o.forEach((u) => {
|
|
674
|
+
var F;
|
|
675
|
+
const f = u.querySelector(R), S = ((F = f == null ? void 0 : f.querySelectorAll(`.${mt}`)) == null ? void 0 : F.length) || 1, x = (100 / S).toFixed(2), { bgStyle: J, bgAttr: Q } = this._extractSegmentBgFromCard(u), H = d > 0 ? Math.min(S, d - c) : S, Z = i.map((M) => {
|
|
676
|
+
if (M === r) {
|
|
677
|
+
const tt = Array.from(
|
|
678
|
+
{ length: H },
|
|
679
|
+
(Lt, rt) => {
|
|
680
|
+
const it = this._resolveAttributeContent(
|
|
641
681
|
t,
|
|
642
682
|
e,
|
|
643
|
-
|
|
683
|
+
c + rt
|
|
644
684
|
);
|
|
645
685
|
return this._getGridCellHtml(
|
|
646
686
|
t,
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
687
|
+
it,
|
|
688
|
+
x,
|
|
689
|
+
J,
|
|
690
|
+
Q,
|
|
691
|
+
l
|
|
652
692
|
);
|
|
653
693
|
}
|
|
654
|
-
).join(""),
|
|
655
|
-
return `<tr class="recommendation-attribute-row" ${
|
|
694
|
+
).join(""), et = gt(x, l).repeat(S - H);
|
|
695
|
+
return `<tr class="recommendation-attribute-row" ${E}="${r}" ${O}="1">${tt}${et}</tr>`;
|
|
656
696
|
}
|
|
657
|
-
|
|
658
|
-
`${$}[${C}="${B}"]`
|
|
659
|
-
);
|
|
660
|
-
return P && "getOuterHTML" in P ? P.getOuterHTML() : "";
|
|
697
|
+
return this._getExistingRowHtml(u, M);
|
|
661
698
|
}).join("");
|
|
662
|
-
|
|
663
|
-
}),
|
|
699
|
+
c += H, d > 0 && c >= d && (c = 0), a.modifyHtml(u).setInnerHtml(Z);
|
|
700
|
+
}), a.apply(new A(`${this.api.translate("Add custom attribute")}: ${e}`));
|
|
664
701
|
}
|
|
665
|
-
_injectListAttributeRow(t, e, r,
|
|
666
|
-
const
|
|
667
|
-
if (!(
|
|
702
|
+
_injectListAttributeRow(t, e, r, i) {
|
|
703
|
+
const o = this.currentNode.querySelectorAll(Y);
|
|
704
|
+
if (!(o != null && o.length))
|
|
668
705
|
return;
|
|
669
|
-
const s =
|
|
670
|
-
|
|
671
|
-
const
|
|
672
|
-
if (
|
|
673
|
-
const
|
|
674
|
-
return this._getListRowHtml(t,
|
|
706
|
+
const s = i.filter((l) => l !== B && l !== q), n = this.api.getDocumentModifier();
|
|
707
|
+
o.forEach((l, a) => {
|
|
708
|
+
const d = s.map((c) => {
|
|
709
|
+
if (c === r) {
|
|
710
|
+
const u = this._resolveAttributeContent(t, e, a);
|
|
711
|
+
return this._getListRowHtml(t, u, r);
|
|
675
712
|
}
|
|
676
|
-
|
|
677
|
-
`${$}[${C}="${d}"]`
|
|
678
|
-
);
|
|
679
|
-
return u && "getOuterHTML" in u ? u.getOuterHTML() : "";
|
|
713
|
+
return this._getExistingRowHtml(l, c);
|
|
680
714
|
}).join("");
|
|
681
|
-
n.modifyHtml(
|
|
682
|
-
}), n.apply(new
|
|
715
|
+
n.modifyHtml(l).setInnerHtml(d);
|
|
716
|
+
}), n.apply(new A(`${this.api.translate("Add custom attribute")}: ${e}`));
|
|
683
717
|
}
|
|
684
718
|
/**
|
|
685
719
|
* Removes a custom attribute by rebuilding product card content without it.
|
|
@@ -690,19 +724,19 @@ class qt extends rt {
|
|
|
690
724
|
return;
|
|
691
725
|
const e = this._getCurrentLayout(), r = this.api.getDocumentModifier();
|
|
692
726
|
if (e === "grid") {
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
-
const s = this._buildCompositionHtml(
|
|
696
|
-
r.modifyHtml(
|
|
727
|
+
const i = this.currentNode.querySelectorAll(U);
|
|
728
|
+
i == null || i.forEach((o) => {
|
|
729
|
+
const s = this._buildCompositionHtml(o, t);
|
|
730
|
+
r.modifyHtml(o).setInnerHtml(s);
|
|
697
731
|
});
|
|
698
732
|
} else {
|
|
699
|
-
const
|
|
700
|
-
|
|
701
|
-
const n = this._buildCompositionHtml(s,
|
|
733
|
+
const i = t.filter((s) => s !== B && s !== q), o = this.currentNode.querySelectorAll(Y);
|
|
734
|
+
o == null || o.forEach((s) => {
|
|
735
|
+
const n = this._buildCompositionHtml(s, i);
|
|
702
736
|
r.modifyHtml(s).setInnerHtml(n);
|
|
703
737
|
});
|
|
704
738
|
}
|
|
705
|
-
r.apply(new
|
|
739
|
+
r.apply(new A(this.api.translate("Remove custom attribute")));
|
|
706
740
|
}
|
|
707
741
|
// ========================================================================
|
|
708
742
|
// DOM Mutation (Block Root Attributes, Reorder)
|
|
@@ -718,10 +752,10 @@ class qt extends rt {
|
|
|
718
752
|
if (!this.currentNode)
|
|
719
753
|
return;
|
|
720
754
|
const r = {
|
|
721
|
-
...
|
|
755
|
+
..._.getConfig(this.currentNode),
|
|
722
756
|
composition: t
|
|
723
757
|
};
|
|
724
|
-
this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute(
|
|
758
|
+
this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute(V, t.join(",")).setAttribute(j, JSON.stringify(e)).setNodeConfig(r).apply(new A(this.api.translate("Update card composition")));
|
|
725
759
|
}
|
|
726
760
|
/**
|
|
727
761
|
* Reorders attribute rows within each product card based on composition order.
|
|
@@ -730,24 +764,21 @@ class qt extends rt {
|
|
|
730
764
|
_reorderProductAttributes(t) {
|
|
731
765
|
if (!this.currentNode)
|
|
732
766
|
return;
|
|
733
|
-
const e = this.currentNode.querySelectorAll(
|
|
767
|
+
const e = this.currentNode.querySelectorAll(U);
|
|
734
768
|
if (!(e != null && e.length))
|
|
735
769
|
return;
|
|
736
770
|
const r = this.api.getDocumentModifier();
|
|
737
|
-
e.forEach((
|
|
738
|
-
const
|
|
739
|
-
r.modifyHtml(
|
|
740
|
-
}), r.apply(new
|
|
771
|
+
e.forEach((i) => {
|
|
772
|
+
const o = this._buildCompositionHtml(i, t);
|
|
773
|
+
r.modifyHtml(i).setInnerHtml(o);
|
|
774
|
+
}), r.apply(new A(this.api.translate("Reorder product attributes")));
|
|
741
775
|
}
|
|
742
776
|
/**
|
|
743
777
|
* Builds HTML string with attributes ordered according to composition.
|
|
744
778
|
* Queries existing rows from the container by data-attribute-type.
|
|
745
779
|
*/
|
|
746
780
|
_buildCompositionHtml(t, e) {
|
|
747
|
-
return e.reduce((r,
|
|
748
|
-
const i = t.querySelector(`${$}[${C}="${o}"]`);
|
|
749
|
-
return i && "getOuterHTML" in i ? r + i.getOuterHTML() : r;
|
|
750
|
-
}, "");
|
|
781
|
+
return e.reduce((r, i) => r + this._getExistingRowHtml(t, i), "");
|
|
751
782
|
}
|
|
752
783
|
// ========================================================================
|
|
753
784
|
// Visibility
|
|
@@ -755,19 +786,19 @@ class qt extends rt {
|
|
|
755
786
|
_applyVisibilityToBlock(t, e) {
|
|
756
787
|
if (!this.currentNode)
|
|
757
788
|
return;
|
|
758
|
-
const r = this.currentNode.querySelectorAll(`${
|
|
789
|
+
const r = this.currentNode.querySelectorAll(`${R}[${E}="${t}"]`);
|
|
759
790
|
if (!(r != null && r.length))
|
|
760
791
|
return;
|
|
761
|
-
const
|
|
762
|
-
r.forEach((
|
|
763
|
-
const
|
|
764
|
-
n.modifyHtml(
|
|
792
|
+
const i = e ? "1" : "0", o = e ? this.api.translate("visible") : this.api.translate("hidden"), s = `${this.api.translate("Set visibility")}: ${t} → ${o}`, n = this.api.getDocumentModifier();
|
|
793
|
+
r.forEach((a) => {
|
|
794
|
+
const d = It(a), c = e ? d : "none";
|
|
795
|
+
n.modifyHtml(a).setStyle("display", c).setAttribute(O, i);
|
|
765
796
|
});
|
|
766
|
-
const
|
|
767
|
-
...
|
|
797
|
+
const l = {
|
|
798
|
+
..._.getConfig(this.currentNode),
|
|
768
799
|
visibility: { ...this._readVisibilityFromRows(), [t]: e }
|
|
769
800
|
};
|
|
770
|
-
n.modifyHtml(this.currentNode).setNodeConfig(
|
|
801
|
+
n.modifyHtml(this.currentNode).setNodeConfig(l), n.apply(new A(s));
|
|
771
802
|
}
|
|
772
803
|
// ========================================================================
|
|
773
804
|
// Utilities
|
|
@@ -779,16 +810,16 @@ class qt extends rt {
|
|
|
779
810
|
*/
|
|
780
811
|
_findNthCustomKeyIndex(t, e) {
|
|
781
812
|
let r = 0;
|
|
782
|
-
for (let
|
|
783
|
-
if (t[
|
|
813
|
+
for (let i = 0; i < t.length; i++)
|
|
814
|
+
if (t[i].startsWith(I)) {
|
|
784
815
|
if (r === e)
|
|
785
|
-
return
|
|
816
|
+
return i;
|
|
786
817
|
r++;
|
|
787
818
|
}
|
|
788
819
|
return -1;
|
|
789
820
|
}
|
|
790
821
|
_getCurrentLayout() {
|
|
791
|
-
return this.store.recommendationConfigs.orientation ||
|
|
822
|
+
return this.store.recommendationConfigs.orientation || Rt(this.currentNode);
|
|
792
823
|
}
|
|
793
824
|
/**
|
|
794
825
|
* Extracts background color properties from existing card elements.
|
|
@@ -797,7 +828,7 @@ class qt extends rt {
|
|
|
797
828
|
* Used when injecting new attribute cells to match the card's current background.
|
|
798
829
|
*/
|
|
799
830
|
_extractSegmentBgFromCard(t) {
|
|
800
|
-
var
|
|
831
|
+
var i;
|
|
801
832
|
const e = t.querySelector(".product-card-segment");
|
|
802
833
|
if (e && "getAttribute" in e) {
|
|
803
834
|
const s = (e.getAttribute("style") || "").match(/background-color:\s*([^;]+)/);
|
|
@@ -806,12 +837,12 @@ class qt extends rt {
|
|
|
806
837
|
return { bgStyle: `background-color: ${s[1].trim()};`, bgAttr: n };
|
|
807
838
|
}
|
|
808
839
|
}
|
|
809
|
-
const r = (
|
|
840
|
+
const r = (i = this.currentNode) == null ? void 0 : i.querySelector(".product-card-wrapper");
|
|
810
841
|
if (r && "getStyle" in r) {
|
|
811
|
-
const
|
|
812
|
-
if (
|
|
842
|
+
const o = r.getStyle("background-color");
|
|
843
|
+
if (o && o !== "transparent") {
|
|
813
844
|
const s = "getAttribute" in r && r.getAttribute("bgcolor") || "";
|
|
814
|
-
return { bgStyle: `background-color: ${
|
|
845
|
+
return { bgStyle: `background-color: ${o};`, bgAttr: s };
|
|
815
846
|
}
|
|
816
847
|
}
|
|
817
848
|
return { bgStyle: "", bgAttr: "" };
|
|
@@ -840,11 +871,11 @@ class qt extends rt {
|
|
|
840
871
|
* or when all available filters have already been added (no unused attributes left).
|
|
841
872
|
*/
|
|
842
873
|
_updateAddButtonState() {
|
|
843
|
-
const t = this._readCustomAttributesFromNode(), e = t.length >=
|
|
874
|
+
const t = this._readCustomAttributesFromNode(), e = t.length >= b, r = new Set(t), i = this._getAddableFilters(), o = i.length > 0 && i.every((s) => r.has(y(s)));
|
|
844
875
|
this.api.setUIEAttribute(
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
e ||
|
|
876
|
+
X.ADD_ATTRIBUTE,
|
|
877
|
+
N.BUTTON.disabled,
|
|
878
|
+
e || o ? "true" : "false"
|
|
848
879
|
);
|
|
849
880
|
}
|
|
850
881
|
/**
|
|
@@ -857,54 +888,64 @@ class qt extends rt {
|
|
|
857
888
|
this.unsubscribeStore = this.store.$subscribe(() => {
|
|
858
889
|
const r = this.store.recommendationConfigs.orientation;
|
|
859
890
|
r !== t && (t = r, this._updateOrderableState());
|
|
860
|
-
const
|
|
861
|
-
|
|
891
|
+
const i = Object.keys(this.store.filterList).sort().join(",");
|
|
892
|
+
i !== e && (e = i, this._initializeComposition());
|
|
862
893
|
});
|
|
863
894
|
}
|
|
864
895
|
/**
|
|
865
|
-
* Returns filters eligible for the custom attribute dropdown,
|
|
866
|
-
*
|
|
896
|
+
* Returns filters eligible for the custom attribute dropdown, excluding default
|
|
897
|
+
* attributes already covered by built-in toggle items.
|
|
898
|
+
*
|
|
899
|
+
* Deduped by canonical value: a partner can own two backend rows of the same type
|
|
900
|
+
* and name (e.g. two `defaultAttribute` "discount"), which are indistinguishable
|
|
901
|
+
* once reduced to a `product-attr`. Left in, they render as identical options and
|
|
902
|
+
* skew the collision count that decides the (Default)/(Custom) suffix. (SD-147101)
|
|
867
903
|
*/
|
|
868
904
|
_getAddableFilters() {
|
|
869
|
-
|
|
905
|
+
const t = /* @__PURE__ */ new Set();
|
|
906
|
+
return Object.values(this.store.filterList).filter((e) => !(e.type === "defaultAttribute" && dt.has(e.attributeName))).filter((e) => {
|
|
907
|
+
const r = y(e);
|
|
908
|
+
return t.has(r) ? !1 : (t.add(r), !0);
|
|
909
|
+
});
|
|
870
910
|
}
|
|
871
911
|
/**
|
|
872
|
-
* Looks up the display name for
|
|
873
|
-
*
|
|
912
|
+
* Looks up the display name for a `product-attr` value from the store's filterList.
|
|
913
|
+
* Matches on the canonical value, so a default and a same-named custom attribute
|
|
914
|
+
* resolve to their own entry. Falls back to Title Case of the bare name.
|
|
874
915
|
*/
|
|
875
916
|
_getDisplayNameForAttribute(t) {
|
|
876
|
-
const e = Object.values(this.store.filterList).find((r) => r
|
|
877
|
-
return e ? e.displayName :
|
|
917
|
+
const e = Object.values(this.store.filterList).find((r) => y(r) === t);
|
|
918
|
+
return e ? e.displayName : _t(D(t));
|
|
878
919
|
}
|
|
879
920
|
/**
|
|
880
921
|
* Resolves the display content for a custom attribute cell.
|
|
881
922
|
* Uses the real product value from the store when available, falls back to displayName.
|
|
882
923
|
*/
|
|
883
924
|
_resolveAttributeContent(t, e, r) {
|
|
884
|
-
var
|
|
885
|
-
const
|
|
886
|
-
return
|
|
887
|
-
}
|
|
888
|
-
_getGridCellHtml(t, e, r,
|
|
889
|
-
const n =
|
|
890
|
-
[
|
|
891
|
-
product_attributes: { [
|
|
925
|
+
var l;
|
|
926
|
+
const o = this.store.recommendationProducts[r], s = D(t), n = $t(t) ? o == null ? void 0 : o[s] : (l = o == null ? void 0 : o.product_attributes) == null ? void 0 : l[s];
|
|
927
|
+
return yt(n) ?? e;
|
|
928
|
+
}
|
|
929
|
+
_getGridCellHtml(t, e, r, i = "", o = "", s = "") {
|
|
930
|
+
const n = k(t), l = D(t), a = z(ht, [n], this.store.filterList), d = {
|
|
931
|
+
[l]: e,
|
|
932
|
+
product_attributes: { [l]: e }
|
|
892
933
|
};
|
|
893
|
-
let
|
|
894
|
-
return
|
|
895
|
-
`padding: ${
|
|
934
|
+
let c = a[n](d);
|
|
935
|
+
return c = c.replace("<td", `<td width="${r}%"`), s && (c = c.replace(
|
|
936
|
+
`padding: ${pt}`,
|
|
896
937
|
`padding: ${s}`
|
|
897
|
-
)),
|
|
938
|
+
)), i && (c = c.replace(/style="table-layout: fixed;"/, `style="table-layout: fixed; ${i}"`)), o && (c = c.replace(/border="0"/, `border="0" bgcolor="${o}"`)), c;
|
|
898
939
|
}
|
|
899
940
|
_getListRowHtml(t, e, r) {
|
|
900
|
-
const o =
|
|
901
|
-
[
|
|
902
|
-
product_attributes: { [
|
|
903
|
-
},
|
|
904
|
-
return `<tr class="recommendation-attribute-row" ${
|
|
941
|
+
const i = D(t), o = z(bt, [r], this.store.filterList), s = {
|
|
942
|
+
[i]: e,
|
|
943
|
+
product_attributes: { [i]: e }
|
|
944
|
+
}, l = o[r](s).replace(/<tr>/, "").replace(/<\/tr>/, "");
|
|
945
|
+
return `<tr class="recommendation-attribute-row" ${E}="${r}" ${O}="1">${l}</tr>`;
|
|
905
946
|
}
|
|
906
947
|
}
|
|
907
948
|
export {
|
|
908
|
-
|
|
909
|
-
|
|
949
|
+
Et as COMPOSITION_CONTROL_BLOCK_ID,
|
|
950
|
+
Wt as RecommendationCardCompositionControl
|
|
910
951
|
};
|