overcentric
Version:
Overcentric watches your website, product, and users - and tells you what matters and what to do about it.
137 lines (136 loc) • 4.97 kB
JavaScript
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) {
handlePageView(trackEvent);
document.addEventListener('click', (e) => handleClick(e, trackEvent), true);
document.addEventListener('submit', (e) => handleFormSubmit(e, trackEvent), true);
document.addEventListener('focus', (e) => handleInputFocus(e, trackEvent), true);
const handleScrollThrottled = handleScroll(trackEvent);
document.addEventListener('scroll', handleScrollThrottled, { passive: true });
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 });
}
});
const originalPushState = window.history.pushState;
const originalReplaceState = window.history.replaceState;
window.addEventListener('popstate', () => handlePageView(trackEvent));
window.history.pushState = function (...args) {
originalPushState.apply(this, args);
handlePageView(trackEvent);
};
window.history.replaceState = function (...args) {
var _a, _b, _c;
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);
};
}