From 6f9f1f9a2534a4fc6c50f6278bcf3cba7dd6f176 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Fri, 26 Jan 2018 10:35:44 -0500 Subject: [PATCH] extract analytics to jslib --- src/abstractions/platformUtils.service.ts | 1 + src/index.ts | 3 +- src/misc/analytics.ts | 96 +++++++++++++++++++++++ src/misc/index.ts | 1 + 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/misc/analytics.ts create mode 100644 src/misc/index.ts diff --git a/src/abstractions/platformUtils.service.ts b/src/abstractions/platformUtils.service.ts index 39857adbd9..7b1e98ebb2 100644 --- a/src/abstractions/platformUtils.service.ts +++ b/src/abstractions/platformUtils.service.ts @@ -15,4 +15,5 @@ export abstract class PlatformUtilsService { launchUri: (uri: string, options?: any) => void; saveFile: (win: Window, blobData: any, blobOptions: any, fileName: string) => void; alertError: (title: string, message: string) => void; + getApplicationVersion: () => string; } diff --git a/src/index.ts b/src/index.ts index da1f6af9e0..5d4c096cc3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,9 +2,10 @@ import * as Abstractions from './abstractions'; import * as Enums from './enums'; import * as Data from './models/data'; import * as Domain from './models/domain'; +import * as Misc from './misc'; import * as Request from './models/request'; import * as Response from './models/response'; import * as Services from './services'; import * as View from './models/view'; -export { Abstractions, Enums, Data, Domain, Request, Response, Services, View }; +export { Abstractions, Enums, Data, Domain, Misc, Request, Response, Services, View }; diff --git a/src/misc/analytics.ts b/src/misc/analytics.ts new file mode 100644 index 0000000000..98cfdebc5b --- /dev/null +++ b/src/misc/analytics.ts @@ -0,0 +1,96 @@ +import { AppIdService } from '../abstractions/appId.service'; +import { PlatformUtilsService } from '../abstractions/platformUtils.service'; +import { StorageService } from '../abstractions/storage.service'; + +import { ConstantsService } from '../services/constants.service'; + +const GaObj = 'ga'; + +export class Analytics { + private gaTrackingId: string = null; + private isFirefox = false; + private appVersion: string; + + constructor(win: Window, private gaFilter?: () => boolean, + private platformUtilsService?: PlatformUtilsService, private storageService?: StorageService, + private appIdService?: AppIdService, private dependencyResolver?: () => any) { + if (dependencyResolver != null) { + const deps = dependencyResolver(); + if (platformUtilsService == null && deps.platformUtilsService) { + this.platformUtilsService = deps.platformUtilsService as PlatformUtilsService; + } + if (storageService == null && deps.storageService) { + this.storageService = deps.storageService as StorageService; + } + if (appIdService == null && deps.appIdService) { + this.appIdService = deps.appIdService as AppIdService; + } + } + + this.appVersion = this.platformUtilsService.getApplicationVersion(); + this.isFirefox = this.platformUtilsService.isFirefox(); + this.gaTrackingId = this.platformUtilsService.analyticsId(); + + (win as any).GoogleAnalyticsObject = GaObj; + (win as any)[GaObj] = async (action: string, param1: any, param2?: any) => { + await this.ga(action, param1, param2); + }; + } + + async ga(action: string, param1: any, param2?: any) { + if (this.gaFilter != null && this.gaFilter()) { + return; + } + + const disabled = await this.storageService.get(ConstantsService.disableGaKey); + // Default for Firefox is disabled. + if ((this.isFirefox && disabled == null) || disabled != null && disabled) { + return; + } + + if (action !== 'send' || !param1) { + return; + } + + const gaAnonAppId = await this.appIdService.getAnonymousAppId(); + const version = encodeURIComponent(this.appVersion); + let message = 'v=1&tid=' + this.gaTrackingId + '&cid=' + gaAnonAppId + '&cd1=' + version; + + if (param1 === 'pageview' && param2) { + message += this.gaTrackPageView(param2); + } else if (typeof param1 === 'object' && param1.hitType === 'pageview') { + message += this.gaTrackPageView(param1.page); + } else if (param1 === 'event' && param2) { + message += this.gaTrackEvent(param2); + } else if (typeof param1 === 'object' && param1.hitType === 'event') { + message += this.gaTrackEvent(param1); + } + + const request = new XMLHttpRequest(); + request.open('POST', 'https://www.google-analytics.com/collect', true); + request.send(message); + } + + private gaTrackEvent(options: any) { + return '&t=event&ec=' + (options.eventCategory ? encodeURIComponent(options.eventCategory) : 'Event') + + '&ea=' + encodeURIComponent(options.eventAction) + + (options.eventLabel ? '&el=' + encodeURIComponent(options.eventLabel) : '') + + (options.eventValue ? '&ev=' + encodeURIComponent(options.eventValue) : '') + + (options.page ? '&dp=' + this.cleanPagePath(options.page) : ''); + } + + private gaTrackPageView(pagePath: string) { + return '&t=pageview&dp=' + this.cleanPagePath(pagePath); + } + + private cleanPagePath(pagePath: string) { + const paramIndex = pagePath.indexOf('?'); + if (paramIndex > -1) { + pagePath = pagePath.substring(0, paramIndex); + } + if (pagePath.indexOf('!/') === 0 || pagePath.indexOf('#/') === 0) { + pagePath = pagePath.substring(1); + } + return encodeURIComponent(pagePath); + } +} diff --git a/src/misc/index.ts b/src/misc/index.ts new file mode 100644 index 0000000000..f26abc15fb --- /dev/null +++ b/src/misc/index.ts @@ -0,0 +1 @@ +export { Analytics } from './analytics';