@phantomstudios/ft-lib
Version:
A collection of Javascript UI & tracking utils for FT sites
132 lines (117 loc) • 3.48 kB
text/typescript
import oTracking from "@financial-times/o-tracking";
import { TrackingOptions } from "../FTTracking";
import { getValueFromCookie } from "../utils/cookies";
import getTrace from "../utils/getTrace";
import {
parseConfig,
validateConfig,
validateOrigamiEvent,
ConfigType,
OrigamiEventType,
} from "../utils/yupValidator";
/* oTracking setup for server-rendered (i.e. Wagtail) sites
The config object is read from the server-rendered o-tracking-data element
*/
export class oTracker {
private _config: ConfigType;
options: TrackingOptions;
constructor(config: ConfigType, options: TrackingOptions) {
this._config = parseConfig(
config,
options.disableAppFormatTransform || false,
);
validateConfig(
this._config,
options.disableAppFormatTransform || false,
options.logValidationErrors || false,
);
this._config.source_id = oTracking.getRootID();
this.options = options;
//init config data
const configData = {
server: "https://spoor-api.ft.com/px.gif",
context: {
...this._config,
},
user: {
ft_session: getValueFromCookie(/FTSession=([^;]+)/),
},
};
oTracking.init(configData);
//setup listeners
this.OTrackingHandler();
//send Origami DomLoaded event
//document.dispatchEvent(new CustomEvent("o.DOMContentLoaded")); //TODO this isnt needed on next and breaks the cookie-message eventhandlers - is it needed for the server sites?
//send page hits
this.broadcastPageView();
if (options.sendBrandedContent) {
this.broadcastBrandedContent();
}
}
set config(c: ConfigType) {
this._config = c;
}
get config() {
return this._config;
}
public eventDispatcher(detail: OrigamiEventType) {
if (typeof detail === "object" && detail.category && detail.action) {
validateOrigamiEvent(detail);
detail.app = this.config.app;
detail.product = this.config.product;
document.body.dispatchEvent(
new CustomEvent("oTracking.event", { detail, bubbles: true }),
);
} else {
throw "Invalid event type";
}
}
public broadcastPageView() {
oTracking.page({
app: this.config.app,
product: this.config.product,
title: document.title,
});
}
public broadcastBrandedContent() {
document.body.dispatchEvent(
new CustomEvent("oTracking.event", {
detail: {
...this.config,
action: "view",
category: "brandedContent",
},
bubbles: true,
}),
);
}
OTrackingHandler() {
document.body.addEventListener("click", (event) => {
const trackableElement = event
.composedPath()
.find(
(elm) =>
elm instanceof HTMLElement &&
elm.hasAttribute &&
elm.hasAttribute("data-o-event"),
);
if (trackableElement && trackableElement instanceof HTMLElement) {
const data = trackableElement.getAttribute("data-o-event");
const detail = {};
const { trace } = getTrace(trackableElement);
if (data) {
data.split("|").forEach((item) => {
const kv = item.split(":");
//TODO
// @ts-ignore
detail[kv[0]] = kv[1];
});
//TODO
// @ts-ignore
detail.domPathTokens = trace;
}
this.eventDispatcher(detail as OrigamiEventType);
}
});
}
}