UNPKG

15 kBJavaScriptView Raw
1import { ɵgetAllInstancesOf, ɵisAnalyticsSupportedFactory, ɵzoneWrap, VERSION, ɵgetDefaultInstanceOf, ɵAngularFireSchedulers } from '@angular/fire';
2import { timer, from, of } from 'rxjs';
3import { concatMap, distinct, filter, switchMap, map, groupBy, mergeMap, distinctUntilChanged, startWith, pairwise } from 'rxjs/operators';
4import * as i0 from '@angular/core';
5import { Injectable, Optional, InjectionToken, APP_INITIALIZER, NgModule, NgZone, Injector } from '@angular/core';
6import { FirebaseApp, FirebaseApps } from '@angular/fire/app';
7import { registerVersion } from 'firebase/app';
8import { __awaiter } from 'tslib';
9import * as i1$1 from '@angular/router';
10import { ActivationEnd, ɵEmptyOutletComponent } from '@angular/router';
11import * as i2 from '@angular/platform-browser';
12import { getAnalytics as getAnalytics$1, initializeAnalytics as initializeAnalytics$1, logEvent as logEvent$1, setAnalyticsCollectionEnabled as setAnalyticsCollectionEnabled$1, setCurrentScreen as setCurrentScreen$1, settings as settings$1, setUserId as setUserId$1, setUserProperties as setUserProperties$1 } from 'firebase/analytics';
13export * from 'firebase/analytics';
14import * as i1 from '@angular/fire/auth';
15import { authState } from '@angular/fire/auth';
16
17class Analytics {
18 constructor(analytics) {
19 return analytics;
20 }
21}
22const ANALYTICS_PROVIDER_NAME = 'analytics';
23class AnalyticsInstances {
24 constructor() {
25 return ɵgetAllInstancesOf(ANALYTICS_PROVIDER_NAME);
26 }
27}
28const analyticInstance$ = timer(0, 300).pipe(concatMap(() => from(ɵgetAllInstancesOf(ANALYTICS_PROVIDER_NAME))), distinct());
29
30const isSupported = ɵisAnalyticsSupportedFactory.async;
31
32// DO NOT MODIFY, this file is autogenerated by tools/build.ts
33const getAnalytics = ɵzoneWrap(getAnalytics$1, true);
34const initializeAnalytics = ɵzoneWrap(initializeAnalytics$1, true);
35const logEvent = ɵzoneWrap(logEvent$1, true);
36const setAnalyticsCollectionEnabled = ɵzoneWrap(setAnalyticsCollectionEnabled$1, true);
37const setCurrentScreen = ɵzoneWrap(setCurrentScreen$1, true);
38const settings = ɵzoneWrap(settings$1, true);
39const setUserId = ɵzoneWrap(setUserId$1, true);
40const setUserProperties = ɵzoneWrap(setUserProperties$1, true);
41
42class UserTrackingService {
43 constructor(auth, zone, injector) {
44 this.disposables = [];
45 registerVersion('angularfire', VERSION.full, 'user-tracking');
46 let resolveInitialized;
47 this.initialized = zone.runOutsideAngular(() => new Promise(resolve => { resolveInitialized = resolve; }));
48 // The APP_INITIALIZER that is making isSupported() sync for the sake of convenient DI
49 // may not be done when services are initialized. Guard the functionality by first ensuring
50 // that the (global) promise has resolved, then get Analytics from the injector.
51 isSupported().then(() => {
52 const analytics = injector.get(Analytics);
53 if (analytics) {
54 this.disposables = [
55 // TODO add credential tracking back in
56 authState(auth).subscribe(user => {
57 setUserId(analytics, user === null || user === void 0 ? void 0 : user.uid);
58 resolveInitialized();
59 }),
60 ];
61 }
62 else {
63 resolveInitialized();
64 }
65 });
66 }
67 ngOnDestroy() {
68 this.disposables.forEach(it => it.unsubscribe());
69 }
70}
71UserTrackingService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: UserTrackingService, deps: [{ token: i1.Auth }, { token: i0.NgZone }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
72UserTrackingService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: UserTrackingService });
73i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: UserTrackingService, decorators: [{
74 type: Injectable
75 }], ctorParameters: function () { return [{ type: i1.Auth }, { type: i0.NgZone }, { type: i0.Injector }]; } });
76
77const FIREBASE_EVENT_ORIGIN_KEY = 'firebase_event_origin';
78const FIREBASE_PREVIOUS_SCREEN_CLASS_KEY = 'firebase_previous_class';
79const FIREBASE_PREVIOUS_SCREEN_INSTANCE_ID_KEY = 'firebase_previous_id';
80const FIREBASE_PREVIOUS_SCREEN_NAME_KEY = 'firebase_previous_screen';
81const FIREBASE_SCREEN_CLASS_KEY = 'firebase_screen_class';
82const FIREBASE_SCREEN_INSTANCE_ID_KEY = 'firebase_screen_id';
83const FIREBASE_SCREEN_NAME_KEY = 'firebase_screen';
84const OUTLET_KEY = 'outlet';
85const PAGE_PATH_KEY = 'page_path';
86const PAGE_TITLE_KEY = 'page_title';
87const SCREEN_CLASS_KEY = 'screen_class';
88const SCREEN_NAME_KEY = 'screen_name';
89const SCREEN_VIEW_EVENT = 'screen_view';
90const EVENT_ORIGIN_AUTO = 'auto';
91const SCREEN_INSTANCE_DELIMITER = '#';
92// this is an INT64 in iOS/Android but use INT32 cause javascript
93let nextScreenInstanceID = Math.floor(Math.random() * (Math.pow(2, 32) - 1)) - Math.pow(2, 31);
94const knownScreenInstanceIDs = {};
95const getScreenInstanceID = (params) => {
96 // unique the screen class against the outlet name
97 const screenInstanceKey = [
98 params[SCREEN_CLASS_KEY],
99 params[OUTLET_KEY]
100 ].join(SCREEN_INSTANCE_DELIMITER);
101 if (knownScreenInstanceIDs.hasOwnProperty(screenInstanceKey)) {
102 return knownScreenInstanceIDs[screenInstanceKey];
103 }
104 else {
105 const ret = nextScreenInstanceID++;
106 knownScreenInstanceIDs[screenInstanceKey] = ret;
107 return ret;
108 }
109};
110const ɵscreenViewEvent = (router, title, componentFactoryResolver) => {
111 const activationEndEvents = router.events.pipe(filter(e => e instanceof ActivationEnd));
112 return activationEndEvents.pipe(switchMap(activationEnd => {
113 var _a;
114 // router parseUrl is having trouble with outlets when they're empty
115 // e.g, /asdf/1(bob://sally:asdf), so put another slash in when empty
116 const urlTree = router.parseUrl(router.url.replace(/(?:\().+(?:\))/g, a => a.replace('://', ':///')));
117 const pagePath = ((_a = urlTree.root.children[activationEnd.snapshot.outlet]) === null || _a === void 0 ? void 0 : _a.toString()) || '';
118 const actualSnapshot = router.routerState.root.children.map(it => it).find(it => it.outlet === activationEnd.snapshot.outlet);
119 if (!actualSnapshot) {
120 return of(null);
121 }
122 let actualDeep = actualSnapshot;
123 while (actualDeep.firstChild) {
124 actualDeep = actualDeep.firstChild;
125 }
126 const screenName = actualDeep.pathFromRoot.map(s => { var _a; return (_a = s.routeConfig) === null || _a === void 0 ? void 0 : _a.path; }).filter(it => it).join('/') || '/';
127 const params = {
128 [SCREEN_NAME_KEY]: screenName,
129 [PAGE_PATH_KEY]: `/${pagePath}`,
130 [FIREBASE_EVENT_ORIGIN_KEY]: EVENT_ORIGIN_AUTO,
131 [FIREBASE_SCREEN_NAME_KEY]: screenName,
132 [OUTLET_KEY]: activationEnd.snapshot.outlet
133 };
134 if (title) {
135 params[PAGE_TITLE_KEY] = title.getTitle();
136 }
137 let component = actualSnapshot.component;
138 if (component) {
139 if (component === ɵEmptyOutletComponent) {
140 let deepSnapshot = activationEnd.snapshot;
141 // TODO when might there be mutple children, different outlets? explore
142 while (deepSnapshot.firstChild) {
143 deepSnapshot = deepSnapshot.firstChild;
144 }
145 component = deepSnapshot.component;
146 }
147 }
148 else {
149 component = activationEnd.snapshot.component;
150 }
151 if (typeof component === 'string') {
152 return of(Object.assign(Object.assign({}, params), { [SCREEN_CLASS_KEY]: component }));
153 }
154 else if (component) {
155 const componentFactory = componentFactoryResolver.resolveComponentFactory(component);
156 return of(Object.assign(Object.assign({}, params), { [SCREEN_CLASS_KEY]: componentFactory.selector }));
157 }
158 // lazy loads cause extra activations, ignore
159 return of(null);
160 }), filter(it => !!it), map(params => (Object.assign({ [FIREBASE_SCREEN_CLASS_KEY]: params[SCREEN_CLASS_KEY], [FIREBASE_SCREEN_INSTANCE_ID_KEY]: getScreenInstanceID(params) }, params))), groupBy(it => it[OUTLET_KEY]), mergeMap(it => it.pipe(distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)), startWith(undefined), pairwise(), map(([prior, current]) => prior ? Object.assign({ [FIREBASE_PREVIOUS_SCREEN_CLASS_KEY]: prior[SCREEN_CLASS_KEY], [FIREBASE_PREVIOUS_SCREEN_NAME_KEY]: prior[SCREEN_NAME_KEY], [FIREBASE_PREVIOUS_SCREEN_INSTANCE_ID_KEY]: prior[FIREBASE_SCREEN_INSTANCE_ID_KEY] }, current) : current))));
161};
162class ScreenTrackingService {
163 constructor(router, title, componentFactoryResolver, zone, userTrackingService, injector) {
164 registerVersion('angularfire', VERSION.full, 'screen-tracking');
165 // The APP_INITIALIZER that is making isSupported() sync for the sake of convenient DI
166 // may not be done when services are initialized. Guard the functionality by first ensuring
167 // that the (global) promise has resolved, then get Analytics from the injector.
168 isSupported().then(() => {
169 const analytics = injector.get(Analytics);
170 if (!router || !analytics) {
171 return;
172 }
173 zone.runOutsideAngular(() => {
174 this.disposable = ɵscreenViewEvent(router, title, componentFactoryResolver).pipe(switchMap((params) => __awaiter(this, void 0, void 0, function* () {
175 if (userTrackingService) {
176 yield userTrackingService.initialized;
177 }
178 return logEvent(analytics, SCREEN_VIEW_EVENT, params);
179 }))).subscribe();
180 });
181 });
182 }
183 ngOnDestroy() {
184 if (this.disposable) {
185 this.disposable.unsubscribe();
186 }
187 }
188}
189ScreenTrackingService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: ScreenTrackingService, deps: [{ token: i1$1.Router, optional: true }, { token: i2.Title, optional: true }, { token: i0.ComponentFactoryResolver }, { token: i0.NgZone }, { token: UserTrackingService, optional: true }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
190ScreenTrackingService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: ScreenTrackingService });
191i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: ScreenTrackingService, decorators: [{
192 type: Injectable
193 }], ctorParameters: function () { return [{ type: i1$1.Router, decorators: [{
194 type: Optional
195 }] }, { type: i2.Title, decorators: [{
196 type: Optional
197 }] }, { type: i0.ComponentFactoryResolver }, { type: i0.NgZone }, { type: UserTrackingService, decorators: [{
198 type: Optional
199 }] }, { type: i0.Injector }]; } });
200
201const PROVIDED_ANALYTICS_INSTANCES = new InjectionToken('angularfire2.analytics-instances');
202function defaultAnalyticsInstanceFactory(provided, defaultApp) {
203 if (!ɵisAnalyticsSupportedFactory.sync()) {
204 return null;
205 }
206 const defaultAnalytics = ɵgetDefaultInstanceOf(ANALYTICS_PROVIDER_NAME, provided, defaultApp);
207 return defaultAnalytics && new Analytics(defaultAnalytics);
208}
209function analyticsInstanceFactory(fn) {
210 return (zone, injector) => {
211 if (!ɵisAnalyticsSupportedFactory.sync()) {
212 return null;
213 }
214 const analytics = zone.runOutsideAngular(() => fn(injector));
215 return new Analytics(analytics);
216 };
217}
218const ANALYTICS_INSTANCES_PROVIDER = {
219 provide: AnalyticsInstances,
220 deps: [
221 [new Optional(), PROVIDED_ANALYTICS_INSTANCES],
222 ]
223};
224const DEFAULT_ANALYTICS_INSTANCE_PROVIDER = {
225 provide: Analytics,
226 useFactory: defaultAnalyticsInstanceFactory,
227 deps: [
228 [new Optional(), PROVIDED_ANALYTICS_INSTANCES],
229 FirebaseApp,
230 ]
231};
232class AnalyticsModule {
233 constructor(_screenTrackingService, _userTrackingService) {
234 registerVersion('angularfire', VERSION.full, 'analytics');
235 }
236}
237AnalyticsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AnalyticsModule, deps: [{ token: ScreenTrackingService, optional: true }, { token: UserTrackingService, optional: true }], target: i0.ɵɵFactoryTarget.NgModule });
238AnalyticsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AnalyticsModule });
239AnalyticsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AnalyticsModule, providers: [
240 DEFAULT_ANALYTICS_INSTANCE_PROVIDER,
241 ANALYTICS_INSTANCES_PROVIDER,
242 {
243 provide: APP_INITIALIZER,
244 useValue: ɵisAnalyticsSupportedFactory.async,
245 multi: true,
246 }
247 ] });
248i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AnalyticsModule, decorators: [{
249 type: NgModule,
250 args: [{
251 providers: [
252 DEFAULT_ANALYTICS_INSTANCE_PROVIDER,
253 ANALYTICS_INSTANCES_PROVIDER,
254 {
255 provide: APP_INITIALIZER,
256 useValue: ɵisAnalyticsSupportedFactory.async,
257 multi: true,
258 }
259 ]
260 }]
261 }], ctorParameters: function () { return [{ type: ScreenTrackingService, decorators: [{
262 type: Optional
263 }] }, { type: UserTrackingService, decorators: [{
264 type: Optional
265 }] }]; } });
266function provideAnalytics(fn, ...deps) {
267 return {
268 ngModule: AnalyticsModule,
269 providers: [{
270 provide: PROVIDED_ANALYTICS_INSTANCES,
271 useFactory: analyticsInstanceFactory(fn),
272 multi: true,
273 deps: [
274 NgZone,
275 Injector,
276 ɵAngularFireSchedulers,
277 FirebaseApps,
278 ...deps,
279 ]
280 }]
281 };
282}
283
284/**
285 * Generated bundle index. Do not edit.
286 */
287
288export { Analytics, AnalyticsInstances, AnalyticsModule, ScreenTrackingService, UserTrackingService, analyticInstance$, getAnalytics, initializeAnalytics, isSupported, logEvent, provideAnalytics, setAnalyticsCollectionEnabled, setCurrentScreen, setUserId, setUserProperties, settings, ɵscreenViewEvent };
289//# sourceMappingURL=angular-fire-analytics.js.map