mixpanel-browser 2.67.0 → 2.68.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.
@@ -13942,7 +13942,7 @@ if (typeof Promise !== 'undefined' && Promise.toString().indexOf('[native code]'
13942
13942
 
13943
13943
  var Config = {
13944
13944
  DEBUG: false,
13945
- LIB_VERSION: '2.67.0'
13945
+ LIB_VERSION: '2.68.0'
13946
13946
  };
13947
13947
 
13948
13948
  /* eslint camelcase: "off", eqeqeq: "off" */
@@ -18227,6 +18227,38 @@ function shouldTrackValue(value) {
18227
18227
  return true;
18228
18228
  }
18229
18229
 
18230
+ /** @const */ var DEFAULT_RAGE_CLICK_THRESHOLD_PX = 30;
18231
+ /** @const */ var DEFAULT_RAGE_CLICK_TIMEOUT_MS = 1000;
18232
+ /** @const */ var DEFAULT_RAGE_CLICK_CLICK_COUNT = 4;
18233
+
18234
+ function RageClickTracker() {
18235
+ this.clicks = [];
18236
+ }
18237
+
18238
+ RageClickTracker.prototype.isRageClick = function(x, y, options) {
18239
+ options = options || {};
18240
+ var thresholdPx = options['threshold_px'] || DEFAULT_RAGE_CLICK_THRESHOLD_PX;
18241
+ var timeoutMs = options['timeout_ms'] || DEFAULT_RAGE_CLICK_TIMEOUT_MS;
18242
+ var clickCount = options['click_count'] || DEFAULT_RAGE_CLICK_CLICK_COUNT;
18243
+ var timestamp = Date.now();
18244
+
18245
+ var lastClick = this.clicks[this.clicks.length - 1];
18246
+ if (
18247
+ lastClick &&
18248
+ timestamp - lastClick.timestamp < timeoutMs &&
18249
+ Math.sqrt(Math.pow(x - lastClick.x, 2) + Math.pow(y - lastClick.y, 2)) < thresholdPx
18250
+ ) {
18251
+ this.clicks.push({ x: x, y: y, timestamp: timestamp });
18252
+ if (this.clicks.length >= clickCount) {
18253
+ this.clicks = [];
18254
+ return true;
18255
+ }
18256
+ } else {
18257
+ this.clicks = [{ x: x, y: y, timestamp: timestamp }];
18258
+ }
18259
+ return false;
18260
+ };
18261
+
18230
18262
  var AUTOCAPTURE_CONFIG_KEY = 'autocapture';
18231
18263
  var LEGACY_PAGEVIEW_CONFIG_KEY = 'track_pageview';
18232
18264
 
@@ -18248,6 +18280,7 @@ var CONFIG_SCROLL_CHECKPOINTS = 'scroll_depth_percent_checkpoints';
18248
18280
  var CONFIG_TRACK_CLICK = 'click';
18249
18281
  var CONFIG_TRACK_INPUT = 'input';
18250
18282
  var CONFIG_TRACK_PAGEVIEW = 'pageview';
18283
+ var CONFIG_TRACK_RAGE_CLICK = 'rage_click';
18251
18284
  var CONFIG_TRACK_SCROLL = 'scroll';
18252
18285
  var CONFIG_TRACK_SUBMIT = 'submit';
18253
18286
 
@@ -18265,6 +18298,7 @@ CONFIG_DEFAULTS$1[CONFIG_SCROLL_CHECKPOINTS] = [25, 50, 75, 100];
18265
18298
  CONFIG_DEFAULTS$1[CONFIG_TRACK_CLICK] = true;
18266
18299
  CONFIG_DEFAULTS$1[CONFIG_TRACK_INPUT] = true;
18267
18300
  CONFIG_DEFAULTS$1[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
18301
+ CONFIG_DEFAULTS$1[CONFIG_TRACK_RAGE_CLICK] = true;
18268
18302
  CONFIG_DEFAULTS$1[CONFIG_TRACK_SCROLL] = true;
18269
18303
  CONFIG_DEFAULTS$1[CONFIG_TRACK_SUBMIT] = true;
18270
18304
 
@@ -18274,6 +18308,7 @@ var DEFAULT_PROPS = {
18274
18308
 
18275
18309
  var MP_EV_CLICK = '$mp_click';
18276
18310
  var MP_EV_INPUT = '$mp_input_change';
18311
+ var MP_EV_RAGE_CLICK = '$mp_rage_click';
18277
18312
  var MP_EV_SCROLL = '$mp_scroll';
18278
18313
  var MP_EV_SUBMIT = '$mp_submit';
18279
18314
 
@@ -18296,6 +18331,7 @@ Autocapture.prototype.init = function() {
18296
18331
  this.initInputTracking();
18297
18332
  this.initScrollTracking();
18298
18333
  this.initSubmitTracking();
18334
+ this.initRageClickTracking();
18299
18335
  };
18300
18336
 
18301
18337
  Autocapture.prototype.getFullConfig = function() {
@@ -18374,6 +18410,11 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
18374
18410
  return;
18375
18411
  }
18376
18412
 
18413
+ var isCapturedForHeatMap = this.mp.is_recording_heatmap_data() && (
18414
+ (mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK)) ||
18415
+ (mpEventName === MP_EV_RAGE_CLICK && !this._getRageClickConfig())
18416
+ );
18417
+
18377
18418
  var props = getPropsForDOMEvent(ev, {
18378
18419
  allowElementCallback: this.getConfig(CONFIG_ALLOW_ELEMENT_CALLBACK),
18379
18420
  allowSelectors: this.getConfig(CONFIG_ALLOW_SELECTORS),
@@ -18382,7 +18423,7 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
18382
18423
  blockSelectors: this.getConfig(CONFIG_BLOCK_SELECTORS),
18383
18424
  captureExtraAttrs: this.getConfig(CONFIG_CAPTURE_EXTRA_ATTRS),
18384
18425
  captureTextContent: this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT),
18385
- capturedForHeatMap: mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK) && this.mp.is_recording_heatmap_data(),
18426
+ capturedForHeatMap: isCapturedForHeatMap,
18386
18427
  });
18387
18428
  if (props) {
18388
18429
  _.extend(props, DEFAULT_PROPS);
@@ -18390,6 +18431,24 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
18390
18431
  }
18391
18432
  };
