UNPKG

overcentric

Version:

A lightweight, privacy-focused toolkit for modern SaaS web applications

165 lines (164 loc) 5.8 kB
function getElementInfo(element) { const info = { tag: element.tagName.toLowerCase(), }; if (element.id) { info.id = element.id; } // For links, capture href if (element instanceof HTMLAnchorElement && element.href) { info.href = element.href; } // Capture ARIA role if present const role = element.getAttribute('role'); if (role) { info.role = role; } return info; } function handleClick(event, trackEvent) { const target = event.target; if (!target) return; const elementInfo = getElementInfo(target); const eventInfo = { element: { tag: elementInfo.tag, text: (target.tagName === 'BUTTON' || target.tagName === 'A') ? (target.innerText || '') : undefined, } }; if (elementInfo.id) { eventInfo.element.id = elementInfo.id; } if (target.hasAttribute('data-oc-value')) { eventInfo.custom_value = target.getAttribute('data-oc-value') || ''; } // Only add coordinates if it's a MouseEvent if (event instanceof MouseEvent) { eventInfo.x = event.clientX; eventInfo.y = event.clientY; } trackEvent('$click', eventInfo); } function handlePageView(trackEvent) { const properties = {}; const searchParams = new URLSearchParams(window.location.search); [ ['title', document.title], ['path', window.location.pathname], ['utm_source', searchParams.get('utm_source')], ['utm_medium', searchParams.get('utm_medium')], ['utm_campaign', searchParams.get('utm_campaign')], ['utm_term', searchParams.get('utm_term')], ['utm_content', searchParams.get('utm_content')] ].forEach(([key, value]) => { if (key && value) { properties[key] = value; } }); trackEvent('$page_view', properties); } function handleScroll(trackEvent) { let timeout; let lastScrollPosition = window.scrollY; return () => { clearTimeout(timeout); timeout = setTimeout(() => { const scrollPosition = window.scrollY; const viewportHeight = window.innerHeight; const documentHeight = document.documentElement.scrollHeight; const scrollPercentage = (scrollPosition / (documentHeight - viewportHeight)) * 100; if (Math.abs(scrollPosition - lastScrollPosition) > viewportHeight * 0.25) { trackEvent('$scroll', { scroll_percentage: Math.round(scrollPercentage), scroll_position: scrollPosition, viewport_height: viewportHeight, document_height: documentHeight }); lastScrollPosition = scrollPosition; } }, 500); }; } function handleFormSubmit(event, trackEvent) { const form = event.target; if (!form) return; const formInfo = { id: form.id, action: form.action, method: form.method, fields: Array.from(form.elements).length }; trackEvent('$form_submit', formInfo); } function handleInputFocus(event, trackEvent) { const input = event.target; if (!input) return; const inputInfo = { type: input.type, id: input.id, name: input.name }; trackEvent('$input_focus', inputInfo); } export function startAutoCapture(trackEvent, config) { // Track initial page view handlePageView(trackEvent); // Track clicks if (config.click) { document.addEventListener('click', (e) => handleClick(e, trackEvent), true); } // Track form submissions if (config.formSubmit) { document.addEventListener('submit', (e) => handleFormSubmit(e, trackEvent), true); } // Track input focus if (config.inputFocus) { document.addEventListener('focus', (e) => handleInputFocus(e, trackEvent), true); } // Track scrolling if (config.scroll) { const handleScrollThrottled = handleScroll(trackEvent); document.addEventListener('scroll', handleScrollThrottled, { passive: true }); } // Track page visibility changes if (config.visibilityChange) { document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') { trackEvent('$page_visible', { title: document.title, url: window.location.href }); } else { trackEvent('$page_hidden', { title: document.title, url: window.location.href }); } }); } // Track history changes (for SPAs) if (config.historyChange) { // Listen for popstate events (browser back/forward) window.addEventListener('popstate', () => handlePageView(trackEvent)); // Listen for pushState/replaceState calls const originalPushState = window.history.pushState; const originalReplaceState = window.history.replaceState; window.history.pushState = function (...args) { originalPushState.apply(this, args); handlePageView(trackEvent); }; window.history.replaceState = function (...args) { var _a, _b, _c; console.log('0.0.49 - replaceState args: ', args); if (((_b = (_a = args[0]) === null || _a === void 0 ? void 0 : _a.id) === null || _b === void 0 ? void 0 : _b.startsWith('phx-')) || ((_c = args[0]) === null || _c === void 0 ? void 0 : _c.hasOwnProperty('scroll'))) { return; } originalReplaceState.apply(this, args); handlePageView(trackEvent); }; } }