mixpanel-browser 2.67.0 → 2.69.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.
@@ -3,7 +3,7 @@
3
3
 
4
4
  var Config = {
5
5
  DEBUG: false,
6
- LIB_VERSION: '2.67.0'
6
+ LIB_VERSION: '2.69.0'
7
7
  };
8
8
 
9
9
  // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
@@ -2655,6 +2655,38 @@
2655
2655
  return true;
2656
2656
  }
2657
2657
 
2658
+ /** @const */ var DEFAULT_RAGE_CLICK_THRESHOLD_PX = 30;
2659
+ /** @const */ var DEFAULT_RAGE_CLICK_TIMEOUT_MS = 1000;
2660
+ /** @const */ var DEFAULT_RAGE_CLICK_CLICK_COUNT = 4;
2661
+
2662
+ function RageClickTracker() {
2663
+ this.clicks = [];
2664
+ }
2665
+
2666
+ RageClickTracker.prototype.isRageClick = function(x, y, options) {
2667
+ options = options || {};
2668
+ var thresholdPx = options['threshold_px'] || DEFAULT_RAGE_CLICK_THRESHOLD_PX;
2669
+ var timeoutMs = options['timeout_ms'] || DEFAULT_RAGE_CLICK_TIMEOUT_MS;
2670
+ var clickCount = options['click_count'] || DEFAULT_RAGE_CLICK_CLICK_COUNT;
2671
+ var timestamp = Date.now();
2672
+
2673
+ var lastClick = this.clicks[this.clicks.length - 1];
2674
+ if (
2675
+ lastClick &&
2676
+ timestamp - lastClick.timestamp < timeoutMs &&
2677
+ Math.sqrt(Math.pow(x - lastClick.x, 2) + Math.pow(y - lastClick.y, 2)) < thresholdPx
2678
+ ) {
2679
+ this.clicks.push({ x: x, y: y, timestamp: timestamp });
2680
+ if (this.clicks.length >= clickCount) {
2681
+ this.clicks = [];
2682
+ return true;
2683
+ }
2684
+ } else {
2685
+ this.clicks = [{ x: x, y: y, timestamp: timestamp }];
2686
+ }
2687
+ return false;
2688
+ };
2689
+
2658
2690
  var AUTOCAPTURE_CONFIG_KEY = 'autocapture';
2659
2691
  var LEGACY_PAGEVIEW_CONFIG_KEY = 'track_pageview';
2660
2692
 
@@ -2676,6 +2708,7 @@
2676
2708
  var CONFIG_TRACK_CLICK = 'click';
2677
2709
  var CONFIG_TRACK_INPUT = 'input';
2678
2710
  var CONFIG_TRACK_PAGEVIEW = 'pageview';
2711
+ var CONFIG_TRACK_RAGE_CLICK = 'rage_click';
2679
2712
  var CONFIG_TRACK_SCROLL = 'scroll';
2680
2713
  var CONFIG_TRACK_SUBMIT = 'submit';
2681
2714
 
@@ -2693,6 +2726,7 @@
2693
2726
  CONFIG_DEFAULTS$1[CONFIG_TRACK_CLICK] = true;
2694
2727
  CONFIG_DEFAULTS$1[CONFIG_TRACK_INPUT] = true;
2695
2728
  CONFIG_DEFAULTS$1[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
2729
+ CONFIG_DEFAULTS$1[CONFIG_TRACK_RAGE_CLICK] = true;
2696
2730
  CONFIG_DEFAULTS$1[CONFIG_TRACK_SCROLL] = true;
2697
2731
  CONFIG_DEFAULTS$1[CONFIG_TRACK_SUBMIT] = true;
2698
2732
 
@@ -2702,6 +2736,7 @@
2702
2736
 
2703
2737
  var MP_EV_CLICK = '$mp_click';
2704
2738
  var MP_EV_INPUT = '$mp_input_change';
2739
+ var MP_EV_RAGE_CLICK = '$mp_rage_click';
2705
2740
  var MP_EV_SCROLL = '$mp_scroll';
2706
2741
  var MP_EV_SUBMIT = '$mp_submit';
2707
2742
 
@@ -2724,6 +2759,7 @@
2724
2759
  this.initInputTracking();
2725
2760
  this.initScrollTracking();
2726
2761
  this.initSubmitTracking();
2762
+ this.initRageClickTracking();
2727
2763
  };
2728
2764
 
2729
2765
  Autocapture.prototype.getFullConfig = function() {
@@ -2802,6 +2838,11 @@
2802
2838
  return;
2803
2839
  }
2804
2840
 