18392
18433
 
18434
+ Autocapture.prototype._getRageClickConfig = function() {
18435
+ var config = this.getConfig(CONFIG_TRACK_RAGE_CLICK);
18436
+
18437
+ if (!config) {
18438
+ return null; // rage click tracking disabled
18439
+ }
18440
+
18441
+ if (config === true) {
18442
+ return {}; // use defaults
18443
+ }
18444
+
18445
+ if (typeof config === 'object') {
18446
+ return config; // use custom configuration
18447
+ }
18448
+
18449
+ return {}; // fallback to defaults for any other truthy value
18450
+ };
18451
+
18393
18452
  Autocapture.prototype.initClickTracking = function() {
18394
18453
  win.removeEventListener(EV_CLICK, this.listenerClick);
18395
18454
 
@@ -18491,6 +18550,36 @@ Autocapture.prototype.initPageviewTracking = function() {
18491
18550
  }.bind(this)));
18492
18551
  };
18493
18552
 
18553
+ Autocapture.prototype.initRageClickTracking = function() {
18554
+ win.removeEventListener(EV_CLICK, this.listenerRageClick);
18555
+
18556
+ var rageClickConfig = this._getRageClickConfig();
18557
+ if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) {
18558
+ return;
18559
+ }
18560
+
18561
+ logger$1.log('Initializing rage click tracking');
18562
+ if (!this._rageClickTracker) {
18563
+ this._rageClickTracker = new RageClickTracker();
18564
+ }
18565
+
18566
+ this.listenerRageClick = function(ev) {
18567
+ var currentRageClickConfig = this._getRageClickConfig();
18568
+ if (!currentRageClickConfig && !this.mp.is_recording_heatmap_data()) {
18569
+ return;
18570
+ }
18571
+
18572
+ if (this.currentUrlBlocked()) {
18573
+ return;
18574
+ }
18575
+
18576
+ if (this._rageClickTracker.isRageClick(ev['pageX'], ev['pageY'], currentRageClickConfig)) {
18577
+ this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
18578
+ }
18579
+ }.bind(this);
18580
+ win.addEventListener(EV_CLICK, this.listenerRageClick);
18581
+ };
18582
+
18494
18583
  Autocapture.prototype.initScrollTracking = function() {
18495
18584
  win.removeEventListener(EV_SCROLLEND, this.listenerScroll);
18496
18585
 
@@ -18577,6 +18666,7 @@ CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
18577
18666
  var FeatureFlagManager = function(initOptions) {
18578
18667
  this.getFullApiRoute = initOptions.getFullApiRoute;
18579
18668
  this.getMpConfig = initOptions.getConfigFunc;
18669
+ this.setMpConfig = initOptions.setConfigFunc;
18580
18670
  this.getMpProperty = initOptions.getPropertyFunc;
18581
18671
  this.track = initOptions.trackingFunc;
18582
18672
  };
@@ -18614,6 +18704,23 @@ FeatureFlagManager.prototype.isSystemEnabled = function() {
18614
18704
  return !!this.getMpConfig(FLAGS_CONFIG_KEY);
18615
18705
  };
18616
18706
 
18707
+ FeatureFlagManager.prototype.updateContext = function(newContext, options) {
18708
+ if (!this.isSystemEnabled()) {
18709
+ logger.critical('Feature Flags not enabled, cannot update context');
18710
+ return Promise.resolve();
18711
+ }
18712
+
18713
+ var ffConfig = this.getMpConfig(FLAGS_CONFIG_KEY);
18714
+ if (!_.isObject(ffConfig)) {
18715
+ ffConfig = {};
18716
+ }
18717
+ var oldContext = (options && options['replace']) ? {} : this.getConfig(CONFIG_CONTEXT);
18718
+ ffConfig[CONFIG_CONTEXT] = _.extend({}, oldContext, newContext);
18719
+
18720
+ this.setMpConfig(FLAGS_CONFIG_KEY, ffConfig);
18721
+ return this.fetchFlags();
18722
+ };
18723
+
18617
18724
  FeatureFlagManager.prototype.areFlagsReady = function() {
18618
18725
  if (!this.isSystemEnabled()) {
18619
18726
  logger.error('Feature Flags not enabled');
@@ -18623,7 +18730,7 @@ FeatureFlagManager.prototype.areFlagsReady = function() {
18623
18730
 
18624
18731
  FeatureFlagManager.prototype.fetchFlags = function() {
18625
18732
  if (!this.isSystemEnabled()) {
18626
- return;
18733
+ return Promise.resolve();
18627
18734
  }
18628
18735
 
18629
18736
  var distinctId = this.getMpProperty('distinct_id');
@@ -18663,6 +18770,8 @@ FeatureFlagManager.prototype.fetchFlags = function() {
18663
18770
  this.markFetchComplete();
18664
18771
  logger.error(error);
18665
18772
  }.bind(this));
18773
+
18774
+ return this.fetchPromise;
18666
18775
  };
18667
18776
 
18668
18777
  FeatureFlagManager.prototype.markFetchComplete = function() {
@@ -18775,6 +18884,7 @@ FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype
18775
18884
  FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
18776
18885
  FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
18777
18886
  FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
18887
+ FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.updateContext;
18778
18888
 
18779
18889
  // Deprecated method
18780
18890
  FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
@@ -20235,7 +20345,7 @@ var DEFAULT_CONFIG = {
20235
20345
  'batch_autostart': true,
20236
20346
  'hooks': {},
20237
20347
  'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
20238
- 'record_block_selector': 'img, video',
20348
+ 'record_block_selector': 'img, video, audio',
20239
20349
  'record_canvas': false,
20240
20350
  'record_collect_fonts': false,
20241
20351
  'record_heatmap_data': false,
@@ -20459,6 +20569,7 @@ MixpanelLib.prototype._init = function(token, config, name) {
20459
20569
  return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
20460
20570
  }, this),
20461
20571
  getConfigFunc: _.bind(this.get_config, this),
20572
+ setConfigFunc: _.bind(this.set_config, this),
20462
20573
  getPropertyFunc: _.bind(this.get_property, this),
20463
20574
  trackingFunc: _.bind(this.track, this)
20464
20575
  });
@@ -13948,7 +13948,7 @@
13948
13948
 
13949
13949
  var Config = {
13950
13950
  DEBUG: false,
13951
- LIB_VERSION: '2.67.0'
13951
+ LIB_VERSION: '2.68.0'
13952
13952
  };
13953
13953
 
13954
13954
  /* eslint camelcase: "off", eqeqeq: "off" */
@@ -18233,6 +18233,38 @@
18233
18233
  return true;
18234
18234
  }
18235
18235
 
18236
+ /** @const */ var DEFAULT_RAGE_CLICK_THRESHOLD_PX = 30;
18237
+ /** @const */ var DEFAULT_RAGE_CLICK_TIMEOUT_MS = 1000;
18238
+ /** @const */ var DEFAULT_RAGE_CLICK_CLICK_COUNT = 4;
18239
+
18240
+ function RageClickTracker() {
18241
+ this.clicks = [];
18242
+ }
18243
+
18244
+ RageClickTracker.prototype.isRageClick = function(x, y, options) {
18245
+ options = options || {};
18246
+ var thresholdPx = options['threshold_px'] || DEFAULT_RAGE_CLICK_THRESHOLD_PX;
18247
+ var timeoutMs = options['timeout_ms'] || DEFAULT_RAGE_CLICK_TIMEOUT_MS;
18248
+ var clickCount = options['click_count'] || DEFAULT_RAGE_CLICK_CLICK_COUNT;
18249
+ var timestamp = Date.now();
18250
+
18251
+ var lastClick = this.clicks[this.clicks.length - 1];
18252
+ if (
18253
+ lastClick &&
18254
+ timestamp - lastClick.timestamp < timeoutMs &&
18255
+ Math.sqrt(Math.pow(x - lastClick.x, 2) + Math.pow(y - lastClick.y, 2)) < thresholdPx
18256
+ ) {
18257
+ this.clicks.push({ x: x, y: y, timestamp: timestamp });
18258
+ if (this.clicks.length >= clickCount) {
18259
+ this.clicks = [];
18260
+ return true;
18261
+ }
18262
+ } else {
18263
+ this.clicks = [{ x: x, y: y, timestamp: timestamp }];
18264
+ }
18265
+ return false;
18266
+ };
18267
+
18236
18268
  var AUTOCAPTURE_CONFIG_KEY = 'autocapture';
18237
18269
  var LEGACY_PAGEVIEW_CONFIG_KEY = 'track_pageview';
18238
18270
 
@@ -18254,6 +18286,7 @@
18254
18286
  var CONFIG_TRACK_CLICK = 'click';
18255
18287
  var CONFIG_TRACK_INPUT = 'input';
18256
18288
  var CONFIG_TRACK_PAGEVIEW = 'pageview';
18289
+ var CONFIG_TRACK_RAGE_CLICK = 'rage_click';
18257
18290
  var CONFIG_TRACK_SCROLL = 'scroll';
18258
18291
  var CONFIG_TRACK_SUBMIT = 'submit';
18259
18292
 
@@ -18271,6 +18304,7 @@
18271
18304
  CONFIG_DEFAULTS$1[CONFIG_TRACK_CLICK] = true;
18272
18305
  CONFIG_DEFAULTS$1[CONFIG_TRACK_INPUT] = true;
18273
18306
  CONFIG_DEFAULTS$1[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
18307
+ CONFIG_DEFAULTS$1[CONFIG_TRACK_RAGE_CLICK] = true;
18274
18308
  CONFIG_DEFAULTS$1[CONFIG_TRACK_SCROLL] = true;
18275
18309
  CONFIG_DEFAULTS$1[CONFIG_TRACK_SUBMIT] = true;
18276
18310
 
@@ -18280,6 +18314,7 @@
18280
18314
 
18281
18315
  var MP_EV_CLICK = '$mp_click';
18282
18316
  var MP_EV_INPUT = '$mp_input_change';
18317
+ var MP_EV_RAGE_CLICK = '$mp_rage_click';
18283
18318
  var MP_EV_SCROLL = '$mp_scroll';
18284
18319
  var MP_EV_SUBMIT = '$mp_submit';
18285
18320
 
@@ -18302,6 +18337,7 @@
18302
18337
  this.initInputTracking();
18303
18338
  this.initScrollTracking();
18304
18339
  this.initSubmitTracking();
18340
+ this.initRageClickTracking();
18305
18341
  };
18306
18342
 
18307
18343
  Autocapture.prototype.getFullConfig = function() {
@@ -18380,6 +18416,11 @@
18380
18416
  return;
18381
18417
  }
18382
18418
 
18419
+ var isCapturedForHeatMap = this.mp.is_recording_heatmap_data() && (
18420
+ (mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK)) ||
18421
+ (mpEventName === MP_EV_RAGE_CLICK && !this._getRageClickConfig())
18422
+ );
18423
+
18383
18424
  var props = getPropsForDOMEvent(ev, {
18384
18425
  allowElementCallback: this.getConfig(CONFIG_ALLOW_ELEMENT_CALLBACK),
18385
18426
  allowSelectors: this.getConfig(CONFIG_ALLOW_SELECTORS),
@@ -18388,7 +18429,7 @@
18388
18429
  blockSelectors: this.getConfig(CONFIG_BLOCK_SELECTORS),
18389
18430
  captureExtraAttrs: this.getConfig(CONFIG_CAPTURE_EXTRA_ATTRS),
18390
18431
  captureTextContent: this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT),
18391
- capturedForHeatMap: mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK) && this.mp.is_recording_heatmap_data(),
18432
+ capturedForHeatMap: isCapturedForHeatMap,
18392
18433
  });
