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