2841
+ var isCapturedForHeatMap = this.mp.is_recording_heatmap_data() && (
2842
+ (mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK)) ||
2843
+ (mpEventName === MP_EV_RAGE_CLICK && !this._getRageClickConfig())
2844
+ );
2845
+
2805
2846
  var props = getPropsForDOMEvent(ev, {
2806
2847
  allowElementCallback: this.getConfig(CONFIG_ALLOW_ELEMENT_CALLBACK),
2807
2848
  allowSelectors: this.getConfig(CONFIG_ALLOW_SELECTORS),
@@ -2810,7 +2851,7 @@
2810
2851
  blockSelectors: this.getConfig(CONFIG_BLOCK_SELECTORS),
2811
2852
  captureExtraAttrs: this.getConfig(CONFIG_CAPTURE_EXTRA_ATTRS),
2812
2853
  captureTextContent: this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT),
2813
- capturedForHeatMap: mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK) && this.mp.is_recording_heatmap_data(),
2854
+ capturedForHeatMap: isCapturedForHeatMap,
2814
2855
  });
2815
2856
  if (props) {
2816
2857
  _.extend(props, DEFAULT_PROPS);
@@ -2818,6 +2859,24 @@
2818
2859
  }
2819
2860
  };
2820
2861
 
2862
+ Autocapture.prototype._getRageClickConfig = function() {
2863
+ var config = this.getConfig(CONFIG_TRACK_RAGE_CLICK);
2864
+
2865
+ if (!config) {
2866
+ return null; // rage click tracking disabled
2867
+ }
2868
+
2869
+ if (config === true) {
2870
+ return {}; // use defaults
2871
+ }
2872
+
2873
+ if (typeof config === 'object') {
2874
+ return config; // use custom configuration
2875
+ }
2876
+
2877
+ return {}; // fallback to defaults for any other truthy value
2878
+ };
2879
+
2821
2880
  Autocapture.prototype.initClickTracking = function() {
2822
2881
  win.removeEventListener(EV_CLICK, this.listenerClick);
2823
2882
 
@@ -2919,6 +2978,36 @@
2919
2978
  }.bind(this)));
2920
2979
  };
2921
2980
 
2981
+ Autocapture.prototype.initRageClickTracking = function() {
2982
+ win.removeEventListener(EV_CLICK, this.listenerRageClick);
2983
+
2984
+ var rageClickConfig = this._getRageClickConfig();
2985
+ if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) {
2986
+ return;
2987
+ }
2988
+
2989
+ logger$4.log('Initializing rage click tracking');
2990
+ if (!this._rageClickTracker) {
2991
+ this._rageClickTracker = new RageClickTracker();
2992
+ }
2993
+
2994
+ this.listenerRageClick = function(ev) {
2995
+ var currentRageClickConfig = this._getRageClickConfig();
2996
+ if (!currentRageClickConfig && !this.mp.is_recording_heatmap_data()) {
2997
+ return;
2998
+ }
2999
+
3000
+ if (this.currentUrlBlocked()) {
3001
+ return;
3002
+ }
3003
+
3004
+ if (this._rageClickTracker.isRageClick(ev['pageX'], ev['pageY'], currentRageClickConfig)) {
3005
+ this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
3006
+ }
3007
+ }.bind(this);
3008
+ win.addEventListener(EV_CLICK, this.listenerRageClick);
3009
+ };
3010
+
2922
3011
  Autocapture.prototype.initScrollTracking = function() {
2923
3012
  win.removeEventListener(EV_SCROLLEND, this.listenerScroll);
2924
3013
 
@@ -3005,6 +3094,7 @@
3005
3094
  var FeatureFlagManager = function(initOptions) {
3006
3095
  this.getFullApiRoute = initOptions.getFullApiRoute;
3007
3096
  this.getMpConfig = initOptions.getConfigFunc;
3097
+ this.setMpConfig = initOptions.setConfigFunc;
3008
3098
  this.getMpProperty = initOptions.getPropertyFunc;
3009
3099
  this.track = initOptions.trackingFunc;
3010
3100
  };
@@ -3042,6 +3132,23 @@
3042
3132
  return !!this.getMpConfig(FLAGS_CONFIG_KEY);
3043
3133
  };
3044
3134
 