18393
18434
  if (props) {
18394
18435
  _.extend(props, DEFAULT_PROPS);
@@ -18396,6 +18437,24 @@
18396
18437
  }
18397
18438
  };
18398
18439
 
18440
+ Autocapture.prototype._getRageClickConfig = function() {
18441
+ var config = this.getConfig(CONFIG_TRACK_RAGE_CLICK);
18442
+
18443
+ if (!config) {
18444
+ return null; // rage click tracking disabled
18445
+ }
18446
+
18447
+ if (config === true) {
18448
+ return {}; // use defaults
18449
+ }
18450
+
18451
+ if (typeof config === 'object') {
18452
+ return config; // use custom configuration
18453
+ }
18454
+
18455
+ return {}; // fallback to defaults for any other truthy value
18456
+ };
18457
+
18399
18458
  Autocapture.prototype.initClickTracking = function() {
18400
18459
  win.removeEventListener(EV_CLICK, this.listenerClick);
18401
18460
 
@@ -18497,6 +18556,36 @@
18497
18556
  }.bind(this)));
18498
18557
  };
18499
18558
 
18559
+ Autocapture.prototype.initRageClickTracking = function() {
18560
+ win.removeEventListener(EV_CLICK, this.listenerRageClick);
18561
+
18562
+ var rageClickConfig = this._getRageClickConfig();
18563
+ if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) {
18564
+ return;
18565
+ }
18566
+
18567
+ logger$1.log('Initializing rage click tracking');
18568
+ if (!this._rageClickTracker) {
18569
+ this._rageClickTracker = new RageClickTracker();
18570
+ }
18571
+
18572
+ this.listenerRageClick = function(ev) {
18573
+ var currentRageClickConfig = this._getRageClickConfig();
18574
+ if (!currentRageClickConfig && !this.mp.is_recording_heatmap_data()) {
18575
+ return;
18576
+ }
18577
+
18578
+ if (this.currentUrlBlocked()) {
18579
+ return;
18580
+ }
18581
+
18582
+ if (this._rageClickTracker.isRageClick(ev['pageX'], ev['pageY'], currentRageClickConfig)) {
18583
+ this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
18584
+ }
18585
+ }.bind(this);
18586
+ win.addEventListener(EV_CLICK, this.listenerRageClick);
18587
+ };
18588
+
18500
18589
  Autocapture.prototype.initScrollTracking = function() {
18501
18590
  win.removeEventListener(EV_SCROLLEND, this.listenerScroll);
18502
18591
 
@@ -18583,6 +18672,7 @@
18583
18672
  var FeatureFlagManager = function(initOptions) {
18584
18673
  this.getFullApiRoute = initOptions.getFullApiRoute;
18585
18674
  this.getMpConfig = initOptions.getConfigFunc;
18675
+ this.setMpConfig = initOptions.setConfigFunc;
18586
18676
  this.getMpProperty = initOptions.getPropertyFunc;
18587
18677
  this.track = initOptions.trackingFunc;
18588
18678
  };
@@ -18620,6 +18710,23 @@
18620
18710
  return !!this.getMpConfig(FLAGS_CONFIG_KEY);
18621
18711
  };
