@phantomstudios/ft-lib
Version:
A collection of Javascript UI & tracking utils for FT sites
211 lines (194 loc) • 6.73 kB
text/typescript
import { FTTracking } from "../FTTracking";
import { permutiveVideoUtils } from "../permutiveVideoUtils";
import { OrigamiEventType } from "../utils/yupValidator";
export class ytIframeTracking {
FTTracker: FTTracking;
progressMilestones = [1, 25, 50, 75];
permutiveUtils: permutiveVideoUtils;
videoProgressInterval = 0;
videoTitle: string;
videoUrl: string | undefined;
constructor(FTTracker: FTTracking, videoTitle?: string, videoUrl?: string) {
this.FTTracker = FTTracker;
this.videoTitle =
videoTitle || window.gtmCategory || window.location.pathname; //reverted fix for channels - use window.gtmCategory to maintain the original label style
this.videoUrl = videoUrl;
this.permutiveUtils = new permutiveVideoUtils(
this.FTTracker.config.campaign,
this.videoTitle,
);
}
progressPercentage = (duration: number, currentTime: number) =>
parseInt(((currentTime / duration) * 100).toFixed(2));
emitProgressEvents = (
progress: number,
duration: number,
isYoutube: boolean,
) => {
while (progress >= this.progressMilestones[0]) {
this.FTTracker.gaEvent(
`Video${window.isOvideoPlayer ? ":fallback" : ""}`,
`${this.progressMilestones[0]}% watched`,
this.videoTitle,
);
if (isYoutube) {
this.FTTracker.oEvent({
category: "video",
action: "progress",
duration: duration,
progress,
} as OrigamiEventType);
}
this.progressMilestones.shift();
}
};
//Fallback oVideo implemented only on channels - uses shared events so added here for now.
public oVideoEventHandler(videoEl: HTMLVideoElement) {
window.isOvideoPlayer = true;
this.permutiveUtils.videoId = videoEl.getAttribute("src") as string;
videoEl.addEventListener("play", () => {
this.playTracking(videoEl.currentTime, videoEl.duration);
});
videoEl.addEventListener("progress", () => {
this.progressTracking(videoEl.currentTime, videoEl.duration);
});
videoEl.addEventListener("seeked", () => {
this.seekedTracking(videoEl.currentTime, videoEl.duration);
});
videoEl.addEventListener("pause", () => {
this.pausedTracking(videoEl.currentTime, videoEl.duration);
});
videoEl.addEventListener("ended", () => {
this.endedTracking(videoEl.currentTime, videoEl.duration);
});
}
public ytIframeEventHandler(event: YT.PlayerEvent) {
const player = event.target as YT.Player;
if (!this.videoUrl) {
this.videoUrl = player.getVideoUrl();
}
this.permutiveUtils.videoId = this.videoUrl;
//player.playerInfo.videoUrl
switch (player.getPlayerState()) {
case YT.PlayerState.ENDED:
this.endedTracking(player.getCurrentTime(), player.getDuration());
break;
case YT.PlayerState.PLAYING:
this.ytPlayTracking(player);
break;
case YT.PlayerState.PAUSED:
//test if still pause after 1 second, otherwise its a seek
setTimeout(() => {
if (player.getPlayerState() == YT.PlayerState.PAUSED) {
this.pausedTracking(player.getCurrentTime(), player.getDuration());
}
}, 1000);
break;
}
}
ytPlayTracking(player: YT.Player) {
this.videoProgressInterval = window.setInterval(() => {
const currentTime = player.getCurrentTime();
const duration = player.getDuration();
this.permutiveUtils.emitPermutiveProgressEvent(
duration - 1,
currentTime,
this.videoProgressInterval,
);
const progress = this.progressPercentage(duration, currentTime);
this.emitProgressEvents(progress, duration, true);
}, 1000);
const currentTime = player.getCurrentTime();
const duration = player.getDuration();
const progress = this.progressPercentage(duration, currentTime);
if (progress < 100) {
this.FTTracker.gaEvent(
`Video${window.isOvideoPlayer ? ":fallback" : ""}`,
`playing`,
this.videoTitle,
);
this.FTTracker.oEvent({
category: "video",
action: "playing",
duration: duration,
progress,
} as OrigamiEventType);
}
}
pausedTracking(currentTime: number, duration: number) {
const progress = this.progressPercentage(duration, currentTime);
this.FTTracker.gaEvent(
`Video${window.isOvideoPlayer ? ":fallback" : ""}`,
`pause`,
`${this.videoTitle}`,
);
this.FTTracker.oEvent({
category: "video",
action: "pause",
duration: duration,
progress,
} as OrigamiEventType);
}
endedTracking(currentTime: number, duration: number) {
const progress = this.progressPercentage(duration, currentTime);
this.FTTracker.gaEvent(
`Video${window.isOvideoPlayer ? ":fallback" : ""}`,
`100% watched`,
`${this.videoTitle}`,
);
this.FTTracker.oEvent({
category: "video",
action: "ended",
duration: duration,
progress,
} as OrigamiEventType);
//force a 100% event on end
if (this.permutiveUtils.remainingProgress.length > 0) {
this.permutiveUtils.emitPermutiveProgressEvent(
currentTime,
currentTime,
this.videoProgressInterval,
);
}
}
/*** Below events only used for FT-Channels videoJS and Origami players - remove if no longer needed ***/
/*** videojs and origami player event only ***/
playTracking(currentTime: number, duration: number) {
this.videoProgressInterval = window.setInterval(() => {
this.permutiveUtils.emitPermutiveProgressEvent(
duration - 1,
currentTime,
this.videoProgressInterval,
);
}, 1000);
const progress = this.progressPercentage(duration, currentTime);
this.FTTracker.oEvent({
category: "video",
action: "playing",
duration: duration,
progress,
} as OrigamiEventType);
}
/*** videojs and origami player event only ***/
progressTracking(currentTime: number, duration: number) {
const progress = this.progressPercentage(duration, currentTime);
this.emitProgressEvents(progress, duration, false);
this.FTTracker.oEvent({
category: "video",
action: "progress",
duration: duration,
progress,
} as OrigamiEventType);
}
/*** videojs and origami player event only ***/
seekedTracking(currentTime: number, duration: number) {
const progress = this.progressPercentage(duration, currentTime);
this.emitProgressEvents(progress, duration, false);
this.FTTracker.oEvent({
category: "video",
action: "seek",
duration: duration,
progress,
} as OrigamiEventType);
}
}