diff --git a/README.md b/README.md index 8c4d8e0d..d1046779 100644 --- a/README.md +++ b/README.md @@ -92,9 +92,11 @@ export class SongDownloadBox {} ## Supported providers * Google Analytics +* Google Tag Manager * Kissmetrics * Mixpanel * Segment +* Adobe Analytics ### For other providers diff --git a/package.json b/package.json index 5d34763e..47b6ec78 100644 --- a/package.json +++ b/package.json @@ -36,12 +36,12 @@ ], "dependencies": {}, "devDependencies": { - "@angular/common": "^2.0.0-rc.1", - "@angular/compiler": "^2.0.0-rc.1", - "@angular/core": "^2.0.0-rc.1", - "@angular/platform-browser": "^2.0.0-rc.1", - "@angular/platform-browser-dynamic": "^2.0.0-rc.1", - "@angular/router": "^2.0.0-rc.1", + "@angular/common": "^2.4.0", + "@angular/compiler": "^2.4.0", + "@angular/core": "^2.4.0", + "@angular/platform-browser": "^2.4.0", + "@angular/platform-browser-dynamic": "^2.4.0", + "@angular/router": "^3.4.0", "commitizen": "^2.8.1", "cz-conventional-changelog": "^1.1.6", "es6-shim": "^0.35.0", @@ -50,14 +50,14 @@ "karma-chrome-launcher": "^1.0.1", "karma-jasmine": "^1.0.2", "karma-typescript-preprocessor": "0.0.21", - "reflect-metadata": "0.1.2", - "rxjs": "5.0.0-beta.6", + "reflect-metadata": "0.1.10", + "rxjs": "^5.1.0", "semantic-release": "^4.3.5", - "systemjs": "^0.19.26", - "tslint": "^3.6.0", - "typescript": "^1.8.10", - "typings": "^0.8.1", - "zone.js": "0.6.12" + "systemjs": "^0.19.40", + "tslint": "^4.5.0", + "typescript": "^2.2.0", + "typings": "^2.1.0", + "zone.js": "^0.7.6" }, "bugs": { "url": "http://github.com/angulartics/angulartics2/issues" diff --git a/src/providers/angulartics2-adobe-analytics.spec.ts b/src/providers/angulartics2-adobe-analytics.spec.ts new file mode 100644 index 00000000..2748e7a6 --- /dev/null +++ b/src/providers/angulartics2-adobe-analytics.spec.ts @@ -0,0 +1,77 @@ +import {Location} from '@angular/common'; +import {ReflectiveInjector, ReplaySubject} from '@angular/core'; +import {fakeAsync, tick} from '@angular/core/testing'; + +import {Angulartics2} from '../core/angulartics2'; +import {Angulartics2AdobeAnalytics} from './angulartics2-adobe-analytics'; + +describe('Angulartics2AdobeAnalytics', () => { + let s: any; + let location: Location; + let angulartics2: Angulartics2; + let angulartics2AdobeAnalytics: Angulartics2AdobeAnalytics; + + beforeEach(() => { + s = { + clearVars: jasmine.createSpy('clearVars'), + t: jasmine.createSpy('t'), + tl: jasmine.createSpy('tl'), + linkTrackVars: '', + linkTrackEvents: '', + events: '' + }; + + const locationMock = { + path: () => '/home', + prepareExternalUrl: (value: string) => value, + subscribe: (next: any) => {} + }; + + const injector = ReflectiveInjector.resolveAndCreate([ + Angulartics2AdobeAnalytics, + Angulartics2, + {provide: Location, useValue: locationMock} + ]); + + window['s'] = s; + location = injector.get(Location); + angulartics2 = injector.get(Angulartics2); + angulartics2AdobeAnalytics = injector.get(Angulartics2AdobeAnalytics); + }); + + afterEach(() => { + delete window['s']; + }); + + it('should track pages', fakeAsync(() => { + angulartics2.pageTrack.next({ path: '/about' }); + tick(); + expect(s.clearVars).toHaveBeenCalled(); + expect(s.t).toHaveBeenCalledWith({ pageName: '/about' }); + })); + + it('should track events', fakeAsync(() => { + angulartics2.eventTrack.next({ action: 'do', properties: { category: 'cat' } }); + tick(); + expect(s.linkTrackVars).toBe('events'); + expect(s.linkTrackEvents).toBe('event1'); + expect(s.events).toBe('event1'); + expect(s.tl).toHaveBeenCalledWith(true, 'o', 'cat - do'); + })); + + it('should set user properties', fakeAsync(() => { + s.prop1 = ''; + s.eVar1 = ''; + angulartics2.setUserProperties.next({ prop1: 'test1', eVar1: 'test2' }); + tick(); + expect(s.prop1).toBe('test1'); + expect(s.eVar1).toBe('test2'); + })); + + it('should set username', fakeAsync(() => { + s.visitorID = ''; + angulartics2.setUsername.next('testuser'); + tick(); + expect(s.visitorID).toBe('testuser'); + })); +}); \ No newline at end of file diff --git a/src/providers/angulartics2-adobe-analytics.ts b/src/providers/angulartics2-adobe-analytics.ts new file mode 100644 index 00000000..a2c5357d --- /dev/null +++ b/src/providers/angulartics2-adobe-analytics.ts @@ -0,0 +1,100 @@ +import {Injectable} from '@angular/core'; + +import {Angulartics2} from '../core/angulartics2'; + +declare var s: any; +declare var location: any; + +@Injectable() +export class Angulartics2AdobeAnalytics { + + constructor( + private angulartics2: Angulartics2 + ) { + this.angulartics2.settings.pageTracking.trackRelativePath = true; + + // Set the default settings for this module + this.angulartics2.settings.adobeAnalytics = { + userId: null + }; + + this.angulartics2.pageTrack.subscribe((x: any) => this.pageTrack(x.path)); + + this.angulartics2.eventTrack.subscribe((x: any) => this.eventTrack(x.action, x.properties)); + + this.angulartics2.exceptionTrack.subscribe((x: any) => this.exceptionTrack(x)); + + this.angulartics2.setUsername.subscribe((x: string) => this.setUsername(x)); + + this.angulartics2.setUserProperties.subscribe((x: any) => this.setUserProperties(x)); + } + + pageTrack(path: string) { + if (typeof s !== 'undefined' && s) { + s.clearVars(); + s.t({ pageName: path }); + } + } + + /** + * Track Event in Adobe Analytics + * @name eventTrack + * + * @param {string} action Required 'action' (string) associated with the event + * @param {object} properties Comprised of the mandatory field 'category' (string) and optional fields 'label' (string), 'value' (integer) and 'noninteraction' (boolean) + */ + eventTrack(action: string, properties: any) { + // Adobe Analytics requires an Event Category + if (!properties || !properties.category) { + properties = properties || {}; + properties.category = 'Event'; + } + if (typeof s !== 'undefined' && s) { + s.linkTrackVars = 'events'; + s.linkTrackEvents = 'event1'; + s.events = 'event1'; + s.tl(true, 'o', properties.category + ' - ' + action); + } + } + + /** + * Exception Track Event in Adobe Analytics + * @name exceptionTrack + * + * @param {object} properties Comprised of the mandatory fields 'appId' (string), 'appName' (string) and 'appVersion' (string) and + * optional fields 'fatal' (boolean) and 'description' (string) + */ + exceptionTrack(properties: any) { + if (!properties || !properties.appId || !properties.appName || !properties.appVersion) { + console.error('Must be setted appId, appName and appVersion.'); + return; + } + + if (typeof s !== 'undefined' && s) { + s.linkTrackVars = 'events,prop20,eVar20'; + s.linkTrackEvents = 'event2'; + s.events = 'event2'; + s.prop20 = properties.appName + ' - ' + properties.appVersion; + s.eVar20 = properties.description || 'No Description'; + s.tl(true, 'o', 'Exception'); + } + } + + setUsername(userId: string) { + this.angulartics2.settings.adobeAnalytics.userId = userId; + if (typeof s !== 'undefined' && s) { + s.visitorID = userId; + } + } + + setUserProperties(properties: any) { + if (typeof s !== 'undefined' && s) { + // Set custom variables for Adobe Analytics + for (let key in properties) { + if (properties.hasOwnProperty(key)) { + s[key] = properties[key]; + } + } + } + } +} \ No newline at end of file diff --git a/src/providers/angulartics2-google-analytics.ts b/src/providers/angulartics2-google-analytics.ts index 782468ef..8ea13547 100644 --- a/src/providers/angulartics2-google-analytics.ts +++ b/src/providers/angulartics2-google-analytics.ts @@ -103,7 +103,7 @@ export class Angulartics2GoogleAnalytics { } else if (_gaq) { _gaq.push(['_trackEvent', properties.category, action, properties.label, properties.value, properties.noninteraction]); } - console.log('event sent to GA'); + } /**