18622
18712
 
18713
+ FeatureFlagManager.prototype.updateContext = function(newContext, options) {
18714
+ if (!this.isSystemEnabled()) {
18715
+ logger.critical('Feature Flags not enabled, cannot update context');
18716
+ return Promise.resolve();
18717
+ }
18718
+
18719
+ var ffConfig = this.getMpConfig(FLAGS_CONFIG_KEY);
18720
+ if (!_.isObject(ffConfig)) {
18721
+ ffConfig = {};
18722
+ }
18723
+ var oldContext = (options && options['replace']) ? {} : this.getConfig(CONFIG_CONTEXT);
18724
+ ffConfig[CONFIG_CONTEXT] = _.extend({}, oldContext, newContext);
18725
+
18726
+ this.setMpConfig(FLAGS_CONFIG_KEY, ffConfig);
18727
+ return this.fetchFlags();
18728
+ };
18729
+
18623
18730
  FeatureFlagManager.prototype.areFlagsReady = function() {
18624
18731
  if (!this.isSystemEnabled()) {
18625
18732
  logger.error('Feature Flags not enabled');
@@ -18629,7 +18736,7 @@
18629
18736
 
18630
18737
  FeatureFlagManager.prototype.fetchFlags = function() {
18631
18738
  if (!this.isSystemEnabled()) {
18632
- return;
18739
+ return Promise.resolve();
18633
18740
  }
18634
18741
 
18635
18742
  var distinctId = this.getMpProperty('distinct_id');
@@ -18669,6 +18776,8 @@
18669
18776
  this.markFetchComplete();
18670
18777
  logger.error(error);
18671
18778
  }.bind(this));
18779
+
18780
+ return this.fetchPromise;
18672
18781
  };
