Untitled
unknown
plain_text
2 years ago
14 kB
4
Indexable
((w) => { "use strict"; let tag = "cv-pjs", debug = document.cookie.includes("cfQA"), window = typeof unsafeWindow !== "undefined" ? unsafeWindow : w, utils; if (window[tag]) return; window[tag] = { init: () => { try { const urlParams = new URLSearchParams(window.location.search), cfQaValue = urlParams.get("cfQA"); if (cfQaValue) { utils.createCookie("cfQA", cfQaValue); utils.log(`QA mode: ${cfQaValue}`); debug = true; } if (debug && !document.title.includes("CONV QA")) { document.title = `[CONV QA] ${document.title}`; } utils.initMetrics(); utils.log("ProjectJS initialised"); } catch (err) { utils.log(err); } }, initMetrics: () => { const isPageCheckout = window.location.href.includes("cart.wearewild.com") && !window.location.search.includes("previous_step="), isPageConfirmation = window.location.pathname.includes("thank_you"); if (!!isPageConfirmation) { utils.waitForElement(".product-table tbody", (prodTable) => { const elsPrices = prodTable.querySelectorAll("tr[class='product'][data-product-type] .product__price span:last-of-type"); elsPrices.forEach((priceElem) => { const elTableRow = priceElem.closest("tr"), isSubscpn = elTableRow.textContent.includes("initial_delivery"), isOneTime = elTableRow.textContent.includes("one_off_purchase"), isFullMty = elTableRow.textContent.includes("the_full_monty"); if (isSubscpn) utils.sendEvt(`[CONV] Subscription purchases`, "Custom"); else if (isOneTime) utils.sendEvt(`[CONV] OTP purchases`, "Custom"); else if (isFullMty) utils.sendEvt(`[CONV] Full Monty purchases`, "Custom"); }); }); } else if (!!isPageCheckout) { utils.sendEvt(`[CONV] Checkout 1 [Details]`, "Pageview"); } else { let isTimedOut, timeout = setTimeout(() => { isTimedOut = true; }, 5000), checkForDataLayer = () => { try { const isLoaded = typeof window.dataLayer !== "undefined" && typeof window.dataLayer.push !== "undefined"; if (isTimedOut) return; else if (!isLoaded) window.requestAnimationFrame(checkForDataLayer); else { clearTimeout(timeout); // Check existing items in datalayer dataLayer.forEach((dlItem) => { checkDlItem(dlItem); }); // Check new items pushed to datalayer const getPushData = window.dataLayer.push; window.dataLayer.push = function (dlItem) { try { getPushData.apply(this, arguments); checkDlItem(dlItem); } catch (err) { utils.log(err); } }; } } catch (err) { utils.log(err); } }; window.requestAnimationFrame(checkForDataLayer); } const checkDlItem = (dlItem) => { try { // prettier-ignore const isPageView = dlItem.pageUrl && dlItem.pageType && dlItem.pageType === "PageView", isBuilderProdAdded = dlItem.event && dlItem.event === "click_item" && dlItem.ecommerce && dlItem.ecommerce.click && dlItem.ecommerce.click.products && dlItem.ecommerce.click.products[0] && "category" in dlItem.ecommerce.click.products[0] && "variant" in dlItem.ecommerce.click.products[0], isCaseAdded = isBuilderProdAdded && dlItem.ecommerce.click.products[0].category === "Case" && dlItem.ecommerce.click.products[0].variant !== "W_ENGRAVED", isPlanAdded = isBuilderProdAdded && dlItem.ecommerce.click.products[0].category === "payment_plan", isContCtaClick = dlItem.event && dlItem.event === "wild.customEvent" && dlItem["wild_label"] && dlItem["wild_label"] === "Continue"; // Regular pageview if (isPageView) { const metrics = [ { name: "Step 1 [Case]", url: "/get-started", contains: true, }, { name: "PLP Pageviews", url: "/shop/", contains: true, }, { name: "PDP Pageviews", url: "/products/", contains: true, }, { name: "Bundles PLP", url: "/shop/bundles", }, { name: "Cases PLP", url: "/shop/deodorant-cases", }, { name: "Refills PLP", url: "/shop/refills", }, { name: "Cart pageview", url: "/cart", }, ], pageUrl = dlItem.pageUrl.split("?")[0].split("#")[0]; metrics.forEach((metric) => { const isMatch = metric.url === pageUrl || (metric.contains && pageUrl.includes(metric.url)); if (isMatch) { utils.sendEvt(`[CONV] ${metric.name}`, "Pageview"); } }); } // Builder flow - step 2 activated else if (isCaseAdded) { const caseName = dlItem.ecommerce.click.products[0].variant.replace("- Limited Edition", "").split("(+£")[0].trim(); utils.sendEvt(`[CONV] Case selected - ${caseName}`, "Custom"); utils.sendEvt("[CONV] Step 2 [Plan]", "Pageview"); } // Builder flow - step 3 activated else if (isPlanAdded) { utils.sendEvt("[CONV] Step 3 [Scent]", "Pageview"); } // Builder flow - step 4 activated else if (isContCtaClick) { utils.sendEvt("[CONV] Step 4 [Extras]", "Pageview"); } } catch (err) { utils.log(err); } }; ["mousedown", "touchstart"].forEach((action) => { utils.on(action, ".configurator-layout__controls button", (e) => { const elBtn = e.target.nodeName === "BUTTON" ? e.target : e.target.closest("button"), isProgressingToStep2 = elBtn && elBtn.textContent.toLowerCase().includes("select plan"), selCase = document.querySelector(".step-optionList li.--is-selected h2"); if (isProgressingToStep2 && selCase) utils.sendEvt(`[CONV] Case selected and progressed - ${selCase.textContent.trim()}`, "Custom"); }); utils.on(action, ".RefillsPage button[icon='plus']", () => { const isRefillsPlp = window.location.pathname === "/shop/refills"; if (isRefillsPlp) utils.sendEvt(`[CONV] Refills ATB`, "Custom"); }); }); }, sendEvt: (label, action, expTag = tag, isOnlyGA4) => { try { let isTimedOut, timeout = setTimeout(() => { isTimedOut = true; utils.log("GA failed to load"); }, 5000), checkForGa = () => { try { const isGaLoaded = !isOnlyGA4 ? typeof window.ga !== "undefined" && typeof window.ga.getAll !== "undefined" : typeof window.gtagDataLayer !== "undefined"; if (isTimedOut) return; else if (!isGaLoaded) { window.requestAnimationFrame(checkForGa); } else { clearTimeout(timeout); if (!!isOnlyGA4 || expTag === tag) { // GA4 only, or any metric in PJS function ga4Tag() { gtagDataLayer.push(arguments); } ga4Tag("event", label, {}); utils.log(`metric triggered (GA4): \n - label: ${label}`, expTag); } if (!!isOnlyGA4) return; // UA only const gaObj = { hitType: "event", eventCategory: "[CONV] Experiments", eventAction: action, eventLabel: label, }, trackers = ga.getAll(); trackers.some((tracker) => { const isMatch = tracker.get("trackingId") && tracker.get("trackingId") === "UA-141350614-1"; if (isMatch) { window.ga(() => { tracker.send("event", gaObj.eventCategory, gaObj.eventAction, gaObj.eventLabel); utils.log( `metric triggered (UA): \n - category: ${gaObj.eventCategory} \n - action : ${gaObj.eventAction} \n - label : ${gaObj.eventLabel}`, expTag ); }); return true; } }); } } catch (err) { utils.log(err, expTag); } }; window.requestAnimationFrame(checkForGa); } catch (err) { utils.log(err, expTag); } }, initHotjar: (expTag, label, isSurvey) => { if (!debug || isSurvey) { label = label || "CONV_" + expTag.replace("cv-", "") + "_" + window[expTag].variation; const maxCalls = 10, waitForHj = setInterval(() => { try { if (typeof window.hj === "function") { clearInterval(waitForHj); hj("event", label); utils.log("Hotjar initialised: " + label, expTag); } if (--maxCalls < 0) { clearInterval(waitForHj); utils.log("Hotjar failed to load", expTag); } } catch (err) { utils.log(err, expTag); } }, 500); } }, log: (msg, expTag = tag) => { debug && console.log(`[CONV] ${expTag} --> ${msg}`); }, waitForElement: (cssSelector, cb, timeout = 5000) => { let elementCached, stop, timer = setTimeout(() => { stop = true; }, timeout), checkForElem = () => { try { elementCached = document.querySelector(cssSelector); if (stop) return; if (elementCached) { cb(elementCached); clearTimeout(timer); } else { window.requestAnimationFrame(checkForElem); } } catch (err) { utils.log(err); } }; window.requestAnimationFrame(checkForElem); }, waitUntil: (cond, cb, expTag = tag, timeout = 5000) => { let stop; const timer = setTimeout(() => { stop = true; }, timeout); const end = () => { clearTimeout(timer); stop = true; }; const check = () => { try { const elCached = typeof cond === "string" ? document.querySelector(cond) : undefined, condSuccess = typeof cond === "function" ? cond() : undefined; if (stop) { return; } else if (elCached) { cb(elCached); end(); } else if (condSuccess) { cb(); end(); } window.requestAnimationFrame(check); } catch (err) { utils.log(err, expTag); } }; window.requestAnimationFrame(check); }, applyChanges: (sel, cb, timeout = 5000) => { let stop, timer = setTimeout(() => { stop = true; }, timeout), check = () => { try { const elem = document.querySelector(sel); if (stop) return; else if (!elem) cb(); window.requestAnimationFrame(check); } catch (err) { utils.log(err); } }; window.requestAnimationFrame(check); }, apply: (cond, cb, timeout = 5000) => { let stop, timer = setTimeout(() => { stop = true; }, timeout), check = () => { try { const success = cond(); if (stop) return; else if (!success) cb(); window.requestAnimationFrame(check); } catch (err) { utils.log(err); } }; window.requestAnimationFrame(check); }, skipToStep(stepNo) { utils.waitUntil(".footer-no-margin #step0 .step-optionList li", (elFirstCase) => { elFirstCase.click(); utils.waitUntil(".configurator-layout__controls button", (elContCta) => { elContCta.click(); if (stepNo === 2) return; utils.waitUntil("#step1 .step-optionList li", (elFirstPlan) => { elFirstPlan.click(); elContCta.click(); utils.waitUntil(".cv-1-3_cta button", (elFauxCta) => { elFauxCta.click(); }); if (stepNo === 3) return; utils.waitUntil("#step2 .step-optionList li", (elFirstScent) => { elFirstScent.click(); elContCta.click(); }); }); }); }); }, on: (n, e, o) => { document.addEventListener(n, (n) => { try { let r = n.target; if (r.matches(e)) o(n); else for (; r && r.parentNode !== document; ) { if (!(r = r.parentNode)) return; r.matches(e) && o(n); } } catch (err) { utils.log(err); } }); }, createCookie: (name, value) => { document.cookie = `${name}=${value};domain=${window.location.host.replace("www", "")};path=/;secure;`; }, deleteCookie: (name) => { document.cookie = `${name}=;domain=${window.location.host.replace("www", "")};path=/;secure;expires=Thu, 01 Jan 1970 00:00:00 GMT`; }, observeNavigation: (expObj, expTag) => { let isTimedOut, timeout = setTimeout(() => { isTimedOut = true; }, 5000), checkForDataLayer = () => { try { const isLoaded = typeof window.dataLayer !== "undefined" && typeof window.dataLayer.push !== "undefined"; if (isTimedOut) return; else if (!isLoaded) window.requestAnimationFrame(checkForDataLayer); else { clearTimeout(timeout); const getPushData = window.dataLayer.push; window.dataLayer.push = function (dlItem) { getPushData.apply(this, arguments); const isPageView = dlItem.pageUrl && dlItem.pageType && dlItem.pageType === "PageView"; if (!isPageView) return; const url = dlItem.pageUrl.split("?")[0].split("#")[0], isTargetPage = expObj.targetUrls && expObj.targetUrls.includes(url), isActivated = document.body.classList.contains(expTag); if (isTargetPage && !isActivated) { expObj.activate(); utils.log("reactivated", expTag); } else if (!isTargetPage && isActivated && isPageView) { expObj.deactivate(); utils.log("deactivated", expTag); } }; } } catch (err) { utils.log(err, expTag); } }; window.requestAnimationFrame(checkForDataLayer); }, addStyles: (expTag, styles) => { const alreadyAdded = document.querySelector(`style#${expTag}`); if (!alreadyAdded) { const link = document.createElement("style"); link.textContent = styles; link.id = expTag; document.querySelector("head").insertAdjacentElement("beforeend", link); } }, }; utils = window[tag]; utils.init(); })(window);
Editor is loading...