UNPKG

@croct/plug

Version:

A fully-featured devkit for building natively personalized applications.

143 lines (142 loc) 4.8 kB
import { parseEntity } from "./structuredData.js"; class AutoTrackingPlugin { constructor(configuration) { this.scanTimeout = null; this.tab = configuration.tab; this.tracker = configuration.tracker; this.options = configuration.options; this.trackStructuredData = this.trackStructuredData.bind(this); this.trackLinkOpened = this.trackLinkOpened.bind(this); this.handleUrlChange = this.handleUrlChange.bind(this); } isDisabled() { return this.options?.disablePostViewed === true && this.options?.disableProductViewed === true && this.options?.disableLinkOpened === true; } enable() { if (this.isDisabled()) { return; } this.trackStructuredData(); this.tab.addListener("urlChange", this.handleUrlChange); if (this.options?.disableLinkOpened !== true) { document.addEventListener("click", this.trackLinkOpened, true); } } disable() { if (this.scanTimeout !== null) { clearTimeout(this.scanTimeout); this.scanTimeout = null; } this.tab.removeListener("urlChange", this.handleUrlChange); document.removeEventListener("click", this.trackLinkOpened, true); } handleUrlChange() { if (this.scanTimeout !== null) { clearTimeout(this.scanTimeout); } this.scanTimeout = setTimeout( () => { this.scanTimeout = null; this.trackStructuredData(); }, 1e3 ); } trackStructuredData() { const structuredDataElements = document.querySelectorAll('script[type="application/ld+json"]'); for (const element of structuredDataElements) { const entity = parseEntity(element.textContent ?? ""); switch (entity?.type) { case "post": if (this.options?.disablePostViewed !== true) { this.trackPostViewed(entity); } break; case "product": case "service": if (this.options?.disableProductViewed !== true) { this.trackProductViewed(entity); } break; } } } trackPostViewed(info) { let postId = info.id; if (postId === void 0 && info.url !== void 0) { const parsedUrl = new URL(info.url); const pathSegments = parsedUrl.pathname.split("/").filter((segment) => segment.length > 0); if (pathSegments.length > 0) { postId = pathSegments[pathSegments.length - 1]; } } if (postId === void 0 || info.title === void 0) { return; } this.tracker.track("postViewed", { post: AutoTrackingPlugin.clean({ postId: AutoTrackingPlugin.truncate(postId, 200), title: AutoTrackingPlugin.truncate(info.title, 200), url: info.url, tags: info.tags?.map((tag) => AutoTrackingPlugin.truncate(tag, 50)), categories: info.categories?.map((category) => AutoTrackingPlugin.truncate(category, 50)), authors: info.authors?.map((author) => AutoTrackingPlugin.truncate(author, 100)), publishTime: info.publishTime ?? Date.now(), updateTime: info.updateTime }) }); } trackProductViewed(info) { if (info.id === void 0 || info.name === void 0 || info.displayPrice === void 0) { return; } this.tracker.track("productViewed", { product: AutoTrackingPlugin.clean({ productId: AutoTrackingPlugin.truncate(info.id, 50), name: AutoTrackingPlugin.truncate(info.name, 200), displayPrice: info.displayPrice, url: info.url, sku: info.sku !== void 0 ? AutoTrackingPlugin.truncate(info.sku, 50) : void 0, brand: info.brand !== void 0 ? AutoTrackingPlugin.truncate(info.brand, 100) : void 0, variant: info.variant !== void 0 ? AutoTrackingPlugin.truncate(info.variant, 50) : void 0, category: info.category !== void 0 ? AutoTrackingPlugin.truncate(info.category, 100) : void 0, originalPrice: info.originalPrice, imageUrl: info.imageUrl }) }); } trackLinkOpened(event) { if (event.target instanceof HTMLElement) { const link = event.target.closest("a"); if (link?.href !== void 0 && URL.canParse(link.href, document.baseURI)) { this.tracker.track("linkOpened", { link: new URL(link.href, document.baseURI).toString() }); } } } static truncate(value, maxLength) { if (value.length <= maxLength) { return value; } return value.slice(0, maxLength); } static clean(obj) { const result = { ...obj }; for (const key of Object.keys(result)) { if (result[key] === void 0) { delete result[key]; } } return result; } } const factory = ((props) => new AutoTrackingPlugin({ tab: props.sdk.tab, tracker: props.sdk.tracker, options: props.options })); export { AutoTrackingPlugin, factory };