18673
18782
 
18674
18783
  FeatureFlagManager.prototype.markFetchComplete = function() {
@@ -18781,6 +18890,7 @@
18781
18890
  FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
18782
18891
  FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
18783
18892
  FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
18893
+ FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.updateContext;
18784
18894
 
18785
18895
  // Deprecated method
18786
18896
  FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
@@ -20241,7 +20351,7 @@
20241
20351
  'batch_autostart': true,
20242
20352
  'hooks': {},
20243
20353
  'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
20244
- 'record_block_selector': 'img, video',
20354
+ 'record_block_selector': 'img, video, audio',
20245
20355
  'record_canvas': false,
20246
20356
  'record_collect_fonts': false,
20247
20357
  'record_heatmap_data': false,
@@ -20465,6 +20575,7 @@
20465
20575
  return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
20466
20576
  }, this),
20467
20577
  getConfigFunc: _.bind(this.get_config, this),
20578
+ setConfigFunc: _.bind(this.set_config, this),
20468
20579
  getPropertyFunc: _.bind(this.get_property, this),
20469
20580
  trackingFunc: _.bind(this.track, this)
20470
20581
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mixpanel-browser",
3
- "version": "2.67.0",
3
+ "version": "2.68.0",
4
4
  "description": "The official Mixpanel JavaScript browser client library",
