function runScript() { try { const organization = document .querySelector('script[data-zoovuid]') .getAttribute('data-zoovuid'); const domainId = () => { const src = document .querySelector('script[data-zoovuid]') .getAttribute('src') const parts = src.split('/'); return parts[parts.length - 2]; } const eventBody = { organization: organization, domainId: domainId(), eventLabel: '', queryParams: {}, origin: 'CLIENT', }; const regex = /\/\?q=/; function getReferrer() { const referrer = document.referrer; if (/^(https?|android-app):\/\//i.test(referrer)) { return referrer; } else { return undefined; } } async function sendEvent(body) { const url = "https://queue-propagator.zoovu.com/fact"; // !!REMEMBER!! to set proper environment await fetch(url, { method: 'POST', mode: 'cors', cache: 'no-cache', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', }, redirect: 'follow', referrerPolicy: 'no-referrer', body: JSON.stringify(body), }); } //_________________________HELPER FUNCTIONS_________________________ function getCookieValue(cookieName) { const cookies = document.cookie.split('; '); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].split('='); if (cookie[0] === cookieName) { return cookie[1]; } } return null; } function generateUuid() { return self.crypto.randomUUID(); } const addZoovuCidToCookies = () => { const uuid = generateUuid() const zoovuCid = `zoovu-cid=${uuid}; path=/` document.cookie = zoovuCid return uuid; } // ADD MISSED FIELDS TO EVENTOBJECT function addMissingFieldsToEventObject() { const path = window.location.href.replace(window.location.origin, ''); const cid = getCookieValue(`zoovu-cid`) !== null ? getCookieValue(`zoovu-cid`) : addZoovuCidToCookies(); eventBody['cid'] = cid; eventBody['path'] = path; eventBody['timezone'] = Intl.DateTimeFormat().resolvedOptions().timeZone; eventBody['currencyCode'] = "USD"; eventBody['referrer'] = getReferrer(); eventBody['locale'] = navigator.language; } // Distinguish which type of page was visited and sent event function handlePageVisited() { const isPDP = window.location.href.replace(window.location.origin, '').includes('/product'); if (isPDP) { eventBody['eventType'] = 'PDP_VISITED'; eventBody['eventLabel'] = 'Product details page visit'; } else { eventBody['eventType'] = 'PAGE_VISITED'; eventBody['eventLabel'] = 'Page visit'; } sendEvent(eventBody); setTimeout(function() { if (regex.test(window.location.href) && document.querySelector("#ss360-filtered-results") === null) { sendEvent({ ...eventBody, isEmpty: true, eventType: 'SEARCH_RESULT', eventLabel: 'Empty search result page' }); } } , 1000); } //_________________________EVENT HANDLERS________________________ const addEventListenerToPLPSearchResults = () => { try { new Promise((resolve) => { const observer = new MutationObserver(() => { const articles = document.querySelectorAll('article[class="ss360-suggests__wrap ss360-n-section"]'); if (articles.length > 0 && regex.test(window.location.href)) { for (const article of articles) { const namedReferral = 'Search'; const sendClickoutEvent = (event) => { const targetUrl = article.querySelector(".ss360-suggests__link.ss360-ac-c").getAttribute("href"); const label = event.button === 0 ? 'Go to PDP - search clickout' : "Right click PLP" eventBody['eventType'] = 'CLICKOUT'; eventBody['eventLabel'] = label; sendEvent({ ...eventBody, targetUrl, namedReferral }); } article.addEventListener('mousedown', (event) => { sendClickoutEvent(event) }); } observer.disconnect(); return resolve(); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } catch (error) { console.debug("Search result product item - error", error) } } const handleAddToCart = (event) => { try { if ((event.target.className === 'button') && event.target.textContent === ' ADD TO CART ') { eventBody['eventType'] = 'ADD_TO_CART'; eventBody['eventLabel'] = 'Add to cart'; sendEvent(eventBody); } } catch (error) { console.debug("Add to cart - error", error) } } const observeAndReactOnPageChange = () => { try { let oldHref; if (oldHref === undefined) { addMissingFieldsToEventObject(); handlePageVisited(); oldHref = document.location.href; } const body = document.querySelector('body'); const observer = new MutationObserver(() => { if (oldHref !== document.location.href) { oldHref = document.location.href; addMissingFieldsToEventObject(); handlePageVisited(); } }); observer.observe(body, { childList: true, subtree: true }); } catch (error) { console.debug("Page change - DOM change error", error) } }; const handleOnEnterSearch = (event) => { try { if (event.target.className === "search__input") { eventBody['eventType'] = 'SEARCH' eventBody['eventLabel'] = 'Search phrase typed'; sendEvent(eventBody); } } catch (error) { console.debug("On enter search event", error) } } const handleSearchFromCategoryButtons = (event) => { try { if (event.target.className === "button" && event.target.parentElement.className.includes("topic")) { eventBody['eventType'] = 'SEARCH' eventBody['eventLabel'] = 'Search topic clicked'; sendEvent(eventBody); } } catch (error) { console.debug("Search topic clicked", error) } } //_________________________EVENT HANDLERS USAGE_________________________ observeAndReactOnPageChange(); addEventListenerToPLPSearchResults(); // ALLOCATE EVENT LISTENER ON BODY document.querySelector('body').addEventListener('mousedown', (event) => { handleAddToCart(event); handleSearchFromCategoryButtons(event); }, { capture: true }) // ALLOCATE KEYDOWN EVENT LISTENER ON BODY document.querySelector('body').addEventListener('keydown', (event) => { if (event.code === "Enter" || event.code === "NumpadEnter") { handleOnEnterSearch(event) handleAddToCart(event); handleSearchFromCategoryButtons(event); } }, { capture: true }) } catch (error) { console.debug("Tracking failed", error) } }; // RUN SCRIPT AFTER PAGE LOAD if (document.readyState === "loading" || document.readyState === "interactive") { // Loading hasn't finished yet document.addEventListener("readystatechange", (event) => { if (event.target.readyState === "complete") { runScript(); } }); } else { runScript(); }