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