@mparticle/web-sdk 3.24.0 → 3.25.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.24.0";
207
+ var version = "3.25.0";
208
208
 
209
209
  var Constants = {
210
210
  sdkVersion: version,
@@ -379,7 +379,8 @@ var mParticle = (function () {
379
379
  CaptureIntegrationSpecificIdsV2: 'captureIntegrationSpecificIds.V2',
380
380
  AstBackgroundEvents: 'astBackgroundEvents',
381
381
  AutoLogPageView: 'autoLogPageView',
382
- AutoButtonTracking: 'autoButtonTracking'
382
+ AutoButtonTracking: 'autoButtonTracking',
383
+ AutoLinkTracking: 'autoLinkTracking'
383
384
  },
384
385
  DefaultInstance: 'default_instance',
385
386
  CCPAPurpose: 'data_sale_opt_out',
@@ -5349,9 +5350,13 @@ var mParticle = (function () {
5349
5350
  if (requiresConsent && mpidIsNotInCookies) {
5350
5351
  return;
5351
5352
  }
5352
- // For Rokt, block cookie sync when noTargeting privacy flag is true
5353
- if (moduleId === PARTNER_MODULE_IDS.Rokt && mpInstance._CookieConsentManager.getNoTargeting()) {
5354
- return;
5353
+ // For Rokt, block cookie sync under the noTargeting or doNotShareOrSell privacy flag,
5354
+ // or when the browser sends Global Privacy Control
5355
+ if (moduleId === PARTNER_MODULE_IDS.Rokt) {
5356
+ var nav = typeof navigator === 'undefined' ? undefined : navigator;
5357
+ if (mpInstance._CookieConsentManager.getNoTargeting() || mpInstance._CookieConsentManager.getDoNotShareOrSell() || !!nav && nav.globalPrivacyControl === true) {
5358
+ return;
5359
+ }
5355
5360
  }
5356
5361
  var isEnabledForUserConsent = mpInstance._Consent.isEnabledForUserConsent;
5357
5362
  if (!isEnabledForUserConsent(filteringConsentRuleValues, mpInstance.Identity.getCurrentUser())) {
@@ -6545,7 +6550,8 @@ var mParticle = (function () {
6545
6550
  CaptureIntegrationSpecificIdsV2 = _a.CaptureIntegrationSpecificIdsV2,
6546
6551
  AstBackgroundEvents = _a.AstBackgroundEvents,
6547
6552
  AutoLogPageView = _a.AutoLogPageView,
6548
- AutoButtonTracking = _a.AutoButtonTracking;
6553
+ AutoButtonTracking = _a.AutoButtonTracking,
6554
+ AutoLinkTracking = _a.AutoLinkTracking;
6549
6555
  if (!config.flags) {
6550
6556
  return {};
6551
6557
  }
@@ -6563,6 +6569,7 @@ var mParticle = (function () {
6563
6569
  flags[AstBackgroundEvents] = config.flags[AstBackgroundEvents] === 'True';
6564
6570
  flags[AutoLogPageView] = config.flags[AutoLogPageView] === 'True';
6565
6571
  flags[AutoButtonTracking] = config.flags[AutoButtonTracking] === 'True';
6572
+ flags[AutoLinkTracking] = config.flags[AutoLinkTracking] === 'True';
6566
6573
  return flags;
6567
6574
  }
6568
6575
  function processBaseUrls(config, flags, apiKey) {
@@ -11035,21 +11042,27 @@ var mParticle = (function () {
11035
11042
  RoktManager.prototype.setAutoButtonClicksForwarded = function (forwarded) {
11036
11043
  this.autoButtonClicksForwarded = forwarded;
11037
11044
  };
11045
+ // noTargeting (which noDeviceId implies), doNotShareOrSell or Global Privacy
11046
+ // Control. Unlike noFunctional, these also stop auto button and link clicks
11047
+ // from being logged.
11048
+ RoktManager.prototype.hasTargetingOptOut = function () {
11049
+ var options = this.launcherOptions || {};
11050
+ if (options.noTargeting || options.doNotShareOrSell) {
11051
+ return true;
11052
+ }
11053
+ var nav = typeof navigator === 'undefined' ? undefined : navigator;
11054
+ return !!nav && nav.globalPrivacyControl === true;
11055
+ };
11038
11056
  // Checkout intent is off unless the flag is on, and under opt-out, any Rokt
11039
11057
  // privacy launcher option, Global Privacy Control, or a Rokt connection that
11040
11058
  // does not receive auto button clicks.
11041
11059
  RoktManager.prototype.isCheckoutIntentSuppressed = function () {
11042
- var _a, _b;
11060
+ var _a, _b, _c;
11043
11061
  var flags = (_b = (_a = this.store) === null || _a === void 0 ? void 0 : _a.SDKConfig) === null || _b === void 0 ? void 0 : _b.flags;
11044
11062
  if (!flags || flags[Constants.FeatureFlags.AutoButtonTracking] !== true || !this.store.isEnabled || !this.autoButtonClicksForwarded) {
11045
11063
  return true;
11046
11064
  }
11047
- var options = this.launcherOptions || {};
11048
- if (options.noFunctional || options.noTargeting || options.doNotShareOrSell) {
11049
- return true;
11050
- }
11051
- var nav = typeof navigator === 'undefined' ? undefined : navigator;
11052
- return !!nav && nav.globalPrivacyControl === true;
11065
+ return !!((_c = this.launcherOptions) === null || _c === void 0 ? void 0 : _c.noFunctional) || this.hasTargetingOptOut();
11053
11066
  };
11054
11067
  // True when the kit can wait for the shopper's confirm click: signals are not
11055
11068
  // suppressed and the browser exposes the composed path the detector reads.
@@ -11091,6 +11104,23 @@ var mParticle = (function () {
11091
11104
  RoktManager.prototype.discardCheckoutIntents = function () {
11092
11105
  this.pendingCheckoutIntents = [];
11093
11106
  };
11107
+ // Under the same gates as checkout intent. A pick made before a kit
11108
+ // attaches is not kept: the shopper is still choosing, and the next pick
11109
+ // replaces it.
11110
+ RoktManager.prototype.notifyPaymentPick = function (signal) {
11111
+ var _a;
11112
+ if (this.isCheckoutIntentSuppressed()) {
11113
+ return;
11114
+ }
11115
+ var kit = this.kit;
11116
+ try {
11117
+ if (kit && isFunction(kit.onPaymentPick)) {
11118
+ kit.onPaymentPick(signal);
11119
+ }
11120
+ } catch (e) {
11121
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.error("RoktManager: Error in onPaymentPick: ".concat(getErrorMessage(e)));
11122
+ }
11123
+ };
11094
11124
  // Replays recent buffered signals raised on the current page, oldest first.
11095
11125
  RoktManager.prototype.flushCheckoutIntents = function () {
11096
11126
  var _this = this;
@@ -11646,12 +11676,12 @@ var mParticle = (function () {
11646
11676
  }();
11647
11677
 
11648
11678
  /**
11649
- * CookieConsentManager handles storage and access of consent flags (noFunctional, noTargeting)
11650
- * that are passed via launcherOptions during SDK initialization.
11679
+ * CookieConsentManager handles storage and access of consent flags (noFunctional, noTargeting,
11680
+ * doNotShareOrSell) that are passed via launcherOptions during SDK initialization.
11651
11681
  *
11652
11682
  * These flags allow Rokt integration to respect user privacy choices.
11653
11683
  *
11654
- * Default behavior: Both flags default to false, meaning all features are allowed
11684
+ * Default behavior: All flags default to false, meaning all features are allowed
11655
11685
  * unless explicitly opted out by the user.
11656
11686
  */
11657
11687
  var CookieConsentManager = /** @class */function () {
@@ -11659,7 +11689,8 @@ var mParticle = (function () {
11659
11689
  this.flags = flags;
11660
11690
  this.flags = {
11661
11691
  noFunctional: flags.noFunctional === true,
11662
- noTargeting: flags.noTargeting === true
11692
+ noTargeting: flags.noTargeting === true,
11693
+ doNotShareOrSell: flags.doNotShareOrSell === true
11663
11694
  };
11664
11695
  }
11665
11696
  /**
@@ -11676,6 +11707,13 @@ var mParticle = (function () {
11676
11707
  CookieConsentManager.prototype.getNoFunctional = function () {
11677
11708
  return this.flags.noFunctional;
11678
11709
  };
11710
+ /**
11711
+ * Returns true if the user has opted out of the sale or sharing of their data.
11712
+ * Sharing is allowed when doNotShareOrSell is false (default).
11713
+ */
11714
+ CookieConsentManager.prototype.getDoNotShareOrSell = function () {
11715
+ return this.flags.doNotShareOrSell;
11716
+ };
11679
11717
  CookieConsentManager.prototype.syncNoTargetingAttribute = function (user) {
11680
11718
  if (!user) return;
11681
11719
  if (this.flags.noTargeting) {
@@ -11733,19 +11771,20 @@ var mParticle = (function () {
11733
11771
  var AUTO_BUTTON_ATTRIBUTE = 'is_auto_button_click';
11734
11772
  // Specific enough not to merge with a customer's own 'Button Click' event.
11735
11773
  var BUTTON_CLICK_EVENT_NAME = 'Auto Button Click';
11736
- // One custom event per click, logged like logLink() with the auto marker and the
11737
- // page fields that auto page views carry. No intent: classifying clicks is left
11738
- // to whoever reads the data.
11739
- var buildButtonClickEvent = function buildButtonClickEvent(click, pathname) {
11740
- var _a;
11741
- var data = (_a = {
11774
+ // Marks an automatically logged click on a link that leaves the page.
11775
+ var AUTO_LINK_ATTRIBUTE = 'is_auto_link_click';
11776
+ var LINK_CLICK_EVENT_NAME = 'Auto Link Click';
11777
+ // The attributes both click events carry, with the page fields that auto page
11778
+ // views carry. No intent: classifying clicks is left to whoever reads the data.
11779
+ var clickAttributes = function clickAttributes(click, pathname) {
11780
+ var data = {
11742
11781
  label_source: click.labelSource,
11743
11782
  element: click.element,
11744
11783
  type: click.type,
11745
11784
  path: pathname,
11746
11785
  hostname: window.location.hostname
11747
- }, _a[AUTO_BUTTON_ATTRIBUTE] = true, _a);
11748
- // Optional fields are left out when the button has no safe value for them.
11786
+ };
11787
+ // Optional fields are left out when the control has no safe value for them.
11749
11788
  var optional = {
11750
11789
  label: click.label,
11751
11790
  aria_label: click.ariaLabel,
@@ -11759,8 +11798,8 @@ var mParticle = (function () {
11759
11798
  link_domain: click.linkDomain,
11760
11799
  file_extension: click.fileExtension
11761
11800
  };
11762
- for (var _i = 0, _b = Object.keys(optional); _i < _b.length; _i++) {
11763
- var key = _b[_i];
11801
+ for (var _i = 0, _a = Object.keys(optional); _i < _a.length; _i++) {
11802
+ var key = _a[_i];
11764
11803
  if (optional[key]) {
11765
11804
  data[key] = optional[key];
11766
11805
  }
@@ -11768,6 +11807,12 @@ var mParticle = (function () {
11768
11807
  if (click.checked !== undefined) {
11769
11808
  data.checked = click.checked;
11770
11809
  }
11810
+ return data;
11811
+ };
11812
+ // One custom event per button click, logged like logLink() with the auto marker.
11813
+ var buildButtonClickEvent = function buildButtonClickEvent(click, pathname) {
11814
+ var data = clickAttributes(click, pathname);
11815
+ data[AUTO_BUTTON_ATTRIBUTE] = true;
11771
11816
  return {
11772
11817
  messageType: MessageType$1.PageEvent,
11773
11818
  name: BUTTON_CLICK_EVENT_NAME,
@@ -11775,28 +11820,52 @@ var mParticle = (function () {
11775
11820
  eventType: EventType.Other
11776
11821
  };
11777
11822
  };
11823
+ // One custom event per click on a link that leaves the page. Typed Other, not
11824
+ // Navigation, so no kit reads it as a page change. A plain link to another page
11825
+ // of the site goes without its text, which can name the shopper ("Hi, Jane");
11826
+ // a button or wallet acting as a link keeps its name.
11827
+ var buildLinkClickEvent = function buildLinkClickEvent(click, pathname) {
11828
+ var data = clickAttributes(click.linkType === 'internal' && click.element === 'link' ? __assign(__assign({}, click), {
11829
+ label: undefined,
11830
+ labelSource: 'none',
11831
+ ariaLabel: undefined
11832
+ }) : click, pathname);
11833
+ data[AUTO_LINK_ATTRIBUTE] = true;
11834
+ return {
11835
+ messageType: MessageType$1.PageEvent,
11836
+ name: LINK_CLICK_EVENT_NAME,
11837
+ data: data,
11838
+ eventType: EventType.Other
11839
+ };
11840
+ };
11778
11841
  // Every attribute buildButtonClickEvent can set apart from the marker and the
11779
11842
  // hostname, which is the same on every click on this page. A spec checks the
11780
11843
  // two stay in step.
11781
11844
  var CLICK_ATTRIBUTES = ['label_source', 'element', 'type', 'path', 'label', 'aria_label', 'icon', 'element_id', 'element_name', 'test_id', 'controls', 'form', 'link_type', 'link_domain', 'file_extension', 'checked'];
11782
- // Which check keeps some or all auto button clicks from a kit, or undefined
11783
- // when the kit receives every one. A forwarding rule on an attribute whose
11784
- // value differs between clicks lets some through and not others. Each other
11785
- // check goes through isEventForwarded on its own, so together they decide as
11786
- // it does for each click.
11787
- var getButtonClickBlocker = function getButtonClickBlocker(forwarder, kitBlocker) {
11788
- var _a;
11845
+ // Which check keeps some or all auto button clicks, or auto link clicks with
11846
+ // `link`, from a kit, or undefined when the kit receives every one. A forwarding
11847
+ // rule on an attribute whose value differs between clicks lets some through and
11848
+ // not others. Each other check goes through isEventForwarded on its own, so
11849
+ // together they decide as it does for each click.
11850
+ var getButtonClickBlocker = function getButtonClickBlocker(forwarder, kitBlocker, link) {
11851
+ if (link === void 0) {
11852
+ link = false;
11853
+ }
11789
11854
  var rule = forwarder.filteringEventAttributeValue;
11790
11855
  if (rule && rule.eventAttributeValue && CLICK_ATTRIBUTES.some(function (name) {
11791
11856
  return KitFilterHelper.hashAttributeConditionalForwarding(name) === rule.eventAttributeName;
11792
11857
  })) {
11793
11858
  return 'forwarding rule';
11794
11859
  }
11860
+ var attributes = {
11861
+ hostname: window.location.hostname
11862
+ };
11863
+ attributes[link ? AUTO_LINK_ATTRIBUTE : AUTO_BUTTON_ATTRIBUTE] = true;
11795
11864
  var click = {
11796
- EventName: BUTTON_CLICK_EVENT_NAME,
11865
+ EventName: link ? LINK_CLICK_EVENT_NAME : BUTTON_CLICK_EVENT_NAME,
11797
11866
  EventCategory: EventType.Other,
11798
11867
  EventDataType: MessageType$1.PageEvent,
11799
- EventAttributes: (_a = {}, _a[AUTO_BUTTON_ATTRIBUTE] = true, _a.hostname = window.location.hostname, _a)
11868
+ EventAttributes: attributes
11800
11869
  };
11801
11870
  var checks = [['data plan', {}], ['forwarding rule', {
11802
11871
  filteringEventAttributeValue: rule
@@ -12020,9 +12089,13 @@ var mParticle = (function () {
12020
12089
  return control;
12021
12090
  }
12022
12091
  // Text that may hold what a shopper typed or what the page opted out: form
12023
- // fields, editable regions, and anything under data-mp-no-track.
12024
- function isUnsafeTextSource(element) {
12025
- return element.matches('input, select, textarea, option, optgroup, datalist, ' + EDITABLE) || !!element.querySelector('input, select, textarea, [data-mp-no-track], ' + EDITABLE) || hasComposedAncestor(element, 'select, datalist, textarea, [data-mp-no-track], ' + EDITABLE);
12092
+ // fields, editable regions, and anything under data-mp-no-track. `own` is a
12093
+ // box the element labels, which holds no typing of its own.
12094
+ function isUnsafeTextSource(element, own) {
12095
+ var inside = 'input, select, textarea, [data-mp-no-track], ' + EDITABLE;
12096
+ return element.matches('input, select, textarea, option, optgroup, datalist, ' + EDITABLE) || (own ? Array.from(element.querySelectorAll(inside)).some(function (found) {
12097
+ return found !== own;
12098
+ }) : !!element.querySelector(inside)) || hasComposedAncestor(element, 'select, datalist, textarea, [data-mp-no-track], ' + EDITABLE);
12026
12099
  }
12027
12100
 
12028
12101
  // Masks a button label before it is logged. Button text can carry personal data,
@@ -12363,8 +12436,8 @@ var mParticle = (function () {
12363
12436
  return tag === 'button' || tag === 'input' ? control.type : 'button';
12364
12437
  }
12365
12438
  // Reads the link's own resolved URL parts, never its full href: only the hostname of
12366
- // a link that leaves the site and the extension of a file it downloads travel. Navigation
12367
- // within the site is left to page views, and mailto:, tel: and other schemes are skipped.
12439
+ // a link that leaves the site and the extension of a file it downloads travel.
12440
+ // mailto:, tel: and other schemes give undefined.
12368
12441
  function describeLink(link) {
12369
12442
  var href = (link.getAttribute('href') || '').trim();
12370
12443
  if (!href || href.charAt(0) === '#') {
@@ -12401,7 +12474,14 @@ var mParticle = (function () {
12401
12474
  }
12402
12475
  return link.pathname === window.location.pathname && link.search === window.location.search ? {
12403
12476
  type: 'same_page'
12404
- } : undefined;
12477
+ } : {
12478
+ type: 'internal'
12479
+ };
12480
+ }
12481
+ // Whether a described click is on a link that leaves the page, logged as a link
12482
+ // click rather than a button click.
12483
+ function isLinkClick(click) {
12484
+ return !!click.linkType && click.linkType !== 'same_page';
12405
12485
  }
12406
12486
  // Checkboxes and radios, and the roles that act as them. A role can list
12407
12487
  // fallbacks, so any of its tokens counts.
@@ -12411,6 +12491,9 @@ var mParticle = (function () {
12411
12491
  var box = element instanceof HTMLLabelElement ? element.control : element;
12412
12492
  return box && box.matches(CHOICE) ? box : null;
12413
12493
  }
12494
+ function isRadio(choice) {
12495
+ return choice instanceof HTMLInputElement ? choice.type === 'radio' : !!choice && choice.matches(RADIO_ROLE);
12496
+ }
12414
12497
  // The box a click on this control picks. One the click passed through below
12415
12498
  // the control comes first: querySelector can't reach a slotted box, a box in a
12416
12499
  // shadow root or the box of a label inside the control, and a row can hold
@@ -12429,8 +12512,9 @@ var mParticle = (function () {
12429
12512
  }
12430
12513
  return boxOf(control) || control.querySelector(CHOICE);
12431
12514
  }
12432
- // Describes a clicked control for auto button tracking. A link counts only when page
12433
- // views can't see the click, and carries its link type.
12515
+ // Describes a clicked control for auto button and link tracking. A link carries its
12516
+ // link type, and one to another scheme is skipped. A role="button" anchor carries one
12517
+ // only when it leaves the page; otherwise it stays a plain button.
12434
12518
  function describeButtonClick(control, path) {
12435
12519
  if (path === void 0) {
12436
12520
  path = [];
@@ -12441,6 +12525,11 @@ var mParticle = (function () {
12441
12525
  if (!link) {
12442
12526
  return undefined;
12443
12527
  }
12528
+ } else if (control.matches('a[href]')) {
12529
+ link = describeLink(control);
12530
+ if (link && link.type === 'same_page') {
12531
+ link = undefined;
12532
+ }
12444
12533
  }
12445
12534
  var element = elementKind(control);
12446
12535
  var box = control instanceof HTMLInputElement && (control.type === 'checkbox' || control.type === 'radio') ? control : undefined;
@@ -12454,7 +12543,7 @@ var mParticle = (function () {
12454
12543
  // radio's id, test id and the panel it opens name the option picked, so
12455
12544
  // only the name of its input, the question, goes with it. A wrapper's own
12456
12545
  // name, or a role radio's, can name the option instead.
12457
- var radio = choice instanceof HTMLInputElement ? choice.type === 'radio' : !!choice && choice.matches(RADIO_ROLE);
12546
+ var radio = isRadio(choice);
12458
12547
  var named = !radio ? control : choice instanceof HTMLInputElement ? choice : null;
12459
12548
  var name = choice ? undefined : accessibleName(control);
12460
12549
  var label = name ? maskLabel(name.raw) : undefined;
@@ -12480,6 +12569,54 @@ var mParticle = (function () {
12480
12569
  checked: box ? box.checked : undefined
12481
12570
  };
12482
12571
  }
12572
+ // A question about payment, read from the names its author gave it, so
12573
+ // "checkout[payment_gateway]", "paymentMethod" and "tender_type" all count and
12574
+ // "payee" does not. A radio's input name is its question; its group or
12575
+ // fieldset speaks only for a radio with no name, as a role radio usually is.
12576
+ var PAYMENT_QUESTION = /(?:^| )(?:pay|payment\w*|tenders?|gateways?)(?: |$)/;
12577
+ var QUESTION_GROUP = '[role="radiogroup"], fieldset';
12578
+ function isPaymentQuestion(radio) {
12579
+ var name = radio.getAttribute('name');
12580
+ var group = name ? null : radio.closest(QUESTION_GROUP);
12581
+ var question = group ? [group.getAttribute('id'), group.getAttribute('name'), group.getAttribute('aria-label')] : [name];
12582
+ return question.some(function (words) {
12583
+ return PAYMENT_QUESTION.test(nameWords(words));
12584
+ });
12585
+ }
12586
+ // What names a payment option: the radio's accessible name, the text and
12587
+ // image of each label, and its hand-written ids, text masked like a label.
12588
+ function optionNames(radio) {
12589
+ var names = [maskLabel(accessibleName(radio).raw)];
12590
+ var labels = radio instanceof HTMLInputElement && radio.labels ? Array.from(radio.labels).slice(0, 2) : [];
12591
+ labels.forEach(function (label) {
12592
+ if (isShown(label) && !isUnsafeTextSource(label, radio)) {
12593
+ names.push(maskLabel(renderedText(label)));
12594
+ names.push(maskLabel(shownImageAlt(label)));
12595
+ }
12596
+ });
12597
+ names.push(stableIdentifier(radio.getAttribute('id')), firstIdentifier(radio, TEST_ID_ATTRIBUTES));
12598
+ return names.filter(function (name, index) {
12599
+ return !!name && names.indexOf(name) === index;
12600
+ });
12601
+ }
12602
+ function describePaymentChoice(control, path) {
12603
+ if (path === void 0) {
12604
+ path = [];
12605
+ }
12606
+ var choice = choiceOf(control, path);
12607
+ if (!isRadio(choice) || hasComposedAncestor(choice, '[data-mp-no-track]') || !isPaymentQuestion(choice)) {
12608
+ return undefined;
12609
+ }
12610
+ var names = optionNames(choice);
12611
+ return names.length ? {
12612
+ radio: choice,
12613
+ names: names
12614
+ } : undefined;
12615
+ }
12616
+ // Read once the page has handled the click, which may have cancelled it.
12617
+ function isPicked(radio) {
12618
+ return radio instanceof HTMLInputElement ? radio.checked : radio.getAttribute('aria-checked') === 'true';
12619
+ }
12483
12620
 
12484
12621
  var checkoutPath = /(?:^|\/)(?:checkouts?|payment|order|kasse|paiement|commander?|pago)(?:\/|$)/i;
12485
12622
  // English look-alikes are whole words; the other languages stay substring
@@ -12495,9 +12632,11 @@ var mParticle = (function () {
12495
12632
  var routeGatedCommits = new RegExp('^(?:buy now|purchase|jetzt kaufen|kaufen|commander|(?:passer|valider) (?:la |ma )?commande|finalizar (?:la |mi )?compra|' + 'comprar ahora|acquista ora|nu kopen|\u4ECA\u3059\u3050\u8CFC\u5165|\u8CFC\u5165\u3059\u308B|\u3053\u306E\u5185\u5BB9\u3067\u7533\u3057\u8FBC\u3080)$');
12496
12633
  var steps = new RegExp('^(?:' + ["(?:let's |lets |go to |proceed to |secure )?(?:check ?out|checkout)(?: now| securely| as guest)?", '(?:continue|proceed) to (?:payment|review|billing|shipping|delivery|order review)|review (?:my |your )?order', 'guest checkout|(?:pay|continue|check ?out) (?:with|by) (?:card|credit card|debit card|credit or debit card)', 'zur kasse|zur kasse gehen|auschecken|weiter zur zahlung', 'passer \u00E0 la caisse|continuer vers le paiement|proc\u00E9der au paiement', 'ir a caja|continuar al pago|tramitar pedido', "procedi al checkout|procedi all'acquisto|procedi al pagamento|vai alla cassa", 'afrekenen|verder naar betalen|doorgaan naar betalen', '\u30EC\u30B8\u306B\u9032\u3080|\u3054?(?:\u8CFC\u5165|\u6CE8\u6587)\u624B\u7D9A\u304D(?:\u3078|\u306B)(?:\u9032\u3080)?|\u304A?\u652F\u6255\u3044(?:\u3078|\u306B)\u9032\u3080|(?:\u3054\u6CE8\u6587\u5185\u5BB9\u306E)?\u78BA\u8A8D\u753B\u9762\u3078(?:\u9032\u3080)?'].join('|') + ')$');
12497
12634
  var CART_NOUN = '(?:(?:my|your|the) )?(?:shopping )?(?:cart|bag|basket)';
12498
- // "Add to bag", "View cart", "Shopping bag", "Bag", and a count badge such as
12499
- // "1 item in bag", which reads "item in bag" once digits are stripped.
12500
- var cartLabels = new RegExp('^(?:add(?: [^ ]+){0,5} to ' + CART_NOUN + '|(?:(?:view|open|go to) )?' + CART_NOUN + '(?: items?)?' + '|items? in ' + CART_NOUN + ')$');
12635
+ // "Add to bag" and "Add 2 to cart": a click that puts something in the cart.
12636
+ var addToCartLabels = new RegExp('^add(?: [^ ]+){0,5} to ' + CART_NOUN + '$');
12637
+ // "View cart", "Shopping bag", "Bag", and a count badge such as "1 item in bag",
12638
+ // which reads "item in bag" once digits are stripped: a click that opens the cart.
12639
+ var openCartLabels = new RegExp('^(?:(?:(?:view|open|go to) )?' + CART_NOUN + '(?: items?)?' + '|items? in ' + CART_NOUN + ')$');
12501
12640
  var WALLET_NAMES = 'apple pay|google pay|paypal|venmo|amazon pay|shop pay|klarna|afterpay|clearpay|cash app(?: pay)?|affirm|sezzle|samsung pay';
12502
12641
  var WALLET_VERBS = 'pay|buy|purchase|order|book|donate|subscribe|check ?out|checkout|express checkout|continue|proceed|' + 'complete purchase|place (?:my |your )?order';
12503
12642
  // "Pay with Klarna", "Buy with GPay", "Continue to PayPal".
@@ -12505,14 +12644,27 @@ var mParticle = (function () {
12505
12644
  // A wallet's own name on a button: "PayPal", "Klarna checkout", "Apple Pay logo".
12506
12645
  var walletBrands = new RegExp('^(?:' + WALLET_NAMES + ')(?: (?:checkout|check out|express(?: checkout)?|express pay|buy now|pay now|pay|now)' + '| (?:logo|icon|mark|button)(?: (?:logo|icon|mark|button))*)?$');
12507
12646
  // Exact HTTPS hosts of hosted wallet button frames.
12508
- var walletFrameHosts = new Set(['pay.google.com', 'applepay.cdn-apple.com', 'payments.amazon.com', 'pay.shopify.com']);
12647
+ var walletFrameFamilies = {
12648
+ 'pay.google.com': 'google_pay',
12649
+ 'applepay.cdn-apple.com': 'apple_pay',
12650
+ 'payments.amazon.com': 'amazon_pay',
12651
+ 'pay.shopify.com': 'shop_pay'
12652
+ };
12509
12653
  // PayPal serves its buttons and its card fields and pay-later messages from
12510
12654
  // the same hosts; only the button frames are wallet taps.
12511
12655
  var paypalFrameHosts = new Set(['www.paypal.com', 'www.sandbox.paypal.com']);
12512
12656
  var PAYPAL_BUTTON_FRAME = /^\/smart\/(?:buttons|menu)(?:\/|$)/;
12657
+ var PAYPAL_CARD_FRAME = /^\/smart\/card-fields?(?:\/|$)/;
12658
+ // PayPal's JS SDK, used directly or wrapped by a processor, leaves its frames
12659
+ // without a src and names them __zoid__paypal_<component>__ instead.
12660
+ var PAYPAL_SDK_FRAME = /^__zoid__paypal_/;
12661
+ var PAYPAL_SDK_BUTTON_FRAME = /^__zoid__paypal_(?:buttons|menu)__/;
12513
12662
  // Stripe's quick-pay button frames; its other frames are card and form fields.
12514
12663
  var STRIPE_WALLET_FRAME = /\/elements-inner-(?:payment-request|express-checkout)-/;
12664
+ var STRIPE_CARD_FRAME = /\/elements-inner-card\b/;
12515
12665
  // Hosted card-entry and fingerprint frames: focus there is typing card details.
12666
+ // Some of these hosts also serve gift card and bank account fields, so none
12667
+ // names a family.
12516
12668
  var CARD_FRAME_DOMAINS = ['adyen.com', 'braintreegateway.com', 'cybersource.com', 'squarecdn.com', 'checkout.com'];
12517
12669
  // Keep these classes ASCII-only in source bytes to avoid mojibake parse failures
12518
12670
  // when a host page forces non-UTF-8 decoding before JavaScript parse.
@@ -12574,11 +12726,19 @@ var mParticle = (function () {
12574
12726
  });
12575
12727
  }
12576
12728
  // A cart button is often a bare icon, so its title names it when nothing else
12577
- // does. Only the cart rule reads the title.
12729
+ // does. Only the cart rule reads the title. Opening the cart counts only for a
12730
+ // control that opens it on the page, such as a flyout: one that leads to the cart
12731
+ // page unloads before a call made on the click can return.
12578
12732
  function isCartControl(control, cores) {
12579
12733
  var title = cores.length ? undefined : normalize(control.getAttribute('title'));
12580
- return (title ? [coreLabel(title)] : cores).some(function (text) {
12581
- return cartLabels.test(text);
12734
+ var texts = title ? [coreLabel(title)] : cores;
12735
+ if (texts.some(function (text) {
12736
+ return addToCartLabels.test(text);
12737
+ })) {
12738
+ return true;
12739
+ }
12740
+ return (control.hasAttribute('aria-expanded') || control.hasAttribute('aria-haspopup')) && texts.some(function (text) {
12741
+ return openCartLabels.test(text);
12582
12742
  });
12583
12743
  }
12584
12744
  // "Buy now" and "Purchase" count only on a checkout route, and never on a plain
@@ -12593,8 +12753,8 @@ var mParticle = (function () {
12593
12753
  // pickers, toggles and pay-later messages never count; a vendor's own wallet
12594
12754
  // button counts before any label rule; a confirm label on any source counts
12595
12755
  // before the look-alike exclusions veto; then a wallet-named control, wallet
12596
- // phrases and steps. A cart label, links included, counts only where none of
12597
- // those do.
12756
+ // phrases and steps. An add-to-cart label, links included, or a control that
12757
+ // opens the cart on the page counts only where none of those do.
12598
12758
  function classifyIntent(control, pathname) {
12599
12759
  var vendor = vendorButtonKind(control);
12600
12760
  if (vendor === 'none') {
@@ -12668,30 +12828,66 @@ var mParticle = (function () {
12668
12828
  return host === domain || host.length > domain.length && host.slice(host.length - domain.length - 1) === '.' + domain;
12669
12829
  }
12670
12830
  // Focus moving into a visible hosted wallet button counts as a wallet click;
12671
- // focus into hosted card fields or messages is only a frame.
12672
- function classifyIntentFrame(target, win) {
12831
+ // focus into hosted card fields or messages is only a frame. A family comes
12832
+ // only from a frame that can draw no other method: PayPal's button frame also
12833
+ // draws Pay Later, Venmo and its card form, Stripe's quick-pay frame draws
12834
+ // Apple Pay or Google Pay by browser, and its payment form holds several.
12835
+ function classifyPaymentFrame(target, win) {
12673
12836
  if (win.document.visibilityState !== 'visible' || !(target instanceof HTMLIFrameElement)) {
12674
12837
  return undefined;
12675
12838
  }
12676
12839
  if (isRoktElement(target) || hasComposedAncestor(target, '[data-mp-no-track]')) {
12677
12840
  return undefined;
12678
12841
  }
12842
+ // A frame that has its own src is judged by that address, never by its name.
12843
+ if ((!target.src || target.src === 'about:blank') && PAYPAL_SDK_FRAME.test(target.name)) {
12844
+ return PAYPAL_SDK_BUTTON_FRAME.test(target.name) ? {
12845
+ kind: 'wallet'
12846
+ } : {
12847
+ kind: 'frame'
12848
+ };
12849
+ }
12679
12850
  try {
12680
12851
  var url = new URL(target.src);
12681
12852
  var host_1 = url.protocol === 'https:' ? url.hostname : '';
12682
12853
  if (paypalFrameHosts.has(host_1)) {
12683
- return PAYPAL_BUTTON_FRAME.test(url.pathname) ? 'wallet' : 'frame';
12854
+ if (PAYPAL_BUTTON_FRAME.test(url.pathname)) {
12855
+ return {
12856
+ kind: 'wallet'
12857
+ };
12858
+ }
12859
+ return PAYPAL_CARD_FRAME.test(url.pathname) ? {
12860
+ kind: 'frame',
12861
+ family: 'card'
12862
+ } : {
12863
+ kind: 'frame'
12864
+ };
12684
12865
  }
12685
- if (walletFrameHosts.has(host_1)) {
12686
- return 'wallet';
12866
+ if (Object.prototype.hasOwnProperty.call(walletFrameFamilies, host_1)) {
12867
+ return {
12868
+ kind: 'wallet',
12869
+ family: walletFrameFamilies[host_1]
12870
+ };
12687
12871
  }
12688
12872
  if (host_1 === 'js.stripe.com') {
12689
- return STRIPE_WALLET_FRAME.test(url.pathname) ? 'wallet' : 'frame';
12873
+ if (STRIPE_WALLET_FRAME.test(url.pathname)) {
12874
+ return {
12875
+ kind: 'wallet'
12876
+ };
12877
+ }
12878
+ return STRIPE_CARD_FRAME.test(url.pathname) ? {
12879
+ kind: 'frame',
12880
+ family: 'card'
12881
+ } : {
12882
+ kind: 'frame'
12883
+ };
12690
12884
  }
12691
12885
  if (CARD_FRAME_DOMAINS.some(function (domain) {
12692
12886
  return isOnDomain(host_1, domain);
12693
12887
  })) {
12694
- return 'frame';
12888
+ return {
12889
+ kind: 'frame'
12890
+ };
12695
12891
  }
12696
12892
  } catch (e) {
12697
12893
  // An unparseable frame src is not a wallet frame.
@@ -12808,13 +13004,16 @@ var mParticle = (function () {
12808
13004
  var PASSIVE = {
12809
13005
  passive: true
12810
13006
  };
12811
- // Logs every button click as an mParticle event, and hands checkout intent to the
12812
- // Rokt kit as a frozen {kind, t, source, pathname}. Submits and wallet frame focus feed the kit only.
13007
+ // 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.
12813
13010
  var ButtonTracker = /** @class */function () {
12814
13011
  function ButtonTracker(mpInstance) {
12815
13012
  var _this = this;
12816
13013
  this.active = false;
12817
13014
  this.hasRoktKit = false;
13015
+ this.logButtons = false;
13016
+ this.logLinks = false;
12818
13017
  // Bumped on reset so classification queued before it is dropped.
12819
13018
  this.generation = 0;
12820
13019
  this.lastCommitClick = -Infinity;
@@ -12888,7 +13087,9 @@ var mParticle = (function () {
12888
13087
  this.teardown();
12889
13088
  }
12890
13089
  this.hasRoktKit = options.hasRoktKit;
12891
- if (!this.eventsEnabled() && this.isKitSuppressed()) {
13090
+ this.logButtons = options.logButtons;
13091
+ this.logLinks = options.logLinks;
13092
+ if ((!(this.logButtons || this.logLinks) || !this.eventsEnabled()) && this.isKitSuppressed()) {
12892
13093
  this.log('opted out, not starting');
12893
13094
  return;
12894
13095
  }
@@ -12989,7 +13190,7 @@ var mParticle = (function () {
12989
13190
  return;
12990
13191
  }
12991
13192
  var layer = event.type;
12992
- var logsEvents = layer === 'click' && this.eventsEnabled();
13193
+ var logsEvents = layer === 'click' && (this.logButtons || this.logLinks) && this.eventsEnabled() && !this.hasTargetingOptOut();
12993
13194
  var signalsKit = !this.isKitSuppressed();
12994
13195
  if (!logsEvents && !signalsKit) {
12995
13196
  return;
@@ -13001,9 +13202,12 @@ var mParticle = (function () {
13001
13202
  // button that disables or relabels itself is seen as it was clicked.
13002
13203
  // Logging and the kit hand-off wait for the next paint.
13003
13204
  var click;
13205
+ var asLink = false;
13004
13206
  var box;
13005
13207
  var kind;
13006
13208
  var source;
13209
+ var choice;
13210
+ var family;
13007
13211
  var unconfirmedCommit = false;
13008
13212
  if (layer === 'click') {
13009
13213
  // The composed path is only populated during dispatch.
@@ -13011,7 +13215,18 @@ var mParticle = (function () {
13011
13215
  var excluded = isExcludedPath(path);
13012
13216
  var control = excluded ? undefined : findControl(path, true);
13013
13217
  if (control) {
13014
- click = logsEvents ? describeButtonClick(control, path) : undefined;
13218
+ // With links alone, only an anchor can be logged.
13219
+ click = logsEvents && (this.logButtons || control.matches('a[href]')) ? describeButtonClick(control, path) : undefined;
13220
+ if (click) {
13221
+ asLink = this.logLinks && isLinkClick(click);
13222
+ // Without link tracking, a link that leaves the page stays a
13223
+ // button click, except a plain link to another page of the
13224
+ // site, which button tracking never logged.
13225
+ var asButton = this.logButtons && !asLink && !(click.linkType === 'internal' && control.matches('a[href]:not([role="button"])'));
13226
+ if (!asLink && !asButton) {
13227
+ click = undefined;
13228
+ }
13229
+ }
13015
13230
  if (click && click.checked !== undefined) {
13016
13231
  box = control;
13017
13232
  }
@@ -13019,6 +13234,7 @@ var mParticle = (function () {
13019
13234
  var intent = signalsKit ? classifyIntent(control, pathname) : undefined;
13020
13235
  kind = intent ? intent.kind : undefined;
13021
13236
  source = intent ? intent.source : undefined;
13237
+ choice = signalsKit ? describePaymentChoice(control, path) : undefined;
13022
13238
  }
13023
13239
  this.lastClick = {
13024
13240
  t: t,
@@ -13050,7 +13266,9 @@ var mParticle = (function () {
13050
13266
  if (layer === 'blur') {
13051
13267
  // Read after the blur settles: some browsers have not moved
13052
13268
  // focus into the frame yet when the window blurs.
13053
- kind = classifyIntentFrame(document.activeElement, window);
13269
+ var frame = classifyPaymentFrame(document.activeElement, window);
13270
+ kind = frame ? frame.kind : undefined;
13271
+ family = frame ? frame.family : undefined;
13054
13272
  source = 'frame';
13055
13273
  } else if (unconfirmedCommit && t - _this.lastCommitClick > SUBMIT_AFTER_COMMIT_CLICK_MS) {
13056
13274
  kind = undefined;
@@ -13064,7 +13282,14 @@ var mParticle = (function () {
13064
13282
  if (box && event.defaultPrevented) {
13065
13283
  click.checked = box.type === 'checkbox' ? !click.checked : box.checked;
13066
13284
  }
13067
- _this.logClick(click, pathname);
13285
+ _this.logClick(click, pathname, asLink);
13286
+ }
13287
+ // Ahead of the intent, so a pre-selection it fires goes out
13288
+ // with this pick.
13289
+ if (choice && isPicked(choice.radio)) {
13290
+ _this.pickPayment(t, pathname, choice.names);
13291
+ } else if (family) {
13292
+ _this.pickPayment(t, pathname, undefined, family);
13068
13293
  }
13069
13294
  if (kind) {
13070
13295
  _this.emit(kind, source, layer, t, pathname);
@@ -13075,8 +13300,8 @@ var mParticle = (function () {
13075
13300
  });
13076
13301
  };
13077
13302
  // Every real click is one event, repeats included, up to a ceiling per page.
13078
- ButtonTracker.prototype.logClick = function (click, pathname) {
13079
- if (!this.eventsEnabled()) {
13303
+ ButtonTracker.prototype.logClick = function (click, pathname, asLink) {
13304
+ if (!this.eventsEnabled() || this.hasTargetingOptOut()) {
13080
13305
  return;
13081
13306
  }
13082
13307
  if (pathname !== this.pagePath) {
@@ -13090,7 +13315,7 @@ var mParticle = (function () {
13090
13315
  // Restarts an expired session, as public logEvent() and page views do.
13091
13316
  this.mpInstance._SessionManager.resetSessionTimer();
13092
13317
  var queued = this.queuedForUpload();
13093
- this.mpInstance._Events.logEvent(buildButtonClickEvent(click, pathname));
13318
+ this.mpInstance._Events.logEvent(asLink ? buildLinkClickEvent(click, pathname) : buildButtonClickEvent(click, pathname));
13094
13319
  // Only a click waiting for the batch interval is sent early: a held
13095
13320
  // one goes out when released, and with batching off it already has.
13096
13321
  // A checkbox or radio waits for the batch, since choosing an option
@@ -13152,11 +13377,29 @@ var mParticle = (function () {
13152
13377
  pathname: pathname
13153
13378
  }), pathname);
13154
13379
  };
13380
+ ButtonTracker.prototype.pickPayment = function (t, pathname, names, family) {
13381
+ if (this.isKitSuppressed()) {
13382
+ return;
13383
+ }
13384
+ this.mpInstance._RoktManager.notifyPaymentPick(Object.freeze({
13385
+ t: t,
13386
+ pathname: pathname,
13387
+ names: names ? Object.freeze(names.slice()) : undefined,
13388
+ family: family
13389
+ }));
13390
+ };
13155
13391
  // Events follow the SDK's opt-out like any other event.
13156
13392
  ButtonTracker.prototype.eventsEnabled = function () {
13157
13393
  var store = this.mpInstance._Store;
13158
13394
  return !!store && store.isEnabled;
13159
13395
  };
13396
+ // Read per click, since the launcher options can arrive after the tracker
13397
+ // starts. Only where this init configures a Rokt kit, so Global Privacy
13398
+ // Control alone doesn't stop click logging elsewhere.
13399
+ ButtonTracker.prototype.hasTargetingOptOut = function () {
13400
+ var roktManager = this.mpInstance._RoktManager;
13401
+ return this.hasRoktKit && !!roktManager && roktManager.hasTargetingOptOut();
13402
+ };
13160
13403
  // The Rokt manager owns the kit's privacy gates: flag, opt-out, launcher
13161
13404
  // options and Global Privacy Control.
13162
13405
  ButtonTracker.prototype.isKitSuppressed = function () {
@@ -14101,7 +14344,8 @@ var mParticle = (function () {
14101
14344
  var getFeatureFlag = mpInstance._Helpers.getFeatureFlag;
14102
14345
  var _e = Constants.FeatureFlags,
14103
14346
  AutoLogPageView = _e.AutoLogPageView,
14104
- AutoButtonTracking = _e.AutoButtonTracking;
14347
+ AutoButtonTracking = _e.AutoButtonTracking,
14348
+ AutoLinkTracking = _e.AutoLinkTracking;
14105
14349
  // Destroy previous batch uploader to prevent leaked timers and event listeners
14106
14350
  if ((_a = mpInstance._APIClient) === null || _a === void 0 ? void 0 : _a.uploader) {
14107
14351
  mpInstance._APIClient.uploader.destroy();
@@ -14168,11 +14412,16 @@ var mParticle = (function () {
14168
14412
  // Rokt kit only when that kit receives them. Set before
14169
14413
  // processForwarders: the kit can read it during this init, from its own
14170
14414
  // init or from a returning shopper's landing page view.
14415
+ var logButtons = !!getFeatureFlag(AutoButtonTracking);
14416
+ var logLinks = !!getFeatureFlag(AutoLinkTracking);
14417
+ // Links feed intent too, so with link tracking on the kit must also
14418
+ // receive Auto Link Click events.
14171
14419
  var buttonClickBlocker = roktConfig_1 ? getButtonClickBlocker(roktConfig_1, kitBlocker) : undefined;
14172
- if (buttonClickBlocker && getFeatureFlag(AutoButtonTracking)) {
14173
- mpInstance.Logger.warning("Checkout intent is off: the ".concat(buttonClickBlocker, " keeps some or all Auto Button Click events from the Rokt kit."));
14420
+ var linkClickBlocker = roktConfig_1 && logLinks ? getButtonClickBlocker(roktConfig_1, kitBlocker, true) : undefined;
14421
+ if (logButtons && (buttonClickBlocker || linkClickBlocker)) {
14422
+ mpInstance.Logger.warning(buttonClickBlocker ? "Checkout intent is off: the ".concat(buttonClickBlocker, " keeps some or all Auto Button Click events from the Rokt kit.") : "Checkout intent is off: the ".concat(linkClickBlocker, " keeps some or all Auto Link Click events from the Rokt kit."));
14174
14423
  }
14175
- mpInstance._RoktManager.setAutoButtonClicksForwarded(!!roktConfig_1 && !buttonClickBlocker);
14424
+ mpInstance._RoktManager.setAutoButtonClicksForwarded(!!roktConfig_1 && !buttonClickBlocker && !linkClickBlocker);
14176
14425
  mpInstance._Forwarders.processForwarders(config, mpInstance._APIClient.prepareForwardingStats);
14177
14426
  mpInstance._Forwarders.processPixelConfigs(config);
14178
14427
  // Checks if session is created, resumed, or needs to be ended
@@ -14207,12 +14456,14 @@ var mParticle = (function () {
14207
14456
  // so it stops listening. Re-created if the flag is re-enabled later.
14208
14457
  mpInstance._PageViewTracker.teardown();
14209
14458
  }
14210
- if (getFeatureFlag(AutoButtonTracking)) {
14459
+ if (logButtons || logLinks) {
14211
14460
  if (!mpInstance._ButtonTracker) {
14212
14461
  mpInstance._ButtonTracker = new ButtonTracker(mpInstance);
14213
14462
  }
14214
14463
  mpInstance._ButtonTracker.init({
14215
- hasRoktKit: !!roktConfig_1
14464
+ hasRoktKit: !!roktConfig_1,
14465
+ logButtons: logButtons,
14466
+ logLinks: logLinks
14216
14467
  });
14217
14468
  } else {
14218
14469
  // Also retires a tracker left by an earlier bundle load. Like APV,
@@ -14318,10 +14569,12 @@ var mParticle = (function () {
14318
14569
  // Initialize CookieConsentManager with privacy flags from launcherOptions
14319
14570
  var _a = normalizeRoktLauncherOptions(config === null || config === void 0 ? void 0 : config.launcherOptions),
14320
14571
  noFunctional = _a.noFunctional,
14321
- noTargeting = _a.noTargeting;
14572
+ noTargeting = _a.noTargeting,
14573
+ doNotShareOrSell = _a.doNotShareOrSell;
14322
14574
  mpInstance._CookieConsentManager = new CookieConsentManager({
14323
14575
  noFunctional: noFunctional,
14324
- noTargeting: noTargeting
14576
+ noTargeting: noTargeting,
14577
+ doNotShareOrSell: doNotShareOrSell
14325
14578
  });
14326
14579
  // Check to see if localStorage is available before main configuration runs
14327
14580
  // since we will need this for the current implementation of user persistence