@useinsider/guido 3.7.2-beta.3cec1a4 → 3.7.2-beta.7b4f9d0
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/htmlCompilerRules.js +34 -6
- package/dist/config/compiler/recommendationCompilerRules.js +83 -108
- package/dist/extensions/Blocks/Recommendation/block.js +1 -4
- package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +135 -152
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const l = [
|
|
2
2
|
{
|
|
3
3
|
id: "fix-url-encoding-start",
|
|
4
4
|
description: "Replace {%22 with %7B%22 to fix URL encoding",
|
|
@@ -111,13 +111,13 @@ const a = [
|
|
|
111
111
|
<w:DontUseAdvancedTypographyReadingMail></w:DontUseAdvancedTypographyReadingMail>
|
|
112
112
|
</w:WordDocument>
|
|
113
113
|
</xml><![endif]-->`
|
|
114
|
-
],
|
|
114
|
+
], i = /<head>([\S\s]*)<\/head>/, o = new RegExp(i);
|
|
115
115
|
if (!e.match(o))
|
|
116
116
|
return e;
|
|
117
|
-
let
|
|
117
|
+
let s = e;
|
|
118
118
|
return t.forEach((r) => {
|
|
119
|
-
|
|
120
|
-
}),
|
|
119
|
+
s = s.replace("</head>", `${r}</head>`);
|
|
120
|
+
}), s;
|
|
121
121
|
},
|
|
122
122
|
priority: 30
|
|
123
123
|
},
|
|
@@ -138,8 +138,36 @@ const a = [
|
|
|
138
138
|
replacement: "email-static.useinsider.com",
|
|
139
139
|
replaceAll: !0,
|
|
140
140
|
priority: 41
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: "convert-rgb-to-hex",
|
|
144
|
+
// SD-142395: rgb()/6-digit hex are verbose; hex/3-digit shorthand is byte-identical
|
|
145
|
+
// to render. Shrinks the whole email to stay under Gmail's ~102KB clip threshold.
|
|
146
|
+
// Leaves rgba()/8-digit hex (alpha) untouched.
|
|
147
|
+
description: "Convert rgb() colors to hex and collapse 6-digit hex to shorthand",
|
|
148
|
+
type: "custom",
|
|
149
|
+
processor: (e) => {
|
|
150
|
+
const t = (i) => i.toString(16).padStart(2, "0");
|
|
151
|
+
return e.replace(/rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/gi, (i, o, n, s) => {
|
|
152
|
+
const [r, a, c] = [Number(o), Number(n), Number(s)];
|
|
153
|
+
return r > 255 || a > 255 || c > 255 ? i : `#${t(r)}${t(a)}${t(c)}`;
|
|
154
|
+
}).replace(/#([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3\b/gi, "#$1$2$3");
|
|
155
|
+
},
|
|
156
|
+
priority: 44
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: "remove-contenteditable",
|
|
160
|
+
// SD-142395: contenteditable is a Stripo editor flag with zero effect in a
|
|
161
|
+
// delivered email. Stripping it globally shaves bytes off every text block,
|
|
162
|
+
// helping the whole email stay under Gmail's ~102KB clip threshold.
|
|
163
|
+
description: "Strip editor-only contenteditable attributes from compiled output",
|
|
164
|
+
type: "regex",
|
|
165
|
+
pattern: '\\s+contenteditable="[^"]*"',
|
|
166
|
+
replacement: "",
|
|
167
|
+
flags: "g",
|
|
168
|
+
priority: 45
|
|
141
169
|
}
|
|
142
170
|
];
|
|
143
171
|
export {
|
|
144
|
-
|
|
172
|
+
l as defaultHtmlCompilerRules
|
|
145
173
|
};
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { useRecommendation as
|
|
2
|
-
import { DUMMY_IMAGE_MAPPINGS as
|
|
3
|
-
import { prepareRecommendationBlocks as
|
|
4
|
-
const
|
|
1
|
+
import { useRecommendation as N } from "../../composables/useRecommendation.js";
|
|
2
|
+
import { DUMMY_IMAGE_MAPPINGS as M, REGEX as d, VerticalOrientation as $, CSS as n, ATTRIBUTES as p, CONDITIONS as T, HTML as g } from "../../enums/recommendation.js";
|
|
3
|
+
import { prepareRecommendationBlocks as O } from "./utils/recommendationCompilerUtils.js";
|
|
4
|
+
const U = [
|
|
5
5
|
{
|
|
6
6
|
id: "replace-images-with-variable-names",
|
|
7
7
|
description: "Replacing dummy images with variable names in recommendation module",
|
|
8
8
|
type: "custom",
|
|
9
|
-
processor: (
|
|
10
|
-
let e =
|
|
11
|
-
return Object.entries(
|
|
12
|
-
Object.entries(
|
|
13
|
-
e = e.replaceAll(
|
|
9
|
+
processor: (o) => {
|
|
10
|
+
let e = o;
|
|
11
|
+
return Object.entries(M).forEach(([, r]) => {
|
|
12
|
+
Object.entries(r).forEach(([t, i]) => {
|
|
13
|
+
e = e.replaceAll(i, `{{${t}}}`);
|
|
14
14
|
});
|
|
15
15
|
}), e;
|
|
16
16
|
},
|
|
@@ -41,21 +41,21 @@ const w = [
|
|
|
41
41
|
id: "add-recommendation-unresponsive-css",
|
|
42
42
|
description: "Adding recommendation unresponsive css",
|
|
43
43
|
type: "custom",
|
|
44
|
-
processor: (
|
|
45
|
-
const { calculateCardWidth: e, getRecommendationCampaignData:
|
|
46
|
-
let
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
}),
|
|
54
|
-
const
|
|
55
|
-
|
|
44
|
+
processor: (o) => {
|
|
45
|
+
const { calculateCardWidth: e, getRecommendationCampaignData: r } = N();
|
|
46
|
+
let t = o;
|
|
47
|
+
const i = t.match(d.ID);
|
|
48
|
+
if (i) {
|
|
49
|
+
const s = [];
|
|
50
|
+
if (i.forEach((c) => {
|
|
51
|
+
const m = /recommendation-id="(.*?)"/i.exec(c), E = m ? m[1].trim() : "", u = r(E);
|
|
52
|
+
u.textTrimming && u.orientation === $ && s.push(e(u));
|
|
53
|
+
}), s.length) {
|
|
54
|
+
const c = `width:${Math.min(...s)}px!important;`;
|
|
55
|
+
t = t.replace(n.REGULAR_NAME_HEIGHT, `${n.TRIMMED_NAME_HEIGHT} ${c} ${n.ELLIPSIS}`).replace(n.REGULAR_NAME_CONTAINER_HEIGHT, n.TRIMMED_NAME_CONTAINER_CSS).replace(n.RESPONSIVE_NAME_SIZE, `${n.RESPONSIVE_NAME_HEIGHT} ${c} ${n.ELLIPSIS}`).replace(n.RESPONSIVE_NAME_CONTAINER_HEIGHT, n.TRIMMED_RESPONSIVE_NAME_CONTAINER_CSS);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
return
|
|
58
|
+
return t;
|
|
59
59
|
},
|
|
60
60
|
priority: 52
|
|
61
61
|
},
|
|
@@ -63,34 +63,34 @@ const w = [
|
|
|
63
63
|
id: "prepare-recommendations",
|
|
64
64
|
description: "Replacing product data with template variables in recommendation blocks",
|
|
65
65
|
type: "custom",
|
|
66
|
-
processor: (
|
|
66
|
+
processor: (o) => O(o),
|
|
67
67
|
priority: 48
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
id: "add-discount-conditions",
|
|
71
71
|
description: "Adding discount conditions to the recommendation block",
|
|
72
72
|
type: "custom",
|
|
73
|
-
processor: (
|
|
74
|
-
let e =
|
|
75
|
-
const
|
|
76
|
-
return
|
|
77
|
-
const
|
|
78
|
-
if (!
|
|
73
|
+
processor: (o) => {
|
|
74
|
+
let e = o;
|
|
75
|
+
const r = e.match(d.ATTRIBUTE_PARAGRAPH), { getRecommendationCampaignData: t } = N();
|
|
76
|
+
return r !== null && r.forEach((i) => {
|
|
77
|
+
const s = i.match(d.CUSTOM_FIELD);
|
|
78
|
+
if (!s)
|
|
79
79
|
return;
|
|
80
|
-
const [
|
|
81
|
-
if (!
|
|
80
|
+
const [c] = s, m = c.match(d.CUSTOM_FIELD_INDEXES_PART), E = c.match(d.CUSTOM_FIELD_NAME_PART), u = i.match(d.ATTRIBUTE_PARAGRAPH_START_TAG);
|
|
81
|
+
if (!m || !E || !u)
|
|
82
82
|
return;
|
|
83
|
-
const [
|
|
84
|
-
let
|
|
85
|
-
if (
|
|
86
|
-
const
|
|
87
|
-
|
|
83
|
+
const [A] = m, [I] = E, [R] = u, b = I.substring(1, I.length - 2), S = R.match(d.COMPOSITION) !== null;
|
|
84
|
+
let a = c;
|
|
85
|
+
if (S) {
|
|
86
|
+
const f = A.substring(2, A.length - 3), l = t(f);
|
|
87
|
+
b === p.OMNIBUS_PRICE && (l.priceBeforeTextValue && (a = `${l.priceBeforeTextValue}${a}`), l.priceAfterTextValue && (a = `${a}${l.priceAfterTextValue}`)), b === p.OMNIBUS_DISCOUNT && (l.discountBeforeTextValue && (a = `${l.discountBeforeTextValue}${a}`), l.discountAfterTextValue && (a = `${a}${l.discountAfterTextValue}`));
|
|
88
88
|
}
|
|
89
|
-
const
|
|
90
|
-
let
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
e = e.replace(
|
|
89
|
+
const _ = A.substring(2);
|
|
90
|
+
let y = "";
|
|
91
|
+
b in T.IF && (y = T.IF[b].replaceAll(`{${p.DISCOUNT}}`, `${_}${p.DISCOUNT}`).replaceAll(`{${p.OMNIBUS_DISCOUNT}}`, `${_}${p.OMNIBUS_DISCOUNT}`).replaceAll(`{${p.OMNIBUS_PRICE}}`, `${_}${p.OMNIBUS_PRICE}`));
|
|
92
|
+
const C = `${R}${a}${g.PARAGRAPH_END_TAG}`, h = `${y}${S ? C : i}${T.ELSE}${R}${g.PARAGRAPH_END_TAG}${T.END_IF}`;
|
|
93
|
+
e = e.replace(i, h);
|
|
94
94
|
}), e;
|
|
95
95
|
},
|
|
96
96
|
priority: 53
|
|
@@ -110,11 +110,11 @@ const w = [
|
|
|
110
110
|
type: "custom",
|
|
111
111
|
// Scoped to REC_START/REC_END markers so it cannot strip `product-attr`
|
|
112
112
|
// from Items block elements, which the items compiler rule depends on.
|
|
113
|
-
processor: (
|
|
113
|
+
processor: (o) => {
|
|
114
114
|
const e = /\s+(?:esd-extension-block-id|data-attribute-type|data-visibility|data-text-before|data-text-after|product-attr|composition)="[^"]*"/g;
|
|
115
|
-
return
|
|
115
|
+
return o.replace(
|
|
116
116
|
/<!--REC_START-->([\s\S]*?)<!--REC_END-->/g,
|
|
117
|
-
(
|
|
117
|
+
(r, t) => `<!--REC_START-->${t.replace(e, "")}<!--REC_END-->`
|
|
118
118
|
);
|
|
119
119
|
},
|
|
120
120
|
priority: 55
|
|
@@ -123,8 +123,8 @@ const w = [
|
|
|
123
123
|
id: "strip-unused-recommendation-classes",
|
|
124
124
|
description: "Remove CSS classes not referenced by any style rule from recommendation elements",
|
|
125
125
|
type: "custom",
|
|
126
|
-
processor: (
|
|
127
|
-
let e =
|
|
126
|
+
processor: (o) => {
|
|
127
|
+
let e = o.replace(
|
|
128
128
|
/ class="(?:product-card-segment|attribute-cell|recommendation-attribute-row|product-image|product-name|product-price|product-old-price|product-omnibus-price|product-omnibus-discount|product-button|recommendation-product-row|product-card-wrapper)"/g,
|
|
129
129
|
""
|
|
130
130
|
);
|
|
@@ -136,8 +136,8 @@ const w = [
|
|
|
136
136
|
id: "remove-empty-mobile-layout-artifacts",
|
|
137
137
|
description: "Remove empty mobile container rows and unused mobile layout CSS",
|
|
138
138
|
type: "custom",
|
|
139
|
-
processor: (
|
|
140
|
-
let e =
|
|
139
|
+
processor: (o) => {
|
|
140
|
+
let e = o;
|
|
141
141
|
return e = e.replace(
|
|
142
142
|
/<tr[^>]*class="ins-recommendation-mobile-row"[^>]*><\/tr>/g,
|
|
143
143
|
""
|
|
@@ -146,75 +146,50 @@ const w = [
|
|
|
146
146
|
""
|
|
147
147
|
), e = e.replace(
|
|
148
148
|
/@media[^{]*max-width\s*:\s*480px[^{]*\{((?:[^{}]*\{[^{}]*\})*[^{}]*)\}/g,
|
|
149
|
-
(
|
|
150
|
-
const
|
|
151
|
-
return
|
|
149
|
+
(r, t) => {
|
|
150
|
+
const i = t.match(/[^{}]+\{[^{}]*\}/g) || [], s = /ins-recommendation|product-image-cell|button-cell|product-info-cell/;
|
|
151
|
+
return i.every((m) => s.test(m)) ? "" : r;
|
|
152
152
|
}
|
|
153
153
|
)), e;
|
|
154
154
|
},
|
|
155
155
|
priority: 57
|
|
156
156
|
},
|
|
157
157
|
{
|
|
158
|
-
id: "
|
|
159
|
-
|
|
158
|
+
id: "protect-gmail-button-link-color",
|
|
159
|
+
// Gmail overrides link colors with `.ii a[href] { color: #15c }`. Force
|
|
160
|
+
// `!important` on es-button anchor colors so the intended button text color
|
|
161
|
+
// wins. Kept INLINE (never moved into a <style> class) so it survives Gmail's
|
|
162
|
+
// clipping — "view entire message" strips <style> blocks but keeps inline styles.
|
|
163
|
+
// (SD-142395: split out of the removed deduplicate-inline-styles rule.)
|
|
164
|
+
description: "Force !important on es-button link color to defeat Gmail link-color override",
|
|
160
165
|
type: "custom",
|
|
161
|
-
processor: (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
), l = /<!--REC_START-->([\s\S]*?)<!--REC_END-->/g, n = / style="([^"]*)"/g, s = /* @__PURE__ */ new Map();
|
|
169
|
-
let a = l.exec(e);
|
|
170
|
-
for (; a !== null; ) {
|
|
171
|
-
let o = n.exec(a[1]);
|
|
172
|
-
for (; o !== null; ) {
|
|
173
|
-
const [, r] = o;
|
|
174
|
-
s.set(r, (s.get(r) || 0) + 1), o = n.exec(a[1]);
|
|
175
|
-
}
|
|
176
|
-
n.lastIndex = 0, a = l.exec(e);
|
|
177
|
-
}
|
|
178
|
-
const i = /* @__PURE__ */ new Map(), u = [];
|
|
179
|
-
let _ = 0;
|
|
180
|
-
if (s.forEach((o, r) => {
|
|
181
|
-
if (!r.includes("v-text-anchor") && o >= 6) {
|
|
182
|
-
const t = `rc${_++}`, p = r.endsWith(";") ? r : `${r};`;
|
|
183
|
-
i.set(r, t), u.push(`.${t}{${p}}`);
|
|
184
|
-
}
|
|
185
|
-
}), i.size === 0) {
|
|
186
|
-
let o = e;
|
|
187
|
-
return o = o.replaceAll("<!--REC_START-->", ""), o = o.replaceAll("<!--REC_END-->", ""), o;
|
|
188
|
-
}
|
|
189
|
-
const R = (o) => o.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), b = (o, r) => `${o.slice(0, -1)} ${r}"`, I = /* @__PURE__ */ new Map();
|
|
190
|
-
i.forEach((o, r) => {
|
|
191
|
-
const t = R(r);
|
|
192
|
-
I.set(r, {
|
|
193
|
-
caseA: new RegExp(`(class="[^"]*")((?:[^>]*?)) style="${t}"`, "g"),
|
|
194
|
-
caseB: new RegExp(` style="${t}"((?:[^>]*?))(class="[^"]*")`, "g")
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
let d = e.replace("</style>", `${u.join("")}</style>`);
|
|
198
|
-
return d = d.replace(
|
|
199
|
-
/<!--REC_START-->([\s\S]*?)<!--REC_END-->/g,
|
|
200
|
-
(o, r) => {
|
|
201
|
-
let t = r;
|
|
202
|
-
return i.forEach((p, f) => {
|
|
203
|
-
const g = I.get(f);
|
|
204
|
-
t = t.replace(
|
|
205
|
-
g.caseA,
|
|
206
|
-
($, S, m) => b(S, p) + m
|
|
207
|
-
), t = t.replace(
|
|
208
|
-
g.caseB,
|
|
209
|
-
($, S, m) => S + b(m, p)
|
|
210
|
-
), t = t.replaceAll(` style="${f}"`, ` class="${p}"`);
|
|
211
|
-
}), t;
|
|
212
|
-
}
|
|
213
|
-
), d = d.replaceAll("<!--REC_START-->", ""), d = d.replaceAll("<!--REC_END-->", ""), d;
|
|
214
|
-
},
|
|
166
|
+
processor: (o) => o.replace(
|
|
167
|
+
/<a\b[^>]*\bes-button\b[^>]*>/g,
|
|
168
|
+
(e) => e.replace(
|
|
169
|
+
/([;"]color:)([^;"]+)/g,
|
|
170
|
+
(r, t, i) => i.includes("!important") ? r : `${t}${i} !important`
|
|
171
|
+
)
|
|
172
|
+
),
|
|
215
173
|
priority: 58
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
id: "minify-recommendation-whitespace",
|
|
177
|
+
// SD-142395: shrink the compiled recommendation block to keep emails under
|
|
178
|
+
// Gmail's ~102KB clip threshold. The editor templates emit deeply-indented
|
|
179
|
+
// markup that the P48 DOMParser round-trip preserves, and nothing else in the
|
|
180
|
+
// pipeline minifies it. Scoped to REC_START/REC_END so it only touches
|
|
181
|
+
// recommendation markup, and strips those markers last (relocated here from the
|
|
182
|
+
// removed deduplicate-inline-styles rule). Render-critical styles are left inline
|
|
183
|
+
// rather than classed, so they survive Gmail clipping.
|
|
184
|
+
description: "Collapse whitespace inside recommendation blocks and strip boundary markers",
|
|
185
|
+
type: "custom",
|
|
186
|
+
processor: (o) => {
|
|
187
|
+
const e = (r) => r.replace(/>\s+</g, "><").replace(/<[^>]+>/g, (t) => t.replace(/\s+/g, " "));
|
|
188
|
+
return o.replace(/<!--REC_START-->([\s\S]*?)<!--REC_END-->/g, (r, t) => e(t)).replaceAll("<!--REC_START-->", "").replaceAll("<!--REC_END-->", "");
|
|
189
|
+
},
|
|
190
|
+
priority: 99
|
|
216
191
|
}
|
|
217
192
|
];
|
|
218
193
|
export {
|
|
219
|
-
|
|
194
|
+
U as recommendationCompilerRules
|
|
220
195
|
};
|
|
@@ -48,11 +48,8 @@ class H extends D {
|
|
|
48
48
|
allowInnerBlocksDND() {
|
|
49
49
|
return !1;
|
|
50
50
|
}
|
|
51
|
-
// A saved module carries its config in the esd-config blob, restored on
|
|
52
|
-
// re-drop by migrateFromDataAttributes; per-element styles ride the
|
|
53
|
-
// preserved inner HTML. (onCreated early-returns for re-drops, never clobbers.)
|
|
54
51
|
canBeSavedAsModule() {
|
|
55
|
-
return !
|
|
52
|
+
return !1;
|
|
56
53
|
}
|
|
57
54
|
/**
|
|
58
55
|
* Returns the template HTML for a new recommendation block.
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var S = (p,
|
|
4
|
-
import { UIElementType as f, UEAttr as
|
|
5
|
-
import { CommonControl as
|
|
6
|
-
import { ATTR_PRODUCT_IMAGE as
|
|
7
|
-
import { DEFAULT_COMPOSITION as P, DEFAULT_VISIBILITY as
|
|
8
|
-
import { RecommendationConfigService as
|
|
1
|
+
var J = Object.defineProperty;
|
|
2
|
+
var Q = (p, _, t) => _ in p ? J(p, _, { enumerable: !0, configurable: !0, writable: !0, value: t }) : p[_] = t;
|
|
3
|
+
var S = (p, _, t) => Q(p, typeof _ != "symbol" ? _ + "" : _, t);
|
|
4
|
+
import { UIElementType as f, UEAttr as I, ModificationDescription as A } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
5
|
+
import { CommonControl as Z } from "../../../common-control.js";
|
|
6
|
+
import { ATTR_PRODUCT_IMAGE as D, ATTR_PRODUCT_NAME as tt, ATTR_PRODUCT_PRICE as et, ATTR_PRODUCT_OLD_PRICE as rt, ATTR_PRODUCT_OMNIBUS_PRICE as ot, ATTR_PRODUCT_OMNIBUS_DISCOUNT as st, ATTR_PRODUCT_BUTTON as U, ATTR_DATA_CUSTOM_ATTRIBUTES as q, ATTR_CUSTOM_PREFIX as m, BUILT_IN_DEFAULT_ATTRIBUTES as it } from "../../constants/selectors.js";
|
|
7
|
+
import { DEFAULT_COMPOSITION as P, DEFAULT_VISIBILITY as F } from "../../constants/defaultConfig.js";
|
|
8
|
+
import { RecommendationConfigService as nt } from "../../services/configService.js";
|
|
9
9
|
import { useRecommendationExtensionStore as lt } from "../../store/recommendation.js";
|
|
10
10
|
import { ATTRIBUTE_CELL_CLASS as at, gridElementRenderer as ct, DEFAULT_CELL_PADDING as ut, buildFillerCell as dt } from "../../templates/grid/elementRenderer.js";
|
|
11
11
|
import { listElementRenderer as mt } from "../../templates/list/elementRenderer.js";
|
|
12
|
-
import { toDisplayName as ht, isDefaultAttribute as pt, toDisplayableAttributeValue as
|
|
12
|
+
import { toDisplayName as ht, isDefaultAttribute as pt, toDisplayableAttributeValue as _t, buildElementRenderer as w } from "../../templates/utils.js";
|
|
13
13
|
import { getTableDisplayValue as ft } from "../../utils/tagName.js";
|
|
14
|
-
import { getCurrentLayout as
|
|
15
|
-
const bt = "ui-elements-recommendation-card-composition",
|
|
14
|
+
import { getCurrentLayout as gt } from "../main/utils.js";
|
|
15
|
+
const bt = "ui-elements-recommendation-card-composition", C = ".recommendation-attribute-row", L = ".product-card-wrapper > tbody", M = ".product-info-cell > table > tbody", V = "data-card-composition", y = "data-attribute-type", v = "data-visibility", x = {
|
|
16
16
|
ADD_ATTRIBUTE: "addAttribute"
|
|
17
|
-
},
|
|
18
|
-
{ key:
|
|
19
|
-
{ key:
|
|
20
|
-
{ key:
|
|
21
|
-
{ key:
|
|
22
|
-
{ key:
|
|
23
|
-
{ key:
|
|
17
|
+
}, g = 5, E = "reorderIcon_", h = [
|
|
18
|
+
{ key: D, label: "Product Image" },
|
|
19
|
+
{ key: tt, label: "Product Name" },
|
|
20
|
+
{ key: et, label: "Product Price" },
|
|
21
|
+
{ key: rt, label: "Product Original Price" },
|
|
22
|
+
{ key: ot, label: "Omnibus Price" },
|
|
23
|
+
{ key: st, label: "Omnibus Discount" },
|
|
24
24
|
{ key: U, label: "Product Button" }
|
|
25
|
-
], yt = new Set(h.map((p) => p.key)), T = "customAttr_",
|
|
26
|
-
class
|
|
25
|
+
], yt = new Set(h.map((p) => p.key)), T = "customAttr_", R = "deleteAttr_";
|
|
26
|
+
class Ut extends Z {
|
|
27
27
|
constructor() {
|
|
28
28
|
super(...arguments);
|
|
29
29
|
S(this, "store", lt());
|
|
@@ -47,7 +47,7 @@ class Ht extends tt {
|
|
|
47
47
|
${this._GuToggle(`visibility_${l.key}`)}
|
|
48
48
|
</div>
|
|
49
49
|
`).join(""), r = Array.from(
|
|
50
|
-
{ length:
|
|
50
|
+
{ length: g },
|
|
51
51
|
(l, u) => `
|
|
52
52
|
<div data-custom-select-key="${T}${u}" style="display: none;">
|
|
53
53
|
${this._GuSelect({
|
|
@@ -57,13 +57,13 @@ class Ht extends tt {
|
|
|
57
57
|
})}
|
|
58
58
|
</div>
|
|
59
59
|
`
|
|
60
|
-
).join(""), e = h.length +
|
|
60
|
+
).join(""), e = h.length + g, o = Array.from(
|
|
61
61
|
{ length: e },
|
|
62
62
|
(l, u) => `
|
|
63
|
-
<div data-reorder-icon-key="${
|
|
63
|
+
<div data-reorder-icon-key="${E}${u}" style="display: none;">
|
|
64
64
|
<${f.BUTTON}
|
|
65
65
|
class="drag-handle-btn flat-inline flat-white"
|
|
66
|
-
${
|
|
66
|
+
${I.BUTTON.name}="${E}${u}"
|
|
67
67
|
>
|
|
68
68
|
<${f.ICON}
|
|
69
69
|
src="reorder"
|
|
@@ -73,12 +73,12 @@ class Ht extends tt {
|
|
|
73
73
|
</div>
|
|
74
74
|
`
|
|
75
75
|
).join(""), s = Array.from(
|
|
76
|
-
{ length:
|
|
76
|
+
{ length: g },
|
|
77
77
|
(l, u) => `
|
|
78
|
-
<div data-custom-delete-key="${
|
|
78
|
+
<div data-custom-delete-key="${R}${u}" style="display: none;">
|
|
79
79
|
<${f.BUTTON}
|
|
80
80
|
class="custom-attr-delete flat-inline flat-white"
|
|
81
|
-
${
|
|
81
|
+
${I.BUTTON.name}="${R}${u}"
|
|
82
82
|
>
|
|
83
83
|
<${f.ICON}
|
|
84
84
|
src="delete"
|
|
@@ -89,15 +89,15 @@ class Ht extends tt {
|
|
|
89
89
|
`
|
|
90
90
|
).join(""), i = "https://academy.insiderone.com/docs/new-editor-email-recommendation-block", n = this.api.translate(
|
|
91
91
|
"Drag and drop the card elements to reorder them, adjust their visibility or add new attributes up to 5."
|
|
92
|
-
),
|
|
92
|
+
), a = this.api.translate("For more information, you can"), c = this.api.translate("visit Academy");
|
|
93
93
|
return `
|
|
94
94
|
<div class="recommendation-controls-container" data-card-composition-control>
|
|
95
95
|
<div class="container">
|
|
96
96
|
<p class="card-composition-description">
|
|
97
97
|
${n}
|
|
98
|
-
${
|
|
98
|
+
${a}
|
|
99
99
|
<!-- cspell:disable-next-line -->
|
|
100
|
-
<a href="${i}" target="_blank" rel="noopener noreferrer">${
|
|
100
|
+
<a href="${i}" target="_blank" rel="noopener noreferrer">${c}</a>.
|
|
101
101
|
</p>
|
|
102
102
|
</div>
|
|
103
103
|
|
|
@@ -120,7 +120,7 @@ class Ht extends tt {
|
|
|
120
120
|
<div class="orderable-list" data-composition-list></div>
|
|
121
121
|
|
|
122
122
|
${this._GuButton({
|
|
123
|
-
name:
|
|
123
|
+
name: x.ADD_ATTRIBUTE,
|
|
124
124
|
label: this.api.translate("Add Attribute"),
|
|
125
125
|
id: "guido__btn-add-attribute"
|
|
126
126
|
})}
|
|
@@ -149,7 +149,7 @@ class Ht extends tt {
|
|
|
149
149
|
this._applyVisibilityToBlock(t.key, r);
|
|
150
150
|
});
|
|
151
151
|
});
|
|
152
|
-
for (let t = 0; t <
|
|
152
|
+
for (let t = 0; t < g; t++) {
|
|
153
153
|
const r = `${T}${t}`, e = t;
|
|
154
154
|
this.api.onValueChanged(r, (o) => {
|
|
155
155
|
this._onCustomAttributeChanged(e, o);
|
|
@@ -162,42 +162,36 @@ class Ht extends tt {
|
|
|
162
162
|
_readCompositionFromNode() {
|
|
163
163
|
if (!this.currentNode || !("getAttribute" in this.currentNode))
|
|
164
164
|
return [...P];
|
|
165
|
-
const t = this.currentNode.getAttribute(
|
|
166
|
-
|
|
167
|
-
return t.split(",").filter(Boolean);
|
|
168
|
-
const { composition: r } = $.getConfig(this.currentNode);
|
|
169
|
-
return r != null && r.length ? [...r] : [...P];
|
|
165
|
+
const t = this.currentNode.getAttribute(V);
|
|
166
|
+
return t ? t.split(",").filter(Boolean) : [...P];
|
|
170
167
|
}
|
|
171
168
|
_readCustomAttributesFromNode() {
|
|
172
169
|
if (!this.currentNode || !("getAttribute" in this.currentNode))
|
|
173
170
|
return [];
|
|
174
|
-
const t = this.currentNode.getAttribute(
|
|
175
|
-
if (t)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
171
|
+
const t = this.currentNode.getAttribute(q);
|
|
172
|
+
if (!t)
|
|
173
|
+
return [];
|
|
174
|
+
try {
|
|
175
|
+
return JSON.parse(t);
|
|
176
|
+
} catch {
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
182
179
|
}
|
|
183
180
|
_readVisibilityFromRows() {
|
|
184
181
|
if (!this.currentNode)
|
|
185
182
|
return this._getDefaultVisibilities();
|
|
186
|
-
const t = Array.from(this.currentNode.querySelectorAll(
|
|
187
|
-
|
|
188
|
-
return this._mergeWithDefaults(r);
|
|
189
|
-
const e = $.getConfig(this.currentNode).visibility;
|
|
190
|
-
return this._mergeWithDefaults({ ...e });
|
|
183
|
+
const t = Array.from(this.currentNode.querySelectorAll(C)), r = this._extractVisibilityFromRows(t);
|
|
184
|
+
return this._mergeWithDefaults(r);
|
|
191
185
|
}
|
|
192
186
|
_getDefaultVisibilities() {
|
|
193
|
-
return { ...
|
|
187
|
+
return { ...F };
|
|
194
188
|
}
|
|
195
189
|
_extractVisibilityFromRows(t) {
|
|
196
190
|
const r = {};
|
|
197
191
|
return t.forEach((e) => {
|
|
198
192
|
if (!("getAttribute" in e))
|
|
199
193
|
return;
|
|
200
|
-
const o = e.getAttribute(y), s = e.getAttribute(
|
|
194
|
+
const o = e.getAttribute(y), s = e.getAttribute(v);
|
|
201
195
|
o && s !== null && (r[o] = this._parseVisibilityValue(s));
|
|
202
196
|
}), r;
|
|
203
197
|
}
|
|
@@ -205,7 +199,7 @@ class Ht extends tt {
|
|
|
205
199
|
return t === "1" || t === "true";
|
|
206
200
|
}
|
|
207
201
|
_mergeWithDefaults(t) {
|
|
208
|
-
return Object.entries(
|
|
202
|
+
return Object.entries(F).forEach(([r, e]) => {
|
|
209
203
|
r in t || (t[r] = e);
|
|
210
204
|
}), t;
|
|
211
205
|
}
|
|
@@ -229,19 +223,19 @@ class Ht extends tt {
|
|
|
229
223
|
return !1;
|
|
230
224
|
const s = new Set(r);
|
|
231
225
|
let i = 0, n = 0;
|
|
232
|
-
const
|
|
233
|
-
if (yt.has(
|
|
234
|
-
const l = h.find((u) => u.key ===
|
|
226
|
+
const a = t.map((c) => {
|
|
227
|
+
if (yt.has(c)) {
|
|
228
|
+
const l = h.find((u) => u.key === c);
|
|
235
229
|
return this._createBuiltInItemHtml(l, n++);
|
|
236
230
|
}
|
|
237
|
-
if (
|
|
238
|
-
const l =
|
|
231
|
+
if (c.startsWith(m)) {
|
|
232
|
+
const l = c.substring(m.length);
|
|
239
233
|
if (s.has(l))
|
|
240
|
-
return this._createCustomItemHtml(
|
|
234
|
+
return this._createCustomItemHtml(c, i++, n++);
|
|
241
235
|
}
|
|
242
236
|
return "";
|
|
243
237
|
}).join("");
|
|
244
|
-
return this._rescueTogglesToStore(e), this._rescueSelectsToStore(e), this._rescueDeleteButtonsToStore(e), this._rescueReorderIconsToStore(e), o.innerHTML =
|
|
238
|
+
return this._rescueTogglesToStore(e), this._rescueSelectsToStore(e), this._rescueDeleteButtonsToStore(e), this._rescueReorderIconsToStore(e), o.innerHTML = a, this._moveTogglesIntoItems(e), this._moveSelectsIntoItems(e, r.length), this._moveDeleteButtonsIntoItems(e, r.length), this._moveReorderIconsIntoItems(e, n), !0;
|
|
245
239
|
}
|
|
246
240
|
/**
|
|
247
241
|
* Attempts to reorder existing orderable-item elements to match the composition order.
|
|
@@ -253,27 +247,27 @@ class Ht extends tt {
|
|
|
253
247
|
const e = Array.from(t.querySelectorAll(".orderable-item"));
|
|
254
248
|
if (e.length !== r.length)
|
|
255
249
|
return !1;
|
|
256
|
-
const o = e.map((
|
|
250
|
+
const o = e.map((c) => c.dataset.key).filter(Boolean);
|
|
257
251
|
if (o.length !== r.length)
|
|
258
252
|
return !1;
|
|
259
253
|
const s = [...o].sort().join(","), i = [...r].sort().join(",");
|
|
260
|
-
if (s !== i || r.some((
|
|
254
|
+
if (s !== i || r.some((c) => c.startsWith(m)))
|
|
261
255
|
return !1;
|
|
262
256
|
const n = /* @__PURE__ */ new Map();
|
|
263
|
-
e.forEach((
|
|
264
|
-
const { key: l } =
|
|
257
|
+
e.forEach((c) => {
|
|
258
|
+
const { key: l } = c.dataset;
|
|
265
259
|
if (l) {
|
|
266
260
|
const u = n.get(l) || [];
|
|
267
|
-
u.push(
|
|
261
|
+
u.push(c), n.set(l, u);
|
|
268
262
|
}
|
|
269
263
|
});
|
|
270
|
-
const
|
|
271
|
-
return r.forEach((
|
|
272
|
-
const l = n.get(
|
|
264
|
+
const a = /* @__PURE__ */ new Map();
|
|
265
|
+
return r.forEach((c) => {
|
|
266
|
+
const l = n.get(c);
|
|
273
267
|
if (!l)
|
|
274
268
|
return;
|
|
275
|
-
const u =
|
|
276
|
-
|
|
269
|
+
const u = a.get(c) || 0;
|
|
270
|
+
a.set(c, u + 1), l[u] && t.appendChild(l[u]);
|
|
277
271
|
}), !0;
|
|
278
272
|
}
|
|
279
273
|
_createBuiltInItemHtml(t, r) {
|
|
@@ -322,7 +316,7 @@ class Ht extends tt {
|
|
|
322
316
|
t.length !== 0 && setTimeout(() => {
|
|
323
317
|
t.forEach((r, e) => {
|
|
324
318
|
const o = `${T}${e}`, s = this._getSelectOptions(r, t);
|
|
325
|
-
this.api.setUIEAttribute(o,
|
|
319
|
+
this.api.setUIEAttribute(o, I.SELECTPICKER.items, s), this.api.updateValues({ [o]: r });
|
|
326
320
|
});
|
|
327
321
|
}, 0);
|
|
328
322
|
}
|
|
@@ -372,7 +366,7 @@ class Ht extends tt {
|
|
|
372
366
|
* Same rescue pattern as _rescueTogglesToStore — prevents innerHTML from destroying them.
|
|
373
367
|
*/
|
|
374
368
|
_rescueSelectsToStore(t) {
|
|
375
|
-
for (let r = 0; r <
|
|
369
|
+
for (let r = 0; r < g; r++) {
|
|
376
370
|
const e = `${T}${r}`, o = t.querySelector(`[data-custom-select-key="${e}"]`), s = t.querySelector(`[data-custom-select-slot="${r}"]`);
|
|
377
371
|
if (s) {
|
|
378
372
|
const i = s.querySelector("ue-select");
|
|
@@ -386,7 +380,7 @@ class Ht extends tt {
|
|
|
386
380
|
*/
|
|
387
381
|
_moveDeleteButtonsIntoItems(t, r) {
|
|
388
382
|
for (let e = 0; e < r; e++) {
|
|
389
|
-
const o = `${
|
|
383
|
+
const o = `${R}${e}`, s = t.querySelector(`[data-custom-delete-key="${o}"]`), i = t.querySelector(`[data-custom-delete-slot="${e}"]`);
|
|
390
384
|
if (s && i) {
|
|
391
385
|
const n = s.querySelector("ue-button");
|
|
392
386
|
n && i.appendChild(n);
|
|
@@ -398,8 +392,8 @@ class Ht extends tt {
|
|
|
398
392
|
* Same rescue pattern as _rescueSelectsToStore — prevents innerHTML from destroying them.
|
|
399
393
|
*/
|
|
400
394
|
_rescueDeleteButtonsToStore(t) {
|
|
401
|
-
for (let r = 0; r <
|
|
402
|
-
const e = `${
|
|
395
|
+
for (let r = 0; r < g; r++) {
|
|
396
|
+
const e = `${R}${r}`, o = t.querySelector(`[data-custom-delete-key="${e}"]`), s = t.querySelector(`[data-custom-delete-slot="${r}"]`);
|
|
403
397
|
if (s) {
|
|
404
398
|
const i = s.querySelector("ue-button");
|
|
405
399
|
i && o && o.appendChild(i);
|
|
@@ -412,7 +406,7 @@ class Ht extends tt {
|
|
|
412
406
|
*/
|
|
413
407
|
_moveReorderIconsIntoItems(t, r) {
|
|
414
408
|
for (let e = 0; e < r; e++) {
|
|
415
|
-
const o = `${
|
|
409
|
+
const o = `${E}${e}`, s = t.querySelector(`[data-reorder-icon-key="${o}"]`), i = t.querySelector(`[data-reorder-icon-slot="${e}"]`);
|
|
416
410
|
if (s && i) {
|
|
417
411
|
const n = s.querySelector("ue-button");
|
|
418
412
|
n && i.appendChild(n);
|
|
@@ -424,9 +418,9 @@ class Ht extends tt {
|
|
|
424
418
|
* Same rescue pattern as _rescueDeleteButtonsToStore — prevents innerHTML from destroying them.
|
|
425
419
|
*/
|
|
426
420
|
_rescueReorderIconsToStore(t) {
|
|
427
|
-
const r = h.length +
|
|
421
|
+
const r = h.length + g;
|
|
428
422
|
for (let e = 0; e < r; e++) {
|
|
429
|
-
const o = `${
|
|
423
|
+
const o = `${E}${e}`, s = t.querySelector(`[data-reorder-icon-key="${o}"]`), i = t.querySelector(`[data-reorder-icon-slot="${e}"]`);
|
|
430
424
|
if (i) {
|
|
431
425
|
const n = i.querySelector("ue-button");
|
|
432
426
|
n && s && s.appendChild(n);
|
|
@@ -450,24 +444,24 @@ class Ht extends tt {
|
|
|
450
444
|
_setupDragAndDrop(t, r) {
|
|
451
445
|
let e = null, o = null;
|
|
452
446
|
t.addEventListener("dragstart", (s) => {
|
|
453
|
-
var
|
|
447
|
+
var a;
|
|
454
448
|
const n = s.target.closest(".orderable-item");
|
|
455
|
-
n && (e = n, n.classList.add("dragging"), (
|
|
449
|
+
n && (e = n, n.classList.add("dragging"), (a = s.dataTransfer) == null || a.setData("text/plain", n.dataset.key || ""));
|
|
456
450
|
}, { signal: r }), t.addEventListener("dragend", () => {
|
|
457
451
|
e && e.classList.remove("dragging"), e = null, o == null || o.classList.remove("drag-over"), o = null;
|
|
458
452
|
}, { signal: r }), t.addEventListener("dragover", (s) => {
|
|
459
453
|
s.preventDefault();
|
|
460
|
-
const n = s.target.closest(".orderable-item"),
|
|
461
|
-
|
|
454
|
+
const n = s.target.closest(".orderable-item"), a = n && n !== e ? n : null;
|
|
455
|
+
a !== o && (o == null || o.classList.remove("drag-over"), o = a, o == null || o.classList.add("drag-over"));
|
|
462
456
|
}, { signal: r }), t.addEventListener("drop", (s) => {
|
|
463
457
|
s.preventDefault();
|
|
464
458
|
const n = s.target.closest(".orderable-item");
|
|
465
459
|
if (!n || !e || n === e)
|
|
466
460
|
return;
|
|
467
|
-
const
|
|
468
|
-
s.clientY <
|
|
469
|
-
const u = t.querySelectorAll(".orderable-item"),
|
|
470
|
-
this._onReorder(
|
|
461
|
+
const a = n.getBoundingClientRect(), c = a.top + a.height / 2;
|
|
462
|
+
s.clientY < c ? t.insertBefore(e, n) : t.insertBefore(e, n.nextSibling), o == null || o.classList.remove("drag-over"), o = null, e.classList.remove("dragging");
|
|
463
|
+
const u = t.querySelectorAll(".orderable-item"), d = Array.from(u).map((b) => b.dataset.key).filter(Boolean);
|
|
464
|
+
this._onReorder(d), e = null;
|
|
471
465
|
}, { signal: r });
|
|
472
466
|
}
|
|
473
467
|
_setupDeleteHandler(t, r) {
|
|
@@ -483,7 +477,7 @@ class Ht extends tt {
|
|
|
483
477
|
// Actions (Add, Delete, Reorder)
|
|
484
478
|
// ========================================================================
|
|
485
479
|
_onAddAttribute(t, r) {
|
|
486
|
-
const e = `${
|
|
480
|
+
const e = `${m}${t}`, o = this._readCompositionFromNode();
|
|
487
481
|
o.push(e);
|
|
488
482
|
const s = [...this._readCustomAttributesFromNode(), t];
|
|
489
483
|
this._updateBothAttributes(o, s), this._injectCustomAttributeHtml(t, r, e, o), this._renderOrderableItems(o, s), this._initializeCustomSelects(s), this._updateAddButtonState();
|
|
@@ -496,7 +490,7 @@ class Ht extends tt {
|
|
|
496
490
|
const r = this._readCustomAttributesFromNode();
|
|
497
491
|
if (r[t] === void 0)
|
|
498
492
|
return;
|
|
499
|
-
const o = this._readCompositionFromNode(), s = this._findNthCustomKeyIndex(o, t), i = o.filter((
|
|
493
|
+
const o = this._readCompositionFromNode(), s = this._findNthCustomKeyIndex(o, t), i = o.filter((a, c) => c !== s), n = r.filter((a, c) => c !== t);
|
|
500
494
|
this._updateBothAttributes(i, n), this._removeCustomAttributeHtml(i), this._renderOrderableItems(i, n), this._initializeCustomSelects(n), this._updateAddButtonState();
|
|
501
495
|
}
|
|
502
496
|
/**
|
|
@@ -507,13 +501,13 @@ class Ht extends tt {
|
|
|
507
501
|
const e = this._readCustomAttributesFromNode(), o = e[t];
|
|
508
502
|
if (o === void 0 || o === r)
|
|
509
503
|
return;
|
|
510
|
-
const s = `${
|
|
504
|
+
const s = `${m}${r}`, i = this._readCompositionFromNode(), n = this._findNthCustomKeyIndex(i, t);
|
|
511
505
|
n !== -1 && (i[n] = s), e[t] = r;
|
|
512
|
-
const
|
|
513
|
-
this._updateBothAttributes(i, e), this._injectCustomAttributeHtml(r,
|
|
506
|
+
const a = this._getDisplayNameForAttribute(r);
|
|
507
|
+
this._updateBothAttributes(i, e), this._injectCustomAttributeHtml(r, a, s, i), this._renderOrderableItems(i, e), this._initializeCustomSelects(e);
|
|
514
508
|
}
|
|
515
509
|
_onReorder(t) {
|
|
516
|
-
const r = t.filter((e) => e.startsWith(
|
|
510
|
+
const r = t.filter((e) => e.startsWith(m)).map((e) => e.substring(m.length));
|
|
517
511
|
this.reorderInProgress = !0;
|
|
518
512
|
try {
|
|
519
513
|
this._updateBothAttributes(t, r), this._getCurrentLayout() === "grid" && this._reorderProductAttributes(t);
|
|
@@ -534,58 +528,58 @@ class Ht extends tt {
|
|
|
534
528
|
const s = this.currentNode.querySelectorAll(L);
|
|
535
529
|
if (!(s != null && s.length))
|
|
536
530
|
return;
|
|
537
|
-
const i =
|
|
531
|
+
const i = nt.getConfig(this.currentNode), a = `0 ${Math.floor(i.columnSpacing / 2)}px`, c = this.api.getDocumentModifier(), l = this.store.recommendationProducts.length;
|
|
538
532
|
let u = 0;
|
|
539
|
-
s.forEach((
|
|
540
|
-
var
|
|
541
|
-
const b =
|
|
542
|
-
if (
|
|
543
|
-
const
|
|
533
|
+
s.forEach((d) => {
|
|
534
|
+
var H;
|
|
535
|
+
const b = d.querySelector(C), $ = ((H = b == null ? void 0 : b.querySelectorAll(`.${at}`)) == null ? void 0 : H.length) || 1, B = (100 / $).toFixed(2), { bgStyle: j, bgAttr: W } = this._extractSegmentBgFromCard(d), O = l > 0 ? Math.min($, l - u) : $, K = o.map((k) => {
|
|
536
|
+
if (k === e) {
|
|
537
|
+
const z = Array.from(
|
|
544
538
|
{ length: O },
|
|
545
|
-
(
|
|
546
|
-
const
|
|
539
|
+
(At, Y) => {
|
|
540
|
+
const X = this._resolveAttributeContent(
|
|
547
541
|
t,
|
|
548
542
|
r,
|
|
549
|
-
u +
|
|
543
|
+
u + Y
|
|
550
544
|
);
|
|
551
545
|
return this._getGridCellHtml(
|
|
552
546
|
t,
|
|
553
|
-
|
|
547
|
+
X,
|
|
554
548
|
B,
|
|
549
|
+
j,
|
|
555
550
|
W,
|
|
556
|
-
|
|
557
|
-
c
|
|
551
|
+
a
|
|
558
552
|
);
|
|
559
553
|
}
|
|
560
|
-
).join(""),
|
|
561
|
-
return `<tr class="recommendation-attribute-row" ${y}="${e}" ${
|
|
554
|
+
).join(""), G = dt(B, a).repeat($ - O);
|
|
555
|
+
return `<tr class="recommendation-attribute-row" ${y}="${e}" ${v}="1">${z}${G}</tr>`;
|
|
562
556
|
}
|
|
563
|
-
const
|
|
564
|
-
`${
|
|
557
|
+
const N = d.querySelector(
|
|
558
|
+
`${C}[${y}="${k}"]`
|
|
565
559
|
);
|
|
566
|
-
return
|
|
560
|
+
return N && "getOuterHTML" in N ? N.getOuterHTML() : "";
|
|
567
561
|
}).join("");
|
|
568
|
-
u += O, l > 0 && u >= l && (u = 0),
|
|
569
|
-
}),
|
|
562
|
+
u += O, l > 0 && u >= l && (u = 0), c.modifyHtml(d).setInnerHtml(K);
|
|
563
|
+
}), c.apply(new A(`${this.api.translate("Add custom attribute")}: ${r}`));
|
|
570
564
|
}
|
|
571
565
|
_injectListAttributeRow(t, r, e, o) {
|
|
572
|
-
const s = this.currentNode.querySelectorAll(
|
|
566
|
+
const s = this.currentNode.querySelectorAll(M);
|
|
573
567
|
if (!(s != null && s.length))
|
|
574
568
|
return;
|
|
575
|
-
const i = o.filter((
|
|
576
|
-
s.forEach((
|
|
569
|
+
const i = o.filter((a) => a !== D && a !== U), n = this.api.getDocumentModifier();
|
|
570
|
+
s.forEach((a, c) => {
|
|
577
571
|
const l = i.map((u) => {
|
|
578
572
|
if (u === e) {
|
|
579
|
-
const b = this._resolveAttributeContent(t, r,
|
|
573
|
+
const b = this._resolveAttributeContent(t, r, c);
|
|
580
574
|
return this._getListRowHtml(t, b, e);
|
|
581
575
|
}
|
|
582
|
-
const
|
|
583
|
-
`${
|
|
576
|
+
const d = a.querySelector(
|
|
577
|
+
`${C}[${y}="${u}"]`
|
|
584
578
|
);
|
|
585
|
-
return
|
|
579
|
+
return d && "getOuterHTML" in d ? d.getOuterHTML() : "";
|
|
586
580
|
}).join("");
|
|
587
|
-
n.modifyHtml(
|
|
588
|
-
}), n.apply(new
|
|
581
|
+
n.modifyHtml(a).setInnerHtml(l);
|
|
582
|
+
}), n.apply(new A(`${this.api.translate("Add custom attribute")}: ${r}`));
|
|
589
583
|
}
|
|
590
584
|
/**
|
|
591
585
|
* Removes a custom attribute by rebuilding product card content without it.
|
|
@@ -602,13 +596,13 @@ class Ht extends tt {
|
|
|
602
596
|
e.modifyHtml(s).setInnerHtml(i);
|
|
603
597
|
});
|
|
604
598
|
} else {
|
|
605
|
-
const o = t.filter((i) => i !==
|
|
599
|
+
const o = t.filter((i) => i !== D && i !== U), s = this.currentNode.querySelectorAll(M);
|
|
606
600
|
s == null || s.forEach((i) => {
|
|
607
601
|
const n = this._buildCompositionHtml(i, o);
|
|
608
602
|
e.modifyHtml(i).setInnerHtml(n);
|
|
609
603
|
});
|
|
610
604
|
}
|
|
611
|
-
e.apply(new
|
|
605
|
+
e.apply(new A(this.api.translate("Remove custom attribute")));
|
|
612
606
|
}
|
|
613
607
|
// ========================================================================
|
|
614
608
|
// DOM Mutation (Block Root Attributes, Reorder)
|
|
@@ -621,13 +615,7 @@ class Ht extends tt {
|
|
|
621
615
|
* producing a flicker on the custom attribute dropdowns.
|
|
622
616
|
*/
|
|
623
617
|
_updateBothAttributes(t, r) {
|
|
624
|
-
|
|
625
|
-
return;
|
|
626
|
-
const e = {
|
|
627
|
-
...$.getConfig(this.currentNode),
|
|
628
|
-
composition: t
|
|
629
|
-
};
|
|
630
|
-
this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute(x, t.join(",")).setAttribute(F, JSON.stringify(r)).setNodeConfig(e).apply(new C(this.api.translate("Update card composition")));
|
|
618
|
+
this.currentNode && this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute(V, t.join(",")).setAttribute(q, JSON.stringify(r)).apply(new A(this.api.translate("Update card composition")));
|
|
631
619
|
}
|
|
632
620
|
/**
|
|
633
621
|
* Reorders attribute rows within each product card based on composition order.
|
|
@@ -643,7 +631,7 @@ class Ht extends tt {
|
|
|
643
631
|
r.forEach((o) => {
|
|
644
632
|
const s = this._buildCompositionHtml(o, t);
|
|
645
633
|
e.modifyHtml(o).setInnerHtml(s);
|
|
646
|
-
}), e.apply(new
|
|
634
|
+
}), e.apply(new A(this.api.translate("Reorder product attributes")));
|
|
647
635
|
}
|
|
648
636
|
/**
|
|
649
637
|
* Builds HTML string with attributes ordered according to composition.
|
|
@@ -651,7 +639,7 @@ class Ht extends tt {
|
|
|
651
639
|
*/
|
|
652
640
|
_buildCompositionHtml(t, r) {
|
|
653
641
|
return r.reduce((e, o) => {
|
|
654
|
-
const s = t.querySelector(`${
|
|
642
|
+
const s = t.querySelector(`${C}[${y}="${o}"]`);
|
|
655
643
|
return s && "getOuterHTML" in s ? e + s.getOuterHTML() : e;
|
|
656
644
|
}, "");
|
|
657
645
|
}
|
|
@@ -661,19 +649,14 @@ class Ht extends tt {
|
|
|
661
649
|
_applyVisibilityToBlock(t, r) {
|
|
662
650
|
if (!this.currentNode)
|
|
663
651
|
return;
|
|
664
|
-
const e = this.currentNode.querySelectorAll(`${
|
|
652
|
+
const e = this.currentNode.querySelectorAll(`${C}[${y}="${t}"]`);
|
|
665
653
|
if (!(e != null && e.length))
|
|
666
654
|
return;
|
|
667
655
|
const o = r ? "1" : "0", s = r ? this.api.translate("visible") : this.api.translate("hidden"), i = `${this.api.translate("Set visibility")}: ${t} → ${s}`, n = this.api.getDocumentModifier();
|
|
668
656
|
e.forEach((a) => {
|
|
669
|
-
const
|
|
670
|
-
n.modifyHtml(a).setStyle("display",
|
|
671
|
-
});
|
|
672
|
-
const c = {
|
|
673
|
-
...$.getConfig(this.currentNode),
|
|
674
|
-
visibility: { ...this._readVisibilityFromRows(), [t]: r }
|
|
675
|
-
};
|
|
676
|
-
n.modifyHtml(this.currentNode).setNodeConfig(c), n.apply(new C(i));
|
|
657
|
+
const c = ft(a), l = r ? c : "none";
|
|
658
|
+
n.modifyHtml(a).setStyle("display", l).setAttribute(v, o);
|
|
659
|
+
}), n.apply(new A(i));
|
|
677
660
|
}
|
|
678
661
|
// ========================================================================
|
|
679
662
|
// Utilities
|
|
@@ -686,7 +669,7 @@ class Ht extends tt {
|
|
|
686
669
|
_findNthCustomKeyIndex(t, r) {
|
|
687
670
|
let e = 0;
|
|
688
671
|
for (let o = 0; o < t.length; o++)
|
|
689
|
-
if (t[o].startsWith(
|
|
672
|
+
if (t[o].startsWith(m)) {
|
|
690
673
|
if (e === r)
|
|
691
674
|
return o;
|
|
692
675
|
e++;
|
|
@@ -694,7 +677,7 @@ class Ht extends tt {
|
|
|
694
677
|
return -1;
|
|
695
678
|
}
|
|
696
679
|
_getCurrentLayout() {
|
|
697
|
-
return this.store.recommendationConfigs.orientation ||
|
|
680
|
+
return this.store.recommendationConfigs.orientation || gt(this.currentNode);
|
|
698
681
|
}
|
|
699
682
|
/**
|
|
700
683
|
* Extracts background color properties from existing card elements.
|
|
@@ -745,10 +728,10 @@ class Ht extends tt {
|
|
|
745
728
|
* or when all available filters have already been added (no unused attributes left).
|
|
746
729
|
*/
|
|
747
730
|
_updateAddButtonState() {
|
|
748
|
-
const t = this._readCustomAttributesFromNode(), r = t.length >=
|
|
731
|
+
const t = this._readCustomAttributesFromNode(), r = t.length >= g, e = new Set(t), o = this._getAddableFilters(), s = o.length > 0 && o.every((i) => e.has(i.attributeName));
|
|
749
732
|
this.api.setUIEAttribute(
|
|
750
|
-
|
|
751
|
-
|
|
733
|
+
x.ADD_ATTRIBUTE,
|
|
734
|
+
I.BUTTON.disabled,
|
|
752
735
|
r || s ? "true" : "false"
|
|
753
736
|
);
|
|
754
737
|
}
|
|
@@ -771,7 +754,7 @@ class Ht extends tt {
|
|
|
771
754
|
* excluding default attributes already covered by built-in toggle items.
|
|
772
755
|
*/
|
|
773
756
|
_getAddableFilters() {
|
|
774
|
-
return Object.values(this.store.filterList).filter((t) => !(t.type === "defaultAttribute" &&
|
|
757
|
+
return Object.values(this.store.filterList).filter((t) => !(t.type === "defaultAttribute" && it.has(t.attributeName)));
|
|
775
758
|
}
|
|
776
759
|
/**
|
|
777
760
|
* Looks up the display name for an attribute from the store's filterList.
|
|
@@ -788,28 +771,28 @@ class Ht extends tt {
|
|
|
788
771
|
_resolveAttributeContent(t, r, e) {
|
|
789
772
|
var n;
|
|
790
773
|
const s = this.store.recommendationProducts[e], i = pt(t, this.store.filterList) ? s == null ? void 0 : s[t] : (n = s == null ? void 0 : s.product_attributes) == null ? void 0 : n[t];
|
|
791
|
-
return
|
|
774
|
+
return _t(i) ?? r;
|
|
792
775
|
}
|
|
793
776
|
_getGridCellHtml(t, r, e, o = "", s = "", i = "") {
|
|
794
|
-
const n = `${
|
|
777
|
+
const n = `${m}${t}`, a = w(ct, [n], this.store.filterList), c = {
|
|
795
778
|
[t]: r,
|
|
796
779
|
product_attributes: { [t]: r }
|
|
797
780
|
};
|
|
798
|
-
let l =
|
|
781
|
+
let l = a[n](c);
|
|
799
782
|
return l = l.replace("<td", `<td width="${e}%"`), i && (l = l.replace(
|
|
800
783
|
`padding: ${ut}`,
|
|
801
784
|
`padding: ${i}`
|
|
802
785
|
)), o && (l = l.replace(/style="table-layout: fixed;"/, `style="table-layout: fixed; ${o}"`)), s && (l = l.replace(/border="0"/, `border="0" bgcolor="${s}"`)), l;
|
|
803
786
|
}
|
|
804
787
|
_getListRowHtml(t, r, e) {
|
|
805
|
-
const o =
|
|
788
|
+
const o = w(mt, [e], this.store.filterList), s = {
|
|
806
789
|
[t]: r,
|
|
807
790
|
product_attributes: { [t]: r }
|
|
808
791
|
}, n = o[e](s).replace(/<tr>/, "").replace(/<\/tr>/, "");
|
|
809
|
-
return `<tr class="recommendation-attribute-row" ${y}="${e}" ${
|
|
792
|
+
return `<tr class="recommendation-attribute-row" ${y}="${e}" ${v}="1">${n}</tr>`;
|
|
810
793
|
}
|
|
811
794
|
}
|
|
812
795
|
export {
|
|
813
796
|
bt as COMPOSITION_CONTROL_BLOCK_ID,
|
|
814
|
-
|
|
797
|
+
Ut as RecommendationCardCompositionControl
|
|
815
798
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useinsider/guido",
|
|
3
|
-
"version": "3.7.2-beta.
|
|
3
|
+
"version": "3.7.2-beta.7b4f9d0",
|
|
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",
|