@causalfoundry/js-sdk
Version:
Causal Foundry WEB SDK (JS/TS)
200 lines (170 loc) • 5.31 kB
text/typescript
import { Event, EventTeaser, ExceptionObject } from "../core/typings";
import { debug } from "../logging";
import CfSender from "./CfSender";
import { ContentBlock } from "../modules/Navigation/typings";
import ImpressionsDetector from "./impressions";
import { ImpressionEventType } from "./impressions/typings";
import CfExceptionHandler from "./CfExceptionHandler";
import { getLocalStorageUserId } from "../drivers/CfSystem";
import { CatalogItemModel } from "../modules/typings";
import CfNetwork from "../drivers/network/CfNetwork";
import { isOnline } from "../drivers/network/helper";
export default class CfCore {
private static instance: CfCore;
private deviceId: string;
private sender: CfSender;
private isUsingAsInternalWrapper: boolean;
private impressionDetectorClass;
private impressionsDetectors: {
[key: string]: ImpressionsDetector;
} = {};
private defaultBlock;
private debug;
private currentBlock;
private user_id = "";
private constructor(
sender: CfSender,
impressionDetector,
debugging: boolean,
defaultBlock: ContentBlock,
deviceId: string,
isUsingAsInternalWrapper: boolean
) {
this.sender = sender;
this.impressionDetectorClass = impressionDetector;
this.deviceId = deviceId;
this.defaultBlock = defaultBlock;
this.debug = debug(debugging);
this.isUsingAsInternalWrapper = isUsingAsInternalWrapper;
}
public static createInstance(
sender: CfSender,
impressionDetectorClass,
debugging: boolean,
defaultBlock: ContentBlock,
deviceId: string,
isUsingAsInternalWrapper: boolean
) {
if (CfCore.instance) {
return CfCore.instance;
}
CfCore.instance = new CfCore(
sender,
impressionDetectorClass,
debugging,
defaultBlock,
deviceId,
isUsingAsInternalWrapper
);
return CfCore.instance;
}
public static getInstance(): CfCore {
if (!CfCore.instance) {
new CfExceptionHandler().throwAndLogError(
"CfLog",
"CfLog instance not created"
);
}
return CfCore.instance;
}
public login(userId: string) {
this.user_id = userId;
}
private resolveModule(module: ContentBlock): ContentBlock {
// logPageEvents are triggered automatically by the system. We do not
// know whether the web application calls setCurrentBlock before or after that:
const delta = 50;
if (module === ContentBlock.Core) {
// in this case the event could be triggered by several modules
// so the SDK must decide which one must be included in the event
// sent to server (i.e.: page or media events)
if (this.currentBlock) {
return this.currentBlock;
} else {
return this.defaultBlock;
}
} else {
// specific module (i.e.: triggered by the ELearning module)
return module;
}
}
private resolveUserId(
overWrittedUserId: string,
user_id: string,
device_id: string
): string {
if (overWrittedUserId && overWrittedUserId.length !== 0) {
return overWrittedUserId;
}
return user_id || getLocalStorageUserId() || device_id;
}
public async trackEvent(
eventTeaser: EventTeaser,
overWrittedUserId: string,
sendNow: boolean,
eventTime?: string
): Promise<void> {
const event: Event = {
...eventTeaser,
time: eventTime || new Date().toISOString(),
};
// Ensure ctx exists and add ol property
event.ctx = event.ctx || {};
event.ctx.__ol = isOnline();
this.sender.add(
this.resolveUserId(overWrittedUserId, this.user_id, this.deviceId),
this.deviceId,
event,
sendNow,
this.isUsingAsInternalWrapper
);
}
public async trackCatalog(catalogItem: CatalogItemModel): Promise<void> {
this.sender.addCatalogItem(catalogItem);
}
public startTrackingImpressions(
impressionHandler,
containerClassname,
itemClassname
) {
this.impressionsDetectors[containerClassname] =
new this.impressionDetectorClass({ intersectionThreshold: 0.5 });
this.impressionsDetectors[containerClassname].on(
ImpressionEventType.Impression,
impressionHandler
);
this.impressionsDetectors[containerClassname].start(
containerClassname,
itemClassname,
{}
);
}
public stopTrackingImpressions(containerClassname) {
if (!containerClassname) {
Object.values(this.impressionsDetectors).forEach((detector) =>
detector.stop()
);
return;
}
if (!this.impressionsDetectors[containerClassname]) {
return;
}
this.impressionsDetectors[containerClassname].stop();
}
public restartTrackingImpressions(containerClassname) {
if (!containerClassname || !this.impressionsDetectors[containerClassname]) {
console.error(
"Impossible to restart impression to unknown containerClassname"
);
throw new Error("unknown-container");
}
this.impressionsDetectors[containerClassname].restart({});
}
public setCurrentBlock(block: ContentBlock) {
// the reason of this delay is that the page event is triggered
// 10 miliseconds after it really happens to wait for the title
setTimeout(() => {
this.currentBlock = block;
}, 15);
}
}