@absmartly/sdk-plugins 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1101 -0
- package/dist/absmartly-cookie.min.js +1 -0
- package/dist/absmartly-dom-changes-core.min.js +1 -0
- package/dist/absmartly-dom-changes-lite.min.js +1 -0
- package/dist/absmartly-overrides-full.min.js +1 -0
- package/dist/absmartly-overrides-lite.min.js +1 -0
- package/dist/absmartly-sdk-plugins.min.js +1 -0
- package/dist/absmartly-vitals.min.js +1 -0
- package/es/cookies/CookiePlugin.js +410 -0
- package/es/cookies/CookiePlugin.js.map +1 -0
- package/es/cookies/index.js +2 -0
- package/es/cookies/index.js.map +1 -0
- package/es/core/DOMChangesPluginLite.js +1124 -0
- package/es/core/DOMChangesPluginLite.js.map +1 -0
- package/es/core/DOMManipulatorLite.js +410 -0
- package/es/core/DOMManipulatorLite.js.map +1 -0
- package/es/core/ExposureTracker.js +501 -0
- package/es/core/ExposureTracker.js.map +1 -0
- package/es/core/HTMLInjector.js +333 -0
- package/es/core/HTMLInjector.js.map +1 -0
- package/es/core/PendingChangeManager.js +440 -0
- package/es/core/PendingChangeManager.js.map +1 -0
- package/es/core/StyleSheetManager.js +78 -0
- package/es/core/StyleSheetManager.js.map +1 -0
- package/es/entries/cookie-only.js +10 -0
- package/es/entries/cookie-only.js.map +1 -0
- package/es/entries/dom-only.js +13 -0
- package/es/entries/dom-only.js.map +1 -0
- package/es/entries/dom-with-overrides-full.js +19 -0
- package/es/entries/dom-with-overrides-full.js.map +1 -0
- package/es/entries/dom-with-overrides-lite.js +15 -0
- package/es/entries/dom-with-overrides-lite.js.map +1 -0
- package/es/entries/overrides-full-only.js +15 -0
- package/es/entries/overrides-full-only.js.map +1 -0
- package/es/entries/overrides-lite-only.js +12 -0
- package/es/entries/overrides-lite-only.js.map +1 -0
- package/es/entries/vitals-only.js +10 -0
- package/es/entries/vitals-only.js.map +1 -0
- package/es/index.js +17 -0
- package/es/index.js.map +1 -0
- package/es/overrides/BrowserCookieAdapter.js +76 -0
- package/es/overrides/BrowserCookieAdapter.js.map +1 -0
- package/es/overrides/OverridesPlugin.js +903 -0
- package/es/overrides/OverridesPlugin.js.map +1 -0
- package/es/overrides/OverridesPluginFull.js +32 -0
- package/es/overrides/OverridesPluginFull.js.map +1 -0
- package/es/overrides/OverridesPluginLite.js +352 -0
- package/es/overrides/OverridesPluginLite.js.map +1 -0
- package/es/overrides/index.js +4 -0
- package/es/overrides/index.js.map +1 -0
- package/es/overrides/types.js +2 -0
- package/es/overrides/types.js.map +1 -0
- package/es/parsers/VariantExtractor.js +570 -0
- package/es/parsers/VariantExtractor.js.map +1 -0
- package/es/types/index.js +2 -0
- package/es/types/index.js.map +1 -0
- package/es/utils/URLMatcher.js +114 -0
- package/es/utils/URLMatcher.js.map +1 -0
- package/es/utils/debug.js +184 -0
- package/es/utils/debug.js.map +1 -0
- package/es/vitals/WebVitalsPlugin.js +379 -0
- package/es/vitals/WebVitalsPlugin.js.map +1 -0
- package/es/vitals/index.js +2 -0
- package/es/vitals/index.js.map +1 -0
- package/lib/cookies/CookiePlugin.d.ts +55 -0
- package/lib/cookies/CookiePlugin.js +413 -0
- package/lib/cookies/CookiePlugin.js.map +1 -0
- package/lib/cookies/index.d.ts +2 -0
- package/lib/cookies/index.js +6 -0
- package/lib/cookies/index.js.map +1 -0
- package/lib/core/DOMChangesPluginLite.d.ts +89 -0
- package/lib/core/DOMChangesPluginLite.js +1127 -0
- package/lib/core/DOMChangesPluginLite.js.map +1 -0
- package/lib/core/DOMManipulatorLite.d.ts +21 -0
- package/lib/core/DOMManipulatorLite.js +413 -0
- package/lib/core/DOMManipulatorLite.js.map +1 -0
- package/lib/core/ExposureTracker.d.ts +81 -0
- package/lib/core/ExposureTracker.js +504 -0
- package/lib/core/ExposureTracker.js.map +1 -0
- package/lib/core/HTMLInjector.d.ts +19 -0
- package/lib/core/HTMLInjector.js +336 -0
- package/lib/core/HTMLInjector.js.map +1 -0
- package/lib/core/PendingChangeManager.d.ts +31 -0
- package/lib/core/PendingChangeManager.js +443 -0
- package/lib/core/PendingChangeManager.js.map +1 -0
- package/lib/core/StyleSheetManager.d.ts +16 -0
- package/lib/core/StyleSheetManager.js +81 -0
- package/lib/core/StyleSheetManager.js.map +1 -0
- package/lib/entries/cookie-only.d.ts +8 -0
- package/lib/entries/cookie-only.js +12 -0
- package/lib/entries/cookie-only.js.map +1 -0
- package/lib/entries/dom-only.d.ts +9 -0
- package/lib/entries/dom-only.js +29 -0
- package/lib/entries/dom-only.js.map +1 -0
- package/lib/entries/dom-with-overrides-full.d.ts +15 -0
- package/lib/entries/dom-with-overrides-full.js +39 -0
- package/lib/entries/dom-with-overrides-full.js.map +1 -0
- package/lib/entries/dom-with-overrides-lite.d.ts +11 -0
- package/lib/entries/dom-with-overrides-lite.js +32 -0
- package/lib/entries/dom-with-overrides-lite.js.map +1 -0
- package/lib/entries/overrides-full-only.d.ts +11 -0
- package/lib/entries/overrides-full-only.js +33 -0
- package/lib/entries/overrides-full-only.js.map +1 -0
- package/lib/entries/overrides-lite-only.d.ts +8 -0
- package/lib/entries/overrides-lite-only.js +28 -0
- package/lib/entries/overrides-lite-only.js.map +1 -0
- package/lib/entries/vitals-only.d.ts +8 -0
- package/lib/entries/vitals-only.js +12 -0
- package/lib/entries/vitals-only.js.map +1 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.js +34 -0
- package/lib/index.js.map +1 -0
- package/lib/overrides/BrowserCookieAdapter.d.ts +6 -0
- package/lib/overrides/BrowserCookieAdapter.js +79 -0
- package/lib/overrides/BrowserCookieAdapter.js.map +1 -0
- package/lib/overrides/OverridesPlugin.d.ts +33 -0
- package/lib/overrides/OverridesPlugin.js +906 -0
- package/lib/overrides/OverridesPlugin.js.map +1 -0
- package/lib/overrides/OverridesPluginFull.d.ts +9 -0
- package/lib/overrides/OverridesPluginFull.js +35 -0
- package/lib/overrides/OverridesPluginFull.js.map +1 -0
- package/lib/overrides/OverridesPluginLite.d.ts +27 -0
- package/lib/overrides/OverridesPluginLite.js +355 -0
- package/lib/overrides/OverridesPluginLite.js.map +1 -0
- package/lib/overrides/index.d.ts +3 -0
- package/lib/overrides/index.js +23 -0
- package/lib/overrides/index.js.map +1 -0
- package/lib/overrides/types.d.ts +43 -0
- package/lib/overrides/types.js +3 -0
- package/lib/overrides/types.js.map +1 -0
- package/lib/parsers/VariantExtractor.d.ts +49 -0
- package/lib/parsers/VariantExtractor.js +573 -0
- package/lib/parsers/VariantExtractor.js.map +1 -0
- package/lib/types/index.d.ts +177 -0
- package/lib/types/index.js +3 -0
- package/lib/types/index.js.map +1 -0
- package/lib/utils/URLMatcher.d.ts +20 -0
- package/lib/utils/URLMatcher.js +117 -0
- package/lib/utils/URLMatcher.js.map +1 -0
- package/lib/utils/debug.d.ts +41 -0
- package/lib/utils/debug.js +195 -0
- package/lib/utils/debug.js.map +1 -0
- package/lib/vitals/WebVitalsPlugin.d.ts +37 -0
- package/lib/vitals/WebVitalsPlugin.js +382 -0
- package/lib/vitals/WebVitalsPlugin.js.map +1 -0
- package/lib/vitals/index.d.ts +2 -0
- package/lib/vitals/index.js +6 -0
- package/lib/vitals/index.js.map +1 -0
- package/package.json +94 -0
- package/types/cookies/CookiePlugin.d.ts +55 -0
- package/types/cookies/index.d.ts +2 -0
- package/types/core/DOMChangesPluginLite.d.ts +89 -0
- package/types/core/DOMManipulatorLite.d.ts +21 -0
- package/types/core/ExposureTracker.d.ts +81 -0
- package/types/core/HTMLInjector.d.ts +19 -0
- package/types/core/PendingChangeManager.d.ts +31 -0
- package/types/core/StyleSheetManager.d.ts +16 -0
- package/types/entries/cookie-only.d.ts +8 -0
- package/types/entries/dom-only.d.ts +9 -0
- package/types/entries/dom-with-overrides-full.d.ts +15 -0
- package/types/entries/dom-with-overrides-lite.d.ts +11 -0
- package/types/entries/overrides-full-only.d.ts +11 -0
- package/types/entries/overrides-lite-only.d.ts +8 -0
- package/types/entries/vitals-only.d.ts +8 -0
- package/types/index.d.ts +13 -0
- package/types/overrides/BrowserCookieAdapter.d.ts +6 -0
- package/types/overrides/OverridesPlugin.d.ts +33 -0
- package/types/overrides/OverridesPluginFull.d.ts +9 -0
- package/types/overrides/OverridesPluginLite.d.ts +27 -0
- package/types/overrides/index.d.ts +3 -0
- package/types/overrides/types.d.ts +43 -0
- package/types/parsers/VariantExtractor.d.ts +49 -0
- package/types/types/index.d.ts +177 -0
- package/types/utils/URLMatcher.d.ts +20 -0
- package/types/utils/debug.d.ts +41 -0
- package/types/vitals/WebVitalsPlugin.d.ts +37 -0
- package/types/vitals/index.d.ts +2 -0
|
@@ -0,0 +1,1127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
24
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var __values = (this && this.__values) || function(o) {
|
|
50
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
51
|
+
if (m) return m.call(o);
|
|
52
|
+
if (o && typeof o.length === "number") return {
|
|
53
|
+
next: function () {
|
|
54
|
+
if (o && i >= o.length) o = void 0;
|
|
55
|
+
return { value: o && o[i++], done: !o };
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
59
|
+
};
|
|
60
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
61
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
62
|
+
if (!m) return o;
|
|
63
|
+
var i = m.call(o), r, ar = [], e;
|
|
64
|
+
try {
|
|
65
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
66
|
+
}
|
|
67
|
+
catch (error) { e = { error: error }; }
|
|
68
|
+
finally {
|
|
69
|
+
try {
|
|
70
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
71
|
+
}
|
|
72
|
+
finally { if (e) throw e.error; }
|
|
73
|
+
}
|
|
74
|
+
return ar;
|
|
75
|
+
};
|
|
76
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
77
|
+
exports.DOMChangesPluginLite = void 0;
|
|
78
|
+
var DOMManipulatorLite_1 = require("./DOMManipulatorLite");
|
|
79
|
+
var VariantExtractor_1 = require("../parsers/VariantExtractor");
|
|
80
|
+
var StyleSheetManager_1 = require("./StyleSheetManager");
|
|
81
|
+
var ExposureTracker_1 = require("./ExposureTracker");
|
|
82
|
+
var HTMLInjector_1 = require("./HTMLInjector");
|
|
83
|
+
var debug_1 = require("../utils/debug");
|
|
84
|
+
var URLMatcher_1 = require("../utils/URLMatcher");
|
|
85
|
+
var DOMChangesPluginLite = /** @class */ (function () {
|
|
86
|
+
function DOMChangesPluginLite(config) {
|
|
87
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
88
|
+
this.mutationObserver = null;
|
|
89
|
+
this.exposedExperiments = new Set();
|
|
90
|
+
this.eventListeners = new Map();
|
|
91
|
+
this.styleManagers = new Map();
|
|
92
|
+
this.initialized = false;
|
|
93
|
+
this.watchedElements = new WeakMap();
|
|
94
|
+
this.persistenceObserver = null;
|
|
95
|
+
this.reapplyingElements = new Set();
|
|
96
|
+
this.reapplyLogThrottle = new Map();
|
|
97
|
+
this.appliedStyleChanges = new Map();
|
|
98
|
+
this.antiFlickerTimeout = null;
|
|
99
|
+
this.antiFlickerStyleId = 'absmartly-antiflicker';
|
|
100
|
+
this.config = {
|
|
101
|
+
context: config.context,
|
|
102
|
+
autoApply: (_a = config.autoApply) !== null && _a !== void 0 ? _a : true,
|
|
103
|
+
spa: (_b = config.spa) !== null && _b !== void 0 ? _b : true,
|
|
104
|
+
visibilityTracking: (_c = config.visibilityTracking) !== null && _c !== void 0 ? _c : true,
|
|
105
|
+
extensionBridge: false, // Always false for lite version
|
|
106
|
+
dataSource: (_d = config.dataSource) !== null && _d !== void 0 ? _d : 'variable',
|
|
107
|
+
dataFieldName: (_e = config.dataFieldName) !== null && _e !== void 0 ? _e : '__dom_changes',
|
|
108
|
+
debug: (_f = config.debug) !== null && _f !== void 0 ? _f : false,
|
|
109
|
+
hideUntilReady: (_g = config.hideUntilReady) !== null && _g !== void 0 ? _g : false,
|
|
110
|
+
hideTimeout: (_h = config.hideTimeout) !== null && _h !== void 0 ? _h : 3000,
|
|
111
|
+
hideSelector: (_j = config.hideSelector) !== null && _j !== void 0 ? _j : '[data-absmartly-hide]',
|
|
112
|
+
hideTransition: (_k = config.hideTransition) !== null && _k !== void 0 ? _k : false,
|
|
113
|
+
};
|
|
114
|
+
if (!this.config.context) {
|
|
115
|
+
throw new Error('[ABsmartly] Context is required');
|
|
116
|
+
}
|
|
117
|
+
// Apply anti-flicker hiding immediately if enabled
|
|
118
|
+
if (this.config.hideUntilReady) {
|
|
119
|
+
this.hideContent();
|
|
120
|
+
}
|
|
121
|
+
this.domManipulator = new DOMManipulatorLite_1.DOMManipulatorLite(this.config.debug, this);
|
|
122
|
+
this.variantExtractor = new VariantExtractor_1.VariantExtractor(this.config.context, this.config.dataSource, this.config.dataFieldName, this.config.debug);
|
|
123
|
+
this.exposureTracker = new ExposureTracker_1.ExposureTracker(this.config.context, this.config.debug);
|
|
124
|
+
this.htmlInjector = new HTMLInjector_1.HTMLInjector(this.config.debug);
|
|
125
|
+
}
|
|
126
|
+
DOMChangesPluginLite.prototype.ready = function () {
|
|
127
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
128
|
+
var startTime, duration, error_1;
|
|
129
|
+
return __generator(this, function (_a) {
|
|
130
|
+
switch (_a.label) {
|
|
131
|
+
case 0:
|
|
132
|
+
if (this.initialized) {
|
|
133
|
+
(0, debug_1.logDebug)('Plugin already initialized');
|
|
134
|
+
return [2 /*return*/];
|
|
135
|
+
}
|
|
136
|
+
startTime = performance.now();
|
|
137
|
+
(0, debug_1.logDebug)('Initializing ABsmartly DOM Changes Plugin Lite', {
|
|
138
|
+
version: DOMChangesPluginLite.VERSION,
|
|
139
|
+
config: {
|
|
140
|
+
autoApply: this.config.autoApply,
|
|
141
|
+
spa: this.config.spa,
|
|
142
|
+
visibilityTracking: this.config.visibilityTracking,
|
|
143
|
+
dataSource: this.config.dataSource,
|
|
144
|
+
DEBUG: debug_1.DEBUG,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
_a.label = 1;
|
|
148
|
+
case 1:
|
|
149
|
+
_a.trys.push([1, 4, , 5]);
|
|
150
|
+
if (this.config.spa) {
|
|
151
|
+
this.setupMutationObserver();
|
|
152
|
+
this.setupURLChangeListener();
|
|
153
|
+
}
|
|
154
|
+
if (!this.config.autoApply) return [3 /*break*/, 3];
|
|
155
|
+
// Apply HTML injections and DOM changes in parallel to minimize flickering
|
|
156
|
+
return [4 /*yield*/, this.applyInjectionsAndChanges()];
|
|
157
|
+
case 2:
|
|
158
|
+
// Apply HTML injections and DOM changes in parallel to minimize flickering
|
|
159
|
+
_a.sent();
|
|
160
|
+
_a.label = 3;
|
|
161
|
+
case 3:
|
|
162
|
+
this.initialized = true;
|
|
163
|
+
this.registerWithContext();
|
|
164
|
+
this.emit('initialized');
|
|
165
|
+
duration = performance.now() - startTime;
|
|
166
|
+
(0, debug_1.logPerformance)('Plugin initialization', duration);
|
|
167
|
+
(0, debug_1.logDebug)("[ABsmartly] DOM plugin lite loaded successfully (v".concat(DOMChangesPluginLite.VERSION, ")"));
|
|
168
|
+
if (this.config.debug) {
|
|
169
|
+
(0, debug_1.logDebug)('[ABsmartly] DOM Changes Plugin Lite initialized with debug mode');
|
|
170
|
+
}
|
|
171
|
+
return [3 /*break*/, 5];
|
|
172
|
+
case 4:
|
|
173
|
+
error_1 = _a.sent();
|
|
174
|
+
(0, debug_1.logDebug)('[ABsmartly] Failed to initialize plugin:', error_1);
|
|
175
|
+
throw error_1;
|
|
176
|
+
case 5: return [2 /*return*/];
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
};
|
|
181
|
+
DOMChangesPluginLite.prototype.initialize = function () {
|
|
182
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
183
|
+
return __generator(this, function (_a) {
|
|
184
|
+
return [2 /*return*/, this.ready()];
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
DOMChangesPluginLite.prototype.setupMutationObserver = function () {
|
|
189
|
+
var observer = new MutationObserver(function () {
|
|
190
|
+
// Check for pending changes that might now be applicable
|
|
191
|
+
// Note: We don't have a centralized pending changes store in lite version,
|
|
192
|
+
// the PendingChangeManager handles this internally
|
|
193
|
+
});
|
|
194
|
+
observer.observe(document.body, {
|
|
195
|
+
childList: true,
|
|
196
|
+
subtree: true,
|
|
197
|
+
});
|
|
198
|
+
this.mutationObserver = observer;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Set up URL change listener for SPA mode
|
|
202
|
+
* Re-evaluates URL filters when URL changes and applies/removes changes accordingly
|
|
203
|
+
*/
|
|
204
|
+
DOMChangesPluginLite.prototype.setupURLChangeListener = function () {
|
|
205
|
+
var _this = this;
|
|
206
|
+
var handleURLChange = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
207
|
+
var newURL;
|
|
208
|
+
return __generator(this, function (_a) {
|
|
209
|
+
switch (_a.label) {
|
|
210
|
+
case 0:
|
|
211
|
+
newURL = window.location.href;
|
|
212
|
+
(0, debug_1.logDebug)('[ABsmartly] URL changed, re-evaluating experiments:', newURL);
|
|
213
|
+
// Remove all current changes
|
|
214
|
+
return [4 /*yield*/, this.removeAllChanges()];
|
|
215
|
+
case 1:
|
|
216
|
+
// Remove all current changes
|
|
217
|
+
_a.sent();
|
|
218
|
+
// Re-apply changes and injections with new URL (in parallel)
|
|
219
|
+
return [4 /*yield*/, this.applyInjectionsAndChanges()];
|
|
220
|
+
case 2:
|
|
221
|
+
// Re-apply changes and injections with new URL (in parallel)
|
|
222
|
+
_a.sent();
|
|
223
|
+
return [2 /*return*/];
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}); };
|
|
227
|
+
// Listen to popstate (back/forward navigation)
|
|
228
|
+
window.addEventListener('popstate', handleURLChange);
|
|
229
|
+
// Intercept pushState and replaceState
|
|
230
|
+
var originalPushState = history.pushState;
|
|
231
|
+
var originalReplaceState = history.replaceState;
|
|
232
|
+
history.pushState = function () {
|
|
233
|
+
var args = [];
|
|
234
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
235
|
+
args[_i] = arguments[_i];
|
|
236
|
+
}
|
|
237
|
+
originalPushState.apply(history, args);
|
|
238
|
+
handleURLChange();
|
|
239
|
+
};
|
|
240
|
+
history.replaceState = function () {
|
|
241
|
+
var args = [];
|
|
242
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
243
|
+
args[_i] = arguments[_i];
|
|
244
|
+
}
|
|
245
|
+
originalReplaceState.apply(history, args);
|
|
246
|
+
handleURLChange();
|
|
247
|
+
};
|
|
248
|
+
if (this.config.debug) {
|
|
249
|
+
(0, debug_1.logDebug)('[ABsmartly] URL change listener set up for SPA mode');
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Remove all currently applied changes
|
|
254
|
+
* Used when URL changes in SPA mode
|
|
255
|
+
*/
|
|
256
|
+
DOMChangesPluginLite.prototype.removeAllChanges = function () {
|
|
257
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
258
|
+
return __generator(this, function (_a) {
|
|
259
|
+
// Clear exposed experiments - ExposureTracker will re-register on next applyChanges
|
|
260
|
+
this.exposedExperiments.clear();
|
|
261
|
+
// Clear style managers - StyleSheetManager doesn't have a remove method
|
|
262
|
+
// The stylesheets will be reused or cleared on next applyChanges
|
|
263
|
+
this.styleManagers.clear();
|
|
264
|
+
// Clear applied style changes
|
|
265
|
+
this.appliedStyleChanges.clear();
|
|
266
|
+
// Clear HTML injections
|
|
267
|
+
this.htmlInjector.destroy();
|
|
268
|
+
// Clear variant extractor cache to force re-extraction
|
|
269
|
+
this.variantExtractor.clearCache();
|
|
270
|
+
if (this.config.debug) {
|
|
271
|
+
(0, debug_1.logDebug)('[ABsmartly] All change tracking cleared for URL change');
|
|
272
|
+
}
|
|
273
|
+
return [2 /*return*/];
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Apply HTML injections and DOM changes in parallel to minimize flickering
|
|
279
|
+
*/
|
|
280
|
+
DOMChangesPluginLite.prototype.applyInjectionsAndChanges = function () {
|
|
281
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
282
|
+
var startTime, currentURL, error_2, allInjectHTML, duration;
|
|
283
|
+
return __generator(this, function (_a) {
|
|
284
|
+
switch (_a.label) {
|
|
285
|
+
case 0:
|
|
286
|
+
startTime = performance.now();
|
|
287
|
+
currentURL = window.location.href;
|
|
288
|
+
_a.label = 1;
|
|
289
|
+
case 1:
|
|
290
|
+
_a.trys.push([1, 3, , 4]);
|
|
291
|
+
return [4 /*yield*/, this.config.context.ready()];
|
|
292
|
+
case 2:
|
|
293
|
+
_a.sent();
|
|
294
|
+
return [3 /*break*/, 4];
|
|
295
|
+
case 3:
|
|
296
|
+
error_2 = _a.sent();
|
|
297
|
+
(0, debug_1.logDebug)('[ABsmartly] Failed to wait for context ready:', error_2);
|
|
298
|
+
return [2 /*return*/];
|
|
299
|
+
case 4:
|
|
300
|
+
allInjectHTML = this.variantExtractor.extractAllInjectHTML();
|
|
301
|
+
// Apply injections and DOM changes in parallel for minimal flickering
|
|
302
|
+
return [4 /*yield*/, Promise.all([this.applyHTMLInjections(allInjectHTML, currentURL), this.applyChanges()])];
|
|
303
|
+
case 5:
|
|
304
|
+
// Apply injections and DOM changes in parallel for minimal flickering
|
|
305
|
+
_a.sent();
|
|
306
|
+
duration = performance.now() - startTime;
|
|
307
|
+
(0, debug_1.logPerformance)('Apply injections and changes (parallel)', duration);
|
|
308
|
+
if (this.config.debug) {
|
|
309
|
+
(0, debug_1.logDebug)('[ABsmartly] HTML injections and DOM changes applied in parallel', {
|
|
310
|
+
duration: "".concat(duration.toFixed(2), "ms"),
|
|
311
|
+
currentURL: currentURL,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
return [2 /*return*/];
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Apply HTML injections from all variants
|
|
321
|
+
*/
|
|
322
|
+
DOMChangesPluginLite.prototype.applyHTMLInjections = function (allInjectHTML_1) {
|
|
323
|
+
return __awaiter(this, arguments, void 0, function (allInjectHTML, currentUrl) {
|
|
324
|
+
var injectionsByLocation;
|
|
325
|
+
if (currentUrl === void 0) { currentUrl = window.location.href; }
|
|
326
|
+
return __generator(this, function (_a) {
|
|
327
|
+
if (allInjectHTML.size === 0) {
|
|
328
|
+
if (this.config.debug) {
|
|
329
|
+
(0, debug_1.logDebug)('[ABsmartly] No HTML injections found');
|
|
330
|
+
}
|
|
331
|
+
return [2 /*return*/];
|
|
332
|
+
}
|
|
333
|
+
injectionsByLocation = this.htmlInjector.collectInjections(allInjectHTML, currentUrl);
|
|
334
|
+
this.htmlInjector.inject(injectionsByLocation);
|
|
335
|
+
if (this.config.debug) {
|
|
336
|
+
(0, debug_1.logDebug)('[ABsmartly] HTML injections complete', {
|
|
337
|
+
experimentsWithInjections: allInjectHTML.size,
|
|
338
|
+
totalLocations: injectionsByLocation.size,
|
|
339
|
+
currentUrl: currentUrl,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
return [2 /*return*/];
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
};
|
|
346
|
+
DOMChangesPluginLite.prototype.applyChanges = function (experimentName) {
|
|
347
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
348
|
+
var startTime, currentURL, error_3, allExperiments, totalApplied, experimentStats, allExperiments_1, allExperiments_1_1, _a, expName, experimentData, currentVariant, variantData, urlFilter, globalDefaults, anyVariantMatchesURL, shouldApplyVisualChanges, changes, allVariantChanges, hasAnyChangesInAnyVariant, stats, hasImmediateTrigger, hasViewportTrigger, changes_1, changes_1_1, change, success, elements, changes_2, changes_2_1, change, hasAnyViewportTriggerInAnyVariant, hasAnyImmediateTriggerInAnyVariant, allVariantChanges_1, allVariantChanges_1_1, variantChanges, variantChanges_1, variantChanges_1_1, change, duration;
|
|
349
|
+
var e_1, _b, e_2, _c, e_3, _d, e_4, _e, e_5, _f;
|
|
350
|
+
return __generator(this, function (_g) {
|
|
351
|
+
switch (_g.label) {
|
|
352
|
+
case 0:
|
|
353
|
+
startTime = performance.now();
|
|
354
|
+
currentURL = window.location.href;
|
|
355
|
+
(0, debug_1.logDebug)('Starting to apply changes', {
|
|
356
|
+
specificExperiment: experimentName || 'all',
|
|
357
|
+
url: currentURL,
|
|
358
|
+
action: 'apply_start',
|
|
359
|
+
});
|
|
360
|
+
if (this.config.debug) {
|
|
361
|
+
(0, debug_1.logDebug)('[ABsmartly] === DOM Changes Application Starting ===');
|
|
362
|
+
(0, debug_1.logDebug)('[ABsmartly] Target:', experimentName || 'all experiments');
|
|
363
|
+
(0, debug_1.logDebug)('[ABsmartly] Current URL:', currentURL);
|
|
364
|
+
(0, debug_1.logDebug)('[ABsmartly] Context ready:', true);
|
|
365
|
+
}
|
|
366
|
+
_g.label = 1;
|
|
367
|
+
case 1:
|
|
368
|
+
_g.trys.push([1, 3, , 4]);
|
|
369
|
+
return [4 /*yield*/, this.config.context.ready()];
|
|
370
|
+
case 2:
|
|
371
|
+
_g.sent();
|
|
372
|
+
return [3 /*break*/, 4];
|
|
373
|
+
case 3:
|
|
374
|
+
error_3 = _g.sent();
|
|
375
|
+
(0, debug_1.logDebug)('[ABsmartly] Failed to wait for context ready:', error_3);
|
|
376
|
+
return [2 /*return*/];
|
|
377
|
+
case 4:
|
|
378
|
+
this.variantExtractor.clearCache();
|
|
379
|
+
allExperiments = this.getAllExperimentsData();
|
|
380
|
+
totalApplied = 0;
|
|
381
|
+
experimentStats = new Map();
|
|
382
|
+
(0, debug_1.logDebug)('[ABsmartly] Experiments to process:', Array.from(allExperiments.keys()));
|
|
383
|
+
(0, debug_1.logDebug)('[ABsmartly] Total experiments with changes:', allExperiments.size);
|
|
384
|
+
try {
|
|
385
|
+
for (allExperiments_1 = __values(allExperiments), allExperiments_1_1 = allExperiments_1.next(); !allExperiments_1_1.done; allExperiments_1_1 = allExperiments_1.next()) {
|
|
386
|
+
_a = __read(allExperiments_1_1.value, 2), expName = _a[0], experimentData = _a[1];
|
|
387
|
+
// Skip if filtering by specific experiment
|
|
388
|
+
if (experimentName && expName !== experimentName) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
currentVariant = this.config.context.peek(expName);
|
|
392
|
+
variantData = experimentData.variantData, urlFilter = experimentData.urlFilter, globalDefaults = experimentData.globalDefaults;
|
|
393
|
+
anyVariantMatchesURL = this.variantExtractor.anyVariantMatchesURL(expName, currentURL);
|
|
394
|
+
if (!anyVariantMatchesURL) {
|
|
395
|
+
(0, debug_1.logDebug)("[ABsmartly] Skipping experiment '".concat(expName, "' - no variant matches URL: ").concat(currentURL));
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
shouldApplyVisualChanges = this.shouldApplyVisualChanges(variantData, urlFilter, currentURL);
|
|
399
|
+
changes = this.extractChangesFromData(variantData, globalDefaults);
|
|
400
|
+
allVariantChanges = this.extractAllVariantChanges(expName);
|
|
401
|
+
hasAnyChangesInAnyVariant = allVariantChanges.some(function (variantChanges) { return variantChanges && variantChanges.length > 0; });
|
|
402
|
+
if (!hasAnyChangesInAnyVariant) {
|
|
403
|
+
// If NO variant has ANY changes, skip the entire experiment
|
|
404
|
+
if (this.config.debug) {
|
|
405
|
+
(0, debug_1.logDebug)("[ABsmartly] Skipping experiment '".concat(expName, "' - no variants have changes"));
|
|
406
|
+
}
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
stats = { total: (changes === null || changes === void 0 ? void 0 : changes.length) || 0, success: 0, pending: 0 };
|
|
410
|
+
if (this.config.debug) {
|
|
411
|
+
(0, debug_1.logDebug)("[ABsmartly] Processing experiment '".concat(expName, "' (variant ").concat(currentVariant, "):"), {
|
|
412
|
+
urlMatches: shouldApplyVisualChanges,
|
|
413
|
+
changeCount: (changes === null || changes === void 0 ? void 0 : changes.length) || 0,
|
|
414
|
+
userVariantHasChanges: ((changes === null || changes === void 0 ? void 0 : changes.length) || 0) > 0,
|
|
415
|
+
changes: (changes === null || changes === void 0 ? void 0 : changes.map(function (c) { return ({
|
|
416
|
+
type: c.type,
|
|
417
|
+
selector: c.selector,
|
|
418
|
+
trigger: c.trigger_on_view ? 'viewport' : 'immediate',
|
|
419
|
+
}); })) || [],
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
hasImmediateTrigger = false;
|
|
423
|
+
hasViewportTrigger = false;
|
|
424
|
+
// Apply visual changes only if URL matches for user's variant AND user has changes
|
|
425
|
+
if (shouldApplyVisualChanges && changes && changes.length > 0) {
|
|
426
|
+
try {
|
|
427
|
+
for (changes_1 = (e_2 = void 0, __values(changes)), changes_1_1 = changes_1.next(); !changes_1_1.done; changes_1_1 = changes_1.next()) {
|
|
428
|
+
change = changes_1_1.value;
|
|
429
|
+
success = this.domManipulator.applyChange(change, expName);
|
|
430
|
+
if (success) {
|
|
431
|
+
totalApplied++;
|
|
432
|
+
stats.success++;
|
|
433
|
+
if (change.trigger_on_view) {
|
|
434
|
+
hasViewportTrigger = true;
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
hasImmediateTrigger = true;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
else if (change.type !== 'create' && change.type !== 'styleRules') {
|
|
441
|
+
// Track pending changes for stats
|
|
442
|
+
try {
|
|
443
|
+
elements = document.querySelectorAll(change.selector);
|
|
444
|
+
if (elements.length === 0 && (this.config.spa || change.waitForElement)) {
|
|
445
|
+
stats.pending++;
|
|
446
|
+
if (change.trigger_on_view) {
|
|
447
|
+
hasViewportTrigger = true;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
if (this.config.debug) {
|
|
453
|
+
(0, debug_1.logDebug)("[ABsmartly] Invalid selector: ".concat(change.selector), error);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
460
|
+
finally {
|
|
461
|
+
try {
|
|
462
|
+
if (changes_1_1 && !changes_1_1.done && (_c = changes_1.return)) _c.call(changes_1);
|
|
463
|
+
}
|
|
464
|
+
finally { if (e_2) throw e_2.error; }
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
else if (changes && changes.length > 0) {
|
|
468
|
+
try {
|
|
469
|
+
// URL doesn't match for user's variant OR user has no changes
|
|
470
|
+
// Check if user's changes have viewport trigger (if they exist)
|
|
471
|
+
// We still need to set up tracking for SRM prevention
|
|
472
|
+
for (changes_2 = (e_3 = void 0, __values(changes)), changes_2_1 = changes_2.next(); !changes_2_1.done; changes_2_1 = changes_2.next()) {
|
|
473
|
+
change = changes_2_1.value;
|
|
474
|
+
if (change.trigger_on_view) {
|
|
475
|
+
hasViewportTrigger = true;
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
hasImmediateTrigger = true;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
483
|
+
finally {
|
|
484
|
+
try {
|
|
485
|
+
if (changes_2_1 && !changes_2_1.done && (_d = changes_2.return)) _d.call(changes_2);
|
|
486
|
+
}
|
|
487
|
+
finally { if (e_3) throw e_3.error; }
|
|
488
|
+
}
|
|
489
|
+
(0, debug_1.logDebug)("[ABsmartly] Experiment '".concat(expName, "' variant ").concat(currentVariant, " doesn't match URL filter or has no changes, but setting up tracking for SRM prevention"));
|
|
490
|
+
}
|
|
491
|
+
hasAnyViewportTriggerInAnyVariant = hasViewportTrigger;
|
|
492
|
+
hasAnyImmediateTriggerInAnyVariant = hasImmediateTrigger;
|
|
493
|
+
if (!hasViewportTrigger || !hasImmediateTrigger) {
|
|
494
|
+
try {
|
|
495
|
+
for (allVariantChanges_1 = (e_4 = void 0, __values(allVariantChanges)), allVariantChanges_1_1 = allVariantChanges_1.next(); !allVariantChanges_1_1.done; allVariantChanges_1_1 = allVariantChanges_1.next()) {
|
|
496
|
+
variantChanges = allVariantChanges_1_1.value;
|
|
497
|
+
if (variantChanges && variantChanges.length > 0) {
|
|
498
|
+
try {
|
|
499
|
+
for (variantChanges_1 = (e_5 = void 0, __values(variantChanges)), variantChanges_1_1 = variantChanges_1.next(); !variantChanges_1_1.done; variantChanges_1_1 = variantChanges_1.next()) {
|
|
500
|
+
change = variantChanges_1_1.value;
|
|
501
|
+
if (change.trigger_on_view) {
|
|
502
|
+
hasAnyViewportTriggerInAnyVariant = true;
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
hasAnyImmediateTriggerInAnyVariant = true;
|
|
506
|
+
}
|
|
507
|
+
// Early exit if we found both types
|
|
508
|
+
if (hasAnyViewportTriggerInAnyVariant && hasAnyImmediateTriggerInAnyVariant) {
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
514
|
+
finally {
|
|
515
|
+
try {
|
|
516
|
+
if (variantChanges_1_1 && !variantChanges_1_1.done && (_f = variantChanges_1.return)) _f.call(variantChanges_1);
|
|
517
|
+
}
|
|
518
|
+
finally { if (e_5) throw e_5.error; }
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (hasAnyViewportTriggerInAnyVariant && hasAnyImmediateTriggerInAnyVariant) {
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
527
|
+
finally {
|
|
528
|
+
try {
|
|
529
|
+
if (allVariantChanges_1_1 && !allVariantChanges_1_1.done && (_e = allVariantChanges_1.return)) _e.call(allVariantChanges_1);
|
|
530
|
+
}
|
|
531
|
+
finally { if (e_4) throw e_4.error; }
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
// CRITICAL: Always register experiment for tracking if ANY variant has ANY trigger type
|
|
535
|
+
// This prevents SRM even when user's variant doesn't match URL filter
|
|
536
|
+
if (hasAnyViewportTriggerInAnyVariant || hasAnyImmediateTriggerInAnyVariant) {
|
|
537
|
+
this.exposureTracker.registerExperiment(expName, currentVariant || 0, changes || [], allVariantChanges);
|
|
538
|
+
}
|
|
539
|
+
// Note: We do NOT call treatment() here anymore to avoid duplicate calls.
|
|
540
|
+
// The ExposureTracker.registerExperiment() will call triggerExposure() internally
|
|
541
|
+
// when hasImmediateTrigger is true (see ExposureTracker line 169-174).
|
|
542
|
+
// This prevents double treatment() calls that were causing test failures.
|
|
543
|
+
experimentStats.set(expName, stats);
|
|
544
|
+
(0, debug_1.logExperimentSummary)(expName, stats.total, stats.success, stats.pending);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
548
|
+
finally {
|
|
549
|
+
try {
|
|
550
|
+
if (allExperiments_1_1 && !allExperiments_1_1.done && (_b = allExperiments_1.return)) _b.call(allExperiments_1);
|
|
551
|
+
}
|
|
552
|
+
finally { if (e_1) throw e_1.error; }
|
|
553
|
+
}
|
|
554
|
+
duration = performance.now() - startTime;
|
|
555
|
+
(0, debug_1.logPerformance)('Apply changes', duration, {
|
|
556
|
+
totalApplied: totalApplied,
|
|
557
|
+
experiments: experimentStats.size,
|
|
558
|
+
});
|
|
559
|
+
if (this.config.debug) {
|
|
560
|
+
(0, debug_1.logDebug)('[ABsmartly] === DOM Changes Application Complete ===');
|
|
561
|
+
(0, debug_1.logDebug)('[ABsmartly] Summary:', {
|
|
562
|
+
totalChangesApplied: totalApplied,
|
|
563
|
+
experimentsProcessed: experimentStats.size,
|
|
564
|
+
duration: "".concat(duration.toFixed(2), "ms"),
|
|
565
|
+
experiments: Array.from(experimentStats.entries()).map(function (_a) {
|
|
566
|
+
var _b = __read(_a, 2), name = _b[0], stats = _b[1];
|
|
567
|
+
return ({
|
|
568
|
+
name: name,
|
|
569
|
+
total: stats.total,
|
|
570
|
+
success: stats.success,
|
|
571
|
+
pending: stats.pending,
|
|
572
|
+
pendingReason: stats.pending > 0 ? 'Elements not found yet (SPA mode will retry)' : undefined,
|
|
573
|
+
});
|
|
574
|
+
}),
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
// Show hidden content after changes are applied
|
|
578
|
+
if (this.config.hideUntilReady) {
|
|
579
|
+
this.showContent();
|
|
580
|
+
}
|
|
581
|
+
this.emit('changes-applied', { count: totalApplied, experimentName: experimentName });
|
|
582
|
+
return [2 /*return*/];
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
};
|
|
587
|
+
/**
|
|
588
|
+
* Get all experiments with their variant data and metadata
|
|
589
|
+
*/
|
|
590
|
+
DOMChangesPluginLite.prototype.getAllExperimentsData = function () {
|
|
591
|
+
var e_6, _a;
|
|
592
|
+
var experiments = new Map();
|
|
593
|
+
var allVariants = this.variantExtractor.extractAllChanges();
|
|
594
|
+
try {
|
|
595
|
+
for (var allVariants_1 = __values(allVariants), allVariants_1_1 = allVariants_1.next(); !allVariants_1_1.done; allVariants_1_1 = allVariants_1.next()) {
|
|
596
|
+
var _b = __read(allVariants_1_1.value, 1), expName = _b[0];
|
|
597
|
+
var currentVariant = this.config.context.peek(expName);
|
|
598
|
+
if (currentVariant === undefined || currentVariant === null) {
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
var variantsData = this.variantExtractor.getAllVariantsData(expName);
|
|
602
|
+
var variantData = variantsData.get(currentVariant);
|
|
603
|
+
if (!variantData) {
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
// Extract URL filter and global defaults if using wrapped format
|
|
607
|
+
var urlFilter = null;
|
|
608
|
+
var globalDefaults = {};
|
|
609
|
+
if (variantData &&
|
|
610
|
+
typeof variantData === 'object' &&
|
|
611
|
+
!Array.isArray(variantData) &&
|
|
612
|
+
'changes' in variantData) {
|
|
613
|
+
var config = variantData;
|
|
614
|
+
urlFilter = config.urlFilter;
|
|
615
|
+
globalDefaults = {
|
|
616
|
+
waitForElement: config.waitForElement,
|
|
617
|
+
persistStyle: config.persistStyle,
|
|
618
|
+
important: config.important,
|
|
619
|
+
observerRoot: config.observerRoot,
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
experiments.set(expName, { variantData: variantData, urlFilter: urlFilter, globalDefaults: globalDefaults });
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
626
|
+
finally {
|
|
627
|
+
try {
|
|
628
|
+
if (allVariants_1_1 && !allVariants_1_1.done && (_a = allVariants_1.return)) _a.call(allVariants_1);
|
|
629
|
+
}
|
|
630
|
+
finally { if (e_6) throw e_6.error; }
|
|
631
|
+
}
|
|
632
|
+
return experiments;
|
|
633
|
+
};
|
|
634
|
+
/**
|
|
635
|
+
* Extract changes from DOMChangesData and apply global defaults
|
|
636
|
+
*/
|
|
637
|
+
DOMChangesPluginLite.prototype.extractChangesFromData = function (data, globalDefaults) {
|
|
638
|
+
var changes = null;
|
|
639
|
+
// Extract changes array
|
|
640
|
+
if (Array.isArray(data)) {
|
|
641
|
+
changes = data;
|
|
642
|
+
}
|
|
643
|
+
else if (data && typeof data === 'object' && 'changes' in data) {
|
|
644
|
+
changes = data.changes;
|
|
645
|
+
}
|
|
646
|
+
if (!changes || changes.length === 0) {
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
// Apply global defaults to each change
|
|
650
|
+
return changes.map(function (change) {
|
|
651
|
+
var _a, _b, _c, _d;
|
|
652
|
+
return (__assign(__assign({}, change), { waitForElement: (_a = change.waitForElement) !== null && _a !== void 0 ? _a : globalDefaults.waitForElement, persistStyle: (_b = change.persistStyle) !== null && _b !== void 0 ? _b : globalDefaults.persistStyle, important: (_c = change.important) !== null && _c !== void 0 ? _c : globalDefaults.important, observerRoot: (_d = change.observerRoot) !== null && _d !== void 0 ? _d : globalDefaults.observerRoot }));
|
|
653
|
+
});
|
|
654
|
+
};
|
|
655
|
+
/**
|
|
656
|
+
* Extract all variant changes for cross-variant tracking
|
|
657
|
+
*/
|
|
658
|
+
DOMChangesPluginLite.prototype.extractAllVariantChanges = function (experimentName) {
|
|
659
|
+
var allVariantChanges = this.variantExtractor.getAllVariantChanges(experimentName);
|
|
660
|
+
var variantsData = this.variantExtractor.getAllVariantsData(experimentName);
|
|
661
|
+
// Apply global defaults to each variant's changes
|
|
662
|
+
var processedVariants = [];
|
|
663
|
+
var _loop_1 = function (i) {
|
|
664
|
+
var variantChanges = allVariantChanges[i];
|
|
665
|
+
var variantData = variantsData.get(i);
|
|
666
|
+
if (!variantChanges || variantChanges.length === 0) {
|
|
667
|
+
processedVariants.push([]);
|
|
668
|
+
return "continue";
|
|
669
|
+
}
|
|
670
|
+
// Extract global defaults if using wrapped format
|
|
671
|
+
var globalDefaults = {};
|
|
672
|
+
if (variantData &&
|
|
673
|
+
typeof variantData === 'object' &&
|
|
674
|
+
!Array.isArray(variantData) &&
|
|
675
|
+
'changes' in variantData) {
|
|
676
|
+
var config = variantData;
|
|
677
|
+
globalDefaults = {
|
|
678
|
+
waitForElement: config.waitForElement,
|
|
679
|
+
persistStyle: config.persistStyle,
|
|
680
|
+
important: config.important,
|
|
681
|
+
observerRoot: config.observerRoot,
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
// Apply global defaults
|
|
685
|
+
var processedChanges = variantChanges.map(function (change) {
|
|
686
|
+
var _a, _b, _c, _d;
|
|
687
|
+
return (__assign(__assign({}, change), { waitForElement: (_a = change.waitForElement) !== null && _a !== void 0 ? _a : globalDefaults.waitForElement, persistStyle: (_b = change.persistStyle) !== null && _b !== void 0 ? _b : globalDefaults.persistStyle, important: (_c = change.important) !== null && _c !== void 0 ? _c : globalDefaults.important, observerRoot: (_d = change.observerRoot) !== null && _d !== void 0 ? _d : globalDefaults.observerRoot }));
|
|
688
|
+
});
|
|
689
|
+
processedVariants.push(processedChanges);
|
|
690
|
+
};
|
|
691
|
+
for (var i = 0; i < allVariantChanges.length; i++) {
|
|
692
|
+
_loop_1(i);
|
|
693
|
+
}
|
|
694
|
+
return processedVariants;
|
|
695
|
+
};
|
|
696
|
+
/**
|
|
697
|
+
* Determine if visual changes should be applied based on URL filter
|
|
698
|
+
*/
|
|
699
|
+
DOMChangesPluginLite.prototype.shouldApplyVisualChanges = function (variantData, urlFilter, url) {
|
|
700
|
+
// Legacy array format has no URL filter - always apply
|
|
701
|
+
if (Array.isArray(variantData)) {
|
|
702
|
+
return true;
|
|
703
|
+
}
|
|
704
|
+
// Wrapped format without URL filter - always apply
|
|
705
|
+
if (!urlFilter) {
|
|
706
|
+
return true;
|
|
707
|
+
}
|
|
708
|
+
// Check URL filter
|
|
709
|
+
return URLMatcher_1.URLMatcher.matches(urlFilter, url);
|
|
710
|
+
};
|
|
711
|
+
DOMChangesPluginLite.prototype.hasChanges = function (experimentName) {
|
|
712
|
+
return this.domManipulator.hasChanges(experimentName);
|
|
713
|
+
};
|
|
714
|
+
DOMChangesPluginLite.prototype.applyChange = function (change, experimentName) {
|
|
715
|
+
(0, debug_1.logDebug)('Applying single change via public API', {
|
|
716
|
+
experimentName: experimentName,
|
|
717
|
+
selector: change.selector,
|
|
718
|
+
changeType: change.type,
|
|
719
|
+
});
|
|
720
|
+
try {
|
|
721
|
+
var success = this.domManipulator.applyChange(change, experimentName);
|
|
722
|
+
if (success) {
|
|
723
|
+
this.emit('change_applied', {
|
|
724
|
+
experimentName: experimentName,
|
|
725
|
+
change: change,
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
return success;
|
|
729
|
+
}
|
|
730
|
+
catch (error) {
|
|
731
|
+
if (this.config.debug) {
|
|
732
|
+
(0, debug_1.logDebug)('[ABsmartly] Error applying change:', error);
|
|
733
|
+
}
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
DOMChangesPluginLite.prototype.on = function (event, callback) {
|
|
738
|
+
var listeners = this.eventListeners.get(event) || [];
|
|
739
|
+
listeners.push(callback);
|
|
740
|
+
this.eventListeners.set(event, listeners);
|
|
741
|
+
};
|
|
742
|
+
DOMChangesPluginLite.prototype.off = function (event, callback) {
|
|
743
|
+
if (!callback) {
|
|
744
|
+
this.eventListeners.delete(event);
|
|
745
|
+
}
|
|
746
|
+
else {
|
|
747
|
+
var listeners = this.eventListeners.get(event) || [];
|
|
748
|
+
var index = listeners.indexOf(callback);
|
|
749
|
+
if (index !== -1) {
|
|
750
|
+
listeners.splice(index, 1);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
DOMChangesPluginLite.prototype.emit = function (event, data) {
|
|
755
|
+
var e_7, _a;
|
|
756
|
+
var listeners = this.eventListeners.get(event) || [];
|
|
757
|
+
try {
|
|
758
|
+
for (var listeners_1 = __values(listeners), listeners_1_1 = listeners_1.next(); !listeners_1_1.done; listeners_1_1 = listeners_1.next()) {
|
|
759
|
+
var callback = listeners_1_1.value;
|
|
760
|
+
try {
|
|
761
|
+
callback(data);
|
|
762
|
+
}
|
|
763
|
+
catch (error) {
|
|
764
|
+
(0, debug_1.logDebug)("[ABsmartly] Error in event listener for ".concat(event, ":"), error);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
|
769
|
+
finally {
|
|
770
|
+
try {
|
|
771
|
+
if (listeners_1_1 && !listeners_1_1.done && (_a = listeners_1.return)) _a.call(listeners_1);
|
|
772
|
+
}
|
|
773
|
+
finally { if (e_7) throw e_7.error; }
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
DOMChangesPluginLite.prototype.getStyleManager = function (experimentName) {
|
|
777
|
+
var id = "absmartly-styles-".concat(experimentName);
|
|
778
|
+
var manager = this.styleManagers.get(experimentName);
|
|
779
|
+
if (!manager) {
|
|
780
|
+
manager = new StyleSheetManager_1.StyleSheetManager(id, this.config.debug);
|
|
781
|
+
this.styleManagers.set(experimentName, manager);
|
|
782
|
+
}
|
|
783
|
+
return manager;
|
|
784
|
+
};
|
|
785
|
+
DOMChangesPluginLite.prototype.buildCssRule = function (selector, properties, important) {
|
|
786
|
+
if (important === void 0) { important = true; }
|
|
787
|
+
var declarations = Object.entries(properties)
|
|
788
|
+
.map(function (_a) {
|
|
789
|
+
var _b = __read(_a, 2), prop = _b[0], value = _b[1];
|
|
790
|
+
var cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
791
|
+
var bang = important ? ' !important' : '';
|
|
792
|
+
return " ".concat(cssProp, ": ").concat(value).concat(bang, ";");
|
|
793
|
+
})
|
|
794
|
+
.join('\n');
|
|
795
|
+
return "".concat(selector, " {\n").concat(declarations, "\n}");
|
|
796
|
+
};
|
|
797
|
+
DOMChangesPluginLite.prototype.buildStateRules = function (selector, states, important) {
|
|
798
|
+
if (important === void 0) { important = true; }
|
|
799
|
+
var rules = [];
|
|
800
|
+
if (states.normal) {
|
|
801
|
+
rules.push(this.buildCssRule(selector, states.normal, important));
|
|
802
|
+
}
|
|
803
|
+
if (states.hover) {
|
|
804
|
+
rules.push(this.buildCssRule("".concat(selector, ":hover"), states.hover, important));
|
|
805
|
+
}
|
|
806
|
+
if (states.active) {
|
|
807
|
+
rules.push(this.buildCssRule("".concat(selector, ":active"), states.active, important));
|
|
808
|
+
}
|
|
809
|
+
if (states.focus) {
|
|
810
|
+
rules.push(this.buildCssRule("".concat(selector, ":focus"), states.focus, important));
|
|
811
|
+
}
|
|
812
|
+
return rules.join('\n\n');
|
|
813
|
+
};
|
|
814
|
+
DOMChangesPluginLite.prototype.refreshExperiments = function () {
|
|
815
|
+
if (this.config.debug) {
|
|
816
|
+
(0, debug_1.logDebug)('[ABsmartly] Refreshing experiments and clearing cache');
|
|
817
|
+
}
|
|
818
|
+
this.variantExtractor.clearCache();
|
|
819
|
+
if (this.config.autoApply) {
|
|
820
|
+
this.applyInjectionsAndChanges();
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
DOMChangesPluginLite.prototype.destroy = function () {
|
|
824
|
+
this.domManipulator.destroy();
|
|
825
|
+
this.exposureTracker.destroy();
|
|
826
|
+
this.htmlInjector.destroy();
|
|
827
|
+
this.styleManagers.forEach(function (manager) { return manager.destroy(); });
|
|
828
|
+
this.styleManagers.clear();
|
|
829
|
+
if (this.mutationObserver) {
|
|
830
|
+
this.mutationObserver.disconnect();
|
|
831
|
+
this.mutationObserver = null;
|
|
832
|
+
}
|
|
833
|
+
if (this.persistenceObserver) {
|
|
834
|
+
this.persistenceObserver.disconnect();
|
|
835
|
+
this.persistenceObserver = null;
|
|
836
|
+
}
|
|
837
|
+
// Clean up anti-flicker timeout and style
|
|
838
|
+
if (this.antiFlickerTimeout !== null) {
|
|
839
|
+
clearTimeout(this.antiFlickerTimeout);
|
|
840
|
+
this.antiFlickerTimeout = null;
|
|
841
|
+
}
|
|
842
|
+
var antiFlickerStyle = document.getElementById(this.antiFlickerStyleId);
|
|
843
|
+
if (antiFlickerStyle) {
|
|
844
|
+
antiFlickerStyle.remove();
|
|
845
|
+
}
|
|
846
|
+
this.eventListeners.clear();
|
|
847
|
+
this.exposedExperiments.clear();
|
|
848
|
+
this.watchedElements = new WeakMap();
|
|
849
|
+
this.appliedStyleChanges.clear();
|
|
850
|
+
this.reapplyingElements.clear();
|
|
851
|
+
this.reapplyLogThrottle.clear();
|
|
852
|
+
this.unregisterFromContext();
|
|
853
|
+
this.initialized = false;
|
|
854
|
+
if (this.config.debug) {
|
|
855
|
+
(0, debug_1.logDebug)('[ABsmartly] DOM Changes Plugin Lite destroyed');
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
DOMChangesPluginLite.prototype.registerWithContext = function () {
|
|
859
|
+
if (this.config.context) {
|
|
860
|
+
if (!this.config.context.__plugins) {
|
|
861
|
+
this.config.context.__plugins = {};
|
|
862
|
+
}
|
|
863
|
+
this.config.context.__plugins.domPlugin = {
|
|
864
|
+
name: 'DOMChangesPluginLite',
|
|
865
|
+
version: DOMChangesPluginLite.VERSION,
|
|
866
|
+
initialized: true,
|
|
867
|
+
capabilities: ['spa', 'visibility'],
|
|
868
|
+
instance: this,
|
|
869
|
+
timestamp: Date.now(),
|
|
870
|
+
};
|
|
871
|
+
this.config.context.__domPlugin = this.config.context.__plugins.domPlugin;
|
|
872
|
+
if (this.config.debug) {
|
|
873
|
+
(0, debug_1.logDebug)('[ABsmartly] DOMChangesPluginLite registered with context at __plugins.domPlugin');
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
DOMChangesPluginLite.prototype.unregisterFromContext = function () {
|
|
878
|
+
var _a;
|
|
879
|
+
if (this.config.context) {
|
|
880
|
+
if ((_a = this.config.context.__plugins) === null || _a === void 0 ? void 0 : _a.domPlugin) {
|
|
881
|
+
delete this.config.context.__plugins.domPlugin;
|
|
882
|
+
}
|
|
883
|
+
if (this.config.context.__domPlugin) {
|
|
884
|
+
delete this.config.context.__domPlugin;
|
|
885
|
+
}
|
|
886
|
+
if (this.config.debug) {
|
|
887
|
+
(0, debug_1.logDebug)('[ABsmartly] DOMChangesPluginLite unregistered from context');
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
/**
|
|
892
|
+
* Hide content to prevent flicker before experiments are applied
|
|
893
|
+
*/
|
|
894
|
+
DOMChangesPluginLite.prototype.hideContent = function () {
|
|
895
|
+
var _this = this;
|
|
896
|
+
var mode = this.config.hideUntilReady;
|
|
897
|
+
if (!mode)
|
|
898
|
+
return;
|
|
899
|
+
// Check if style already exists (prevent duplicate injection)
|
|
900
|
+
if (document.getElementById(this.antiFlickerStyleId)) {
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
var style = document.createElement('style');
|
|
904
|
+
style.id = this.antiFlickerStyleId;
|
|
905
|
+
var hasTransition = this.config.hideTransition !== false;
|
|
906
|
+
var selector = mode === 'body' ? 'body' : this.config.hideSelector || '[data-absmartly-hide]';
|
|
907
|
+
if (hasTransition) {
|
|
908
|
+
// Use both visibility:hidden and opacity:0 for smooth transition
|
|
909
|
+
style.textContent = "\n ".concat(selector, " {\n visibility: hidden !important;\n opacity: 0 !important;\n }\n ");
|
|
910
|
+
}
|
|
911
|
+
else {
|
|
912
|
+
// Use only visibility:hidden for instant reveal (no layout shift)
|
|
913
|
+
style.textContent = "\n ".concat(selector, " {\n visibility: hidden !important;\n }\n ");
|
|
914
|
+
}
|
|
915
|
+
document.head.appendChild(style);
|
|
916
|
+
// Set timeout to show content even if experiments fail to load
|
|
917
|
+
this.antiFlickerTimeout = window.setTimeout(function () {
|
|
918
|
+
if (_this.config.debug) {
|
|
919
|
+
(0, debug_1.logDebug)("[ABsmartly] Anti-flicker timeout reached (".concat(_this.config.hideTimeout, "ms), showing content"));
|
|
920
|
+
}
|
|
921
|
+
_this.showContent();
|
|
922
|
+
}, this.config.hideTimeout);
|
|
923
|
+
if (this.config.debug) {
|
|
924
|
+
(0, debug_1.logDebug)("[ABsmartly] Anti-flicker enabled (mode: ".concat(mode, ", transition: ").concat(hasTransition ? this.config.hideTransition : 'none', ", timeout: ").concat(this.config.hideTimeout, "ms)"));
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
/**
|
|
928
|
+
* Show hidden content after experiments are applied
|
|
929
|
+
*/
|
|
930
|
+
DOMChangesPluginLite.prototype.showContent = function () {
|
|
931
|
+
var _this = this;
|
|
932
|
+
// Clear timeout if still pending
|
|
933
|
+
if (this.antiFlickerTimeout !== null) {
|
|
934
|
+
clearTimeout(this.antiFlickerTimeout);
|
|
935
|
+
this.antiFlickerTimeout = null;
|
|
936
|
+
}
|
|
937
|
+
var style = document.getElementById(this.antiFlickerStyleId);
|
|
938
|
+
if (!style)
|
|
939
|
+
return;
|
|
940
|
+
var hasTransition = this.config.hideTransition !== false;
|
|
941
|
+
if (hasTransition) {
|
|
942
|
+
// Smooth fade-in: remove visibility, add transition, then animate opacity
|
|
943
|
+
var mode = this.config.hideUntilReady;
|
|
944
|
+
var selector = mode === 'body' ? 'body' : this.config.hideSelector || '[data-absmartly-hide]';
|
|
945
|
+
// Step 1: Remove visibility:hidden, keep opacity:0, add transition
|
|
946
|
+
style.textContent = "\n ".concat(selector, " {\n opacity: 0 !important;\n transition: opacity ").concat(this.config.hideTransition, " !important;\n }\n ");
|
|
947
|
+
// Step 2: Force reflow to ensure transition applies
|
|
948
|
+
style.offsetHeight;
|
|
949
|
+
// Step 3: Trigger fade-in by setting opacity to 1
|
|
950
|
+
style.textContent = "\n ".concat(selector, " {\n opacity: 1 !important;\n transition: opacity ").concat(this.config.hideTransition, " !important;\n }\n ");
|
|
951
|
+
// Step 4: Remove style after transition completes
|
|
952
|
+
var transitionDuration = parseFloat(this.config.hideTransition) * 1000;
|
|
953
|
+
setTimeout(function () {
|
|
954
|
+
style.remove();
|
|
955
|
+
if (_this.config.debug) {
|
|
956
|
+
(0, debug_1.logDebug)('[ABsmartly] Anti-flicker fade-in complete, style removed');
|
|
957
|
+
}
|
|
958
|
+
}, transitionDuration);
|
|
959
|
+
if (this.config.debug) {
|
|
960
|
+
(0, debug_1.logDebug)("[ABsmartly] Anti-flicker fading in with transition: ".concat(this.config.hideTransition));
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
else {
|
|
964
|
+
// Instant reveal: just remove the style
|
|
965
|
+
style.remove();
|
|
966
|
+
if (this.config.debug) {
|
|
967
|
+
(0, debug_1.logDebug)('[ABsmartly] Anti-flicker removed, content now visible');
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
DOMChangesPluginLite.prototype.watchElement = function (element, experimentName, change) {
|
|
972
|
+
var experiments = this.watchedElements.get(element);
|
|
973
|
+
if (!experiments) {
|
|
974
|
+
experiments = new Set();
|
|
975
|
+
this.watchedElements.set(element, experiments);
|
|
976
|
+
}
|
|
977
|
+
experiments.add(experimentName);
|
|
978
|
+
// Store the applied style change for this experiment
|
|
979
|
+
if (!this.appliedStyleChanges.has(experimentName)) {
|
|
980
|
+
this.appliedStyleChanges.set(experimentName, []);
|
|
981
|
+
}
|
|
982
|
+
var changes = this.appliedStyleChanges.get(experimentName);
|
|
983
|
+
var isNewWatch = !changes.includes(change);
|
|
984
|
+
if (isNewWatch) {
|
|
985
|
+
changes.push(change);
|
|
986
|
+
// Only log when actually adding a new watch, not on every reapply
|
|
987
|
+
if (this.config.debug) {
|
|
988
|
+
(0, debug_1.logDebug)('[ABsmartly] Watching element for style persistence', {
|
|
989
|
+
experimentName: experimentName,
|
|
990
|
+
selector: change.selector,
|
|
991
|
+
element: element.tagName,
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
if (!this.persistenceObserver) {
|
|
996
|
+
this.setupPersistenceObserver();
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
DOMChangesPluginLite.prototype.unwatchElement = function (element, experimentName) {
|
|
1000
|
+
var experiments = this.watchedElements.get(element);
|
|
1001
|
+
if (experiments) {
|
|
1002
|
+
experiments.delete(experimentName);
|
|
1003
|
+
if (experiments.size === 0) {
|
|
1004
|
+
this.watchedElements.delete(element);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
DOMChangesPluginLite.prototype.setupPersistenceObserver = function () {
|
|
1009
|
+
var _this = this;
|
|
1010
|
+
if (this.persistenceObserver)
|
|
1011
|
+
return;
|
|
1012
|
+
this.persistenceObserver = new MutationObserver(function (mutations) {
|
|
1013
|
+
mutations.forEach(function (mutation) {
|
|
1014
|
+
var element = mutation.target;
|
|
1015
|
+
if (_this.reapplyingElements.has(element)) {
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
var experiments = _this.watchedElements.get(element);
|
|
1019
|
+
if (experiments) {
|
|
1020
|
+
// Throttle mutation detection logs to once per 5 seconds per element
|
|
1021
|
+
if (_this.config.debug) {
|
|
1022
|
+
var elementKey = "mutation:".concat(element.tagName, ":").concat(element.getAttribute('name') || element.className);
|
|
1023
|
+
var now = Date.now();
|
|
1024
|
+
var lastLogged = _this.reapplyLogThrottle.get(elementKey) || 0;
|
|
1025
|
+
if (now - lastLogged > 5000) {
|
|
1026
|
+
(0, debug_1.logDebug)('[ABsmartly] Style mutation detected on watched element', {
|
|
1027
|
+
element: element.tagName,
|
|
1028
|
+
selector: element.getAttribute('name') || element.className,
|
|
1029
|
+
oldValue: mutation.oldValue,
|
|
1030
|
+
});
|
|
1031
|
+
_this.reapplyLogThrottle.set(elementKey, now);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
experiments.forEach(function (experimentName) {
|
|
1035
|
+
var appliedChanges = _this.appliedStyleChanges.get(experimentName);
|
|
1036
|
+
if (appliedChanges) {
|
|
1037
|
+
appliedChanges.forEach(function (change) {
|
|
1038
|
+
var e_8, _a;
|
|
1039
|
+
if (change.type === 'style' && element.matches(change.selector)) {
|
|
1040
|
+
var needsReapply = _this.checkStyleOverwritten(element, change.value);
|
|
1041
|
+
if (needsReapply) {
|
|
1042
|
+
_this.reapplyingElements.add(element);
|
|
1043
|
+
_this.domManipulator.applyChange(change, experimentName);
|
|
1044
|
+
var logKey = "".concat(experimentName, "-").concat(change.selector);
|
|
1045
|
+
var now = Date.now();
|
|
1046
|
+
var lastLogged = _this.reapplyLogThrottle.get(logKey) || 0;
|
|
1047
|
+
if (_this.config.debug && now - lastLogged > 5000) {
|
|
1048
|
+
(0, debug_1.logDebug)('Reapplied style after mutation (React/framework conflict detected)', {
|
|
1049
|
+
experimentName: experimentName,
|
|
1050
|
+
selector: change.selector,
|
|
1051
|
+
note: 'This happens when the page framework (React/Vue/etc) fights with DOM changes',
|
|
1052
|
+
});
|
|
1053
|
+
_this.reapplyLogThrottle.set(logKey, now);
|
|
1054
|
+
// Cleanup old throttle entries to prevent memory leak
|
|
1055
|
+
if (_this.reapplyLogThrottle.size > 100) {
|
|
1056
|
+
var oldestAllowed = now - 60000; // 1 minute
|
|
1057
|
+
try {
|
|
1058
|
+
for (var _b = __values(_this.reapplyLogThrottle.entries()), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
1059
|
+
var _d = __read(_c.value, 2), key = _d[0], time = _d[1];
|
|
1060
|
+
if (time < oldestAllowed) {
|
|
1061
|
+
_this.reapplyLogThrottle.delete(key);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
catch (e_8_1) { e_8 = { error: e_8_1 }; }
|
|
1066
|
+
finally {
|
|
1067
|
+
try {
|
|
1068
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
1069
|
+
}
|
|
1070
|
+
finally { if (e_8) throw e_8.error; }
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
setTimeout(function () {
|
|
1075
|
+
_this.reapplyingElements.delete(element);
|
|
1076
|
+
}, 0);
|
|
1077
|
+
}
|
|
1078
|
+
else if (_this.config.debug) {
|
|
1079
|
+
(0, debug_1.logDebug)('[ABsmartly] Style mutation detected but no reapply needed', {
|
|
1080
|
+
experimentName: experimentName,
|
|
1081
|
+
selector: change.selector,
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
});
|
|
1091
|
+
this.persistenceObserver.observe(document.body, {
|
|
1092
|
+
attributes: true,
|
|
1093
|
+
attributeFilter: ['style'],
|
|
1094
|
+
subtree: true,
|
|
1095
|
+
attributeOldValue: true,
|
|
1096
|
+
});
|
|
1097
|
+
if (this.config.debug) {
|
|
1098
|
+
(0, debug_1.logDebug)('[ABsmartly] Style persistence observer setup complete');
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
1101
|
+
DOMChangesPluginLite.prototype.checkStyleOverwritten = function (element, expectedStyles) {
|
|
1102
|
+
var e_9, _a;
|
|
1103
|
+
try {
|
|
1104
|
+
for (var _b = __values(Object.entries(expectedStyles)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
1105
|
+
var _d = __read(_c.value, 2), prop = _d[0], value = _d[1];
|
|
1106
|
+
var cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
1107
|
+
var currentValue = element.style.getPropertyValue(cssProp);
|
|
1108
|
+
var currentPriority = element.style.getPropertyPriority(cssProp);
|
|
1109
|
+
if (currentValue !== value || (value.includes('!important') && !currentPriority)) {
|
|
1110
|
+
return true;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
catch (e_9_1) { e_9 = { error: e_9_1 }; }
|
|
1115
|
+
finally {
|
|
1116
|
+
try {
|
|
1117
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
1118
|
+
}
|
|
1119
|
+
finally { if (e_9) throw e_9.error; }
|
|
1120
|
+
}
|
|
1121
|
+
return false;
|
|
1122
|
+
};
|
|
1123
|
+
DOMChangesPluginLite.VERSION = '1.0.0-lite';
|
|
1124
|
+
return DOMChangesPluginLite;
|
|
1125
|
+
}());
|
|
1126
|
+
exports.DOMChangesPluginLite = DOMChangesPluginLite;
|
|
1127
|
+
//# sourceMappingURL=DOMChangesPluginLite.js.map
|