-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
gtm-support.ts
219 lines (203 loc) · 6.66 KB
/
gtm-support.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
import { assertIsGtmId } from './assert-is-gtm-id';
import type { DataLayerObject } from './data-layer-object';
import type { GtmIdContainer } from './gtm-container';
import type { GtmSupportOptions } from './options';
import type { LoadScriptOptions } from './utils';
import { hasScript, loadScript } from './utils';
/**
* Object definition for a track event.
*/
export interface TrackEventOptions {
[key: string]: any;
event?: string;
category?: any;
action?: any;
label?: any;
value?: any;
noninteraction?: boolean;
}
/**
* The GTM Support main class.
*/
export class GtmSupport {
/** GTM Container ID. */
public readonly id: string | string[] | GtmIdContainer[];
/** GTM Support Options. */
public readonly options: Omit<GtmSupportOptions, 'id'>;
/**
* Constructs a new `GtmSupport` instance.
*
* @param options Options.
*/
public constructor(options: GtmSupportOptions) {
if (Array.isArray(options.id)) {
for (const idOrObject of options.id) {
if (typeof idOrObject === 'string') {
assertIsGtmId(idOrObject);
} else {
assertIsGtmId(idOrObject.id);
}
}
} else {
assertIsGtmId(options.id);
}
this.id = options.id;
this.options = {
enabled: true,
debug: false,
loadScript: true,
defer: false,
compatibility: false,
...options
};
// @ts-expect-error: Just remove the id from options
delete this.options.id;
}
/**
* Whether the script is running in a browser or not.
*
* You can override this function if you need to.
*
* @returns `true` if the script runs in browser context.
*/
public isInBrowserContext: () => boolean = () => typeof window !== 'undefined';
/**
* Check if plugin is enabled.
*
* @returns `true` if the plugin is enabled, otherwise `false`.
*/
public enabled(): boolean {
return this.options.enabled ?? true;
}
/**
* Enable or disable plugin.
*
* When enabling with this function, the script will be attached to the `document` if:
*
* - the script runs in browser context
* - the `document` doesn't have the script already attached
* - the `loadScript` option is set to `true`
*
* @param enabled `true` to enable, `false` to disable. Default: `true`.
*/
public enable(enabled: boolean = true): void {
this.options.enabled = enabled;
if (this.isInBrowserContext() && enabled && !hasScript() && this.options.loadScript) {
if (Array.isArray(this.id)) {
this.id.forEach((id: string | GtmIdContainer) => {
if (typeof id === 'string') {
loadScript(id, { ...this.options } as LoadScriptOptions);
} else {
loadScript(id.id, { ...this.options, queryParams: id.queryParams } as LoadScriptOptions);
}
});
} else {
loadScript(this.id, { ...this.options } as LoadScriptOptions);
}
}
}
/**
* Check if plugin is in debug mode.
*
* @returns `true` if the plugin is in debug mode, otherwise `false`.
*/
public debugEnabled(): boolean {
return this.options.debug ?? false;
}
/**
* Enable or disable debug mode.
*
* @param enable `true` to enable, `false` to disable.
*/
public debug(enable: boolean): void {
this.options.debug = enable;
}
/**
* Returns the `window.dataLayer` array if the script is running in browser context and the plugin is enabled,
* otherwise `false`.
*
* @returns The `window.dataLayer` if script is running in browser context and plugin is enabled, otherwise `false`.
*/
public dataLayer(): DataLayerObject[] | false {
if (this.isInBrowserContext() && this.options.enabled) {
return (window.dataLayer = window.dataLayer ?? []);
}
return false;
}
/**
* Track a view event with `event: "content-view"`.
*
* The event will only be send if the script runs in browser context and the if plugin is enabled.
*
* If debug mode is enabled, a "Dispatching TrackView" is logged,
* regardless of whether the plugin is enabled or the plugin is being executed in browser context.
*
* @param screenName Name of the screen passed as `"content-view-name"`.
* @param path Path passed as `"content-name"`.
* @param additionalEventData Additional data for the event object. `event`, `"content-name"` and `"content-view-name"` will always be overridden.
*/
public trackView(screenName: string, path: string, additionalEventData: Record<string, any> = {}): void {
const trigger: boolean = this.isInBrowserContext() && (this.options.enabled ?? false);
if (this.options.debug) {
console.log(`[GTM-Support${trigger ? '' : '(disabled)'}]: Dispatching TrackView`, { screenName, path });
}
if (trigger) {
const dataLayer: DataLayerObject[] = (window.dataLayer = window.dataLayer ?? []);
dataLayer.push({
...additionalEventData,
event: 'content-view',
'content-name': path,
'content-view-name': screenName
});
}
}
/**
* Track an event.
*
* The event will only be send if the script runs in browser context and the if plugin is enabled.
*
* If debug mode is enabled, a "Dispatching event" is logged,
* regardless of whether the plugin is enabled or the plugin is being executed in browser context.
*
* @param param0 Object that will be used for configuring the event object passed to GTM.
* @param param0.event `event`, default to `"interaction"` when pushed to `window.dataLayer`.
* @param param0.category Optional `category`, passed as `target`.
* @param param0.action Optional `action`, passed as `action`.
* @param param0.label Optional `label`, passed as `"target-properties"`.
* @param param0.value Optional `value`, passed as `value`.
* @param param0.noninteraction Optional `noninteraction`, passed as `"interaction-type"`.
*/
public trackEvent({
event,
category = null,
action = null,
label = null,
value = null,
noninteraction = false,
...rest
}: TrackEventOptions = {}): void {
const trigger: boolean = this.isInBrowserContext() && (this.options.enabled ?? false);
if (this.options.debug) {
console.log(`[GTM-Support${trigger ? '' : '(disabled)'}]: Dispatching event`, {
event,
category,
action,
label,
value,
...rest
});
}
if (trigger) {
const dataLayer: DataLayerObject[] = (window.dataLayer = window.dataLayer ?? []);
dataLayer.push({
event: event ?? 'interaction',
target: category,
action: action,
'target-properties': label,
value: value,
'interaction-type': noninteraction,
...rest
});
}
}
}