@absmartly/sdk-plugins 1.2.2 → 1.3.2
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/absmartly-cookie.min.js +1 -1
- package/dist/absmartly-dom-changes-core.min.js +1 -1
- package/dist/absmartly-dom-changes-lite.min.js +1 -1
- package/dist/absmartly-overrides-full.min.js +1 -1
- package/dist/absmartly-overrides-lite.min.js +1 -1
- package/dist/absmartly-sdk-plugins.min.js +1 -1
- package/dist/absmartly-vitals.min.js +1 -1
- package/es/analytics/AnalyticsPlugin.js +96 -0
- package/es/analytics/AnalyticsPlugin.js.map +1 -0
- package/es/analytics/index.js +2 -0
- package/es/analytics/index.js.map +1 -0
- package/es/analytics/types.js +2 -0
- package/es/analytics/types.js.map +1 -0
- package/es/cookies/CookiePlugin.js +59 -18
- package/es/cookies/CookiePlugin.js.map +1 -1
- package/es/core/DOMChangesPluginLite.js +217 -106
- package/es/core/DOMChangesPluginLite.js.map +1 -1
- package/es/core/DOMManipulatorLite.js +285 -153
- package/es/core/DOMManipulatorLite.js.map +1 -1
- package/es/core/ExposureTracker.js +310 -108
- package/es/core/ExposureTracker.js.map +1 -1
- package/es/core/HTMLInjector.js +11 -1
- package/es/core/HTMLInjector.js.map +1 -1
- package/es/core/PendingChangeManager.js +114 -54
- package/es/core/PendingChangeManager.js.map +1 -1
- package/es/generated/buildInfo.js +1 -1
- package/es/index.js +1 -0
- package/es/index.js.map +1 -1
- package/es/overrides/BrowserCookieAdapter.js +3 -31
- package/es/overrides/BrowserCookieAdapter.js.map +1 -1
- package/es/overrides/OverridesPlugin.js +39 -107
- package/es/overrides/OverridesPlugin.js.map +1 -1
- package/es/overrides/OverridesPluginLite.js +5 -136
- package/es/overrides/OverridesPluginLite.js.map +1 -1
- package/es/parsers/VariantExtractor.js +21 -18
- package/es/parsers/VariantExtractor.js.map +1 -1
- package/es/url-redirect/URLRedirectExtractor.js +8 -2
- package/es/url-redirect/URLRedirectExtractor.js.map +1 -1
- package/es/url-redirect/URLRedirectMatcher.js +130 -0
- package/es/url-redirect/URLRedirectMatcher.js.map +1 -1
- package/es/url-redirect/URLRedirectPlugin.js +14 -5
- package/es/url-redirect/URLRedirectPlugin.js.map +1 -1
- package/es/utils/URLMatcher.js.map +1 -1
- package/es/utils/debug.js +11 -0
- package/es/utils/debug.js.map +1 -1
- package/es/utils/persistence.js +143 -75
- package/es/utils/persistence.js.map +1 -1
- package/es/utils/plugin-registry.js.map +1 -1
- package/es/vitals/WebVitalsPlugin.js +9 -4
- package/es/vitals/WebVitalsPlugin.js.map +1 -1
- package/lib/analytics/AnalyticsPlugin.d.ts +8 -0
- package/lib/analytics/AnalyticsPlugin.js +99 -0
- package/lib/analytics/AnalyticsPlugin.js.map +1 -0
- package/lib/analytics/index.d.ts +2 -0
- package/lib/analytics/index.js +6 -0
- package/lib/analytics/index.js.map +1 -0
- package/lib/analytics/types.d.ts +5 -0
- package/lib/analytics/types.js +3 -0
- package/lib/analytics/types.js.map +1 -0
- package/lib/cookies/CookiePlugin.js +59 -18
- package/lib/cookies/CookiePlugin.js.map +1 -1
- package/lib/core/DOMChangesPluginLite.d.ts +5 -2
- package/lib/core/DOMChangesPluginLite.js +217 -106
- package/lib/core/DOMChangesPluginLite.js.map +1 -1
- package/lib/core/DOMManipulatorLite.d.ts +24 -0
- package/lib/core/DOMManipulatorLite.js +284 -152
- package/lib/core/DOMManipulatorLite.js.map +1 -1
- package/lib/core/ExposureTracker.js +310 -108
- package/lib/core/ExposureTracker.js.map +1 -1
- package/lib/core/HTMLInjector.d.ts +1 -0
- package/lib/core/HTMLInjector.js +11 -1
- package/lib/core/HTMLInjector.js.map +1 -1
- package/lib/core/PendingChangeManager.js +114 -54
- package/lib/core/PendingChangeManager.js.map +1 -1
- package/lib/generated/buildInfo.d.ts +1 -1
- package/lib/generated/buildInfo.js +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/overrides/BrowserCookieAdapter.js +3 -31
- package/lib/overrides/BrowserCookieAdapter.js.map +1 -1
- package/lib/overrides/OverridesPlugin.js +39 -107
- package/lib/overrides/OverridesPlugin.js.map +1 -1
- package/lib/overrides/OverridesPluginLite.d.ts +5 -1
- package/lib/overrides/OverridesPluginLite.js +5 -136
- package/lib/overrides/OverridesPluginLite.js.map +1 -1
- package/lib/parsers/VariantExtractor.js +21 -18
- package/lib/parsers/VariantExtractor.js.map +1 -1
- package/lib/types/index.d.ts +5 -0
- package/lib/url-redirect/URLRedirectExtractor.js +8 -2
- package/lib/url-redirect/URLRedirectExtractor.js.map +1 -1
- package/lib/url-redirect/URLRedirectMatcher.d.ts +3 -0
- package/lib/url-redirect/URLRedirectMatcher.js +130 -0
- package/lib/url-redirect/URLRedirectMatcher.js.map +1 -1
- package/lib/url-redirect/URLRedirectPlugin.js +13 -4
- package/lib/url-redirect/URLRedirectPlugin.js.map +1 -1
- package/lib/url-redirect/types.d.ts +1 -1
- package/lib/utils/URLMatcher.d.ts +1 -7
- package/lib/utils/URLMatcher.js.map +1 -1
- package/lib/utils/debug.d.ts +5 -0
- package/lib/utils/debug.js +12 -0
- package/lib/utils/debug.js.map +1 -1
- package/lib/utils/persistence.js +143 -75
- package/lib/utils/persistence.js.map +1 -1
- package/lib/utils/plugin-registry.d.ts +1 -0
- package/lib/utils/plugin-registry.js.map +1 -1
- package/lib/vitals/WebVitalsPlugin.js +9 -4
- package/lib/vitals/WebVitalsPlugin.js.map +1 -1
- package/package.json +13 -3
- package/types/analytics/AnalyticsPlugin.d.ts +8 -0
- package/types/analytics/index.d.ts +2 -0
- package/types/analytics/types.d.ts +5 -0
- package/types/core/DOMChangesPluginLite.d.ts +5 -2
- package/types/core/DOMManipulatorLite.d.ts +24 -0
- package/types/core/HTMLInjector.d.ts +1 -0
- package/types/generated/buildInfo.d.ts +1 -1
- package/types/index.d.ts +2 -0
- package/types/overrides/OverridesPluginLite.d.ts +5 -1
- package/types/types/index.d.ts +5 -0
- package/types/url-redirect/URLRedirectMatcher.d.ts +3 -0
- package/types/url-redirect/types.d.ts +1 -1
- package/types/utils/URLMatcher.d.ts +1 -7
- package/types/utils/debug.d.ts +5 -0
- package/types/utils/plugin-registry.d.ts +1 -0
|
@@ -34,7 +34,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
34
34
|
}
|
|
35
35
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
36
36
|
};
|
|
37
|
-
import { logDebug, logChangeApplication } from '../utils/debug';
|
|
37
|
+
import { logDebug, logChangeApplication, logProductionWarn } from '../utils/debug';
|
|
38
38
|
import { PendingChangeManager } from './PendingChangeManager';
|
|
39
39
|
var DOMManipulatorLite = /** @class */ (function () {
|
|
40
40
|
function DOMManipulatorLite(debug, plugin) {
|
|
@@ -50,9 +50,120 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
50
50
|
return _this.applyChange(change, experimentName);
|
|
51
51
|
}, debug);
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Execute a user-authored JavaScript DOM change against an element.
|
|
55
|
+
*
|
|
56
|
+
* Strategy:
|
|
57
|
+
* 1. Primary path uses `new Function(...)`. On pages whose CSP includes
|
|
58
|
+
* `unsafe-eval` this succeeds and keeps the fast debug-friendly path
|
|
59
|
+
* with a `//# sourceURL` tag.
|
|
60
|
+
* 2. When CSP blocks dynamic code evaluation the fallback injects a
|
|
61
|
+
* one-shot `<script>` element that calls an anonymous IIFE with the
|
|
62
|
+
* target element bound through a temporary `window` slot. This path
|
|
63
|
+
* works on pages that allow inline scripts but not eval.
|
|
64
|
+
* 3. If both paths fail, the error is logged unconditionally at
|
|
65
|
+
* `console.error` and surfaced via a `CustomEvent('absmartly:js-error', ...)`
|
|
66
|
+
* on `document` so hosting code (browser extension preview, telemetry,
|
|
67
|
+
* etc.) can distinguish CSP failures from runtime errors.
|
|
68
|
+
*
|
|
69
|
+
* Returns true when the code executed successfully through either path.
|
|
70
|
+
*/
|
|
71
|
+
DOMManipulatorLite.prototype.executeUserJavaScript = function (code, element, experimentName, selector) {
|
|
72
|
+
var sourceTag = "absmartly-experiment-".concat(experimentName || 'unknown', ".js");
|
|
73
|
+
var debugPrelude = "var _debug = (typeof _debug !== 'undefined' ? _debug : { debugLog: console.log.bind(console), debugWarn: console.warn.bind(console), debugError: console.error.bind(console) });\n";
|
|
74
|
+
try {
|
|
75
|
+
var fn = new Function('element', debugPrelude + code + "\n//# sourceURL=".concat(sourceTag));
|
|
76
|
+
fn(element);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
catch (evalError) {
|
|
80
|
+
var evalMessage = evalError instanceof Error ? evalError.message : String(evalError);
|
|
81
|
+
var cspBlockedEval = evalError instanceof EvalError ||
|
|
82
|
+
/unsafe-eval|Content Security Policy|CSP|refused to evaluate/i.test(evalMessage);
|
|
83
|
+
if (!cspBlockedEval) {
|
|
84
|
+
// Runtime error in user code — don't try the fallback, surface immediately.
|
|
85
|
+
this.reportJsExecutionFailure({
|
|
86
|
+
experimentName: experimentName,
|
|
87
|
+
selector: selector,
|
|
88
|
+
reason: 'runtime',
|
|
89
|
+
error: evalMessage,
|
|
90
|
+
stack: evalError instanceof Error ? evalError.stack : undefined,
|
|
91
|
+
});
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
// Fallback: inline <script> tag that binds the element through a temporary window slot.
|
|
95
|
+
// When CSP blocks inline scripts, appendChild does NOT throw — Chrome silently refuses
|
|
96
|
+
// execution and logs a console violation. We detect that by flipping a sentinel inside
|
|
97
|
+
// the injected script and checking it after append.
|
|
98
|
+
try {
|
|
99
|
+
var slotId = "__absmartly_js_target_".concat(Date.now(), "_").concat(Math.floor(Math.random() * 1e9));
|
|
100
|
+
var sentinelId = "".concat(slotId, "_ran");
|
|
101
|
+
window[slotId] = element;
|
|
102
|
+
window[sentinelId] = false;
|
|
103
|
+
var script = document.createElement('script');
|
|
104
|
+
script.textContent =
|
|
105
|
+
"(function(element){".concat(debugPrelude).concat(code, "\n})(window['").concat(slotId, "']);\n") +
|
|
106
|
+
"window['".concat(sentinelId, "'] = true;\n") +
|
|
107
|
+
"try { delete window['".concat(slotId, "']; } catch(_e) { window['").concat(slotId, "'] = undefined; }\n") +
|
|
108
|
+
"//# sourceURL=".concat(sourceTag);
|
|
109
|
+
var parent_1 = document.head || document.documentElement;
|
|
110
|
+
parent_1.appendChild(script);
|
|
111
|
+
script.remove();
|
|
112
|
+
var ran = window[sentinelId] === true;
|
|
113
|
+
try {
|
|
114
|
+
delete window[sentinelId];
|
|
115
|
+
}
|
|
116
|
+
catch (_a) {
|
|
117
|
+
window[sentinelId] = undefined;
|
|
118
|
+
}
|
|
119
|
+
if (!ran) {
|
|
120
|
+
this.reportJsExecutionFailure({
|
|
121
|
+
experimentName: experimentName,
|
|
122
|
+
selector: selector,
|
|
123
|
+
reason: 'csp',
|
|
124
|
+
error: "CSP blocked dynamic script execution. eval(): ".concat(evalMessage, "; inline <script> did not execute (likely blocked by script-src without 'unsafe-inline')."),
|
|
125
|
+
});
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
catch (scriptError) {
|
|
131
|
+
var scriptMessage = scriptError instanceof Error ? scriptError.message : String(scriptError);
|
|
132
|
+
this.reportJsExecutionFailure({
|
|
133
|
+
experimentName: experimentName,
|
|
134
|
+
selector: selector,
|
|
135
|
+
reason: 'csp',
|
|
136
|
+
error: "CSP blocked dynamic script execution. eval(): ".concat(evalMessage, "; inline <script>: ").concat(scriptMessage),
|
|
137
|
+
stack: scriptError instanceof Error ? scriptError.stack : undefined,
|
|
138
|
+
});
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Report a JavaScript execution failure to listeners, without relying on this.debug.
|
|
145
|
+
* Always logs at `console.error` and dispatches a `CustomEvent` on `document`.
|
|
146
|
+
*/
|
|
147
|
+
DOMManipulatorLite.prototype.reportJsExecutionFailure = function (detail) {
|
|
148
|
+
try {
|
|
149
|
+
logProductionWarn("[ABsmartly] JavaScript DOM change failed (".concat(detail.reason, ") for \"").concat(detail.experimentName, "\" selector \"").concat(detail.selector, "\": ").concat(detail.error), detail.stack ? { stack: detail.stack } : undefined);
|
|
150
|
+
}
|
|
151
|
+
catch (_a) {
|
|
152
|
+
// console unavailable; ignore
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
if (typeof document !== 'undefined' && typeof CustomEvent === 'function') {
|
|
156
|
+
document.dispatchEvent(new CustomEvent('absmartly:js-error', { detail: detail }));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (_b) {
|
|
160
|
+
// environments without CustomEvent support
|
|
161
|
+
}
|
|
162
|
+
};
|
|
53
163
|
DOMManipulatorLite.prototype.applyChange = function (change, experimentName) {
|
|
164
|
+
var e_1, _a, e_2, _b, e_3, _c;
|
|
54
165
|
var _this = this;
|
|
55
|
-
var
|
|
166
|
+
var _d, _e, _f, _g, _h, _j, _k, _l;
|
|
56
167
|
if (!change.enabled && change.enabled !== undefined) {
|
|
57
168
|
logDebug("Skipping disabled change for experiment: ".concat(experimentName), {
|
|
58
169
|
experimentName: experimentName,
|
|
@@ -64,7 +175,7 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
64
175
|
var isReapplying = !!this.plugin.reapplyingElements &&
|
|
65
176
|
Array.from(this.plugin.reapplyingElements).length > 0;
|
|
66
177
|
// Get user's variant for this experiment
|
|
67
|
-
var userVariant = (
|
|
178
|
+
var userVariant = (_e = (_d = this.plugin.config) === null || _d === void 0 ? void 0 : _d.context) === null || _e === void 0 ? void 0 : _e.peek(experimentName);
|
|
68
179
|
if (this.debug) {
|
|
69
180
|
logDebug("[DOM-APPLY] [".concat(experimentName, "] ").concat(isReapplying ? 'RE-APPLYING' : 'APPLYING', " change"), {
|
|
70
181
|
experimentName: experimentName,
|
|
@@ -72,7 +183,7 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
72
183
|
selector: change.selector,
|
|
73
184
|
type: change.type,
|
|
74
185
|
timestamp: Date.now(),
|
|
75
|
-
callStack: (
|
|
186
|
+
callStack: (_f = new Error().stack) === null || _f === void 0 ? void 0 : _f.split('\n').slice(2, 4).join('\n'),
|
|
76
187
|
});
|
|
77
188
|
}
|
|
78
189
|
try {
|
|
@@ -92,10 +203,10 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
92
203
|
return false;
|
|
93
204
|
}
|
|
94
205
|
var elements = document.querySelectorAll(change.selector);
|
|
95
|
-
var
|
|
206
|
+
var appliedElements = [];
|
|
96
207
|
if (elements.length === 0) {
|
|
97
208
|
// Add to pending if waitForElement is explicitly true OR if SPA mode is enabled
|
|
98
|
-
var shouldWaitForElement = change.waitForElement || ((
|
|
209
|
+
var shouldWaitForElement = change.waitForElement || ((_g = this.plugin.config) === null || _g === void 0 ? void 0 : _g.spa);
|
|
99
210
|
if (shouldWaitForElement) {
|
|
100
211
|
if (this.debug) {
|
|
101
212
|
logDebug("[ABsmartly] Element not found, adding to pending: ".concat(change.selector));
|
|
@@ -117,45 +228,65 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
117
228
|
});
|
|
118
229
|
return false;
|
|
119
230
|
}
|
|
120
|
-
|
|
121
|
-
var
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
231
|
+
try {
|
|
232
|
+
for (var elements_1 = __values(elements), elements_1_1 = elements_1.next(); !elements_1_1.done; elements_1_1 = elements_1.next()) {
|
|
233
|
+
var element = elements_1_1.value;
|
|
234
|
+
if (this.debug && change.type === 'style') {
|
|
235
|
+
var oldStyles = {};
|
|
236
|
+
if (change.value && typeof change.value === 'object') {
|
|
237
|
+
try {
|
|
238
|
+
for (var _m = (e_2 = void 0, __values(Object.keys(change.value))), _o = _m.next(); !_o.done; _o = _m.next()) {
|
|
239
|
+
var prop = _o.value;
|
|
240
|
+
var cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
241
|
+
oldStyles[cssProp] = element.style.getPropertyValue(cssProp);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
245
|
+
finally {
|
|
246
|
+
try {
|
|
247
|
+
if (_o && !_o.done && (_b = _m.return)) _b.call(_m);
|
|
248
|
+
}
|
|
249
|
+
finally { if (e_2) throw e_2.error; }
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
logDebug("[DOM-BEFORE-APPLY] Element styles before change", {
|
|
253
|
+
experimentName: experimentName,
|
|
254
|
+
selector: change.selector,
|
|
255
|
+
element: element.tagName,
|
|
256
|
+
oldStyles: oldStyles,
|
|
257
|
+
newStyles: change.value,
|
|
128
258
|
});
|
|
129
259
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
260
|
+
this.applyChangeToElement(element, change);
|
|
261
|
+
if (this.debug && change.type === 'style') {
|
|
262
|
+
var appliedStyles = {};
|
|
263
|
+
if (change.value && typeof change.value === 'object') {
|
|
264
|
+
try {
|
|
265
|
+
for (var _p = (e_3 = void 0, __values(Object.keys(change.value))), _q = _p.next(); !_q.done; _q = _p.next()) {
|
|
266
|
+
var prop = _q.value;
|
|
267
|
+
var cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
268
|
+
appliedStyles[cssProp] = element.style.getPropertyValue(cssProp);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
272
|
+
finally {
|
|
273
|
+
try {
|
|
274
|
+
if (_q && !_q.done && (_c = _p.return)) _c.call(_p);
|
|
275
|
+
}
|
|
276
|
+
finally { if (e_3) throw e_3.error; }
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
logDebug("[DOM-AFTER-APPLY] Element styles after change", {
|
|
280
|
+
experimentName: experimentName,
|
|
281
|
+
selector: change.selector,
|
|
282
|
+
element: element.tagName,
|
|
283
|
+
appliedStyles: appliedStyles,
|
|
145
284
|
});
|
|
146
285
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
appliedStyles: appliedStyles_1,
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
if (change.type === 'javascript') {
|
|
155
|
-
if (change.value) {
|
|
156
|
-
var userVariant_1 = (_b = (_a = _this.plugin.config) === null || _a === void 0 ? void 0 : _a.context) === null || _b === void 0 ? void 0 : _b.peek(experimentName);
|
|
157
|
-
try {
|
|
158
|
-
if (_this.debug) {
|
|
286
|
+
if (change.type === 'javascript') {
|
|
287
|
+
if (change.value) {
|
|
288
|
+
var userVariant_1 = (_j = (_h = this.plugin.config) === null || _h === void 0 ? void 0 : _h.context) === null || _j === void 0 ? void 0 : _j.peek(experimentName);
|
|
289
|
+
if (this.debug) {
|
|
159
290
|
logDebug("[JAVASCRIPT] [".concat(experimentName, "] Executing JavaScript change"), {
|
|
160
291
|
experimentName: experimentName,
|
|
161
292
|
userVariant: userVariant_1,
|
|
@@ -165,93 +296,85 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
165
296
|
});
|
|
166
297
|
}
|
|
167
298
|
var codeString = String(change.value);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
experimentName: experimentName,
|
|
181
|
-
userVariant: userVariant_1,
|
|
182
|
-
selector: change.selector,
|
|
183
|
-
element: element.tagName,
|
|
184
|
-
code: codeString,
|
|
185
|
-
});
|
|
299
|
+
var executed = this.executeUserJavaScript(codeString, element, experimentName, change.selector);
|
|
300
|
+
if (executed) {
|
|
301
|
+
appliedElements.push(element);
|
|
302
|
+
if (this.debug) {
|
|
303
|
+
logDebug("[JAVASCRIPT] [".concat(experimentName, "] \u2713 JavaScript executed successfully"), {
|
|
304
|
+
experimentName: experimentName,
|
|
305
|
+
userVariant: userVariant_1,
|
|
306
|
+
selector: change.selector,
|
|
307
|
+
element: element.tagName,
|
|
308
|
+
code: codeString,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
186
311
|
}
|
|
187
312
|
}
|
|
188
|
-
|
|
189
|
-
logDebug("[JAVASCRIPT] [".concat(experimentName, "] \u2717 JavaScript
|
|
313
|
+
else {
|
|
314
|
+
logDebug("[JAVASCRIPT] [".concat(experimentName, "] \u2717 No JavaScript code provided in change.value"), {
|
|
190
315
|
experimentName: experimentName,
|
|
191
|
-
userVariant: userVariant_1,
|
|
192
316
|
selector: change.selector,
|
|
193
|
-
element: element.tagName,
|
|
194
|
-
code: String(change.value),
|
|
195
|
-
error: error instanceof Error ? error.message : String(error),
|
|
196
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
197
317
|
});
|
|
198
318
|
}
|
|
199
319
|
}
|
|
320
|
+
else if (change.type === 'move') {
|
|
321
|
+
var targetSelector = change.targetSelector ||
|
|
322
|
+
(change.value && typeof change.value === 'object'
|
|
323
|
+
? change.value.targetSelector
|
|
324
|
+
: null);
|
|
325
|
+
var position = change.position ||
|
|
326
|
+
(change.value && typeof change.value === 'object'
|
|
327
|
+
? change.value.position
|
|
328
|
+
: null);
|
|
329
|
+
if (targetSelector) {
|
|
330
|
+
var target = document.querySelector(targetSelector);
|
|
331
|
+
if (target) {
|
|
332
|
+
this.moveElement(element, target, position);
|
|
333
|
+
appliedElements.push(element);
|
|
334
|
+
}
|
|
335
|
+
else if (this.debug) {
|
|
336
|
+
logDebug("[ABsmartly] Move target not found: ".concat(targetSelector));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
200
340
|
else {
|
|
201
|
-
|
|
341
|
+
appliedElements.push(element);
|
|
342
|
+
}
|
|
343
|
+
// Watch element for persistence or SPA hydration recovery
|
|
344
|
+
var shouldWatch = (change.type === 'style' && change.persistStyle) ||
|
|
345
|
+
(change.type === 'attribute' && change.persistAttribute) ||
|
|
346
|
+
(change.type === 'javascript' && change.persistScript === true) ||
|
|
347
|
+
((_k = this.plugin.config) === null || _k === void 0 ? void 0 : _k.spa); // SPA mode watches ALL types for hydration recovery
|
|
348
|
+
if (shouldWatch) {
|
|
349
|
+
this.plugin.watchElement(element, experimentName, change);
|
|
350
|
+
}
|
|
351
|
+
else if (this.debug) {
|
|
352
|
+
logDebug("[WATCH-SKIP] NOT watching element - no persist flag and SPA disabled", {
|
|
202
353
|
experimentName: experimentName,
|
|
203
354
|
selector: change.selector,
|
|
355
|
+
element: element.tagName,
|
|
356
|
+
changeType: change.type,
|
|
357
|
+
spaMode: (_l = this.plugin.config) === null || _l === void 0 ? void 0 : _l.spa,
|
|
204
358
|
});
|
|
205
359
|
}
|
|
206
360
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
var position = change.position ||
|
|
213
|
-
(change.value && typeof change.value === 'object'
|
|
214
|
-
? change.value.position
|
|
215
|
-
: null);
|
|
216
|
-
if (targetSelector) {
|
|
217
|
-
var target = document.querySelector(targetSelector);
|
|
218
|
-
if (target) {
|
|
219
|
-
_this.moveElement(element, target, position);
|
|
220
|
-
appliedElements_1.push(element);
|
|
221
|
-
}
|
|
222
|
-
else if (_this.debug) {
|
|
223
|
-
logDebug("[ABsmartly] Move target not found: ".concat(targetSelector));
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
appliedElements_1.push(element);
|
|
229
|
-
}
|
|
230
|
-
// Watch element for React hydration recovery (ALL types) OR style persistence (styles only)
|
|
231
|
-
var shouldWatch = (change.type === 'style' && change.persistStyle) || // Explicit style persistence
|
|
232
|
-
((_c = _this.plugin.config) === null || _c === void 0 ? void 0 : _c.spa); // SPA mode watches ALL types for hydration recovery
|
|
233
|
-
if (shouldWatch) {
|
|
234
|
-
_this.plugin.watchElement(element, experimentName, change);
|
|
235
|
-
}
|
|
236
|
-
else if (change.type === 'style' && _this.debug) {
|
|
237
|
-
logDebug("[WATCH-SKIP] NOT watching element - persistStyle and SPA both disabled", {
|
|
238
|
-
experimentName: experimentName,
|
|
239
|
-
selector: change.selector,
|
|
240
|
-
element: element.tagName,
|
|
241
|
-
persistStyle: change.persistStyle,
|
|
242
|
-
spaMode: (_d = _this.plugin.config) === null || _d === void 0 ? void 0 : _d.spa,
|
|
243
|
-
});
|
|
361
|
+
}
|
|
362
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
363
|
+
finally {
|
|
364
|
+
try {
|
|
365
|
+
if (elements_1_1 && !elements_1_1.done && (_a = elements_1.return)) _a.call(elements_1);
|
|
244
366
|
}
|
|
245
|
-
|
|
246
|
-
|
|
367
|
+
finally { if (e_1) throw e_1.error; }
|
|
368
|
+
}
|
|
369
|
+
if (appliedElements.length > 0) {
|
|
247
370
|
this.trackAppliedChange(experimentName, change);
|
|
248
371
|
if (change.waitForElement) {
|
|
249
372
|
this.pendingManager.removePending(change.selector, experimentName, change.observerRoot);
|
|
250
373
|
}
|
|
251
374
|
// Throttle logs during style persistence reapplies (animations can trigger many times per second)
|
|
252
|
-
var isReapplying_1 =
|
|
375
|
+
var isReapplying_1 = appliedElements.some(function (el) { var _a; return (_a = _this.plugin.reapplyingElements) === null || _a === void 0 ? void 0 : _a.has(el); });
|
|
253
376
|
if (!isReapplying_1) {
|
|
254
|
-
logChangeApplication(experimentName, change.selector, change.type,
|
|
377
|
+
logChangeApplication(experimentName, change.selector, change.type, appliedElements.length, true);
|
|
255
378
|
}
|
|
256
379
|
return true;
|
|
257
380
|
}
|
|
@@ -300,7 +423,7 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
300
423
|
}
|
|
301
424
|
};
|
|
302
425
|
DOMManipulatorLite.prototype.createElement = function (change, _experimentName) {
|
|
303
|
-
var
|
|
426
|
+
var e_4, _a;
|
|
304
427
|
if (!change.element || !change.targetSelector) {
|
|
305
428
|
return null;
|
|
306
429
|
}
|
|
@@ -324,12 +447,12 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
324
447
|
this.moveElement(child, target, change.position);
|
|
325
448
|
}
|
|
326
449
|
}
|
|
327
|
-
catch (
|
|
450
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
328
451
|
finally {
|
|
329
452
|
try {
|
|
330
453
|
if (children_1_1 && !children_1_1.done && (_a = children_1.return)) _a.call(children_1);
|
|
331
454
|
}
|
|
332
|
-
finally { if (
|
|
455
|
+
finally { if (e_4) throw e_4.error; }
|
|
333
456
|
}
|
|
334
457
|
// Return the first element for compatibility
|
|
335
458
|
return children[0];
|
|
@@ -369,7 +492,7 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
369
492
|
}
|
|
370
493
|
};
|
|
371
494
|
DOMManipulatorLite.prototype.applyChangeToElement = function (element, change) {
|
|
372
|
-
var _a, _b;
|
|
495
|
+
var e_5, _a, _b, _c, e_6, _d;
|
|
373
496
|
switch (change.type) {
|
|
374
497
|
case 'text':
|
|
375
498
|
if (change.value !== undefined) {
|
|
@@ -383,33 +506,51 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
383
506
|
break;
|
|
384
507
|
case 'style':
|
|
385
508
|
if (change.value && typeof change.value === 'object') {
|
|
386
|
-
|
|
387
|
-
var
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
509
|
+
try {
|
|
510
|
+
for (var _e = __values(Object.entries(change.value)), _f = _e.next(); !_f.done; _f = _e.next()) {
|
|
511
|
+
var _g = __read(_f.value, 2), property = _g[0], value = _g[1];
|
|
512
|
+
var cssProperty = property.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
513
|
+
var priority = change.important === true ? 'important' : '';
|
|
514
|
+
element.style.setProperty(cssProperty, String(value), priority);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
518
|
+
finally {
|
|
519
|
+
try {
|
|
520
|
+
if (_f && !_f.done && (_a = _e.return)) _a.call(_e);
|
|
521
|
+
}
|
|
522
|
+
finally { if (e_5) throw e_5.error; }
|
|
523
|
+
}
|
|
392
524
|
}
|
|
393
525
|
break;
|
|
394
526
|
case 'class':
|
|
395
527
|
if (change.add && Array.isArray(change.add)) {
|
|
396
|
-
(
|
|
528
|
+
(_b = element.classList).add.apply(_b, __spreadArray([], __read(change.add), false));
|
|
397
529
|
}
|
|
398
530
|
if (change.remove && Array.isArray(change.remove)) {
|
|
399
|
-
(
|
|
531
|
+
(_c = element.classList).remove.apply(_c, __spreadArray([], __read(change.remove), false));
|
|
400
532
|
}
|
|
401
533
|
break;
|
|
402
534
|
case 'attribute':
|
|
403
535
|
if (change.value && typeof change.value === 'object') {
|
|
404
|
-
|
|
405
|
-
var
|
|
406
|
-
|
|
407
|
-
|
|
536
|
+
try {
|
|
537
|
+
for (var _h = __values(Object.entries(change.value)), _j = _h.next(); !_j.done; _j = _h.next()) {
|
|
538
|
+
var _k = __read(_j.value, 2), attr = _k[0], value = _k[1];
|
|
539
|
+
if (value === null || value === undefined) {
|
|
540
|
+
element.removeAttribute(attr);
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
element.setAttribute(attr, String(value));
|
|
544
|
+
}
|
|
408
545
|
}
|
|
409
|
-
|
|
410
|
-
|
|
546
|
+
}
|
|
547
|
+
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
548
|
+
finally {
|
|
549
|
+
try {
|
|
550
|
+
if (_j && !_j.done && (_d = _h.return)) _d.call(_h);
|
|
411
551
|
}
|
|
412
|
-
|
|
552
|
+
finally { if (e_6) throw e_6.error; }
|
|
553
|
+
}
|
|
413
554
|
}
|
|
414
555
|
break;
|
|
415
556
|
case 'move':
|
|
@@ -434,36 +575,25 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
434
575
|
try {
|
|
435
576
|
this.applyChangeToElement(element, change);
|
|
436
577
|
if (change.type === 'javascript' && change.value) {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
logDebug("[JAVASCRIPT] [".concat(experimentName, "] Executing JavaScript on specific element"), {
|
|
440
|
-
experimentName: experimentName,
|
|
441
|
-
selector: change.selector,
|
|
442
|
-
element: element.tagName,
|
|
443
|
-
code: String(change.value).substring(0, 100) + '...',
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
var fn = new Function('element', String(change.value));
|
|
447
|
-
fn(element);
|
|
448
|
-
if (this.debug) {
|
|
449
|
-
logDebug("[JAVASCRIPT] [".concat(experimentName, "] \u2713 JavaScript executed successfully"), {
|
|
450
|
-
experimentName: experimentName,
|
|
451
|
-
selector: change.selector,
|
|
452
|
-
element: element.tagName,
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
catch (error) {
|
|
457
|
-
logDebug("[JAVASCRIPT] [".concat(experimentName, "] \u2717 JavaScript execution error on specific element:"), {
|
|
578
|
+
if (this.debug) {
|
|
579
|
+
logDebug("[JAVASCRIPT] [".concat(experimentName, "] Executing JavaScript on specific element"), {
|
|
458
580
|
experimentName: experimentName,
|
|
459
581
|
selector: change.selector,
|
|
460
582
|
element: element.tagName,
|
|
461
|
-
code: String(change.value),
|
|
462
|
-
error: error instanceof Error ? error.message : String(error),
|
|
463
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
583
|
+
code: String(change.value).substring(0, 100) + '...',
|
|
464
584
|
});
|
|
585
|
+
}
|
|
586
|
+
var executed = this.executeUserJavaScript(String(change.value), element, experimentName, change.selector);
|
|
587
|
+
if (!executed) {
|
|
465
588
|
return false;
|
|
466
589
|
}
|
|
590
|
+
if (this.debug) {
|
|
591
|
+
logDebug("[JAVASCRIPT] [".concat(experimentName, "] \u2713 JavaScript executed successfully"), {
|
|
592
|
+
experimentName: experimentName,
|
|
593
|
+
selector: change.selector,
|
|
594
|
+
element: element.tagName,
|
|
595
|
+
});
|
|
596
|
+
}
|
|
467
597
|
}
|
|
468
598
|
else if (change.type === 'move') {
|
|
469
599
|
var targetSelector = change.targetSelector ||
|
|
@@ -484,8 +614,10 @@ var DOMManipulatorLite = /** @class */ (function () {
|
|
|
484
614
|
}
|
|
485
615
|
}
|
|
486
616
|
}
|
|
487
|
-
// Watch element for
|
|
488
|
-
var shouldWatch = (change.type === 'style' && change.persistStyle) ||
|
|
617
|
+
// Watch element for persistence or SPA hydration recovery
|
|
618
|
+
var shouldWatch = (change.type === 'style' && change.persistStyle) ||
|
|
619
|
+
(change.type === 'attribute' && change.persistAttribute) ||
|
|
620
|
+
(change.type === 'javascript' && change.persistScript === true) ||
|
|
489
621
|
((_a = this.plugin.config) === null || _a === void 0 ? void 0 : _a.spa); // SPA mode watches ALL types for hydration recovery
|
|
490
622
|
if (shouldWatch) {
|
|
491
623
|
this.plugin.watchElement(element, experimentName, change);
|