mixpanel-browser 2.58.0 → 2.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/tests.yml +1 -1
- package/CHANGELOG.md +4 -0
- package/dist/mixpanel-core.cjs.js +720 -56
- package/dist/mixpanel-recorder.js +7 -3
- package/dist/mixpanel-recorder.min.js +2 -2
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +720 -56
- package/dist/mixpanel.amd.js +739 -75
- package/dist/mixpanel.cjs.js +739 -75
- package/dist/mixpanel.globals.js +720 -56
- package/dist/mixpanel.min.js +134 -122
- package/dist/mixpanel.module.js +739 -75
- package/dist/mixpanel.umd.js +739 -75
- package/package.json +1 -1
- package/src/autocapture/index.js +271 -0
- package/src/autocapture/utils.js +434 -0
- package/src/config.js +1 -1
- package/src/mixpanel-core.js +8 -53
- package/src/utils.js +27 -1
- package/src/window.js +4 -1
package/package.json
CHANGED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { _, document, safewrap, safewrapClass } from '../utils';
|
|
2
|
+
import { window } from '../window';
|
|
3
|
+
import {
|
|
4
|
+
getPropsForDOMEvent, logger, minDOMApisSupported,
|
|
5
|
+
EV_CHANGE, EV_CLICK, EV_HASHCHANGE, EV_MP_LOCATION_CHANGE, EV_POPSTATE,
|
|
6
|
+
EV_SCROLLEND, EV_SUBMIT
|
|
7
|
+
} from './utils';
|
|
8
|
+
|
|
9
|
+
var AUTOCAPTURE_CONFIG_KEY = 'autocapture';
|
|
10
|
+
var LEGACY_PAGEVIEW_CONFIG_KEY = 'track_pageview';
|
|
11
|
+
|
|
12
|
+
var PAGEVIEW_OPTION_FULL_URL = 'full-url';
|
|
13
|
+
var PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING = 'url-with-path-and-query-string';
|
|
14
|
+
var PAGEVIEW_OPTION_URL_WITH_PATH = 'url-with-path';
|
|
15
|
+
|
|
16
|
+
var CONFIG_BLOCK_SELECTORS = 'block_selectors';
|
|
17
|
+
var CONFIG_BLOCK_URL_REGEXES = 'block_url_regexes';
|
|
18
|
+
var CONFIG_CAPTURE_TEXT_CONTENT = 'capture_text_content';
|
|
19
|
+
var CONFIG_TRACK_CLICK = 'click';
|
|
20
|
+
var CONFIG_TRACK_INPUT = 'input';
|
|
21
|
+
var CONFIG_TRACK_PAGEVIEW = 'pageview';
|
|
22
|
+
var CONFIG_TRACK_SCROLL = 'scroll';
|
|
23
|
+
var CONFIG_TRACK_SUBMIT = 'submit';
|
|
24
|
+
|
|
25
|
+
var CONFIG_DEFAULTS = {};
|
|
26
|
+
CONFIG_DEFAULTS[CONFIG_CAPTURE_TEXT_CONTENT] = false;
|
|
27
|
+
CONFIG_DEFAULTS[CONFIG_TRACK_CLICK] = true;
|
|
28
|
+
CONFIG_DEFAULTS[CONFIG_TRACK_INPUT] = true;
|
|
29
|
+
CONFIG_DEFAULTS[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
|
|
30
|
+
CONFIG_DEFAULTS[CONFIG_TRACK_SCROLL] = true;
|
|
31
|
+
CONFIG_DEFAULTS[CONFIG_TRACK_SUBMIT] = true;
|
|
32
|
+
|
|
33
|
+
var DEFAULT_PROPS = {
|
|
34
|
+
'$mp_autocapture': true
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
var MP_EV_CLICK = '$mp_click';
|
|
38
|
+
var MP_EV_INPUT = '$mp_input_change';
|
|
39
|
+
var MP_EV_SCROLL = '$mp_scroll';
|
|
40
|
+
var MP_EV_SUBMIT = '$mp_submit';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Autocapture: manages automatic event tracking
|
|
44
|
+
* @constructor
|
|
45
|
+
*/
|
|
46
|
+
var Autocapture = function(mp) {
|
|
47
|
+
this.mp = mp;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
Autocapture.prototype.init = function() {
|
|
51
|
+
if (!minDOMApisSupported()) {
|
|
52
|
+
logger.critical('Autocapture unavailable: missing required DOM APIs');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.initPageviewTracking();
|
|
57
|
+
this.initClickTracking();
|
|
58
|
+
this.initInputTracking();
|
|
59
|
+
this.initScrollTracking();
|
|
60
|
+
this.initSubmitTracking();
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
Autocapture.prototype.getFullConfig = function() {
|
|
64
|
+
var autocaptureConfig = this.mp.get_config(AUTOCAPTURE_CONFIG_KEY);
|
|
65
|
+
if (!autocaptureConfig) {
|
|
66
|
+
// Autocapture is completely off
|
|
67
|
+
return {};
|
|
68
|
+
} else if (_.isObject(autocaptureConfig)) {
|
|
69
|
+
return _.extend({}, CONFIG_DEFAULTS, autocaptureConfig);
|
|
70
|
+
} else {
|
|
71
|
+
// Autocapture config is non-object truthy value, return default
|
|
72
|
+
return CONFIG_DEFAULTS;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
Autocapture.prototype.getConfig = function(key) {
|
|
77
|
+
return this.getFullConfig()[key];
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
Autocapture.prototype.currentUrlBlocked = function() {
|
|
81
|
+
var blockUrlRegexes = this.getConfig(CONFIG_BLOCK_URL_REGEXES) || [];
|
|
82
|
+
if (!blockUrlRegexes || !blockUrlRegexes.length) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
var currentUrl = _.info.currentUrl();
|
|
87
|
+
for (var i = 0; i < blockUrlRegexes.length; i++) {
|
|
88
|
+
try {
|
|
89
|
+
if (currentUrl.match(blockUrlRegexes[i])) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
logger.critical('Error while checking block URL regex: ' + blockUrlRegexes[i], err);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
Autocapture.prototype.pageviewTrackingConfig = function() {
|
|
101
|
+
// supports both autocapture config and old track_pageview config
|
|
102
|
+
if (this.mp.get_config(AUTOCAPTURE_CONFIG_KEY)) {
|
|
103
|
+
return this.getConfig(CONFIG_TRACK_PAGEVIEW);
|
|
104
|
+
} else {
|
|
105
|
+
return this.mp.get_config(LEGACY_PAGEVIEW_CONFIG_KEY);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// helper for event handlers
|
|
110
|
+
Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
|
|
111
|
+
if (this.currentUrlBlocked()) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
var props = getPropsForDOMEvent(
|
|
116
|
+
ev,
|
|
117
|
+
this.getConfig(CONFIG_BLOCK_SELECTORS),
|
|
118
|
+
this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT)
|
|
119
|
+
);
|
|
120
|
+
if (props) {
|
|
121
|
+
_.extend(props, DEFAULT_PROPS);
|
|
122
|
+
this.mp.track(mpEventName, props);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
Autocapture.prototype.initClickTracking = function() {
|
|
127
|
+
window.removeEventListener(EV_CLICK, this.listenerClick);
|
|
128
|
+
|
|
129
|
+
if (!this.getConfig(CONFIG_TRACK_CLICK)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
logger.log('Initializing click tracking');
|
|
133
|
+
|
|
134
|
+
this.listenerClick = window.addEventListener(EV_CLICK, function(ev) {
|
|
135
|
+
if (!this.getConfig(CONFIG_TRACK_CLICK)) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this.trackDomEvent(ev, MP_EV_CLICK);
|
|
139
|
+
}.bind(this));
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
Autocapture.prototype.initInputTracking = function() {
|
|
143
|
+
window.removeEventListener(EV_CHANGE, this.listenerChange);
|
|
144
|
+
|
|
145
|
+
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
logger.log('Initializing input tracking');
|
|
149
|
+
|
|
150
|
+
this.listenerChange = window.addEventListener(EV_CHANGE, function(ev) {
|
|
151
|
+
if (!this.getConfig(CONFIG_TRACK_INPUT)) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
this.trackDomEvent(ev, MP_EV_INPUT);
|
|
155
|
+
}.bind(this));
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
Autocapture.prototype.initPageviewTracking = function() {
|
|
159
|
+
window.removeEventListener(EV_POPSTATE, this.listenerPopstate);
|
|
160
|
+
window.removeEventListener(EV_HASHCHANGE, this.listenerHashchange);
|
|
161
|
+
window.removeEventListener(EV_MP_LOCATION_CHANGE, this.listenerLocationchange);
|
|
162
|
+
|
|
163
|
+
if (!this.pageviewTrackingConfig()) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
logger.log('Initializing pageview tracking');
|
|
167
|
+
|
|
168
|
+
var previousTrackedUrl = '';
|
|
169
|
+
var tracked = false;
|
|
170
|
+
if (!this.currentUrlBlocked()) {
|
|
171
|
+
tracked = this.mp.track_pageview(DEFAULT_PROPS);
|
|
172
|
+
}
|
|
173
|
+
if (tracked) {
|
|
174
|
+
previousTrackedUrl = _.info.currentUrl();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.listenerPopstate = window.addEventListener(EV_POPSTATE, function() {
|
|
178
|
+
window.dispatchEvent(new Event(EV_MP_LOCATION_CHANGE));
|
|
179
|
+
});
|
|
180
|
+
this.listenerHashchange = window.addEventListener(EV_HASHCHANGE, function() {
|
|
181
|
+
window.dispatchEvent(new Event(EV_MP_LOCATION_CHANGE));
|
|
182
|
+
});
|
|
183
|
+
var nativePushState = window.history.pushState;
|
|
184
|
+
if (typeof nativePushState === 'function') {
|
|
185
|
+
window.history.pushState = function(state, unused, url) {
|
|
186
|
+
nativePushState.call(window.history, state, unused, url);
|
|
187
|
+
window.dispatchEvent(new Event(EV_MP_LOCATION_CHANGE));
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
var nativeReplaceState = window.history.replaceState;
|
|
191
|
+
if (typeof nativeReplaceState === 'function') {
|
|
192
|
+
window.history.replaceState = function(state, unused, url) {
|
|
193
|
+
nativeReplaceState.call(window.history, state, unused, url);
|
|
194
|
+
window.dispatchEvent(new Event(EV_MP_LOCATION_CHANGE));
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
this.listenerLocationchange = window.addEventListener(EV_MP_LOCATION_CHANGE, safewrap(function() {
|
|
198
|
+
if (this.currentUrlBlocked()) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
var currentUrl = _.info.currentUrl();
|
|
203
|
+
var shouldTrack = false;
|
|
204
|
+
var trackPageviewOption = this.pageviewTrackingConfig();
|
|
205
|
+
if (trackPageviewOption === PAGEVIEW_OPTION_FULL_URL) {
|
|
206
|
+
shouldTrack = currentUrl !== previousTrackedUrl;
|
|
207
|
+
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING) {
|
|
208
|
+
shouldTrack = currentUrl.split('#')[0] !== previousTrackedUrl.split('#')[0];
|
|
209
|
+
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH) {
|
|
210
|
+
shouldTrack = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (shouldTrack) {
|
|
214
|
+
var tracked = this.mp.track_pageview(DEFAULT_PROPS);
|
|
215
|
+
if (tracked) {
|
|
216
|
+
previousTrackedUrl = currentUrl;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}.bind(this)));
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
Autocapture.prototype.initScrollTracking = function() {
|
|
223
|
+
window.removeEventListener(EV_SCROLLEND, this.listenerScroll);
|
|
224
|
+
|
|
225
|
+
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
logger.log('Initializing scroll tracking');
|
|
229
|
+
|
|
230
|
+
this.listenerScroll = window.addEventListener(EV_SCROLLEND, safewrap(function() {
|
|
231
|
+
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (this.currentUrlBlocked()) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
var scrollTop = window.scrollY;
|
|
239
|
+
var props = _.extend({'$scroll_top': scrollTop}, DEFAULT_PROPS);
|
|
240
|
+
try {
|
|
241
|
+
var scrollHeight = document.body.scrollHeight;
|
|
242
|
+
var scrollPercentage = Math.round((scrollTop / (scrollHeight - window.innerHeight)) * 100);
|
|
243
|
+
props['$scroll_height'] = scrollHeight;
|
|
244
|
+
props['$scroll_percentage'] = scrollPercentage;
|
|
245
|
+
} catch (err) {
|
|
246
|
+
logger.critical('Error while calculating scroll percentage', err);
|
|
247
|
+
}
|
|
248
|
+
this.mp.track(MP_EV_SCROLL, props);
|
|
249
|
+
}.bind(this)));
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
Autocapture.prototype.initSubmitTracking = function() {
|
|
253
|
+
window.removeEventListener(EV_SUBMIT, this.listenerSubmit);
|
|
254
|
+
|
|
255
|
+
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
logger.log('Initializing submit tracking');
|
|
259
|
+
|
|
260
|
+
this.listenerSubmit = window.addEventListener(EV_SUBMIT, function(ev) {
|
|
261
|
+
if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
this.trackDomEvent(ev, MP_EV_SUBMIT);
|
|
265
|
+
}.bind(this));
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// TODO integrate error_reporter from mixpanel instance
|
|
269
|
+
safewrapClass(Autocapture);
|
|
270
|
+
|
|
271
|
+
export { Autocapture };
|