Untitled
unknown
plain_text
2 years ago
14 kB
9
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...