5
5
  "main": "dist/mixpanel.cjs.js",
6
6
  "module": "dist/mixpanel.module.js",
@@ -5,6 +5,7 @@ import {
5
5
  EV_CHANGE, EV_CLICK, EV_HASHCHANGE, EV_MP_LOCATION_CHANGE, EV_POPSTATE,
6
6
  EV_SCROLLEND, EV_SUBMIT
7
7
  } from './utils';
8
+ import { RageClickTracker } from './rageclick';
8
9
 
9
10
  var AUTOCAPTURE_CONFIG_KEY = 'autocapture';
10
11
  var LEGACY_PAGEVIEW_CONFIG_KEY = 'track_pageview';
@@ -27,6 +28,7 @@ var CONFIG_SCROLL_CHECKPOINTS = 'scroll_depth_percent_checkpoints';
27
28
  var CONFIG_TRACK_CLICK = 'click';
28
29
  var CONFIG_TRACK_INPUT = 'input';
29
30
  var CONFIG_TRACK_PAGEVIEW = 'pageview';
31
+ var CONFIG_TRACK_RAGE_CLICK = 'rage_click';
30
32
  var CONFIG_TRACK_SCROLL = 'scroll';
31
33
  var CONFIG_TRACK_SUBMIT = 'submit';
32
34
 