3135
+ FeatureFlagManager.prototype.updateContext = function(newContext, options) {
3136
+ if (!this.isSystemEnabled()) {
3137
+ logger$3.critical('Feature Flags not enabled, cannot update context');
3138
+ return Promise.resolve();
3139
+ }
3140
+
3141
+ var ffConfig = this.getMpConfig(FLAGS_CONFIG_KEY);
3142
+ if (!_.isObject(ffConfig)) {
3143
+ ffConfig = {};
3144
+ }
3145
+ var oldContext = (options && options['replace']) ? {} : this.getConfig(CONFIG_CONTEXT);
3146
+ ffConfig[CONFIG_CONTEXT] = _.extend({}, oldContext, newContext);
3147
+
3148
+ this.setMpConfig(FLAGS_CONFIG_KEY, ffConfig);
3149
+ return this.fetchFlags();
3150
+ };
3151
+
3045
3152
  FeatureFlagManager.prototype.areFlagsReady = function() {
3046
3153
  if (!this.isSystemEnabled()) {
3047
3154
  logger$3.error('Feature Flags not enabled');
@@ -3051,7 +3158,7 @@
3051
3158
 
3052
3159
  FeatureFlagManager.prototype.fetchFlags = function() {
3053
3160
  if (!this.isSystemEnabled()) {
3054
- return;
3161
+ return Promise.resolve();
3055
3162
  }
3056
3163
 
3057
3164
  var distinctId = this.getMpProperty('distinct_id');
@@ -3091,6 +3198,8 @@
3091
3198
  this.markFetchComplete();
3092
3199
  logger$3.error(error);
3093
3200
  }.bind(this));
3201
+
3202
+ return this.fetchPromise;
3094
3203
  };
3095
3204
 
3096
3205
  FeatureFlagManager.prototype.markFetchComplete = function() {
@@ -3203,6 +3312,7 @@
3203
3312
  FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
3204
3313
  FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
3205
3314
  FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
3315
+ FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.updateContext;
3206
3316
 
3207
3317
  // Deprecated method
3208
3318
  FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
@@ -3520,6 +3630,10 @@
3520
3630
  return PromisePolyfill.resolve();
3521
3631
  };
3522
3632
 
3633
+ LocalStorageWrapper.prototype.isInitialized = function () {
3634
+ return true;
3635
+ };
3636
+
3523
3637
  LocalStorageWrapper.prototype.setItem = function (key, value) {
3524
3638
  return new PromisePolyfill(_.bind(function (resolve, reject) {
3525
3639
  try {
@@ -3600,7 +3714,7 @@
3600
3714
  };
3601
3715
 
3602
3716
  RequestQueue.prototype.ensureInit = function () {
3603
- if (this.initialized) {
3717
+ if (this.initialized || !this.usePersistence) {
3604
3718
  return PromisePolyfill.resolve();
3605
3719
  }
3606
3720
 
@@ -5784,6 +5898,10 @@
5784
5898
  });
5785
5899
  };
5786
5900
 
5901
+ IDBStorageWrapper.prototype.isInitialized = function () {
5902
+ return !!this.dbPromise;
5903
+ };
5904
+
5787
5905
  /**
5788
5906
  * @param {IDBTransactionMode} mode
5789
5907
  * @param {function(IDBObjectStore): void} storeCb
@@ -5974,7 +6092,7 @@
5974
6092
  'batch_autostart': true,
5975
6093
  'hooks': {},
5976
6094
  'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
5977
- 'record_block_selector': 'img, video',
6095
+ 'record_block_selector': 'img, video, audio',
5978
6096
  'record_canvas': false,
5979
6097
  'record_collect_fonts': false,
5980
6098
  'record_heatmap_data': false,
@@ -6198,6 +6316,7 @@
6198
6316
  return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
6199
6317
  }, this),
6200
6318
  getConfigFunc: _.bind(this.get_config, this),
6319
+ setConfigFunc: _.bind(this.set_config, this),
6201
6320
  getPropertyFunc: _.bind(this.get_property, this),
6202
6321
  trackingFunc: _.bind(this.track, this)
6203
6322
  });
@@ -6216,7 +6335,9 @@
6216
6335
  * This is primarily used for session recording, where data must be isolated to the current tab.
6217
6336
  */
6218
6337
  MixpanelLib.prototype._init_tab_id = function() {
6219
- if (_.sessionStorage.is_supported()) {
6338
+ if (this.get_config('disable_persistence')) {
6339
+ console.log('Tab ID initialization skipped due to disable_persistence config');
6340
+ } else if (_.sessionStorage.is_supported()) {
6220
6341
  try {
6221
6342
  var key_suffix = this.get_config('name') + '_' + this.get_config('token');
6222
6343
  var tab_id_key = 'mp_tab_id_' + key_suffix;
@@ -6250,6 +6371,11 @@
6250
6371
  };
6251
6372
 
6252
6373
  MixpanelLib.prototype._should_load_recorder = function () {
6374
+ if (this.get_config('disable_persistence')) {
6375
+ console.log('Load recorder check skipped due to disable_persistence config');
6376
+ return Promise.resolve(false);
6377
+ }
6378
+
6253
6379
  var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
6254
6380
  var tab_id = this.get_tab_id();
6255
6381
  return recording_registry_idb.init()