@zaplier/sdk 1.6.8 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +404 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +18 -0
- package/dist/index.esm.js +404 -84
- package/dist/index.esm.js.map +1 -1
- package/dist/sdk.js +404 -84
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.min.js +1 -1
- package/dist/src/modules/auto-tracker.d.ts +59 -11
- package/dist/src/modules/auto-tracker.d.ts.map +1 -1
- package/dist/src/modules/global-interface.d.ts +2 -0
- package/dist/src/modules/global-interface.d.ts.map +1 -1
- package/dist/src/sdk.d.ts +16 -0
- package/dist/src/sdk.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -19266,6 +19266,8 @@ class AutoTracker {
|
|
|
19266
19266
|
constructor(sdkInstance, config = {}) {
|
|
19267
19267
|
this.observedElements = new Set();
|
|
19268
19268
|
this.scrollThrottle = 0;
|
|
19269
|
+
this.isInitialized = false;
|
|
19270
|
+
this.delegationHandlers = new Map();
|
|
19269
19271
|
this.handleScroll = () => {
|
|
19270
19272
|
if (!this.config.trackScrolls)
|
|
19271
19273
|
return;
|
|
@@ -19276,7 +19278,10 @@ class AutoTracker {
|
|
|
19276
19278
|
this.scrollThrottle = now;
|
|
19277
19279
|
const scrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
19278
19280
|
if (this.config.debug && scrollElements.length > 0) {
|
|
19279
|
-
console.log(`[AutoTracker] Checking ${scrollElements.length} scroll elements
|
|
19281
|
+
console.log(`[AutoTracker] Checking ${scrollElements.length} scroll elements`, {
|
|
19282
|
+
scrollY: window.scrollY,
|
|
19283
|
+
innerHeight: window.innerHeight
|
|
19284
|
+
});
|
|
19280
19285
|
}
|
|
19281
19286
|
scrollElements.forEach((element) => {
|
|
19282
19287
|
let hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
|
|
@@ -19320,6 +19325,28 @@ class AutoTracker {
|
|
|
19320
19325
|
}
|
|
19321
19326
|
});
|
|
19322
19327
|
};
|
|
19328
|
+
this.handleClick = (event) => {
|
|
19329
|
+
if (!this.config.trackClicks)
|
|
19330
|
+
return;
|
|
19331
|
+
const target = event.target;
|
|
19332
|
+
if (!target || !target.hasAttribute("data-track-click"))
|
|
19333
|
+
return;
|
|
19334
|
+
const eventName = target.getAttribute("data-track-click");
|
|
19335
|
+
if (!eventName)
|
|
19336
|
+
return;
|
|
19337
|
+
const metadata = this.extractMetadata(target);
|
|
19338
|
+
this.trackEvent(eventName, {
|
|
19339
|
+
type: "click",
|
|
19340
|
+
element: target.tagName.toLowerCase(),
|
|
19341
|
+
...metadata,
|
|
19342
|
+
});
|
|
19343
|
+
if (this.config.debug) {
|
|
19344
|
+
console.log(`[AutoTracker] Click tracked: ${eventName}`, {
|
|
19345
|
+
element: target.tagName.toLowerCase(),
|
|
19346
|
+
...metadata
|
|
19347
|
+
});
|
|
19348
|
+
}
|
|
19349
|
+
};
|
|
19323
19350
|
this.sdkInstance = sdkInstance;
|
|
19324
19351
|
this.config = {
|
|
19325
19352
|
enabled: true,
|
|
@@ -19345,9 +19372,30 @@ class AutoTracker {
|
|
|
19345
19372
|
trackScrolls: this.config.trackScrolls,
|
|
19346
19373
|
trackViews: this.config.trackViews,
|
|
19347
19374
|
trackHovers: this.config.trackHovers,
|
|
19348
|
-
trackForms: this.config.trackForms
|
|
19375
|
+
trackForms: this.config.trackForms,
|
|
19376
|
+
domReady: document.readyState
|
|
19349
19377
|
});
|
|
19350
19378
|
}
|
|
19379
|
+
// Aguardar DOM ready se necessário
|
|
19380
|
+
if (document.readyState === 'loading') {
|
|
19381
|
+
if (this.config.debug) {
|
|
19382
|
+
console.log("[Zaplier AutoTracker] DOM still loading, waiting for DOMContentLoaded...");
|
|
19383
|
+
}
|
|
19384
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
19385
|
+
if (this.config.debug) {
|
|
19386
|
+
console.log("[Zaplier AutoTracker] DOMContentLoaded fired, initializing tracking...");
|
|
19387
|
+
}
|
|
19388
|
+
this.initializeTracking();
|
|
19389
|
+
}, { once: true });
|
|
19390
|
+
}
|
|
19391
|
+
else {
|
|
19392
|
+
this.initializeTracking();
|
|
19393
|
+
}
|
|
19394
|
+
}
|
|
19395
|
+
initializeTracking() {
|
|
19396
|
+
if (this.config.debug) {
|
|
19397
|
+
console.log("[Zaplier AutoTracker] Initializing tracking...");
|
|
19398
|
+
}
|
|
19351
19399
|
// Observer para novos elementos no DOM
|
|
19352
19400
|
this.observeDOM();
|
|
19353
19401
|
// Processar elementos já existentes
|
|
@@ -19356,38 +19404,269 @@ class AutoTracker {
|
|
|
19356
19404
|
if (this.config.trackViews) {
|
|
19357
19405
|
this.setupViewTracking();
|
|
19358
19406
|
}
|
|
19359
|
-
// Setup
|
|
19407
|
+
// Setup event delegation (modern approach)
|
|
19408
|
+
this.setupEventDelegation();
|
|
19409
|
+
// Debug: Log elementos encontrados após inicialização
|
|
19410
|
+
if (this.config.debug) {
|
|
19411
|
+
this.logFoundElements();
|
|
19412
|
+
// Também agendar uma verificação após delay para elementos React
|
|
19413
|
+
setTimeout(() => {
|
|
19414
|
+
console.log("[Zaplier AutoTracker] Re-checking elements after 500ms...");
|
|
19415
|
+
this.logFoundElements();
|
|
19416
|
+
}, 500);
|
|
19417
|
+
setTimeout(() => {
|
|
19418
|
+
console.log("[Zaplier AutoTracker] Re-checking elements after 2s...");
|
|
19419
|
+
this.logFoundElements();
|
|
19420
|
+
}, 2000);
|
|
19421
|
+
}
|
|
19422
|
+
}
|
|
19423
|
+
logFoundElements() {
|
|
19424
|
+
const clickElements = document.querySelectorAll('[data-track-click]');
|
|
19425
|
+
const scrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
19426
|
+
const viewElements = document.querySelectorAll('[data-track-view]');
|
|
19427
|
+
const hoverElements = document.querySelectorAll('[data-track-hover]');
|
|
19428
|
+
const formElements = document.querySelectorAll('[data-track-form]');
|
|
19429
|
+
console.log("[Zaplier AutoTracker] Elementos encontrados:", {
|
|
19430
|
+
clickElements: clickElements.length,
|
|
19431
|
+
scrollElements: scrollElements.length,
|
|
19432
|
+
viewElements: viewElements.length,
|
|
19433
|
+
hoverElements: hoverElements.length,
|
|
19434
|
+
formElements: formElements.length,
|
|
19435
|
+
totalElements: clickElements.length + scrollElements.length + viewElements.length + hoverElements.length + formElements.length
|
|
19436
|
+
});
|
|
19437
|
+
if (scrollElements.length > 0) {
|
|
19438
|
+
console.log("[Zaplier AutoTracker] Elementos de scroll:", Array.from(scrollElements).map(el => ({
|
|
19439
|
+
tagName: el.tagName,
|
|
19440
|
+
trackEvent: el.getAttribute('data-track-scroll'),
|
|
19441
|
+
threshold: el.getAttribute('data-scroll-threshold') || '0.5',
|
|
19442
|
+
id: el.id || 'no-id',
|
|
19443
|
+
classes: el.className || 'no-classes'
|
|
19444
|
+
})));
|
|
19445
|
+
}
|
|
19446
|
+
}
|
|
19447
|
+
/**
|
|
19448
|
+
* Setup Event Delegation (Industry Best Practice)
|
|
19449
|
+
* Uses single document-level listeners instead of individual element listeners
|
|
19450
|
+
*/
|
|
19451
|
+
setupEventDelegation() {
|
|
19452
|
+
if (this.config.debug) {
|
|
19453
|
+
console.log("[AutoTracker] Setting up event delegation...");
|
|
19454
|
+
}
|
|
19455
|
+
// Click delegation
|
|
19456
|
+
if (this.config.trackClicks) {
|
|
19457
|
+
const clickHandler = this.createDelegatedClickHandler();
|
|
19458
|
+
this.delegationHandlers.set('click', clickHandler);
|
|
19459
|
+
document.addEventListener('click', clickHandler, { passive: true });
|
|
19460
|
+
}
|
|
19461
|
+
// Scroll delegation (using global handler with element detection)
|
|
19360
19462
|
if (this.config.trackScrolls) {
|
|
19361
|
-
|
|
19463
|
+
const scrollHandler = this.createDelegatedScrollHandler();
|
|
19464
|
+
this.delegationHandlers.set('scroll', scrollHandler);
|
|
19465
|
+
document.addEventListener('scroll', scrollHandler, { passive: true });
|
|
19362
19466
|
}
|
|
19467
|
+
// Setup debounced mutation observer for dynamic content
|
|
19468
|
+
this.setupIntelligentMutationObserver();
|
|
19469
|
+
this.isInitialized = true;
|
|
19363
19470
|
}
|
|
19364
19471
|
/**
|
|
19365
|
-
*
|
|
19472
|
+
* Create delegated click handler (no individual listeners needed)
|
|
19366
19473
|
*/
|
|
19367
|
-
|
|
19368
|
-
|
|
19369
|
-
|
|
19370
|
-
this.
|
|
19474
|
+
createDelegatedClickHandler() {
|
|
19475
|
+
return (event) => {
|
|
19476
|
+
const target = event.target;
|
|
19477
|
+
if (!target || !this.config.trackClicks)
|
|
19478
|
+
return;
|
|
19479
|
+
// Check if target or any parent has data-track-click
|
|
19480
|
+
const trackingElement = target.closest('[data-track-click]');
|
|
19481
|
+
if (!trackingElement)
|
|
19482
|
+
return;
|
|
19483
|
+
const eventName = trackingElement.getAttribute('data-track-click');
|
|
19484
|
+
if (!eventName)
|
|
19485
|
+
return;
|
|
19486
|
+
const metadata = this.extractMetadata(trackingElement);
|
|
19487
|
+
this.trackEvent(eventName, {
|
|
19488
|
+
type: 'click',
|
|
19489
|
+
element: trackingElement.tagName.toLowerCase(),
|
|
19490
|
+
...metadata,
|
|
19491
|
+
});
|
|
19492
|
+
if (this.config.debug) {
|
|
19493
|
+
console.log(`[AutoTracker] Click tracked via delegation: ${eventName}`, {
|
|
19494
|
+
element: trackingElement.tagName.toLowerCase(),
|
|
19495
|
+
...metadata
|
|
19496
|
+
});
|
|
19497
|
+
}
|
|
19498
|
+
};
|
|
19499
|
+
}
|
|
19500
|
+
/**
|
|
19501
|
+
* Create delegated scroll handler (efficient global approach)
|
|
19502
|
+
*/
|
|
19503
|
+
createDelegatedScrollHandler() {
|
|
19504
|
+
return () => {
|
|
19505
|
+
if (!this.config.trackScrolls)
|
|
19506
|
+
return;
|
|
19507
|
+
// Throttle scroll events for performance
|
|
19508
|
+
const now = Date.now();
|
|
19509
|
+
if (now - this.scrollThrottle < 100)
|
|
19510
|
+
return;
|
|
19511
|
+
this.scrollThrottle = now;
|
|
19512
|
+
// Find all scroll tracking elements and check visibility
|
|
19513
|
+
const scrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
19514
|
+
if (this.config.debug && scrollElements.length > 0) {
|
|
19515
|
+
console.log(`[AutoTracker] Checking ${scrollElements.length} scroll elements via delegation`);
|
|
19516
|
+
}
|
|
19517
|
+
scrollElements.forEach((element) => {
|
|
19518
|
+
this.processScrollElement(element);
|
|
19519
|
+
});
|
|
19520
|
+
};
|
|
19521
|
+
}
|
|
19522
|
+
/**
|
|
19523
|
+
* Process individual scroll element (extracted for reusability)
|
|
19524
|
+
*/
|
|
19525
|
+
processScrollElement(element) {
|
|
19526
|
+
const hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
|
|
19527
|
+
if (hasTriggered)
|
|
19528
|
+
return;
|
|
19529
|
+
const threshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
|
|
19530
|
+
const rect = element.getBoundingClientRect();
|
|
19531
|
+
const elementHeight = rect.height;
|
|
19532
|
+
const visibleHeight = Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0);
|
|
19533
|
+
const visibilityRatio = Math.max(0, visibleHeight) / elementHeight;
|
|
19534
|
+
if (this.config.debug) {
|
|
19535
|
+
console.log(`[AutoTracker] Scroll element check via delegation:`, {
|
|
19536
|
+
elementId: element.id || element.className,
|
|
19537
|
+
visibilityRatio: Math.round(visibilityRatio * 100) / 100,
|
|
19538
|
+
threshold,
|
|
19539
|
+
triggered: hasTriggered
|
|
19540
|
+
});
|
|
19541
|
+
}
|
|
19542
|
+
if (visibilityRatio >= threshold) {
|
|
19543
|
+
element.setAttribute('data-scroll-triggered', 'true');
|
|
19544
|
+
const eventName = element.getAttribute('data-track-scroll');
|
|
19545
|
+
if (!eventName)
|
|
19546
|
+
return;
|
|
19547
|
+
const metadata = this.extractMetadata(element);
|
|
19548
|
+
this.trackEvent(eventName, {
|
|
19549
|
+
type: 'scroll',
|
|
19550
|
+
element: element.tagName.toLowerCase(),
|
|
19551
|
+
threshold,
|
|
19552
|
+
scrollDepth: window.scrollY,
|
|
19553
|
+
visibilityRatio: Math.round(visibilityRatio * 100) / 100,
|
|
19554
|
+
...metadata,
|
|
19555
|
+
});
|
|
19556
|
+
if (this.config.debug) {
|
|
19557
|
+
console.log(`[AutoTracker] Scroll tracked via delegation: ${eventName}`, {
|
|
19558
|
+
threshold,
|
|
19559
|
+
visibilityRatio,
|
|
19560
|
+
scrollDepth: window.scrollY,
|
|
19561
|
+
...metadata
|
|
19562
|
+
});
|
|
19563
|
+
}
|
|
19371
19564
|
}
|
|
19372
|
-
this.observedElements.clear();
|
|
19373
19565
|
}
|
|
19374
19566
|
/**
|
|
19375
|
-
*
|
|
19567
|
+
* Setup intelligent mutation observer (debounced for performance)
|
|
19376
19568
|
*/
|
|
19377
|
-
|
|
19378
|
-
|
|
19379
|
-
|
|
19380
|
-
|
|
19569
|
+
setupIntelligentMutationObserver() {
|
|
19570
|
+
if (this.mutationObserver)
|
|
19571
|
+
return; // Already setup
|
|
19572
|
+
const debouncedCallback = this.debounce((mutations) => {
|
|
19573
|
+
let hasRelevantChanges = false;
|
|
19574
|
+
mutations.forEach(mutation => {
|
|
19575
|
+
mutation.addedNodes.forEach(node => {
|
|
19381
19576
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
19382
|
-
|
|
19577
|
+
const element = node;
|
|
19578
|
+
if (this.hasTrackingAttributes(element) || this.hasTrackingDescendants(element)) {
|
|
19579
|
+
hasRelevantChanges = true;
|
|
19580
|
+
if (this.config.debug) {
|
|
19581
|
+
console.log('[AutoTracker] New trackable element detected via mutation observer:', element);
|
|
19582
|
+
}
|
|
19583
|
+
}
|
|
19383
19584
|
}
|
|
19384
19585
|
});
|
|
19385
19586
|
});
|
|
19386
|
-
|
|
19387
|
-
|
|
19587
|
+
if (hasRelevantChanges) {
|
|
19588
|
+
if (this.config.debug) {
|
|
19589
|
+
console.log('[AutoTracker] Processing new elements from mutations...');
|
|
19590
|
+
}
|
|
19591
|
+
// Process elements for view tracking (only thing that needs setup)
|
|
19592
|
+
this.processExistingElements();
|
|
19593
|
+
}
|
|
19594
|
+
}, 150);
|
|
19595
|
+
this.mutationObserver = new MutationObserver(debouncedCallback);
|
|
19596
|
+
this.mutationObserver.observe(document.body, {
|
|
19388
19597
|
childList: true,
|
|
19389
19598
|
subtree: true,
|
|
19390
19599
|
});
|
|
19600
|
+
if (this.config.debug) {
|
|
19601
|
+
console.log('[AutoTracker] Intelligent mutation observer setup complete');
|
|
19602
|
+
}
|
|
19603
|
+
}
|
|
19604
|
+
/**
|
|
19605
|
+
* Check if element has tracking attributes
|
|
19606
|
+
*/
|
|
19607
|
+
hasTrackingAttributes(element) {
|
|
19608
|
+
return element.hasAttribute && (element.hasAttribute('data-track-click') ||
|
|
19609
|
+
element.hasAttribute('data-track-scroll') ||
|
|
19610
|
+
element.hasAttribute('data-track-view') ||
|
|
19611
|
+
element.hasAttribute('data-track-hover') ||
|
|
19612
|
+
element.hasAttribute('data-track-form'));
|
|
19613
|
+
}
|
|
19614
|
+
/**
|
|
19615
|
+
* Check if element has tracking descendants
|
|
19616
|
+
*/
|
|
19617
|
+
hasTrackingDescendants(element) {
|
|
19618
|
+
if (!element.querySelector)
|
|
19619
|
+
return false;
|
|
19620
|
+
return !!(element.querySelector('[data-track-click]') ||
|
|
19621
|
+
element.querySelector('[data-track-scroll]') ||
|
|
19622
|
+
element.querySelector('[data-track-view]') ||
|
|
19623
|
+
element.querySelector('[data-track-hover]') ||
|
|
19624
|
+
element.querySelector('[data-track-form]'));
|
|
19625
|
+
}
|
|
19626
|
+
/**
|
|
19627
|
+
* Utility: Debounce function for performance optimization
|
|
19628
|
+
*/
|
|
19629
|
+
debounce(func, wait) {
|
|
19630
|
+
let timeout;
|
|
19631
|
+
return (...args) => {
|
|
19632
|
+
clearTimeout(timeout);
|
|
19633
|
+
timeout = setTimeout(() => func.apply(this, args), wait);
|
|
19634
|
+
};
|
|
19635
|
+
}
|
|
19636
|
+
/**
|
|
19637
|
+
* Parar auto tracking (with proper cleanup)
|
|
19638
|
+
*/
|
|
19639
|
+
stop() {
|
|
19640
|
+
if (this.config.debug) {
|
|
19641
|
+
console.log('[AutoTracker] Stopping auto tracking and cleaning up...');
|
|
19642
|
+
}
|
|
19643
|
+
// Remove delegation handlers
|
|
19644
|
+
this.delegationHandlers.forEach((handler, eventType) => {
|
|
19645
|
+
document.removeEventListener(eventType, handler);
|
|
19646
|
+
});
|
|
19647
|
+
this.delegationHandlers.clear();
|
|
19648
|
+
// Disconnect observers
|
|
19649
|
+
if (this.intersectionObserver) {
|
|
19650
|
+
this.intersectionObserver.disconnect();
|
|
19651
|
+
this.intersectionObserver = undefined;
|
|
19652
|
+
}
|
|
19653
|
+
if (this.mutationObserver) {
|
|
19654
|
+
this.mutationObserver.disconnect();
|
|
19655
|
+
this.mutationObserver = undefined;
|
|
19656
|
+
}
|
|
19657
|
+
// Clear caches
|
|
19658
|
+
this.observedElements.clear();
|
|
19659
|
+
this.isInitialized = false;
|
|
19660
|
+
}
|
|
19661
|
+
/**
|
|
19662
|
+
* Legacy method - now handled by intelligent mutation observer
|
|
19663
|
+
* @deprecated Use setupIntelligentMutationObserver instead
|
|
19664
|
+
*/
|
|
19665
|
+
observeDOM() {
|
|
19666
|
+
// This is now handled by setupIntelligentMutationObserver in setupEventDelegation
|
|
19667
|
+
if (this.config.debug) {
|
|
19668
|
+
console.log('[AutoTracker] observeDOM() is deprecated - using intelligent mutation observer');
|
|
19669
|
+
}
|
|
19391
19670
|
}
|
|
19392
19671
|
/**
|
|
19393
19672
|
* Processar elementos já existentes no DOM
|
|
@@ -19403,14 +19682,8 @@ class AutoTracker {
|
|
|
19403
19682
|
* Processar um elemento específico
|
|
19404
19683
|
*/
|
|
19405
19684
|
processElement(element) {
|
|
19406
|
-
// Click tracking
|
|
19407
|
-
|
|
19408
|
-
this.setupClickTracking(element);
|
|
19409
|
-
}
|
|
19410
|
-
// Scroll tracking
|
|
19411
|
-
if (this.config.trackScrolls && element.hasAttribute("data-track-scroll")) {
|
|
19412
|
-
this.setupScrollTracking(element);
|
|
19413
|
-
}
|
|
19685
|
+
// Click tracking - handled by global listener
|
|
19686
|
+
// Scroll tracking - handled by global listener
|
|
19414
19687
|
// View tracking
|
|
19415
19688
|
if (this.config.trackViews && element.hasAttribute("data-track-view")) {
|
|
19416
19689
|
this.setupElementViewTracking(element);
|
|
@@ -19424,60 +19697,6 @@ class AutoTracker {
|
|
|
19424
19697
|
this.setupFormTracking(element);
|
|
19425
19698
|
}
|
|
19426
19699
|
}
|
|
19427
|
-
/**
|
|
19428
|
-
* Setup click tracking
|
|
19429
|
-
*/
|
|
19430
|
-
setupClickTracking(element) {
|
|
19431
|
-
element.addEventListener("click", (event) => {
|
|
19432
|
-
const eventName = element.getAttribute("data-track-click");
|
|
19433
|
-
if (!eventName)
|
|
19434
|
-
return;
|
|
19435
|
-
const metadata = this.extractMetadata(element);
|
|
19436
|
-
this.trackEvent(eventName, {
|
|
19437
|
-
type: "click",
|
|
19438
|
-
element: element.tagName.toLowerCase(),
|
|
19439
|
-
...metadata,
|
|
19440
|
-
});
|
|
19441
|
-
if (this.config.debug) {
|
|
19442
|
-
console.log(`[AutoTracker] Click tracked: ${eventName}`, metadata);
|
|
19443
|
-
}
|
|
19444
|
-
});
|
|
19445
|
-
}
|
|
19446
|
-
/**
|
|
19447
|
-
* Setup scroll tracking
|
|
19448
|
-
*/
|
|
19449
|
-
setupScrollTracking(element) {
|
|
19450
|
-
let hasTriggered = false;
|
|
19451
|
-
const threshold = parseFloat(element.getAttribute("data-scroll-threshold") || "0.5");
|
|
19452
|
-
const handleScroll = () => {
|
|
19453
|
-
if (hasTriggered)
|
|
19454
|
-
return;
|
|
19455
|
-
const rect = element.getBoundingClientRect();
|
|
19456
|
-
const elementHeight = rect.height;
|
|
19457
|
-
const visibleHeight = Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0);
|
|
19458
|
-
const visibilityRatio = Math.max(0, visibleHeight) / elementHeight;
|
|
19459
|
-
if (visibilityRatio >= threshold) {
|
|
19460
|
-
hasTriggered = true;
|
|
19461
|
-
const eventName = element.getAttribute("data-track-scroll");
|
|
19462
|
-
if (!eventName)
|
|
19463
|
-
return;
|
|
19464
|
-
const metadata = this.extractMetadata(element);
|
|
19465
|
-
this.trackEvent(eventName, {
|
|
19466
|
-
type: "scroll",
|
|
19467
|
-
element: element.tagName.toLowerCase(),
|
|
19468
|
-
threshold,
|
|
19469
|
-
scrollDepth: window.scrollY,
|
|
19470
|
-
...metadata,
|
|
19471
|
-
});
|
|
19472
|
-
if (this.config.debug) {
|
|
19473
|
-
console.log(`[AutoTracker] Scroll tracked: ${eventName}`, metadata);
|
|
19474
|
-
}
|
|
19475
|
-
}
|
|
19476
|
-
};
|
|
19477
|
-
document.addEventListener("scroll", handleScroll, { passive: true });
|
|
19478
|
-
// Check immediately in case element is already in view
|
|
19479
|
-
setTimeout(handleScroll, 100);
|
|
19480
|
-
}
|
|
19481
19700
|
/**
|
|
19482
19701
|
* Setup view tracking usando Intersection Observer
|
|
19483
19702
|
*/
|
|
@@ -19635,15 +19854,35 @@ class AutoTracker {
|
|
|
19635
19854
|
* Enviar evento para o SDK
|
|
19636
19855
|
*/
|
|
19637
19856
|
trackEvent(eventName, metadata) {
|
|
19638
|
-
if (
|
|
19857
|
+
if (this.config.debug) {
|
|
19858
|
+
console.log("[AutoTracker] trackEvent called:", { eventName, metadata });
|
|
19859
|
+
}
|
|
19860
|
+
if (!this.sdkInstance) {
|
|
19861
|
+
if (this.config.debug) {
|
|
19862
|
+
console.error("[AutoTracker] SDK instance is null!");
|
|
19863
|
+
}
|
|
19639
19864
|
return;
|
|
19865
|
+
}
|
|
19866
|
+
if (typeof this.sdkInstance.trackCustomEvent !== 'function') {
|
|
19867
|
+
if (this.config.debug) {
|
|
19868
|
+
console.error("[AutoTracker] trackCustomEvent is not a function:", typeof this.sdkInstance.trackCustomEvent);
|
|
19869
|
+
}
|
|
19870
|
+
return;
|
|
19871
|
+
}
|
|
19640
19872
|
try {
|
|
19641
|
-
|
|
19873
|
+
const eventData = {
|
|
19642
19874
|
autoTracked: true,
|
|
19643
19875
|
timestamp: Date.now(),
|
|
19644
19876
|
url: window.location.href,
|
|
19645
19877
|
...metadata,
|
|
19646
|
-
}
|
|
19878
|
+
};
|
|
19879
|
+
if (this.config.debug) {
|
|
19880
|
+
console.log("[AutoTracker] Calling trackCustomEvent:", { eventName, eventData });
|
|
19881
|
+
}
|
|
19882
|
+
const result = this.sdkInstance.trackCustomEvent(eventName, eventData);
|
|
19883
|
+
if (this.config.debug) {
|
|
19884
|
+
console.log("[AutoTracker] trackCustomEvent result:", result);
|
|
19885
|
+
}
|
|
19647
19886
|
}
|
|
19648
19887
|
catch (error) {
|
|
19649
19888
|
if (this.config.debug) {
|
|
@@ -19651,6 +19890,55 @@ class AutoTracker {
|
|
|
19651
19890
|
}
|
|
19652
19891
|
}
|
|
19653
19892
|
}
|
|
19893
|
+
/**
|
|
19894
|
+
* Modern API: Refresh tracking for dynamic content (React/SPA support)
|
|
19895
|
+
* Industry best practice for SPA route changes
|
|
19896
|
+
*/
|
|
19897
|
+
refreshTracking() {
|
|
19898
|
+
if (!this.isInitialized) {
|
|
19899
|
+
if (this.config.debug) {
|
|
19900
|
+
console.log('[AutoTracker] Not initialized, cannot refresh tracking');
|
|
19901
|
+
}
|
|
19902
|
+
return;
|
|
19903
|
+
}
|
|
19904
|
+
if (this.config.debug) {
|
|
19905
|
+
console.log('[AutoTracker] Refreshing tracking for dynamic content...');
|
|
19906
|
+
}
|
|
19907
|
+
// Re-process elements for view tracking (only thing that needs setup)
|
|
19908
|
+
this.processExistingElements();
|
|
19909
|
+
// Log current state
|
|
19910
|
+
if (this.config.debug) {
|
|
19911
|
+
this.logFoundElements();
|
|
19912
|
+
}
|
|
19913
|
+
}
|
|
19914
|
+
/**
|
|
19915
|
+
* Legacy method - use refreshTracking() instead
|
|
19916
|
+
* @deprecated Use refreshTracking() for better performance
|
|
19917
|
+
*/
|
|
19918
|
+
rescan() {
|
|
19919
|
+
this.refreshTracking();
|
|
19920
|
+
}
|
|
19921
|
+
/**
|
|
19922
|
+
* Get diagnostic information for debugging
|
|
19923
|
+
*/
|
|
19924
|
+
getDiagnostics() {
|
|
19925
|
+
return {
|
|
19926
|
+
isInitialized: this.isInitialized,
|
|
19927
|
+
hasClickHandler: this.delegationHandlers.has('click'),
|
|
19928
|
+
hasScrollHandler: this.delegationHandlers.has('scroll'),
|
|
19929
|
+
observedElements: this.observedElements.size,
|
|
19930
|
+
hasMutationObserver: !!this.mutationObserver,
|
|
19931
|
+
hasIntersectionObserver: !!this.intersectionObserver,
|
|
19932
|
+
config: this.config,
|
|
19933
|
+
elementsFound: {
|
|
19934
|
+
click: document.querySelectorAll('[data-track-click]').length,
|
|
19935
|
+
scroll: document.querySelectorAll('[data-track-scroll]').length,
|
|
19936
|
+
view: document.querySelectorAll('[data-track-view]').length,
|
|
19937
|
+
hover: document.querySelectorAll('[data-track-hover]').length,
|
|
19938
|
+
form: document.querySelectorAll('[data-track-form]').length
|
|
19939
|
+
}
|
|
19940
|
+
};
|
|
19941
|
+
}
|
|
19654
19942
|
/**
|
|
19655
19943
|
* Configurar tracking
|
|
19656
19944
|
*/
|
|
@@ -19658,12 +19946,14 @@ class AutoTracker {
|
|
|
19658
19946
|
this.config = { ...this.config, ...config };
|
|
19659
19947
|
}
|
|
19660
19948
|
/**
|
|
19661
|
-
*
|
|
19949
|
+
* Enhanced stats with diagnostic information
|
|
19662
19950
|
*/
|
|
19663
19951
|
getStats() {
|
|
19664
19952
|
return {
|
|
19665
19953
|
observedElements: this.observedElements.size,
|
|
19666
19954
|
config: this.config,
|
|
19955
|
+
isModern: this.isInitialized, // Indicates if using new delegation system
|
|
19956
|
+
diagnostics: this.config.debug ? this.getDiagnostics() : undefined
|
|
19667
19957
|
};
|
|
19668
19958
|
}
|
|
19669
19959
|
}
|
|
@@ -20212,6 +20502,36 @@ class ZaplierSDK {
|
|
|
20212
20502
|
console.log("[Zaplier] Auto tracking configured:", config);
|
|
20213
20503
|
}
|
|
20214
20504
|
},
|
|
20505
|
+
/**
|
|
20506
|
+
* Refresh tracking for dynamic content (React/SPA route changes)
|
|
20507
|
+
* Modern alternative to rescan() - follows GA4/industry best practices
|
|
20508
|
+
*/
|
|
20509
|
+
refreshTracking: () => {
|
|
20510
|
+
if (this.autoTracker) {
|
|
20511
|
+
this.autoTracker.refreshTracking();
|
|
20512
|
+
}
|
|
20513
|
+
if (this.config.debug) {
|
|
20514
|
+
console.log("[Zaplier] Auto tracking refreshed");
|
|
20515
|
+
}
|
|
20516
|
+
},
|
|
20517
|
+
/**
|
|
20518
|
+
* Legacy rescan method - use refreshTracking() instead
|
|
20519
|
+
* @deprecated Use refreshTracking() for better performance
|
|
20520
|
+
*/
|
|
20521
|
+
rescan: () => {
|
|
20522
|
+
if (this.autoTracker) {
|
|
20523
|
+
this.autoTracker.rescan();
|
|
20524
|
+
}
|
|
20525
|
+
if (this.config.debug) {
|
|
20526
|
+
console.log("[Zaplier] Auto tracking rescanned (deprecated - use refreshTracking)");
|
|
20527
|
+
}
|
|
20528
|
+
},
|
|
20529
|
+
/**
|
|
20530
|
+
* Get diagnostic information for debugging
|
|
20531
|
+
*/
|
|
20532
|
+
getDiagnostics: () => {
|
|
20533
|
+
return this.autoTracker ? this.autoTracker.getDiagnostics() : null;
|
|
20534
|
+
},
|
|
20215
20535
|
getStats: () => {
|
|
20216
20536
|
return this.autoTracker ? this.autoTracker.getStats() : null;
|
|
20217
20537
|
},
|