@@ -44,6 +46,7 @@ CONFIG_DEFAULTS[CONFIG_SCROLL_CHECKPOINTS] = [25, 50, 75, 100];
44
46
  CONFIG_DEFAULTS[CONFIG_TRACK_CLICK] = true;
45
47
  CONFIG_DEFAULTS[CONFIG_TRACK_INPUT] = true;
46
48
  CONFIG_DEFAULTS[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
49
+ CONFIG_DEFAULTS[CONFIG_TRACK_RAGE_CLICK] = true;
47
50
  CONFIG_DEFAULTS[CONFIG_TRACK_SCROLL] = true;
48
51
  CONFIG_DEFAULTS[CONFIG_TRACK_SUBMIT] = true;
49
52
 
@@ -53,6 +56,7 @@ var DEFAULT_PROPS = {
53
56
 
54
57
  var MP_EV_CLICK = '$mp_click';
55
58
  var MP_EV_INPUT = '$mp_input_change';
59
+ var MP_EV_RAGE_CLICK = '$mp_rage_click';
56
60
  var MP_EV_SCROLL = '$mp_scroll';
57
61
  var MP_EV_SUBMIT = '$mp_submit';
58
62
 
@@ -75,6 +79,7 @@ Autocapture.prototype.init = function() {
75
79
  this.initInputTracking();
76
80
  this.initScrollTracking();
77
81
  this.initSubmitTracking();
82
+ this.initRageClickTracking();
78
83
  };
79
84
 
80
85
  Autocapture.prototype.getFullConfig = function() {
@@ -153,6 +158,11 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
153
158
  return;
154
159
  }
155
160
 
161
+ var isCapturedForHeatMap = this.mp.is_recording_heatmap_data() && (
162
+ (mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK)) ||
163
+ (mpEventName === MP_EV_RAGE_CLICK && !this._getRageClickConfig())
164
+ );
165
+
156
166
  var props = getPropsForDOMEvent(ev, {
157
167
  allowElementCallback: this.getConfig(CONFIG_ALLOW_ELEMENT_CALLBACK),
158
168
  allowSelectors: this.getConfig(CONFIG_ALLOW_SELECTORS),
@@ -161,7 +171,7 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
161
171
  blockSelectors: this.getConfig(CONFIG_BLOCK_SELECTORS),
162
172
  captureExtraAttrs: this.getConfig(CONFIG_CAPTURE_EXTRA_ATTRS),
163
173
  captureTextContent: this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT),
164
- capturedForHeatMap: mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK) && this.mp.is_recording_heatmap_data(),
174
+ capturedForHeatMap: isCapturedForHeatMap,
165
175
  });
166
176
  if (props) {
167
177
  _.extend(props, DEFAULT_PROPS);
@@ -169,6 +179,24 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
169
179
  }
170
180
  };
171
181
 
