@mparticle/web-sdk 3.25.0 → 3.26.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/dist/mparticle.js CHANGED
@@ -204,7 +204,7 @@ var mParticle = (function () {
204
204
  Base64: Base64$1
205
205
  };
206
206
 
207
- var version = "3.25.0";
207
+ var version = "3.26.0";
208
208
 
209
209
  var Constants = {
210
210
  sdkVersion: version,
@@ -10881,8 +10881,9 @@ var mParticle = (function () {
10881
10881
  }
10882
10882
 
10883
10883
  var PASSBACK_CONVERSION_TRACKING_ID = 'passbackconversiontrackingid';
10884
- // One signal per kind (commit, wallet, checkout_step, frame and cart), so a new kind never evicts another.
10885
- var CHECKOUT_INTENT_BUFFER_LIMIT = 5;
10884
+ // One signal per kind (commit, wallet, checkout_step, frame and cart), with an
10885
+ // add-to-cart click apart from a cart open, so a new one never evicts another.
10886
+ var CHECKOUT_INTENT_BUFFER_LIMIT = 6;
10886
10887
  var CHECKOUT_INTENT_MAX_AGE_MS = 30000;
10887
10888
  var ON_SHOPPABLE_ADS_READY_METHOD = 'onShoppableAdsReady';
10888
10889
  // The purpose of this class is to create a link between the Core mParticle SDK and the
@@ -11085,8 +11086,10 @@ var mParticle = (function () {
11085
11086
  }
11086
11087
  var kit = this.kit;
11087
11088
  if (!kit) {
11089
+ // One per kind, with an add-to-cart click kept apart from a
11090
+ // click that opens the cart.
11088
11091
  this.pendingCheckoutIntents = this.pendingCheckoutIntents.filter(function (pending) {
11089
- return pending.signal.kind !== signal.kind;
11092
+ return pending.signal.kind !== signal.kind || !!pending.signal.adds !== !!signal.adds;
11090
11093
  }).concat({
11091
11094
  signal: signal,
11092
11095
  pathname: pathname
@@ -12729,17 +12732,17 @@ var mParticle = (function () {
12729
12732
  // does. Only the cart rule reads the title. Opening the cart counts only for a
12730
12733
  // control that opens it on the page, such as a flyout: one that leads to the cart
12731
12734
  // page unloads before a call made on the click can return.
12732
- function isCartControl(control, cores) {
12735
+ function cartControlAction(control, cores) {
12733
12736
  var title = cores.length ? undefined : normalize(control.getAttribute('title'));
12734
12737
  var texts = title ? [coreLabel(title)] : cores;
12735
12738
  if (texts.some(function (text) {
12736
12739
  return addToCartLabels.test(text);
12737
12740
  })) {
12738
- return true;
12741
+ return 'add';
12739
12742
  }
12740
12743
  return (control.hasAttribute('aria-expanded') || control.hasAttribute('aria-haspopup')) && texts.some(function (text) {
12741
12744
  return openCartLabels.test(text);
12742
- });
12745
+ }) ? 'open' : undefined;
12743
12746
  }
12744
12747
  // "Buy now" and "Purchase" count only on a checkout route, and never on a plain
12745
12748
  // link, which is navigation.
@@ -12768,10 +12771,20 @@ var mParticle = (function () {
12768
12771
  }
12769
12772
  var texts = labels(control);
12770
12773
  var cores = texts.map(coreLabel);
12771
- var cart = isCartControl(control, cores) ? {
12772
- kind: 'cart',
12773
- source: 'label'
12774
- } : undefined;
12774
+ var cartAction = cartControlAction(control, cores);
12775
+ var cart;
12776
+ if (cartAction === 'add') {
12777
+ cart = {
12778
+ kind: 'cart',
12779
+ source: 'label',
12780
+ adds: true
12781
+ };
12782
+ } else if (cartAction === 'open') {
12783
+ cart = {
12784
+ kind: 'cart',
12785
+ source: 'label'
12786
+ };
12787
+ }
12775
12788
  if (isQuietIntentControl(control, false, !!cart)) {
12776
12789
  return undefined;
12777
12790
  }
@@ -13005,8 +13018,9 @@ var mParticle = (function () {
13005
13018
  passive: true
13006
13019
  };
13007
13020
  // Logs button clicks and clicks on links that leave the page as mParticle events, and hands checkout
13008
- // intent to the Rokt kit as a frozen {kind, t, source, pathname}. Submits and wallet frame focus feed the kit only,
13009
- // and so do payment picks: a payment radio's option names, or the payment family of a focused frame.
13021
+ // intent to the Rokt kit as a frozen {kind, t, source, pathname}, with adds on an add-to-cart click.
13022
+ // Submits and wallet frame focus feed the kit only, and so do payment picks: a payment radio's option
13023
+ // names, or the payment family of a focused frame.
13010
13024
  var ButtonTracker = /** @class */function () {
13011
13025
  function ButtonTracker(mpInstance) {
13012
13026
  var _this = this;
@@ -13206,6 +13220,7 @@ var mParticle = (function () {
13206
13220
  var box;
13207
13221
  var kind;
13208
13222
  var source;
13223
+ var adds;
13209
13224
  var choice;
13210
13225
  var family;
13211
13226
  var unconfirmedCommit = false;
@@ -13234,6 +13249,7 @@ var mParticle = (function () {
13234
13249
  var intent = signalsKit ? classifyIntent(control, pathname) : undefined;
13235
13250
  kind = intent ? intent.kind : undefined;
13236
13251
  source = intent ? intent.source : undefined;
13252
+ adds = intent ? intent.adds : undefined;
13237
13253
  choice = signalsKit ? describePaymentChoice(control, path) : undefined;
13238
13254
  }
13239
13255
  this.lastClick = {
@@ -13254,6 +13270,7 @@ var mParticle = (function () {
13254
13270
  var intent = classifyIntent(control, pathname);
13255
13271
  kind = intent ? intent.kind : undefined;
13256
13272
  source = intent ? intent.source : undefined;
13273
+ adds = intent ? intent.adds : undefined;
13257
13274
  }
13258
13275
  unconfirmedCommit = !submitter;
13259
13276
  }
@@ -13292,7 +13309,7 @@ var mParticle = (function () {
13292
13309
  _this.pickPayment(t, pathname, undefined, family);
13293
13310
  }
13294
13311
  if (kind) {
13295
- _this.emit(kind, source, layer, t, pathname);
13312
+ _this.emit(kind, source, layer, t, pathname, adds);
13296
13313
  }
13297
13314
  } catch (e) {
13298
13315
  _this.log('[error] delivery threw: ' + e);
@@ -13355,22 +13372,31 @@ var mParticle = (function () {
13355
13372
  }
13356
13373
  this.uploadHeld = false;
13357
13374
  };
13358
- ButtonTracker.prototype.emit = function (kind, source, layer, t, pathname) {
13375
+ ButtonTracker.prototype.emit = function (kind, source, layer, t, pathname, adds) {
13359
13376
  if (this.isKitSuppressed()) {
13360
13377
  return;
13361
13378
  }
13362
13379
  if (kind === 'commit' && layer === 'click') {
13363
13380
  this.lastCommitClick = t;
13364
13381
  }
13365
- var last = this.lastSent[kind];
13382
+ // An add-to-cart click throttles apart from a click that opens the
13383
+ // cart, so opening the cart first never drops the add.
13384
+ var key = adds ? kind + ':adds' : kind;
13385
+ var last = this.lastSent[key];
13366
13386
  if (last && last.pathname === pathname && t - last.t < THROTTLE_MS) {
13367
13387
  return;
13368
13388
  }
13369
- this.lastSent[kind] = {
13389
+ this.lastSent[key] = {
13370
13390
  t: t,
13371
13391
  pathname: pathname
13372
13392
  };
13373
- this.mpInstance._RoktManager.notifyCheckoutIntent(Object.freeze({
13393
+ this.mpInstance._RoktManager.notifyCheckoutIntent(Object.freeze(adds ? {
13394
+ kind: kind,
13395
+ t: t,
13396
+ source: source,
13397
+ pathname: pathname,
13398
+ adds: adds
13399
+ } : {
13374
13400
  kind: kind,
13375
13401
  t: t,
13376
13402
  source: source,
@@ -4,6 +4,7 @@ export type CheckoutIntentSource = 'vendor' | 'label' | 'brand' | 'frame' | 'sub
4
4
  export interface ICheckoutIntent {
5
5
  kind: Exclude<CheckoutIntentKind, 'frame'>;
6
6
  source: CheckoutIntentSource;
7
+ adds?: true;
7
8
  }
8
9
  export declare function classifyIntent(control: Element, pathname: string): ICheckoutIntent | undefined;
9
10
  export declare function classifyIntentControl(control: Element, pathname: string): Exclude<CheckoutIntentKind, 'frame'> | undefined;
@@ -49,6 +49,7 @@ export interface ICheckoutIntentSignal {
49
49
  t: number;
50
50
  source?: CheckoutIntentSource;
51
51
  pathname?: string;
52
+ adds?: true;
52
53
  }
53
54
  export interface IPaymentPickSignal {
54
55
  t: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mparticle/web-sdk",
3
- "version": "3.25.0",
3
+ "version": "3.26.0",
4
4
  "description": "mParticle core SDK for web applications",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -149,8 +149,9 @@ const CAPTURE_PASSIVE: AddEventListenerOptions = {
149
149
  const PASSIVE: AddEventListenerOptions = { passive: true };
150
150
 
151
151
  // Logs button clicks and clicks on links that leave the page as mParticle events, and hands checkout
152
- // intent to the Rokt kit as a frozen {kind, t, source, pathname}. Submits and wallet frame focus feed the kit only,
153
- // and so do payment picks: a payment radio's option names, or the payment family of a focused frame.
152
+ // intent to the Rokt kit as a frozen {kind, t, source, pathname}, with adds on an add-to-cart click.
153
+ // Submits and wallet frame focus feed the kit only, and so do payment picks: a payment radio's option
154
+ // names, or the payment family of a focused frame.
154
155
  export class ButtonTracker {
155
156
  private readonly mpInstance: IMParticleWebSDKInstance;
156
157
  private active = false;
@@ -399,6 +400,7 @@ export class ButtonTracker {
399
400
  let box: HTMLInputElement | undefined;
400
401
  let kind: CheckoutIntentKind | undefined;
401
402
  let source: CheckoutIntentSource | undefined;
403
+ let adds: true | undefined;
402
404
  let choice: IPaymentChoice | undefined;
403
405
  let family: PaymentFrameFamily | undefined;
404
406
  let unconfirmedCommit = false;
@@ -441,6 +443,7 @@ export class ButtonTracker {
441
443
  : undefined;
442
444
  kind = intent ? intent.kind : undefined;
443
445
  source = intent ? intent.source : undefined;
446
+ adds = intent ? intent.adds : undefined;
444
447
  choice = signalsKit
445
448
  ? describePaymentChoice(control, path)
446
449
  : undefined;
@@ -459,6 +462,7 @@ export class ButtonTracker {
459
462
  const intent = classifyIntent(control, pathname);
460
463
  kind = intent ? intent.kind : undefined;
461
464
  source = intent ? intent.source : undefined;
465
+ adds = intent ? intent.adds : undefined;
462
466
  }
463
467
  unconfirmedCommit = !submitter;
464
468
  }
@@ -507,7 +511,7 @@ export class ButtonTracker {
507
511
  this.pickPayment(t, pathname, undefined, family);
508
512
  }
509
513
  if (kind) {
510
- this.emit(kind, source, layer, t, pathname);
514
+ this.emit(kind, source, layer, t, pathname, adds);
511
515
  }
512
516
  } catch (e) {
513
517
  this.log('[error] delivery threw: ' + e);
@@ -591,7 +595,8 @@ export class ButtonTracker {
591
595
  source: CheckoutIntentSource | undefined,
592
596
  layer: string,
593
597
  t: number,
594
- pathname: string
598
+ pathname: string,
599
+ adds?: true
595
600
  ): void {
596
601
  if (this.isKitSuppressed()) {
597
602
  return;
@@ -600,14 +605,21 @@ export class ButtonTracker {
600
605
  this.lastCommitClick = t;
601
606
  }
602
607
 
603
- const last = this.lastSent[kind];
608
+ // An add-to-cart click throttles apart from a click that opens the
609
+ // cart, so opening the cart first never drops the add.
610
+ const key = adds ? kind + ':adds' : kind;
611
+ const last = this.lastSent[key];
604
612
  if (last && last.pathname === pathname && t - last.t < THROTTLE_MS) {
605
613
  return;
606
614
  }
607
- this.lastSent[kind] = { t, pathname };
615
+ this.lastSent[key] = { t, pathname };
608
616
 
609
617
  this.mpInstance._RoktManager.notifyCheckoutIntent(
610
- Object.freeze({ kind, t, source, pathname }),
618
+ Object.freeze(
619
+ adds
620
+ ? { kind, t, source, pathname, adds }
621
+ : { kind, t, source, pathname }
622
+ ),
611
623
  pathname
612
624
  );
613
625
  }
@@ -230,16 +230,16 @@ function labels(element: Element): string[] {
230
230
  // does. Only the cart rule reads the title. Opening the cart counts only for a
231
231
  // control that opens it on the page, such as a flyout: one that leads to the cart
232
232
  // page unloads before a call made on the click can return.
233
- function isCartControl(control: Element, cores: string[]): boolean {
233
+ function cartControlAction(control: Element, cores: string[]): 'add' | 'open' | undefined {
234
234
  const title = cores.length ? undefined : normalize(control.getAttribute('title'));
235
235
  const texts = title ? [coreLabel(title)] : cores;
236
236
  if (texts.some(text => addToCartLabels.test(text))) {
237
- return true;
237
+ return 'add';
238
238
  }
239
- return (
240
- (control.hasAttribute('aria-expanded') || control.hasAttribute('aria-haspopup')) &&
239
+ return (control.hasAttribute('aria-expanded') || control.hasAttribute('aria-haspopup')) &&
241
240
  texts.some(text => openCartLabels.test(text))
242
- );
241
+ ? 'open'
242
+ : undefined;
243
243
  }
244
244
 
245
245
  // Which rule recognised the intent: a vendor's own markup, a phrase in the
@@ -258,6 +258,8 @@ export type CheckoutIntentSource =
258
258
  export interface ICheckoutIntent {
259
259
  kind: Exclude<CheckoutIntentKind, 'frame'>;
260
260
  source: CheckoutIntentSource;
261
+ // Set on a cart click that puts something in the cart, not one that opens it.
262
+ adds?: true;
261
263
  }
262
264
 
263
265
  // "Buy now" and "Purchase" count only on a checkout route, and never on a plain
@@ -294,9 +296,13 @@ export function classifyIntent(
294
296
  }
295
297
  const texts = labels(control);
296
298
  const cores = texts.map(coreLabel);
297
- const cart: ICheckoutIntent | undefined = isCartControl(control, cores)
298
- ? { kind: 'cart', source: 'label' }
299
- : undefined;
299
+ const cartAction = cartControlAction(control, cores);
300
+ let cart: ICheckoutIntent | undefined;
301
+ if (cartAction === 'add') {
302
+ cart = { kind: 'cart', source: 'label', adds: true };
303
+ } else if (cartAction === 'open') {
304
+ cart = { kind: 'cart', source: 'label' };
305
+ }
300
306
  if (isQuietIntentControl(control, false, !!cart)) {
301
307
  return undefined;
302
308
  }
@@ -26,8 +26,9 @@ import { subscribeToRouteChange } from "./routeChangeMonitor";
26
26
  import type { CheckoutIntentKind, CheckoutIntentSource, PaymentFrameFamily } from "./buttonTracking/checkoutIntent";
27
27
 
28
28
  const PASSBACK_CONVERSION_TRACKING_ID = 'passbackconversiontrackingid';
29
- // One signal per kind (commit, wallet, checkout_step, frame and cart), so a new kind never evicts another.
30
- const CHECKOUT_INTENT_BUFFER_LIMIT = 5;
29
+ // One signal per kind (commit, wallet, checkout_step, frame and cart), with an
30
+ // add-to-cart click apart from a cart open, so a new one never evicts another.
31
+ const CHECKOUT_INTENT_BUFFER_LIMIT = 6;
31
32
  const CHECKOUT_INTENT_MAX_AGE_MS = 30000;
32
33
 
33
34
  type AttributeTargetUser = Pick<IMParticleUser, 'getUserIdentities' | 'setUserAttributes'>;
@@ -83,6 +84,8 @@ export interface ICheckoutIntentSignal {
83
84
  t: number;
84
85
  source?: CheckoutIntentSource;
85
86
  pathname?: string;
87
+ // On a cart click that puts something in the cart. Older kits ignore it.
88
+ adds?: true;
86
89
  }
87
90
 
88
91
  // What a kit receives when the shopper picks a payment method: the names of a
@@ -375,8 +378,14 @@ export default class RoktManager {
375
378
 
376
379
  const kit = this.kit;
377
380
  if (!kit) {
381
+ // One per kind, with an add-to-cart click kept apart from a
382
+ // click that opens the cart.
378
383
  this.pendingCheckoutIntents = this.pendingCheckoutIntents
379
- .filter(pending => pending.signal.kind !== signal.kind)
384
+ .filter(
385
+ pending =>
386
+ pending.signal.kind !== signal.kind ||
387
+ !!pending.signal.adds !== !!signal.adds
388
+ )
380
389
  .concat({ signal, pathname })
381
390
  .slice(-CHECKOUT_INTENT_BUFFER_LIMIT);
382
391
  return;