@magicfeedback/popup-sdk 1.0.10 → 1.0.12
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 +269 -204
- package/dist/index.d.mts +56 -18
- package/dist/index.d.ts +56 -18
- package/dist/index.js +574 -88
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +574 -88
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1721,10 +1721,18 @@ var require_magicfeedback_sdk_browser = __commonJS({
|
|
|
1721
1721
|
// src/index.ts
|
|
1722
1722
|
var index_exports = {};
|
|
1723
1723
|
__export(index_exports, {
|
|
1724
|
-
DeepdotsPopups: () => DeepdotsPopups
|
|
1724
|
+
DeepdotsPopups: () => DeepdotsPopups,
|
|
1725
|
+
POPUP_TRIGGER_CONDITION_STATUSES: () => POPUP_TRIGGER_CONDITION_STATUSES
|
|
1725
1726
|
});
|
|
1726
1727
|
module.exports = __toCommonJS(index_exports);
|
|
1727
1728
|
|
|
1729
|
+
// src/types/index.ts
|
|
1730
|
+
var POPUP_TRIGGER_CONDITION_STATUSES = [
|
|
1731
|
+
"SHOWED",
|
|
1732
|
+
"PARTIAL",
|
|
1733
|
+
"COMPLETED"
|
|
1734
|
+
];
|
|
1735
|
+
|
|
1728
1736
|
// src/ui/renderPopup.ts
|
|
1729
1737
|
var import_native = __toESM(require_magicfeedback_sdk_browser());
|
|
1730
1738
|
function ensureMagicFeedbackStyles(popup) {
|
|
@@ -1787,7 +1795,7 @@ function ensureResponsiveStyles(popup) {
|
|
|
1787
1795
|
`;
|
|
1788
1796
|
popup.appendChild(style);
|
|
1789
1797
|
}
|
|
1790
|
-
async function renderPopup(container, surveyId, productId, actions, emit, onClose) {
|
|
1798
|
+
async function renderPopup(container, surveyId, productId, actions, emit, onClose, env = "production") {
|
|
1791
1799
|
let surveyCompletedEmitted = false;
|
|
1792
1800
|
let stylesInjected = false;
|
|
1793
1801
|
const popup = document.createElement("div");
|
|
@@ -2071,7 +2079,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2071
2079
|
setLoading(false);
|
|
2072
2080
|
return;
|
|
2073
2081
|
}
|
|
2074
|
-
import_native.default.init({ debug: true, env: "prod" });
|
|
2082
|
+
import_native.default.init({ debug: true, env: env === "production" ? "prod" : "dev" });
|
|
2075
2083
|
formInstance = import_native.default.form(surveyId, productId);
|
|
2076
2084
|
const generateOptions = {
|
|
2077
2085
|
addButton: false,
|
|
@@ -2186,6 +2194,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2186
2194
|
updateButtons("completed");
|
|
2187
2195
|
return;
|
|
2188
2196
|
}
|
|
2197
|
+
emit("popup_clicked", surveyId, { action: "partial" });
|
|
2189
2198
|
if (total > 1 && progress > 0 && progress < total) {
|
|
2190
2199
|
updateButtons("in_progress_next");
|
|
2191
2200
|
} else {
|
|
@@ -2222,12 +2231,18 @@ function setupTrigger(popups, trigger) {
|
|
|
2222
2231
|
case "exit":
|
|
2223
2232
|
setupExitTrigger(popups, trigger);
|
|
2224
2233
|
break;
|
|
2234
|
+
case "event":
|
|
2235
|
+
setupEventTrigger(popups, trigger);
|
|
2236
|
+
break;
|
|
2237
|
+
case "click":
|
|
2238
|
+
setupClickTrigger(popups, trigger);
|
|
2239
|
+
break;
|
|
2225
2240
|
}
|
|
2226
2241
|
}
|
|
2227
2242
|
function setupTimeTrigger(popups, trigger) {
|
|
2228
2243
|
const delay = trigger.value || 5e3;
|
|
2229
2244
|
setTimeout(() => {
|
|
2230
|
-
popups.triggerSurvey(trigger.surveyId);
|
|
2245
|
+
popups.triggerSurvey(trigger.surveyId, trigger.popupId);
|
|
2231
2246
|
}, delay);
|
|
2232
2247
|
popups.debug(`Time trigger set for ${delay}ms`);
|
|
2233
2248
|
}
|
|
@@ -2236,7 +2251,7 @@ function setupScrollTrigger(popups, trigger) {
|
|
|
2236
2251
|
const handler = () => {
|
|
2237
2252
|
const scrollPercentage = window.scrollY / (document.documentElement.scrollHeight - window.innerHeight) * 100;
|
|
2238
2253
|
if (scrollPercentage >= threshold) {
|
|
2239
|
-
popups.triggerSurvey(trigger.surveyId);
|
|
2254
|
+
popups.triggerSurvey(trigger.surveyId, trigger.popupId);
|
|
2240
2255
|
window.removeEventListener("scroll", handler);
|
|
2241
2256
|
}
|
|
2242
2257
|
};
|
|
@@ -2244,23 +2259,137 @@ function setupScrollTrigger(popups, trigger) {
|
|
|
2244
2259
|
popups.debug(`Scroll trigger set for ${threshold}%`);
|
|
2245
2260
|
}
|
|
2246
2261
|
function setupExitTrigger(popups, trigger) {
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2262
|
+
if (typeof window === "undefined") return;
|
|
2263
|
+
const delaySeconds = parseExitDelaySeconds(trigger.value);
|
|
2264
|
+
const historyRef = window.history;
|
|
2265
|
+
const originalPushState = historyRef.pushState.bind(historyRef);
|
|
2266
|
+
const originalReplaceState = historyRef.replaceState.bind(historyRef);
|
|
2267
|
+
let lastUrl = normalizeUrl(window.location.href);
|
|
2268
|
+
let lastQueuedKey = "";
|
|
2269
|
+
let lastQueuedAt = 0;
|
|
2270
|
+
const queueLeave = (fromRaw, toRaw) => {
|
|
2271
|
+
const from = normalizeUrl(fromRaw);
|
|
2272
|
+
const to = normalizeUrl(toRaw);
|
|
2273
|
+
if (!from || !to || from === to) return;
|
|
2274
|
+
const key = `${from}=>${to}`;
|
|
2275
|
+
const now = Date.now();
|
|
2276
|
+
if (key === lastQueuedKey && now - lastQueuedAt < 150) return;
|
|
2277
|
+
lastQueuedKey = key;
|
|
2278
|
+
lastQueuedAt = now;
|
|
2279
|
+
popups.queueExitPopup(trigger.surveyId, delaySeconds, from, trigger.popupId);
|
|
2280
|
+
};
|
|
2281
|
+
const handleNavigation = (to) => {
|
|
2282
|
+
const from = lastUrl;
|
|
2283
|
+
queueLeave(from, to);
|
|
2284
|
+
lastUrl = normalizeUrl(to);
|
|
2285
|
+
};
|
|
2286
|
+
const handleDocumentClick = (event) => {
|
|
2287
|
+
if (event.defaultPrevented) return;
|
|
2288
|
+
if (event.button !== 0) return;
|
|
2289
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
2290
|
+
const anchor = event.target?.closest?.("a");
|
|
2291
|
+
if (!(anchor instanceof HTMLAnchorElement)) return;
|
|
2292
|
+
const href = anchor.getAttribute("href");
|
|
2293
|
+
if (!href || href.startsWith("javascript:") || href.startsWith("mailto:") || href.startsWith("tel:")) {
|
|
2294
|
+
return;
|
|
2295
|
+
}
|
|
2296
|
+
const target = anchor.getAttribute("target");
|
|
2297
|
+
if (target && target !== "_self") return;
|
|
2298
|
+
let destination;
|
|
2299
|
+
try {
|
|
2300
|
+
destination = new URL(href, window.location.href);
|
|
2301
|
+
} catch {
|
|
2302
|
+
return;
|
|
2251
2303
|
}
|
|
2304
|
+
if (destination.origin !== window.location.origin) return;
|
|
2305
|
+
queueLeave(window.location.href, destination.href);
|
|
2306
|
+
};
|
|
2307
|
+
const handleHashChange = (event) => {
|
|
2308
|
+
const to = event.newURL || window.location.href;
|
|
2309
|
+
const from = event.oldURL || lastUrl;
|
|
2310
|
+
queueLeave(from, to);
|
|
2311
|
+
lastUrl = normalizeUrl(to);
|
|
2252
2312
|
};
|
|
2253
|
-
|
|
2254
|
-
|
|
2313
|
+
const handlePopState = () => {
|
|
2314
|
+
handleNavigation(window.location.href);
|
|
2315
|
+
};
|
|
2316
|
+
historyRef.pushState = function(data, unused, url) {
|
|
2317
|
+
const from = window.location.href;
|
|
2318
|
+
const result = originalPushState(data, unused, url);
|
|
2319
|
+
queueLeave(from, window.location.href);
|
|
2320
|
+
lastUrl = normalizeUrl(window.location.href);
|
|
2321
|
+
return result;
|
|
2322
|
+
};
|
|
2323
|
+
historyRef.replaceState = function(data, unused, url) {
|
|
2324
|
+
const from = window.location.href;
|
|
2325
|
+
const result = originalReplaceState(data, unused, url);
|
|
2326
|
+
queueLeave(from, window.location.href);
|
|
2327
|
+
lastUrl = normalizeUrl(window.location.href);
|
|
2328
|
+
return result;
|
|
2329
|
+
};
|
|
2330
|
+
document.addEventListener("click", handleDocumentClick, true);
|
|
2331
|
+
window.addEventListener("hashchange", handleHashChange);
|
|
2332
|
+
window.addEventListener("popstate", handlePopState);
|
|
2333
|
+
popups.debug("Exit trigger set (deferred to next route)", {
|
|
2334
|
+
surveyId: trigger.surveyId,
|
|
2335
|
+
delaySeconds
|
|
2336
|
+
});
|
|
2337
|
+
}
|
|
2338
|
+
function setupEventTrigger(popups, trigger) {
|
|
2339
|
+
popups.debug("Event trigger registered", {
|
|
2340
|
+
popupId: trigger.popupId,
|
|
2341
|
+
surveyId: trigger.surveyId,
|
|
2342
|
+
eventName: String(trigger.value || "")
|
|
2343
|
+
});
|
|
2344
|
+
}
|
|
2345
|
+
function parseExitDelaySeconds(value) {
|
|
2346
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2347
|
+
return Math.max(0, value);
|
|
2348
|
+
}
|
|
2349
|
+
if (typeof value === "string" && value.trim()) {
|
|
2350
|
+
const parsed = Number(value);
|
|
2351
|
+
if (Number.isFinite(parsed)) return Math.max(0, parsed);
|
|
2352
|
+
}
|
|
2353
|
+
return 0;
|
|
2354
|
+
}
|
|
2355
|
+
function normalizeUrl(value) {
|
|
2356
|
+
if (!value) return "";
|
|
2357
|
+
const withoutIndex = value.replace(/\/index\.html(?=($|[?#]))/i, "");
|
|
2358
|
+
return withoutIndex.length > 1 && withoutIndex.endsWith("/") ? withoutIndex.slice(0, -1) : withoutIndex;
|
|
2359
|
+
}
|
|
2360
|
+
function setupClickTrigger(popups, trigger) {
|
|
2361
|
+
const targetId = typeof trigger.value === "string" ? trigger.value : "";
|
|
2362
|
+
if (!targetId) {
|
|
2363
|
+
popups.debug("Click trigger missing element id", trigger);
|
|
2364
|
+
return;
|
|
2365
|
+
}
|
|
2366
|
+
const attach = () => {
|
|
2367
|
+
const el = document.getElementById(targetId);
|
|
2368
|
+
if (!el) {
|
|
2369
|
+
popups.debug("Click trigger target not found", targetId);
|
|
2370
|
+
return false;
|
|
2371
|
+
}
|
|
2372
|
+
const handler = (e) => {
|
|
2373
|
+
if (e.defaultPrevented) return;
|
|
2374
|
+
popups.triggerSurvey(trigger.surveyId, trigger.popupId);
|
|
2375
|
+
el.removeEventListener("click", handler);
|
|
2376
|
+
};
|
|
2377
|
+
el.addEventListener("click", handler);
|
|
2378
|
+
popups.debug(`Click trigger set for #${targetId}`);
|
|
2379
|
+
return true;
|
|
2380
|
+
};
|
|
2381
|
+
if (typeof document === "undefined") return;
|
|
2382
|
+
if (attach()) return;
|
|
2383
|
+
window.addEventListener("DOMContentLoaded", () => attach(), { once: true });
|
|
2255
2384
|
}
|
|
2256
2385
|
|
|
2257
2386
|
// src/config/env.ts
|
|
2258
2387
|
var ENVIRONMENT_MAP = {
|
|
2259
2388
|
development: {
|
|
2260
|
-
apiBaseUrl: "https://api-dev.
|
|
2389
|
+
apiBaseUrl: "https://api-dev.deepdots.com"
|
|
2261
2390
|
},
|
|
2262
2391
|
production: {
|
|
2263
|
-
apiBaseUrl: "https://api.
|
|
2392
|
+
apiBaseUrl: "https://api.deepdots.com"
|
|
2264
2393
|
}
|
|
2265
2394
|
};
|
|
2266
2395
|
function resolveEnvironment(nodeEnv) {
|
|
@@ -2342,10 +2471,10 @@ var BrowserPopupRenderer = class {
|
|
|
2342
2471
|
document.body.appendChild(this.container);
|
|
2343
2472
|
}
|
|
2344
2473
|
}
|
|
2345
|
-
show(surveyId, productId, actions, emit, onClose) {
|
|
2474
|
+
show(surveyId, productId, actions, emit, onClose, env = "production") {
|
|
2346
2475
|
if (!this.container) this.init();
|
|
2347
2476
|
if (!this.container) return;
|
|
2348
|
-
renderPopup(this.container, surveyId, productId, actions, emit, onClose);
|
|
2477
|
+
renderPopup(this.container, surveyId, productId, actions, emit, onClose, env);
|
|
2349
2478
|
}
|
|
2350
2479
|
hide() {
|
|
2351
2480
|
if (this.container) {
|
|
@@ -2364,6 +2493,8 @@ function createDefaultRenderer() {
|
|
|
2364
2493
|
}
|
|
2365
2494
|
|
|
2366
2495
|
// src/core/deepdots-popups.ts
|
|
2496
|
+
var EXIT_QUEUE_STORAGE_KEY = "__deepdots_exit_popup_queue__";
|
|
2497
|
+
var DAY_IN_MS = 24 * 60 * 60 * 1e3;
|
|
2367
2498
|
var DeepdotsPopups = class {
|
|
2368
2499
|
constructor() {
|
|
2369
2500
|
this.config = null;
|
|
@@ -2377,9 +2508,15 @@ var DeepdotsPopups = class {
|
|
|
2377
2508
|
this.popupsLoaded = false;
|
|
2378
2509
|
this.pendingAutoLaunch = false;
|
|
2379
2510
|
this.answeredSurveys = /* @__PURE__ */ new Set();
|
|
2511
|
+
this.surveyProgress = /* @__PURE__ */ new Map();
|
|
2380
2512
|
this.lastShown = /* @__PURE__ */ new Map();
|
|
2513
|
+
// popupId -> timestamp mostrado
|
|
2514
|
+
this.surveyToPopupId = /* @__PURE__ */ new Map();
|
|
2515
|
+
// surveyId -> popupId
|
|
2516
|
+
this.deferredExitTimers = [];
|
|
2517
|
+
this.baseUrl = "";
|
|
2518
|
+
this.env = "production";
|
|
2381
2519
|
}
|
|
2382
|
-
// popupId -> timestamp mostrado
|
|
2383
2520
|
/** Initialize the SDK with configuration */
|
|
2384
2521
|
init(config) {
|
|
2385
2522
|
if (this.initialized) {
|
|
@@ -2387,27 +2524,31 @@ var DeepdotsPopups = class {
|
|
|
2387
2524
|
return;
|
|
2388
2525
|
}
|
|
2389
2526
|
const env = resolveEnvironment(config.nodeEnv);
|
|
2527
|
+
this.baseUrl = env.apiBaseUrl;
|
|
2528
|
+
this.env = config.nodeEnv || "production";
|
|
2390
2529
|
this.config = {
|
|
2391
2530
|
apiKey: config.apiKey || void 0,
|
|
2392
|
-
baseUrl: env.apiBaseUrl,
|
|
2393
2531
|
mode: config.mode || "client",
|
|
2394
2532
|
debug: config.debug || false,
|
|
2395
|
-
popups: config.popups || []
|
|
2533
|
+
popups: config.popups || [],
|
|
2534
|
+
userId: config.userId || void 0
|
|
2396
2535
|
};
|
|
2397
2536
|
this.initialized = true;
|
|
2398
2537
|
this.log("SDK initialized", this.config);
|
|
2399
2538
|
if (this.renderer.init) this.renderer.init();
|
|
2400
2539
|
this.setupPopupContainer();
|
|
2401
2540
|
if (this.config.mode === "client") {
|
|
2402
|
-
this.popupDefinitions = this.config.popups || [];
|
|
2541
|
+
this.popupDefinitions = this.validatePopupDefinitions(this.config.popups || []);
|
|
2403
2542
|
this.popupsLoaded = true;
|
|
2404
2543
|
this.configureTriggersFromDefinitions();
|
|
2544
|
+
this.processDeferredExitQueue();
|
|
2405
2545
|
} else {
|
|
2406
2546
|
this.fetchPopupsFromServer().then((defs) => {
|
|
2407
|
-
this.popupDefinitions = defs;
|
|
2547
|
+
this.popupDefinitions = this.validatePopupDefinitions(defs);
|
|
2408
2548
|
this.popupsLoaded = true;
|
|
2409
|
-
this.log("Popups loaded from server (fake)",
|
|
2549
|
+
this.log("Popups loaded from server (fake)", this.popupDefinitions);
|
|
2410
2550
|
this.configureTriggersFromDefinitions();
|
|
2551
|
+
this.processDeferredExitQueue();
|
|
2411
2552
|
if (this.pendingAutoLaunch) {
|
|
2412
2553
|
this.startTriggers();
|
|
2413
2554
|
}
|
|
@@ -2433,7 +2574,6 @@ var DeepdotsPopups = class {
|
|
|
2433
2574
|
}
|
|
2434
2575
|
/** Show a popup immediately (supports legacy ShowOptions and new PopupDefinition) */
|
|
2435
2576
|
show(options) {
|
|
2436
|
-
console.log("Show popup called with options:", options);
|
|
2437
2577
|
if (!this.initialized) {
|
|
2438
2578
|
throw new Error("SDK not initialized. Call init() first.");
|
|
2439
2579
|
}
|
|
@@ -2441,8 +2581,10 @@ var DeepdotsPopups = class {
|
|
|
2441
2581
|
if (isDefinition) {
|
|
2442
2582
|
const def = options;
|
|
2443
2583
|
this.log("Showing popup (definition)", def);
|
|
2584
|
+
this.surveyToPopupId.set(def.surveyId, def.id);
|
|
2585
|
+
this.lastShown.set(def.id, Date.now());
|
|
2444
2586
|
this.renderPopup(def.surveyId, def.productId, def.actions);
|
|
2445
|
-
this.emitEvent("popup_shown", def.surveyId);
|
|
2587
|
+
this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
|
|
2446
2588
|
} else {
|
|
2447
2589
|
const opt = options;
|
|
2448
2590
|
this.log("Showing popup (legacy options)", opt);
|
|
@@ -2452,7 +2594,7 @@ var DeepdotsPopups = class {
|
|
|
2452
2594
|
}
|
|
2453
2595
|
/** Mostrar popup por id de definición (usa surveyId interno) */
|
|
2454
2596
|
showByPopupId(popupId) {
|
|
2455
|
-
const def = this.popupDefinitions.find((
|
|
2597
|
+
const def = this.popupDefinitions.find((popup) => popup.id === popupId);
|
|
2456
2598
|
if (!def) {
|
|
2457
2599
|
this.log("Popup definition not found", popupId);
|
|
2458
2600
|
return;
|
|
@@ -2470,92 +2612,315 @@ var DeepdotsPopups = class {
|
|
|
2470
2612
|
/** Deriva triggers desde las definiciones de popup */
|
|
2471
2613
|
configureTriggersFromDefinitions() {
|
|
2472
2614
|
const derived = [];
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
case "time_on_page":
|
|
2480
|
-
type = "time";
|
|
2481
|
-
break;
|
|
2482
|
-
case "scroll":
|
|
2483
|
-
type = "scroll";
|
|
2484
|
-
break;
|
|
2485
|
-
case "exit":
|
|
2486
|
-
type = "exit";
|
|
2487
|
-
break;
|
|
2488
|
-
default:
|
|
2489
|
-
this.debug("Unsupported trigger type", t.type);
|
|
2615
|
+
this.debug("Validated popup definitions", this.popupDefinitions);
|
|
2616
|
+
this.popupDefinitions.forEach((def) => {
|
|
2617
|
+
def.triggers.forEach((trigger) => {
|
|
2618
|
+
const type = this.mapPopupTriggerType(trigger.type);
|
|
2619
|
+
if (!type) {
|
|
2620
|
+
this.debug("Unsupported trigger type", trigger.type);
|
|
2490
2621
|
return;
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2622
|
+
}
|
|
2623
|
+
const value = type === "time" && typeof trigger.value === "number" ? trigger.value * 1e3 : trigger.value;
|
|
2624
|
+
derived.push({ type, value, surveyId: def.surveyId, popupId: def.id });
|
|
2625
|
+
});
|
|
2494
2626
|
});
|
|
2495
2627
|
if (derived.length) {
|
|
2496
2628
|
this.configureTriggers(derived);
|
|
2497
2629
|
}
|
|
2498
2630
|
}
|
|
2499
2631
|
/** Lógica para evaluar condiciones antes de mostrar una encuesta */
|
|
2500
|
-
triggerSurvey(surveyId) {
|
|
2501
|
-
const def = this.
|
|
2632
|
+
triggerSurvey(surveyId, popupId) {
|
|
2633
|
+
const def = this.findPopupDefinition(surveyId, popupId);
|
|
2502
2634
|
if (!def) {
|
|
2503
|
-
this.debug("No popup definition for
|
|
2635
|
+
this.debug("No popup definition for trigger", { surveyId, popupId });
|
|
2504
2636
|
return;
|
|
2505
2637
|
}
|
|
2506
2638
|
if (!this.shouldShow(def)) {
|
|
2507
2639
|
this.debug("Conditions prevented showing popup", def.id);
|
|
2508
2640
|
return;
|
|
2509
2641
|
}
|
|
2642
|
+
this.showDefinition(def);
|
|
2643
|
+
}
|
|
2644
|
+
/** Trigger popups configured with trigger.type = 'event' and matching trigger.value */
|
|
2645
|
+
triggerEvent(eventName) {
|
|
2646
|
+
if (!this.initialized) {
|
|
2647
|
+
throw new Error("SDK not initialized. Call init() first.");
|
|
2648
|
+
}
|
|
2649
|
+
const normalized = String(eventName || "").trim();
|
|
2650
|
+
if (!normalized) {
|
|
2651
|
+
this.debug("Ignoring empty event trigger name");
|
|
2652
|
+
return;
|
|
2653
|
+
}
|
|
2654
|
+
const candidates = this.popupDefinitions.filter((def) => {
|
|
2655
|
+
return def.triggers.some((trigger) => {
|
|
2656
|
+
const triggerValue = String(trigger.value ?? "").trim();
|
|
2657
|
+
return trigger.type === "event" && triggerValue === normalized;
|
|
2658
|
+
});
|
|
2659
|
+
});
|
|
2660
|
+
if (!candidates.length) {
|
|
2661
|
+
this.debug("No event popup definitions found", { eventName: normalized });
|
|
2662
|
+
return;
|
|
2663
|
+
}
|
|
2664
|
+
const matched = candidates.find((def) => this.shouldShow(def));
|
|
2665
|
+
if (!matched) {
|
|
2666
|
+
this.debug("Event popup blocked by conditions/segments", { eventName: normalized });
|
|
2667
|
+
return;
|
|
2668
|
+
}
|
|
2669
|
+
this.showDefinition(matched);
|
|
2670
|
+
}
|
|
2671
|
+
showDefinition(def) {
|
|
2510
2672
|
this.show(def);
|
|
2511
|
-
this.lastShown.set(def.id, Date.now());
|
|
2512
2673
|
}
|
|
2513
|
-
shouldShow(def) {
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2674
|
+
shouldShow(def, pathUrl, skipPathCheck = false) {
|
|
2675
|
+
if (!skipPathCheck && !this.matchesSegmentsPath(def, pathUrl)) {
|
|
2676
|
+
return false;
|
|
2677
|
+
}
|
|
2678
|
+
const cooldowns = def.cooldown || [];
|
|
2679
|
+
if (cooldowns.length && !cooldowns.every((cooldown) => this.evaluateCooldown(def, cooldown))) {
|
|
2680
|
+
return false;
|
|
2681
|
+
}
|
|
2682
|
+
const legacyConditions = def.legacyConditions || [];
|
|
2683
|
+
if (!legacyConditions.length) return true;
|
|
2684
|
+
return legacyConditions.every((condition) => this.evaluateLegacyCondition(def, condition));
|
|
2517
2685
|
}
|
|
2518
|
-
|
|
2686
|
+
matchesSegmentsPath(def, pathUrl) {
|
|
2687
|
+
const paths = def.segments?.path;
|
|
2688
|
+
if (!paths || paths.length === 0) return true;
|
|
2689
|
+
if (typeof window === "undefined" || !window.location) {
|
|
2690
|
+
this.debug("No window.location available for path comparison", { popupId: def.id, paths });
|
|
2691
|
+
return true;
|
|
2692
|
+
}
|
|
2693
|
+
const normalizedHref = this.normalizeUrl(pathUrl || window.location.href || "");
|
|
2694
|
+
const currentUrl = this.safeParseUrl(normalizedHref);
|
|
2695
|
+
const normalizedPath = this.normalizeUrl(currentUrl?.pathname || window.location.pathname || "");
|
|
2696
|
+
const matches = paths.some((rawCandidate) => {
|
|
2697
|
+
const candidate = this.normalizeUrl(rawCandidate);
|
|
2698
|
+
let match = false;
|
|
2699
|
+
if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
|
|
2700
|
+
match = normalizedHref === candidate;
|
|
2701
|
+
} else if (candidate.startsWith("/")) {
|
|
2702
|
+
match = normalizedHref.includes(candidate);
|
|
2703
|
+
} else {
|
|
2704
|
+
match = normalizedPath === candidate;
|
|
2705
|
+
}
|
|
2706
|
+
this.debug("Path comparison", {
|
|
2707
|
+
popupId: def.id,
|
|
2708
|
+
candidate,
|
|
2709
|
+
currentPath: normalizedPath,
|
|
2710
|
+
currentHref: normalizedHref,
|
|
2711
|
+
match
|
|
2712
|
+
});
|
|
2713
|
+
return match;
|
|
2714
|
+
});
|
|
2715
|
+
if (!matches) {
|
|
2716
|
+
this.debug("No path match for popup", { popupId: def.id, paths, currentPath: normalizedPath });
|
|
2717
|
+
}
|
|
2718
|
+
return matches;
|
|
2719
|
+
}
|
|
2720
|
+
evaluateCooldown(def, condition) {
|
|
2721
|
+
switch (condition.answered) {
|
|
2722
|
+
case "SHOWED":
|
|
2723
|
+
return this.hasCooldownElapsed(this.lastShown.get(def.id), condition.cooldownDays);
|
|
2724
|
+
case "PARTIAL":
|
|
2725
|
+
case "COMPLETED": {
|
|
2726
|
+
const progress = this.surveyProgress.get(def.surveyId);
|
|
2727
|
+
if (!progress || progress.status !== condition.answered) {
|
|
2728
|
+
return true;
|
|
2729
|
+
}
|
|
2730
|
+
return this.hasCooldownElapsed(progress.timestamp, condition.cooldownDays);
|
|
2731
|
+
}
|
|
2732
|
+
default:
|
|
2733
|
+
return true;
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
evaluateLegacyCondition(def, condition) {
|
|
2519
2737
|
if (!condition.answered && this.answeredSurveys.has(def.surveyId)) {
|
|
2520
2738
|
return false;
|
|
2521
2739
|
}
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
if (msSince < required) return false;
|
|
2528
|
-
}
|
|
2740
|
+
return this.hasCooldownElapsed(this.lastShown.get(def.id), condition.cooldownDays);
|
|
2741
|
+
}
|
|
2742
|
+
hasCooldownElapsed(timestamp, cooldownDays) {
|
|
2743
|
+
if (!timestamp || !cooldownDays) {
|
|
2744
|
+
return true;
|
|
2529
2745
|
}
|
|
2530
|
-
return
|
|
2746
|
+
return Date.now() - timestamp >= cooldownDays * DAY_IN_MS;
|
|
2531
2747
|
}
|
|
2532
2748
|
/** Marcar encuesta como contestada externamente */
|
|
2533
2749
|
markSurveyAnswered(surveyId) {
|
|
2534
2750
|
this.answeredSurveys.add(surveyId);
|
|
2751
|
+
this.markSurveyProgress(surveyId, "COMPLETED");
|
|
2752
|
+
}
|
|
2753
|
+
/** Queue an exit popup so it can render after navigation */
|
|
2754
|
+
queueExitPopup(surveyId, delaySeconds, sourceUrl, popupId) {
|
|
2755
|
+
const def = this.findPopupDefinition(surveyId, popupId);
|
|
2756
|
+
if (!def) {
|
|
2757
|
+
this.debug("No popup definition for exit trigger", { surveyId, popupId });
|
|
2758
|
+
return;
|
|
2759
|
+
}
|
|
2760
|
+
const originUrl = sourceUrl || (typeof window !== "undefined" ? window.location.href : "");
|
|
2761
|
+
if (!originUrl) {
|
|
2762
|
+
this.debug("Exit popup skipped: missing source URL", { surveyId });
|
|
2763
|
+
return;
|
|
2764
|
+
}
|
|
2765
|
+
if (!this.shouldShow(def, originUrl)) {
|
|
2766
|
+
this.debug("Exit popup skipped by conditions/path", { popupId: def.id, sourceUrl: originUrl });
|
|
2767
|
+
return;
|
|
2768
|
+
}
|
|
2769
|
+
const safeDelayMs = Number.isFinite(delaySeconds) ? Math.max(0, delaySeconds * 1e3) : 0;
|
|
2770
|
+
const deferred = {
|
|
2771
|
+
id: def.id,
|
|
2772
|
+
surveyId: def.surveyId,
|
|
2773
|
+
sourceUrl: this.normalizeUrl(originUrl),
|
|
2774
|
+
dueAt: Date.now() + safeDelayMs
|
|
2775
|
+
};
|
|
2776
|
+
const queue = this.getDeferredExitQueue().filter((item) => !(item.id === deferred.id && item.sourceUrl === deferred.sourceUrl));
|
|
2777
|
+
queue.push(deferred);
|
|
2778
|
+
this.setDeferredExitQueue(queue);
|
|
2779
|
+
this.scheduleDeferredExitPopup(deferred);
|
|
2780
|
+
this.debug("Exit popup queued", deferred);
|
|
2781
|
+
}
|
|
2782
|
+
processDeferredExitQueue() {
|
|
2783
|
+
const queue = this.getDeferredExitQueue();
|
|
2784
|
+
if (!queue.length) return;
|
|
2785
|
+
const pending = [];
|
|
2786
|
+
const now = Date.now();
|
|
2787
|
+
queue.forEach((item) => {
|
|
2788
|
+
const def = this.popupDefinitions.find((popup) => popup.id === item.id && popup.surveyId === item.surveyId);
|
|
2789
|
+
if (!def) {
|
|
2790
|
+
return;
|
|
2791
|
+
}
|
|
2792
|
+
if (item.dueAt <= now) {
|
|
2793
|
+
this.tryShowDeferredExitPopup(item);
|
|
2794
|
+
return;
|
|
2795
|
+
}
|
|
2796
|
+
pending.push(item);
|
|
2797
|
+
this.scheduleDeferredExitPopup(item);
|
|
2798
|
+
});
|
|
2799
|
+
this.setDeferredExitQueue(pending);
|
|
2800
|
+
}
|
|
2801
|
+
scheduleDeferredExitPopup(item) {
|
|
2802
|
+
if (typeof window === "undefined") return;
|
|
2803
|
+
const delay = Math.max(0, item.dueAt - Date.now());
|
|
2804
|
+
const timer = window.setTimeout(() => this.tryShowDeferredExitPopup(item), delay);
|
|
2805
|
+
this.deferredExitTimers.push(timer);
|
|
2806
|
+
}
|
|
2807
|
+
tryShowDeferredExitPopup(item) {
|
|
2808
|
+
const def = this.popupDefinitions.find((popup) => popup.id === item.id && popup.surveyId === item.surveyId);
|
|
2809
|
+
if (!def) {
|
|
2810
|
+
this.removeDeferredExitPopup(item);
|
|
2811
|
+
return;
|
|
2812
|
+
}
|
|
2813
|
+
const currentUrl = typeof window !== "undefined" ? this.normalizeUrl(window.location.href || "") : "";
|
|
2814
|
+
if (!currentUrl || currentUrl === this.normalizeUrl(item.sourceUrl)) {
|
|
2815
|
+
this.removeDeferredExitPopup(item);
|
|
2816
|
+
this.debug("Exit popup dropped because route did not change", item);
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
if (!this.shouldShow(def, void 0, true)) {
|
|
2820
|
+
this.removeDeferredExitPopup(item);
|
|
2821
|
+
this.debug("Exit popup skipped at render-time conditions", item);
|
|
2822
|
+
return;
|
|
2823
|
+
}
|
|
2824
|
+
this.showDefinition(def);
|
|
2825
|
+
this.removeDeferredExitPopup(item);
|
|
2535
2826
|
}
|
|
2536
|
-
|
|
2827
|
+
findPopupDefinition(surveyId, popupId) {
|
|
2828
|
+
if (popupId) {
|
|
2829
|
+
const byId = this.popupDefinitions.find((popup) => popup.id === popupId);
|
|
2830
|
+
if (byId) return byId;
|
|
2831
|
+
}
|
|
2832
|
+
return this.popupDefinitions.find((popup) => popup.surveyId === surveyId);
|
|
2833
|
+
}
|
|
2834
|
+
removeDeferredExitPopup(item) {
|
|
2835
|
+
const queue = this.getDeferredExitQueue().filter((entry) => !(entry.id === item.id && entry.sourceUrl === item.sourceUrl));
|
|
2836
|
+
this.setDeferredExitQueue(queue);
|
|
2837
|
+
}
|
|
2838
|
+
getDeferredExitQueue() {
|
|
2839
|
+
if (typeof window === "undefined") return [];
|
|
2840
|
+
try {
|
|
2841
|
+
const raw = window.sessionStorage.getItem(EXIT_QUEUE_STORAGE_KEY);
|
|
2842
|
+
if (!raw) return [];
|
|
2843
|
+
const parsed = JSON.parse(raw);
|
|
2844
|
+
if (!Array.isArray(parsed)) return [];
|
|
2845
|
+
return parsed.filter((entry) => {
|
|
2846
|
+
if (typeof entry !== "object" || entry === null) return false;
|
|
2847
|
+
const item = entry;
|
|
2848
|
+
return typeof item.id === "string" && typeof item.surveyId === "string" && typeof item.sourceUrl === "string" && typeof item.dueAt === "number" && Number.isFinite(item.dueAt);
|
|
2849
|
+
}).map((item) => ({
|
|
2850
|
+
...item,
|
|
2851
|
+
sourceUrl: this.normalizeUrl(item.sourceUrl)
|
|
2852
|
+
}));
|
|
2853
|
+
} catch {
|
|
2854
|
+
return [];
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
setDeferredExitQueue(queue) {
|
|
2858
|
+
if (typeof window === "undefined") return;
|
|
2859
|
+
try {
|
|
2860
|
+
if (!queue.length) {
|
|
2861
|
+
window.sessionStorage.removeItem(EXIT_QUEUE_STORAGE_KEY);
|
|
2862
|
+
return;
|
|
2863
|
+
}
|
|
2864
|
+
window.sessionStorage.setItem(EXIT_QUEUE_STORAGE_KEY, JSON.stringify(queue));
|
|
2865
|
+
} catch {
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
/** Fetch al servidor para obtener popups */
|
|
2537
2869
|
async fetchPopupsFromServer() {
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
surveyId: "survey-abc",
|
|
2554
|
-
productId: "product-xyz",
|
|
2555
|
-
style: { theme: "light", position: "bottom-right", imageUrl: null },
|
|
2556
|
-
segments: { lang: ["en"], path: ["/checkout"] }
|
|
2870
|
+
const apiKey = this.config?.apiKey;
|
|
2871
|
+
const baseUrl = this.baseUrl;
|
|
2872
|
+
const userId = this.config?.userId;
|
|
2873
|
+
if (!apiKey || !baseUrl) {
|
|
2874
|
+
this.log("Missing apiKey or baseUrl. Skipping popups fetch.");
|
|
2875
|
+
return [];
|
|
2876
|
+
}
|
|
2877
|
+
const filter = userId ? { where: { userId } } : null;
|
|
2878
|
+
const query = filter ? `?filter=${encodeURIComponent(JSON.stringify(filter))}` : "";
|
|
2879
|
+
const endpoint = `${baseUrl}/sdk/${encodeURIComponent(apiKey)}/popups${query}`;
|
|
2880
|
+
try {
|
|
2881
|
+
const response = await fetch(endpoint);
|
|
2882
|
+
if (!response.ok) {
|
|
2883
|
+
this.log("Failed to fetch popups", response.status, response.statusText);
|
|
2884
|
+
return [];
|
|
2557
2885
|
}
|
|
2558
|
-
|
|
2886
|
+
const raw = await response.text();
|
|
2887
|
+
const parsed = JSON.parse(raw);
|
|
2888
|
+
if (!Array.isArray(parsed)) {
|
|
2889
|
+
this.log("Unexpected popups payload", parsed);
|
|
2890
|
+
return [];
|
|
2891
|
+
}
|
|
2892
|
+
this.debug("Fetched popups payload", parsed);
|
|
2893
|
+
return parsed;
|
|
2894
|
+
} catch (error) {
|
|
2895
|
+
this.log("Error fetching popups", error);
|
|
2896
|
+
return [];
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
/** Notifica eventos de popup a la API */
|
|
2900
|
+
async postPopupEvent(status, popupId, userId) {
|
|
2901
|
+
const apiKey = this.config?.apiKey;
|
|
2902
|
+
const baseUrl = this.baseUrl;
|
|
2903
|
+
if (!apiKey || !baseUrl) {
|
|
2904
|
+
return;
|
|
2905
|
+
}
|
|
2906
|
+
const endpoint = `${baseUrl}/sdk/popups`;
|
|
2907
|
+
try {
|
|
2908
|
+
const response = await fetch(endpoint, {
|
|
2909
|
+
method: "POST",
|
|
2910
|
+
headers: { "Content-Type": "application/json" },
|
|
2911
|
+
body: JSON.stringify({
|
|
2912
|
+
publicKey: apiKey,
|
|
2913
|
+
status,
|
|
2914
|
+
popupId,
|
|
2915
|
+
userId: userId || void 0
|
|
2916
|
+
})
|
|
2917
|
+
});
|
|
2918
|
+
if (!response.ok) {
|
|
2919
|
+
this.log("Failed to post popup event", response.status, response.statusText);
|
|
2920
|
+
}
|
|
2921
|
+
} catch (error) {
|
|
2922
|
+
this.log("Error posting popup event", error);
|
|
2923
|
+
}
|
|
2559
2924
|
}
|
|
2560
2925
|
/** Add an event listener */
|
|
2561
2926
|
on(eventType, listener) {
|
|
@@ -2595,11 +2960,26 @@ var DeepdotsPopups = class {
|
|
|
2595
2960
|
/** Render the popup UI */
|
|
2596
2961
|
renderPopup(surveyId, productId, actions) {
|
|
2597
2962
|
if (this.renderer) {
|
|
2598
|
-
this.renderer.show(
|
|
2963
|
+
this.renderer.show(
|
|
2964
|
+
surveyId,
|
|
2965
|
+
productId,
|
|
2966
|
+
actions,
|
|
2967
|
+
(type, id, payload) => this.emitEvent(type, id, payload),
|
|
2968
|
+
() => this.hidePopup(),
|
|
2969
|
+
this.env
|
|
2970
|
+
);
|
|
2599
2971
|
return;
|
|
2600
2972
|
}
|
|
2601
2973
|
if (!this.popupContainer) return;
|
|
2602
|
-
renderPopup(
|
|
2974
|
+
renderPopup(
|
|
2975
|
+
this.popupContainer,
|
|
2976
|
+
surveyId,
|
|
2977
|
+
productId,
|
|
2978
|
+
actions,
|
|
2979
|
+
(type, id, payload) => this.emitEvent(type, id, payload),
|
|
2980
|
+
() => this.hidePopup(),
|
|
2981
|
+
this.env
|
|
2982
|
+
);
|
|
2603
2983
|
}
|
|
2604
2984
|
/** Hide the popup */
|
|
2605
2985
|
hidePopup() {
|
|
@@ -2616,9 +2996,22 @@ var DeepdotsPopups = class {
|
|
|
2616
2996
|
emitEvent(type, surveyId, data) {
|
|
2617
2997
|
const event = { type, surveyId, timestamp: Date.now(), data };
|
|
2618
2998
|
this.log("Event emitted", event);
|
|
2999
|
+
if (type === "popup_clicked" && data?.action === "partial") {
|
|
3000
|
+
this.markSurveyProgress(surveyId, "PARTIAL");
|
|
3001
|
+
}
|
|
2619
3002
|
if (type === "survey_completed") {
|
|
2620
3003
|
this.markSurveyAnswered(surveyId);
|
|
2621
3004
|
}
|
|
3005
|
+
if (type === "popup_shown" || type === "survey_completed") {
|
|
3006
|
+
const popupIdFromData = data?.popupId;
|
|
3007
|
+
const popupId = popupIdFromData || this.surveyToPopupId.get(surveyId);
|
|
3008
|
+
if (popupId) {
|
|
3009
|
+
const userIdFromData = data?.userId;
|
|
3010
|
+
void this.postPopupEvent(type === "popup_shown" ? "opened" : "completed", popupId, userIdFromData || this.config?.userId);
|
|
3011
|
+
} else {
|
|
3012
|
+
this.debug("No popupId available to post event", { type, surveyId });
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
2622
3015
|
const listeners = this.listeners.get(type);
|
|
2623
3016
|
if (listeners) {
|
|
2624
3017
|
listeners.forEach((listener) => {
|
|
@@ -2647,14 +3040,107 @@ var DeepdotsPopups = class {
|
|
|
2647
3040
|
this.renderer.init();
|
|
2648
3041
|
}
|
|
2649
3042
|
}
|
|
2650
|
-
|
|
3043
|
+
normalizeUrl(value) {
|
|
3044
|
+
if (!value) return "";
|
|
3045
|
+
const withoutIndex = value.replace(/\/index\.html(?=($|[?#]))/i, "");
|
|
3046
|
+
return withoutIndex.length > 1 && withoutIndex.endsWith("/") ? withoutIndex.slice(0, -1) : withoutIndex;
|
|
3047
|
+
}
|
|
3048
|
+
safeParseUrl(url) {
|
|
3049
|
+
if (!url) return null;
|
|
3050
|
+
try {
|
|
3051
|
+
return new URL(url, typeof window !== "undefined" ? window.location.href : void 0);
|
|
3052
|
+
} catch {
|
|
3053
|
+
return null;
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
mapPopupTriggerType(type) {
|
|
3057
|
+
switch (type) {
|
|
3058
|
+
case "time_on_page":
|
|
3059
|
+
return "time";
|
|
3060
|
+
case "scroll":
|
|
3061
|
+
return "scroll";
|
|
3062
|
+
case "exit":
|
|
3063
|
+
return "exit";
|
|
3064
|
+
case "click":
|
|
3065
|
+
return "click";
|
|
3066
|
+
case "event":
|
|
3067
|
+
return "event";
|
|
3068
|
+
default:
|
|
3069
|
+
return null;
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
markSurveyProgress(surveyId, status) {
|
|
3073
|
+
const current = this.surveyProgress.get(surveyId);
|
|
3074
|
+
if (current?.status === "COMPLETED" && status !== "COMPLETED") {
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3077
|
+
this.surveyProgress.set(surveyId, { status, timestamp: Date.now() });
|
|
3078
|
+
}
|
|
2651
3079
|
isPopupDefinition(value) {
|
|
2652
3080
|
if (typeof value !== "object" || value === null) return false;
|
|
2653
|
-
const
|
|
2654
|
-
return typeof
|
|
3081
|
+
const popup = value;
|
|
3082
|
+
return typeof popup.id === "string" && typeof popup.title === "string" && typeof popup.message === "string" && typeof popup.surveyId === "string" && typeof popup.productId === "string" && Array.isArray(popup.triggers) && popup.triggers.length > 0 && popup.triggers.every((trigger) => this.isPopupTrigger(trigger)) && (!popup.cooldown || popup.cooldown.every((condition) => this.isPopupTriggerCondition(condition)));
|
|
3083
|
+
}
|
|
3084
|
+
isPopupTrigger(value) {
|
|
3085
|
+
if (typeof value !== "object" || value === null) return false;
|
|
3086
|
+
const trigger = value;
|
|
3087
|
+
return this.isPopupTriggerType(trigger.type) && (typeof trigger.value === "number" || typeof trigger.value === "string");
|
|
3088
|
+
}
|
|
3089
|
+
isPopupTriggerType(value) {
|
|
3090
|
+
return value === "time_on_page" || value === "scroll" || value === "exit" || value === "click" || value === "event";
|
|
3091
|
+
}
|
|
3092
|
+
isPopupTriggerCondition(value) {
|
|
3093
|
+
if (typeof value !== "object" || value === null) return false;
|
|
3094
|
+
const condition = value;
|
|
3095
|
+
return POPUP_TRIGGER_CONDITION_STATUSES.includes(condition.answered) && typeof condition.cooldownDays === "number" && Number.isFinite(condition.cooldownDays) && condition.cooldownDays >= 0;
|
|
3096
|
+
}
|
|
3097
|
+
isLegacyPopupTriggerCondition(value) {
|
|
3098
|
+
if (typeof value !== "object" || value === null) return false;
|
|
3099
|
+
const condition = value;
|
|
3100
|
+
if (condition.answered !== void 0 && typeof condition.answered !== "boolean") {
|
|
3101
|
+
return false;
|
|
3102
|
+
}
|
|
3103
|
+
if (condition.cooldownDays !== void 0) {
|
|
3104
|
+
return typeof condition.cooldownDays === "number" && Number.isFinite(condition.cooldownDays) && condition.cooldownDays >= 0;
|
|
3105
|
+
}
|
|
3106
|
+
return true;
|
|
3107
|
+
}
|
|
3108
|
+
normalizeTriggers(value) {
|
|
3109
|
+
const items = Array.isArray(value) ? value : value ? [value] : [];
|
|
3110
|
+
return items.filter((trigger) => this.isPopupTrigger(trigger)).map((trigger) => ({
|
|
3111
|
+
type: trigger.type,
|
|
3112
|
+
value: trigger.value
|
|
3113
|
+
}));
|
|
3114
|
+
}
|
|
3115
|
+
normalizeCooldown(value) {
|
|
3116
|
+
if (!Array.isArray(value)) return [];
|
|
3117
|
+
return value.filter((condition) => this.isPopupTriggerCondition(condition));
|
|
3118
|
+
}
|
|
3119
|
+
normalizeLegacyConditions(value) {
|
|
3120
|
+
if (!Array.isArray(value)) return [];
|
|
3121
|
+
return value.filter((condition) => this.isLegacyPopupTriggerCondition(condition));
|
|
3122
|
+
}
|
|
3123
|
+
normalizePopupDefinition(def) {
|
|
3124
|
+
if (typeof def !== "object" || def === null) return null;
|
|
3125
|
+
const raw = def;
|
|
3126
|
+
const rawTriggers = raw.triggers ?? raw.trigger;
|
|
3127
|
+
const triggers = this.normalizeTriggers(rawTriggers);
|
|
3128
|
+
if (!triggers.length) return null;
|
|
3129
|
+
const rawTriggerList = Array.isArray(rawTriggers) ? rawTriggers : rawTriggers ? [rawTriggers] : [];
|
|
3130
|
+
const legacyConditions = [
|
|
3131
|
+
...this.normalizeLegacyConditions(raw.conditions),
|
|
3132
|
+
...rawTriggerList.flatMap((trigger) => this.normalizeLegacyConditions(trigger.condition))
|
|
3133
|
+
];
|
|
3134
|
+
const cooldown = this.normalizeCooldown(raw.cooldown);
|
|
3135
|
+
return {
|
|
3136
|
+
...raw,
|
|
3137
|
+
triggers,
|
|
3138
|
+
cooldown,
|
|
3139
|
+
legacyConditions
|
|
3140
|
+
};
|
|
2655
3141
|
}
|
|
2656
3142
|
validatePopupDefinitions(defs) {
|
|
2657
|
-
return defs.filter((
|
|
3143
|
+
return defs.map((def) => this.normalizePopupDefinition(def)).filter((def) => !!def && this.isPopupDefinition(def));
|
|
2658
3144
|
}
|
|
2659
3145
|
};
|
|
2660
3146
|
//# sourceMappingURL=index.js.map
|