182
+ Autocapture.prototype._getRageClickConfig = function() {
183
+ var config = this.getConfig(CONFIG_TRACK_RAGE_CLICK);
184
+
185
+ if (!config) {
186
+ return null; // rage click tracking disabled
187
+ }
188
+
189
+ if (config === true) {
190
+ return {}; // use defaults
191
+ }
192
+
193
+ if (typeof config === 'object') {
194
+ return config; // use custom configuration
195
+ }
196
+
197
+ return {}; // fallback to defaults for any other truthy value
198
+ };
199
+
172
200
  Autocapture.prototype.initClickTracking = function() {
173
201
  window.removeEventListener(EV_CLICK, this.listenerClick);
174
202
 
@@ -270,6 +298,36 @@ Autocapture.prototype.initPageviewTracking = function() {
270
298
  }.bind(this)));
271
299
  };
272
300
 
301
+ Autocapture.prototype.initRageClickTracking = function() {
302
+ window.removeEventListener(EV_CLICK, this.listenerRageClick);
303
+
304
+ var rageClickConfig = this._getRageClickConfig();
305
+ if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) {
306
+ return;
307
+ }
308
+
309
+ logger.log('Initializing rage click tracking');
310
+ if (!this._rageClickTracker) {
311
+ this._rageClickTracker = new RageClickTracker();
312
+ }
313
+
314
+ this.listenerRageClick = function(ev) {
315
+ var currentRageClickConfig = this._getRageClickConfig();
316
+ if (!currentRageClickConfig && !this.mp.is_recording_heatmap_data()) {
317
+ return;
318
+ }
319
+
320
+ if (this.currentUrlBlocked()) {
321
+ return;
322
+ }
323
+
324
+ if (this._rageClickTracker.isRageClick(ev['pageX'], ev['pageY'], currentRageClickConfig)) {
325
+ this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
326
+ }
327
+ }.bind(this);
328
+ window.addEventListener(EV_CLICK, this.listenerRageClick);
329
+ };
330
+
273
331
  Autocapture.prototype.initScrollTracking = function() {
274
332
  window.removeEventListener(EV_SCROLLEND, this.listenerScroll);
275
333
 
@@ -0,0 +1,38 @@
1
+ /** @const */ var DEFAULT_RAGE_CLICK_THRESHOLD_PX = 30;
2
+ /** @const */ var DEFAULT_RAGE_CLICK_TIMEOUT_MS = 1000;
3
+ /** @const */ var DEFAULT_RAGE_CLICK_CLICK_COUNT = 4;
4
+
5
+ function RageClickTracker() {
6
+ this.clicks = [];
7
+ }
8
+
9
+ RageClickTracker.prototype.isRageClick = function(x, y, options) {
10
+ options = options || {};
11
+ var thresholdPx = options['threshold_px'] || DEFAULT_RAGE_CLICK_THRESHOLD_PX;
12
+ var timeoutMs = options['timeout_ms'] || DEFAULT_RAGE_CLICK_TIMEOUT_MS;
13
+ var clickCount = options['click_count'] || DEFAULT_RAGE_CLICK_CLICK_COUNT;
14
+ var timestamp = Date.now();
15
+
16
+ var lastClick = this.clicks[this.clicks.length - 1];
17
+ if (
18
+ lastClick &&
19
+ timestamp - lastClick.timestamp < timeoutMs &&
20
+ Math.sqrt(Math.pow(x - lastClick.x, 2) + Math.pow(y - lastClick.y, 2)) < thresholdPx
21
+ ) {
22
+ this.clicks.push({ x: x, y: y, timestamp: timestamp });
23
+ if (this.clicks.length >= clickCount) {
24
+ this.clicks = [];
25
+ return true;
26
+ }
27
+ } else {
28
+ this.clicks = [{ x: x, y: y, timestamp: timestamp }];
29
+ }
30
+ return false;
31
+ };
32
+
33
+ export {
34
+ RageClickTracker,
35
+ DEFAULT_RAGE_CLICK_THRESHOLD_PX,
36
+ DEFAULT_RAGE_CLICK_TIMEOUT_MS,
37
+ DEFAULT_RAGE_CLICK_CLICK_COUNT
38
+ };
package/src/config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  var Config = {
2
2
  DEBUG: false,
3
- LIB_VERSION: '2.67.0'
3
+ LIB_VERSION: '2.68.0'
4
4
  };
5
5
 
6
6
  export default Config;