mixpanel-browser 2.59.0 → 2.60.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/CHANGELOG.md +5 -1
- package/README.md +1 -1
- package/dist/mixpanel-core.cjs.js +215 -49
- package/dist/mixpanel-recorder.js +1 -1
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +215 -49
- package/dist/mixpanel.amd.js +215 -49
- package/dist/mixpanel.cjs.js +215 -49
- package/dist/mixpanel.globals.js +215 -49
- package/dist/mixpanel.min.js +138 -134
- package/dist/mixpanel.module.js +215 -49
- package/dist/mixpanel.umd.js +215 -49
- package/package.json +1 -1
- package/src/autocapture/index.js +80 -9
- package/src/autocapture/utils.js +129 -38
- package/src/config.js +1 -1
- package/src/mixpanel-persistence.js +6 -2
package/dist/mixpanel.module.js
CHANGED
|
@@ -4507,7 +4507,7 @@ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => {
|
|
|
4507
4507
|
|
|
4508
4508
|
var Config = {
|
|
4509
4509
|
DEBUG: false,
|
|
4510
|
-
LIB_VERSION: '2.
|
|
4510
|
+
LIB_VERSION: '2.60.0'
|
|
4511
4511
|
};
|
|
4512
4512
|
|
|
4513
4513
|
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
@@ -8262,7 +8262,7 @@ function getPreviousElementSibling(el) {
|
|
|
8262
8262
|
}
|
|
8263
8263
|
}
|
|
8264
8264
|
|
|
8265
|
-
function getPropertiesFromElement(el) {
|
|
8265
|
+
function getPropertiesFromElement(el, ev, blockAttrsSet, extraAttrs, allowElementCallback, allowSelectors) {
|
|
8266
8266
|
var props = {
|
|
8267
8267
|
'$classes': getClassName(el).split(' '),
|
|
8268
8268
|
'$tag_name': el.tagName.toLowerCase()
|
|
@@ -8272,9 +8272,9 @@ function getPropertiesFromElement(el) {
|
|
|
8272
8272
|
props['$id'] = elId;
|
|
8273
8273
|
}
|
|
8274
8274
|
|
|
8275
|
-
if (
|
|
8276
|
-
_.each(TRACKED_ATTRS, function(attr) {
|
|
8277
|
-
if (el.hasAttribute(attr)) {
|
|
8275
|
+
if (shouldTrackElementDetails(el, ev, allowElementCallback, allowSelectors)) {
|
|
8276
|
+
_.each(TRACKED_ATTRS.concat(extraAttrs), function(attr) {
|
|
8277
|
+
if (el.hasAttribute(attr) && !blockAttrsSet[attr]) {
|
|
8278
8278
|
var attrVal = el.getAttribute(attr);
|
|
8279
8279
|
if (shouldTrackValue(attrVal)) {
|
|
8280
8280
|
props['$attr-' + attr] = attrVal;
|
|
@@ -8298,8 +8298,21 @@ function getPropertiesFromElement(el) {
|
|
|
8298
8298
|
return props;
|
|
8299
8299
|
}
|
|
8300
8300
|
|
|
8301
|
-
function getPropsForDOMEvent(ev,
|
|
8302
|
-
|
|
8301
|
+
function getPropsForDOMEvent(ev, config) {
|
|
8302
|
+
var allowElementCallback = config.allowElementCallback;
|
|
8303
|
+
var allowSelectors = config.allowSelectors || [];
|
|
8304
|
+
var blockAttrs = config.blockAttrs || [];
|
|
8305
|
+
var blockElementCallback = config.blockElementCallback;
|
|
8306
|
+
var blockSelectors = config.blockSelectors || [];
|
|
8307
|
+
var captureTextContent = config.captureTextContent || false;
|
|
8308
|
+
var captureExtraAttrs = config.captureExtraAttrs || [];
|
|
8309
|
+
|
|
8310
|
+
// convert array to set every time, as the config may have changed
|
|
8311
|
+
var blockAttrsSet = {};
|
|
8312
|
+
_.each(blockAttrs, function(attr) {
|
|
8313
|
+
blockAttrsSet[attr] = true;
|
|
8314
|
+
});
|
|
8315
|
+
|
|
8303
8316
|
var props = null;
|
|
8304
8317
|
|
|
8305
8318
|
var target = typeof ev.target === 'undefined' ? ev.srcElement : ev.target;
|
|
@@ -8307,7 +8320,11 @@ function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
|
|
|
8307
8320
|
target = target.parentNode;
|
|
8308
8321
|
}
|
|
8309
8322
|
|
|
8310
|
-
if (
|
|
8323
|
+
if (
|
|
8324
|
+
shouldTrackDomEvent(target, ev) &&
|
|
8325
|
+
isElementAllowed(target, ev, allowElementCallback, allowSelectors) &&
|
|
8326
|
+
!isElementBlocked(target, ev, blockElementCallback, blockSelectors)
|
|
8327
|
+
) {
|
|
8311
8328
|
var targetElementList = [target];
|
|
8312
8329
|
var curEl = target;
|
|
8313
8330
|
while (curEl.parentNode && !isTag(curEl, 'body')) {
|
|
@@ -8318,37 +8335,20 @@ function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
|
|
|
8318
8335
|
var elementsJson = [];
|
|
8319
8336
|
var href, explicitNoTrack = false;
|
|
8320
8337
|
_.each(targetElementList, function(el) {
|
|
8321
|
-
var
|
|
8338
|
+
var shouldTrackDetails = shouldTrackElementDetails(el, ev, allowElementCallback, allowSelectors);
|
|
8322
8339
|
|
|
8323
8340
|
// if the element or a parent element is an anchor tag
|
|
8324
8341
|
// include the href as a property
|
|
8325
|
-
if (el.tagName.toLowerCase() === 'a') {
|
|
8342
|
+
if (!blockAttrsSet['href'] && el.tagName.toLowerCase() === 'a') {
|
|
8326
8343
|
href = el.getAttribute('href');
|
|
8327
|
-
href =
|
|
8344
|
+
href = shouldTrackDetails && shouldTrackValue(href) && href;
|
|
8328
8345
|
}
|
|
8329
8346
|
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
_.each(OPT_OUT_CLASSES, function(cls) {
|
|
8333
|
-
if (classes[cls]) {
|
|
8334
|
-
explicitNoTrack = true;
|
|
8335
|
-
}
|
|
8336
|
-
});
|
|
8337
|
-
|
|
8338
|
-
if (!explicitNoTrack) {
|
|
8339
|
-
// programmatically prevent tracking of elements that match CSS selectors
|
|
8340
|
-
_.each(blockSelectors, function(sel) {
|
|
8341
|
-
try {
|
|
8342
|
-
if (el['matches'](sel)) {
|
|
8343
|
-
explicitNoTrack = true;
|
|
8344
|
-
}
|
|
8345
|
-
} catch (err) {
|
|
8346
|
-
logger.critical('Error while checking selector: ' + sel, err);
|
|
8347
|
-
}
|
|
8348
|
-
});
|
|
8347
|
+
if (isElementBlocked(el, ev, blockElementCallback, blockSelectors)) {
|
|
8348
|
+
explicitNoTrack = true;
|
|
8349
8349
|
}
|
|
8350
8350
|
|
|
8351
|
-
elementsJson.push(getPropertiesFromElement(el));
|
|
8351
|
+
elementsJson.push(getPropertiesFromElement(el, ev, blockAttrsSet, captureExtraAttrs, allowElementCallback, allowSelectors));
|
|
8352
8352
|
}, this);
|
|
8353
8353
|
|
|
8354
8354
|
if (!explicitNoTrack) {
|
|
@@ -8362,9 +8362,17 @@ function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
|
|
|
8362
8362
|
'$viewportHeight': Math.max(docElement['clientHeight'], win['innerHeight'] || 0),
|
|
8363
8363
|
'$viewportWidth': Math.max(docElement['clientWidth'], win['innerWidth'] || 0)
|
|
8364
8364
|
};
|
|
8365
|
+
_.each(captureExtraAttrs, function(attr) {
|
|
8366
|
+
if (!blockAttrsSet[attr] && target.hasAttribute(attr)) {
|
|
8367
|
+
var attrVal = target.getAttribute(attr);
|
|
8368
|
+
if (shouldTrackValue(attrVal)) {
|
|
8369
|
+
props['$el_attr__' + attr] = attrVal;
|
|
8370
|
+
}
|
|
8371
|
+
}
|
|
8372
|
+
});
|
|
8365
8373
|
|
|
8366
8374
|
if (captureTextContent) {
|
|
8367
|
-
elementText = getSafeText(target);
|
|
8375
|
+
elementText = getSafeText(target, ev, allowElementCallback, allowSelectors);
|
|
8368
8376
|
if (elementText && elementText.length) {
|
|
8369
8377
|
props['$el_text'] = elementText;
|
|
8370
8378
|
}
|
|
@@ -8380,14 +8388,22 @@ function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
|
|
|
8380
8388
|
}
|
|
8381
8389
|
// prioritize text content from "real" click target if different from original target
|
|
8382
8390
|
if (captureTextContent) {
|
|
8383
|
-
var elementText = getSafeText(target);
|
|
8391
|
+
var elementText = getSafeText(target, ev, allowElementCallback, allowSelectors);
|
|
8384
8392
|
if (elementText && elementText.length) {
|
|
8385
8393
|
props['$el_text'] = elementText;
|
|
8386
8394
|
}
|
|
8387
8395
|
}
|
|
8388
8396
|
|
|
8389
8397
|
if (target) {
|
|
8390
|
-
|
|
8398
|
+
// target may have been recalculated; check allowlists and blocklists again
|
|
8399
|
+
if (
|
|
8400
|
+
!isElementAllowed(target, ev, allowElementCallback, allowSelectors) ||
|
|
8401
|
+
isElementBlocked(target, ev, blockElementCallback, blockSelectors)
|
|
8402
|
+
) {
|
|
8403
|
+
return null;
|
|
8404
|
+
}
|
|
8405
|
+
|
|
8406
|
+
var targetProps = getPropertiesFromElement(target, ev, blockAttrsSet, captureExtraAttrs, allowElementCallback, allowSelectors);
|
|
8391
8407
|
props['$target'] = targetProps;
|
|
8392
8408
|
// pull up more props onto main event props
|
|
8393
8409
|
props['$el_classes'] = targetProps['$classes'];
|
|
@@ -8403,19 +8419,20 @@ function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
|
|
|
8403
8419
|
}
|
|
8404
8420
|
|
|
8405
8421
|
|
|
8406
|
-
|
|
8422
|
+
/**
|
|
8407
8423
|
* Get the direct text content of an element, protecting against sensitive data collection.
|
|
8408
8424
|
* Concats textContent of each of the element's text node children; this avoids potential
|
|
8409
8425
|
* collection of sensitive data that could happen if we used element.textContent and the
|
|
8410
8426
|
* element had sensitive child elements, since element.textContent includes child content.
|
|
8411
8427
|
* Scrubs values that look like they could be sensitive (i.e. cc or ssn number).
|
|
8412
8428
|
* @param {Element} el - element to get the text of
|
|
8429
|
+
* @param {Array<string>} allowSelectors - CSS selectors for elements that should be included
|
|
8413
8430
|
* @returns {string} the element's direct text content
|
|
8414
8431
|
*/
|
|
8415
|
-
function getSafeText(el) {
|
|
8432
|
+
function getSafeText(el, ev, allowElementCallback, allowSelectors) {
|
|
8416
8433
|
var elText = '';
|
|
8417
8434
|
|
|
8418
|
-
if (
|
|
8435
|
+
if (shouldTrackElementDetails(el, ev, allowElementCallback, allowSelectors) && el.childNodes && el.childNodes.length) {
|
|
8419
8436
|
_.each(el.childNodes, function(child) {
|
|
8420
8437
|
if (isTextNode(child) && child.textContent) {
|
|
8421
8438
|
elText += _.trim(child.textContent)
|
|
@@ -8454,6 +8471,75 @@ function guessRealClickTarget(ev) {
|
|
|
8454
8471
|
return target;
|
|
8455
8472
|
}
|
|
8456
8473
|
|
|
8474
|
+
function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
|
|
8475
|
+
if (allowElementCallback) {
|
|
8476
|
+
try {
|
|
8477
|
+
if (!allowElementCallback(el, ev)) {
|
|
8478
|
+
return false;
|
|
8479
|
+
}
|
|
8480
|
+
} catch (err) {
|
|
8481
|
+
logger.critical('Error while checking element in allowElementCallback', err);
|
|
8482
|
+
return false;
|
|
8483
|
+
}
|
|
8484
|
+
}
|
|
8485
|
+
|
|
8486
|
+
if (!allowSelectors.length) {
|
|
8487
|
+
// no allowlist; all elements are fair game
|
|
8488
|
+
return true;
|
|
8489
|
+
}
|
|
8490
|
+
|
|
8491
|
+
for (var i = 0; i < allowSelectors.length; i++) {
|
|
8492
|
+
var sel = allowSelectors[i];
|
|
8493
|
+
try {
|
|
8494
|
+
if (el['matches'](sel)) {
|
|
8495
|
+
return true;
|
|
8496
|
+
}
|
|
8497
|
+
} catch (err) {
|
|
8498
|
+
logger.critical('Error while checking selector: ' + sel, err);
|
|
8499
|
+
}
|
|
8500
|
+
}
|
|
8501
|
+
return false;
|
|
8502
|
+
}
|
|
8503
|
+
|
|
8504
|
+
function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
|
|
8505
|
+
var i;
|
|
8506
|
+
|
|
8507
|
+
if (blockElementCallback) {
|
|
8508
|
+
try {
|
|
8509
|
+
if (blockElementCallback(el, ev)) {
|
|
8510
|
+
return true;
|
|
8511
|
+
}
|
|
8512
|
+
} catch (err) {
|
|
8513
|
+
logger.critical('Error while checking element in blockElementCallback', err);
|
|
8514
|
+
return true;
|
|
8515
|
+
}
|
|
8516
|
+
}
|
|
8517
|
+
|
|
8518
|
+
if (blockSelectors && blockSelectors.length) {
|
|
8519
|
+
// programmatically prevent tracking of elements that match CSS selectors
|
|
8520
|
+
for (i = 0; i < blockSelectors.length; i++) {
|
|
8521
|
+
var sel = blockSelectors[i];
|
|
8522
|
+
try {
|
|
8523
|
+
if (el['matches'](sel)) {
|
|
8524
|
+
return true;
|
|
8525
|
+
}
|
|
8526
|
+
} catch (err) {
|
|
8527
|
+
logger.critical('Error while checking selector: ' + sel, err);
|
|
8528
|
+
}
|
|
8529
|
+
}
|
|
8530
|
+
}
|
|
8531
|
+
|
|
8532
|
+
// allow users to programmatically prevent tracking of elements by adding default classes such as 'mp-no-track'
|
|
8533
|
+
var classes = getClasses(el);
|
|
8534
|
+
for (i = 0; i < OPT_OUT_CLASSES.length; i++) {
|
|
8535
|
+
if (classes[OPT_OUT_CLASSES[i]]) {
|
|
8536
|
+
return true;
|
|
8537
|
+
}
|
|
8538
|
+
}
|
|
8539
|
+
|
|
8540
|
+
return false;
|
|
8541
|
+
}
|
|
8542
|
+
|
|
8457
8543
|
/*
|
|
8458
8544
|
* Check whether a DOM node has nodeType Node.ELEMENT_NODE
|
|
8459
8545
|
* @param {Node} node - node to check
|
|
@@ -8528,11 +8614,16 @@ function shouldTrackDomEvent(el, ev) {
|
|
|
8528
8614
|
* Check whether a DOM element should be "tracked" or if it may contain sensitive data
|
|
8529
8615
|
* using a variety of heuristics.
|
|
8530
8616
|
* @param {Element} el - element to check
|
|
8617
|
+
* @param {Array<string>} allowSelectors - CSS selectors for elements that should be included
|
|
8531
8618
|
* @returns {boolean} whether the element should be tracked
|
|
8532
8619
|
*/
|
|
8533
|
-
function
|
|
8620
|
+
function shouldTrackElementDetails(el, ev, allowElementCallback, allowSelectors) {
|
|
8534
8621
|
var i;
|
|
8535
8622
|
|
|
8623
|
+
if (!isElementAllowed(el, ev, allowElementCallback, allowSelectors)) {
|
|
8624
|
+
return false;
|
|
8625
|
+
}
|
|
8626
|
+
|
|
8536
8627
|
for (var curEl = el; curEl.parentNode && !isTag(curEl, 'body'); curEl = curEl.parentNode) {
|
|
8537
8628
|
var classes = getClasses(curEl);
|
|
8538
8629
|
for (i = 0; i < SENSITIVE_DATA_CLASSES.length; i++) {
|
|
@@ -8622,9 +8713,17 @@ var PAGEVIEW_OPTION_FULL_URL = 'full-url';
|
|
|
8622
8713
|
var PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING = 'url-with-path-and-query-string';
|
|
8623
8714
|
var PAGEVIEW_OPTION_URL_WITH_PATH = 'url-with-path';
|
|
8624
8715
|
|
|
8716
|
+
var CONFIG_ALLOW_ELEMENT_CALLBACK = 'allow_element_callback';
|
|
8717
|
+
var CONFIG_ALLOW_SELECTORS = 'allow_selectors';
|
|
8718
|
+
var CONFIG_ALLOW_URL_REGEXES = 'allow_url_regexes';
|
|
8719
|
+
var CONFIG_BLOCK_ATTRS = 'block_attrs';
|
|
8720
|
+
var CONFIG_BLOCK_ELEMENT_CALLBACK = 'block_element_callback';
|
|
8625
8721
|
var CONFIG_BLOCK_SELECTORS = 'block_selectors';
|
|
8626
8722
|
var CONFIG_BLOCK_URL_REGEXES = 'block_url_regexes';
|
|
8723
|
+
var CONFIG_CAPTURE_EXTRA_ATTRS = 'capture_extra_attrs';
|
|
8627
8724
|
var CONFIG_CAPTURE_TEXT_CONTENT = 'capture_text_content';
|
|
8725
|
+
var CONFIG_SCROLL_CAPTURE_ALL = 'scroll_capture_all';
|
|
8726
|
+
var CONFIG_SCROLL_CHECKPOINTS = 'scroll_depth_percent_checkpoints';
|
|
8628
8727
|
var CONFIG_TRACK_CLICK = 'click';
|
|
8629
8728
|
var CONFIG_TRACK_INPUT = 'input';
|
|
8630
8729
|
var CONFIG_TRACK_PAGEVIEW = 'pageview';
|
|
@@ -8632,7 +8731,16 @@ var CONFIG_TRACK_SCROLL = 'scroll';
|
|
|
8632
8731
|
var CONFIG_TRACK_SUBMIT = 'submit';
|
|
8633
8732
|
|
|
8634
8733
|
var CONFIG_DEFAULTS = {};
|
|
8734
|
+
CONFIG_DEFAULTS[CONFIG_ALLOW_SELECTORS] = [];
|
|
8735
|
+
CONFIG_DEFAULTS[CONFIG_ALLOW_URL_REGEXES] = [];
|
|
8736
|
+
CONFIG_DEFAULTS[CONFIG_BLOCK_ATTRS] = [];
|
|
8737
|
+
CONFIG_DEFAULTS[CONFIG_BLOCK_ELEMENT_CALLBACK] = null;
|
|
8738
|
+
CONFIG_DEFAULTS[CONFIG_BLOCK_SELECTORS] = [];
|
|
8739
|
+
CONFIG_DEFAULTS[CONFIG_BLOCK_URL_REGEXES] = [];
|
|
8740
|
+
CONFIG_DEFAULTS[CONFIG_CAPTURE_EXTRA_ATTRS] = [];
|
|
8635
8741
|
CONFIG_DEFAULTS[CONFIG_CAPTURE_TEXT_CONTENT] = false;
|
|
8742
|
+
CONFIG_DEFAULTS[CONFIG_SCROLL_CAPTURE_ALL] = false;
|
|
8743
|
+
CONFIG_DEFAULTS[CONFIG_SCROLL_CHECKPOINTS] = [25, 50, 75, 100];
|
|
8636
8744
|
CONFIG_DEFAULTS[CONFIG_TRACK_CLICK] = true;
|
|
8637
8745
|
CONFIG_DEFAULTS[CONFIG_TRACK_INPUT] = true;
|
|
8638
8746
|
CONFIG_DEFAULTS[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
|
|
@@ -8687,13 +8795,37 @@ Autocapture.prototype.getConfig = function(key) {
|
|
|
8687
8795
|
};
|
|
8688
8796
|
|
|
8689
8797
|
Autocapture.prototype.currentUrlBlocked = function() {
|
|
8798
|
+
var i;
|
|
8799
|
+
var currentUrl = _.info.currentUrl();
|
|
8800
|
+
|
|
8801
|
+
var allowUrlRegexes = this.getConfig(CONFIG_ALLOW_URL_REGEXES) || [];
|
|
8802
|
+
if (allowUrlRegexes.length) {
|
|
8803
|
+
// we're using an allowlist, only track if current URL matches
|
|
8804
|
+
var allowed = false;
|
|
8805
|
+
for (i = 0; i < allowUrlRegexes.length; i++) {
|
|
8806
|
+
var allowRegex = allowUrlRegexes[i];
|
|
8807
|
+
try {
|
|
8808
|
+
if (currentUrl.match(allowRegex)) {
|
|
8809
|
+
allowed = true;
|
|
8810
|
+
break;
|
|
8811
|
+
}
|
|
8812
|
+
} catch (err) {
|
|
8813
|
+
logger.critical('Error while checking block URL regex: ' + allowRegex, err);
|
|
8814
|
+
return true;
|
|
8815
|
+
}
|
|
8816
|
+
}
|
|
8817
|
+
if (!allowed) {
|
|
8818
|
+
// wasn't allowed by any regex
|
|
8819
|
+
return true;
|
|
8820
|
+
}
|
|
8821
|
+
}
|
|
8822
|
+
|
|
8690
8823
|
var blockUrlRegexes = this.getConfig(CONFIG_BLOCK_URL_REGEXES) || [];
|
|
8691
8824
|
if (!blockUrlRegexes || !blockUrlRegexes.length) {
|
|
8692
8825
|
return false;
|
|
8693
8826
|
}
|
|
8694
8827
|
|
|
8695
|
-
|
|
8696
|
-
for (var i = 0; i < blockUrlRegexes.length; i++) {
|
|
8828
|
+
for (i = 0; i < blockUrlRegexes.length; i++) {
|
|
8697
8829
|
try {
|
|
8698
8830
|
if (currentUrl.match(blockUrlRegexes[i])) {
|
|
8699
8831
|
return true;
|
|
@@ -8721,11 +8853,15 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
|
|
|
8721
8853
|
return;
|
|
8722
8854
|
}
|
|
8723
8855
|
|
|
8724
|
-
var props = getPropsForDOMEvent(
|
|
8725
|
-
|
|
8726
|
-
this.getConfig(
|
|
8727
|
-
this.getConfig(
|
|
8728
|
-
|
|
8856
|
+
var props = getPropsForDOMEvent(ev, {
|
|
8857
|
+
allowElementCallback: this.getConfig(CONFIG_ALLOW_ELEMENT_CALLBACK),
|
|
8858
|
+
allowSelectors: this.getConfig(CONFIG_ALLOW_SELECTORS),
|
|
8859
|
+
blockAttrs: this.getConfig(CONFIG_BLOCK_ATTRS),
|
|
8860
|
+
blockElementCallback: this.getConfig(CONFIG_BLOCK_ELEMENT_CALLBACK),
|
|
8861
|
+
blockSelectors: this.getConfig(CONFIG_BLOCK_SELECTORS),
|
|
8862
|
+
captureExtraAttrs: this.getConfig(CONFIG_CAPTURE_EXTRA_ATTRS),
|
|
8863
|
+
captureTextContent: this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT)
|
|
8864
|
+
});
|
|
8729
8865
|
if (props) {
|
|
8730
8866
|
_.extend(props, DEFAULT_PROPS);
|
|
8731
8867
|
this.mp.track(mpEventName, props);
|
|
@@ -8810,13 +8946,14 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
8810
8946
|
|
|
8811
8947
|
var currentUrl = _.info.currentUrl();
|
|
8812
8948
|
var shouldTrack = false;
|
|
8949
|
+
var didPathChange = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
|
|
8813
8950
|
var trackPageviewOption = this.pageviewTrackingConfig();
|
|
8814
8951
|
if (trackPageviewOption === PAGEVIEW_OPTION_FULL_URL) {
|
|
8815
8952
|
shouldTrack = currentUrl !== previousTrackedUrl;
|
|
8816
8953
|
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING) {
|
|
8817
8954
|
shouldTrack = currentUrl.split('#')[0] !== previousTrackedUrl.split('#')[0];
|
|
8818
8955
|
} else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH) {
|
|
8819
|
-
shouldTrack =
|
|
8956
|
+
shouldTrack = didPathChange;
|
|
8820
8957
|
}
|
|
8821
8958
|
|
|
8822
8959
|
if (shouldTrack) {
|
|
@@ -8824,6 +8961,10 @@ Autocapture.prototype.initPageviewTracking = function() {
|
|
|
8824
8961
|
if (tracked) {
|
|
8825
8962
|
previousTrackedUrl = currentUrl;
|
|
8826
8963
|
}
|
|
8964
|
+
if (didPathChange) {
|
|
8965
|
+
this.lastScrollCheckpoint = 0;
|
|
8966
|
+
logger.log('Path change: re-initializing scroll depth checkpoints');
|
|
8967
|
+
}
|
|
8827
8968
|
}
|
|
8828
8969
|
}.bind(this)));
|
|
8829
8970
|
};
|
|
@@ -8835,6 +8976,7 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
8835
8976
|
return;
|
|
8836
8977
|
}
|
|
8837
8978
|
logger.log('Initializing scroll tracking');
|
|
8979
|
+
this.lastScrollCheckpoint = 0;
|
|
8838
8980
|
|
|
8839
8981
|
this.listenerScroll = win.addEventListener(EV_SCROLLEND, safewrap(function() {
|
|
8840
8982
|
if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
|
|
@@ -8844,6 +8986,11 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
8844
8986
|
return;
|
|
8845
8987
|
}
|
|
8846
8988
|
|
|
8989
|
+
var shouldTrack = this.getConfig(CONFIG_SCROLL_CAPTURE_ALL);
|
|
8990
|
+
var scrollCheckpoints = (this.getConfig(CONFIG_SCROLL_CHECKPOINTS) || [])
|
|
8991
|
+
.slice()
|
|
8992
|
+
.sort(function(a, b) { return a - b; });
|
|
8993
|
+
|
|
8847
8994
|
var scrollTop = win.scrollY;
|
|
8848
8995
|
var props = _.extend({'$scroll_top': scrollTop}, DEFAULT_PROPS);
|
|
8849
8996
|
try {
|
|
@@ -8851,10 +8998,25 @@ Autocapture.prototype.initScrollTracking = function() {
|
|
|
8851
8998
|
var scrollPercentage = Math.round((scrollTop / (scrollHeight - win.innerHeight)) * 100);
|
|
8852
8999
|
props['$scroll_height'] = scrollHeight;
|
|
8853
9000
|
props['$scroll_percentage'] = scrollPercentage;
|
|
9001
|
+
if (scrollPercentage > this.lastScrollCheckpoint) {
|
|
9002
|
+
for (var i = 0; i < scrollCheckpoints.length; i++) {
|
|
9003
|
+
var checkpoint = scrollCheckpoints[i];
|
|
9004
|
+
if (
|
|
9005
|
+
scrollPercentage >= checkpoint &&
|
|
9006
|
+
this.lastScrollCheckpoint < checkpoint
|
|
9007
|
+
) {
|
|
9008
|
+
props['$scroll_checkpoint'] = checkpoint;
|
|
9009
|
+
this.lastScrollCheckpoint = checkpoint;
|
|
9010
|
+
shouldTrack = true;
|
|
9011
|
+
}
|
|
9012
|
+
}
|
|
9013
|
+
}
|
|
8854
9014
|
} catch (err) {
|
|
8855
9015
|
logger.critical('Error while calculating scroll percentage', err);
|
|
8856
9016
|
}
|
|
8857
|
-
|
|
9017
|
+
if (shouldTrack) {
|
|
9018
|
+
this.mp.track(MP_EV_SCROLL, props);
|
|
9019
|
+
}
|
|
8858
9020
|
}.bind(this)));
|
|
8859
9021
|
};
|
|
8860
9022
|
|
|
@@ -10123,8 +10285,12 @@ MixpanelPersistence.prototype._add_to_people_queue = function(queue, data) {
|
|
|
10123
10285
|
if (!(k in union_q)) {
|
|
10124
10286
|
union_q[k] = [];
|
|
10125
10287
|
}
|
|
10126
|
-
//
|
|
10127
|
-
|
|
10288
|
+
// Prevent duplicate values
|
|
10289
|
+
_.each(v, function(item) {
|
|
10290
|
+
if (!_.include(union_q[k], item)) {
|
|
10291
|
+
union_q[k].push(item);
|
|
10292
|
+
}
|
|
10293
|
+
});
|
|
10128
10294
|
}
|
|
10129
10295
|
});
|
|
10130
10296
|
this._pop_from_people_queue(UNSET_ACTION, q_data);
|