@mparticle/web-sdk 3.17.0 → 3.19.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/README.md +11 -6
- package/dist/mparticle.common.js +110 -47
- package/dist/mparticle.esm.js +110 -47
- package/dist/mparticle.js +561 -158
- package/dist/types/src/buttonTracking/buttonClickEvent.d.ts +5 -0
- package/dist/types/src/buttonTracking/buttonDescription.d.ts +16 -0
- package/dist/types/src/buttonTracking/buttonTracker.d.ts +35 -0
- package/dist/types/src/buttonTracking/checkoutIntent.d.ts +3 -0
- package/dist/types/src/buttonTracking/controls.d.ts +6 -0
- package/dist/types/src/buttonTracking/labelMasking.d.ts +1 -0
- package/dist/types/src/constants.d.ts +1 -1
- package/dist/types/src/mp-instance.d.ts +2 -2
- package/dist/types/src/roktManager.d.ts +1 -1
- package/dist/types/src/store.d.ts +1 -1
- package/package.json +4 -3
- package/src/buttonTracking/buttonClickEvent.ts +48 -0
- package/src/buttonTracking/buttonDescription.ts +259 -0
- package/src/buttonTracking/buttonTracker.ts +370 -0
- package/src/{checkoutIntentClassifier.ts → buttonTracking/checkoutIntent.ts} +39 -80
- package/src/buttonTracking/controls.ts +111 -0
- package/src/buttonTracking/labelMasking.ts +41 -0
- package/src/constants.ts +1 -1
- package/src/mp-instance.ts +22 -27
- package/src/roktManager.ts +2 -2
- package/src/store.ts +3 -3
- package/dist/types/src/checkoutIntentClassifier.d.ts +0 -4
- package/dist/types/src/checkoutIntentTracker.d.ts +0 -23
- package/src/checkoutIntentTracker.ts +0 -244
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.
|
|
207
|
+
var version = "3.19.0";
|
|
208
208
|
|
|
209
209
|
var Constants = {
|
|
210
210
|
sdkVersion: version,
|
|
@@ -370,17 +370,17 @@ var mParticle = (function () {
|
|
|
370
370
|
CacheIdentity: 'cacheIdentity',
|
|
371
371
|
AudienceAPI: 'audienceAPI',
|
|
372
372
|
// CaptureIntegrationSpecificIds (legacy): boolean flag from server/UI
|
|
373
|
-
// - 'True'
|
|
374
|
-
// - 'False'
|
|
373
|
+
// - 'True' \u2192 capture all integration-specific IDs
|
|
374
|
+
// - 'False' \u2192 capture none
|
|
375
375
|
CaptureIntegrationSpecificIds: 'captureIntegrationSpecificIds',
|
|
376
376
|
// CaptureIntegrationSpecificIdsV2 (new): string mode from server
|
|
377
|
-
// - 'all'
|
|
378
|
-
// - 'none'
|
|
379
|
-
// - 'roktonly'
|
|
377
|
+
// - 'all' \u2192 capture all IDs
|
|
378
|
+
// - 'none' \u2192 capture none
|
|
379
|
+
// - 'roktonly' \u2192 capture only Rokt-related IDs
|
|
380
380
|
CaptureIntegrationSpecificIdsV2: 'captureIntegrationSpecificIds.V2',
|
|
381
381
|
AstBackgroundEvents: 'astBackgroundEvents',
|
|
382
382
|
AutoLogPageView: 'autoLogPageView',
|
|
383
|
-
|
|
383
|
+
AutoButtonTracking: 'autoButtonTracking'
|
|
384
384
|
},
|
|
385
385
|
DefaultInstance: 'default_instance',
|
|
386
386
|
CCPAPurpose: 'data_sale_opt_out',
|
|
@@ -697,7 +697,7 @@ var mParticle = (function () {
|
|
|
697
697
|
return fullUrl;
|
|
698
698
|
};
|
|
699
699
|
// Google's cookie matching service requires `google_hm` values to be web-safe
|
|
700
|
-
// base64 (RFC 4648
|
|
700
|
+
// base64 (RFC 4648 \u00A75) without padding, otherwise the write to the hosted
|
|
701
701
|
// match table fails: https://developers.google.com/authorized-buyers/rtb/cookie-guide
|
|
702
702
|
// (String#replaceAll is not available in our ES5 browser targets.)
|
|
703
703
|
var WEB_SAFE_BASE64_REPLACEMENTS = {
|
|
@@ -3975,7 +3975,7 @@ var mParticle = (function () {
|
|
|
3975
3975
|
}
|
|
3976
3976
|
// The Search endpoint is colocated with /v1/identify under
|
|
3977
3977
|
// identityUrl, so we reuse the same service URL builder. We do
|
|
3978
|
-
// NOT append the apiKey to the URL
|
|
3978
|
+
// NOT append the apiKey to the URL \u2014 auth is done via x-mp-key.
|
|
3979
3979
|
var serviceUrl = _Helpers.createServiceUrl(identityUrl);
|
|
3980
3980
|
var searchUrl = serviceUrl + 'search?cb=1';
|
|
3981
3981
|
var environment = isDevelopmentMode ? 'development' : 'production';
|
|
@@ -4617,7 +4617,7 @@ var mParticle = (function () {
|
|
|
4617
4617
|
var domain = moduleId === PARTNER_MODULE_IDS.TradeDesk ? window.location.hostname : undefined;
|
|
4618
4618
|
// Google Marketing Platform accepts a web-safe base64-encoded MPID via the
|
|
4619
4619
|
// `google_hm` query parameter, but only for accounts provisioned for Google
|
|
4620
|
-
// Hosted Matching
|
|
4620
|
+
// Hosted Matching \u2014 Google returns errors otherwise. It is therefore gated
|
|
4621
4621
|
// behind the opt-in `enableHmTag` setting (off by default), which the server
|
|
4622
4622
|
// delivers as the string 'True' when the UI toggle is enabled.
|
|
4623
4623
|
var enableHmTag = ((_c = settings === null || settings === void 0 ? void 0 : settings.enableHmTag) === null || _c === void 0 ? void 0 : _c.toLowerCase()) === 'true';
|
|
@@ -5790,7 +5790,7 @@ var mParticle = (function () {
|
|
|
5790
5790
|
CaptureIntegrationSpecificIdsV2 = _a.CaptureIntegrationSpecificIdsV2,
|
|
5791
5791
|
AstBackgroundEvents = _a.AstBackgroundEvents,
|
|
5792
5792
|
AutoLogPageView = _a.AutoLogPageView,
|
|
5793
|
-
|
|
5793
|
+
AutoButtonTracking = _a.AutoButtonTracking;
|
|
5794
5794
|
if (!config.flags) {
|
|
5795
5795
|
return {};
|
|
5796
5796
|
}
|
|
@@ -5807,7 +5807,7 @@ var mParticle = (function () {
|
|
|
5807
5807
|
flags[CaptureIntegrationSpecificIdsV2] = config.flags[CaptureIntegrationSpecificIdsV2] || 'none';
|
|
5808
5808
|
flags[AstBackgroundEvents] = config.flags[AstBackgroundEvents] === 'True';
|
|
5809
5809
|
flags[AutoLogPageView] = config.flags[AutoLogPageView] === 'True';
|
|
5810
|
-
flags[
|
|
5810
|
+
flags[AutoButtonTracking] = config.flags[AutoButtonTracking] === 'True';
|
|
5811
5811
|
return flags;
|
|
5812
5812
|
}
|
|
5813
5813
|
function processBaseUrls(config, flags, apiKey) {
|
|
@@ -6703,14 +6703,14 @@ var mParticle = (function () {
|
|
|
6703
6703
|
return !!win && win.history !== undefined && typeof win.history.pushState === 'function' && typeof win.addEventListener === 'function';
|
|
6704
6704
|
};
|
|
6705
6705
|
// Wraps pushState/replaceState so `onNavigate` runs after the real method, and
|
|
6706
|
-
// returns the single function that undoes it
|
|
6706
|
+
// returns the single function that undoes it \u2014 or null when nothing was
|
|
6707
6707
|
// installed (history is already wrapped, or a frozen/sealed History rejected the
|
|
6708
6708
|
// assignment). Handing back one undo closure keeps the wrapper and original
|
|
6709
6709
|
// references out of the tracker entirely: there is no half-patched state for a
|
|
6710
6710
|
// caller to inspect, and no way to restore the wrong pair.
|
|
6711
6711
|
var patchHistory = function patchHistory(onNavigate, log) {
|
|
6712
6712
|
if (window.history.pushState[WRAPPED_MARKER]) {
|
|
6713
|
-
log('[patch] history already wrapped, skipping to avoid double-wrap
|
|
6713
|
+
log('[patch] history already wrapped, skipping to avoid double-wrap \u2014 STACKED WRAPPER DETECTED');
|
|
6714
6714
|
return null;
|
|
6715
6715
|
}
|
|
6716
6716
|
var originals = {};
|
|
@@ -6857,14 +6857,14 @@ var mParticle = (function () {
|
|
|
6857
6857
|
// SECURITY: `code`, `state` and `nonce` are the OAuth 2.0 / OIDC authorization
|
|
6858
6858
|
// code and the CSRF/replay tokens. They are credentials until redeemed, and
|
|
6859
6859
|
// attaching them here persists them in the event store and forwards them to
|
|
6860
|
-
// every configured kit. They are on the list by explicit product decision
|
|
6860
|
+
// every configured kit. They are on the list by explicit product decision \u2014
|
|
6861
6861
|
// deleting that line is the whole of the fix if that decision is revisited.
|
|
6862
6862
|
var ALLOWED_QUERY_PARAMS = [
|
|
6863
6863
|
// Campaign attribution
|
|
6864
6864
|
'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_id',
|
|
6865
6865
|
// Ad-network click ids
|
|
6866
6866
|
'gclid', 'gbraid', 'wbraid', 'fbclid', 'msclkid', 'ttclid', 'twclid', 'li_fat_id', 'dclid',
|
|
6867
|
-
// OAuth / OIDC
|
|
6867
|
+
// OAuth / OIDC \u2014 see the SECURITY note above
|
|
6868
6868
|
'client_id', 'redirect_uri', 'response_type', 'scope', 'state', 'code', 'nonce',
|
|
6869
6869
|
// Pagination
|
|
6870
6870
|
'page', 'limit', 'offset', 'cursor', 'per_page',
|
|
@@ -6879,7 +6879,7 @@ var mParticle = (function () {
|
|
|
6879
6879
|
// Referral
|
|
6880
6880
|
'ref', 'referrer'];
|
|
6881
6881
|
// ---------------------------------------------------------------------------
|
|
6882
|
-
// Pure helpers. No `this`, no globals, no side effects
|
|
6882
|
+
// Pure helpers. No `this`, no globals, no side effects \u2014 callable and assertable
|
|
6883
6883
|
// on their own, which is where the interesting rules live.
|
|
6884
6884
|
// ---------------------------------------------------------------------------
|
|
6885
6885
|
// Pulls the allowlisted query params off a URL. Delegates to the SDK's own
|
|
@@ -6906,7 +6906,7 @@ var mParticle = (function () {
|
|
|
6906
6906
|
// Membership is an own-property check, not `in`. `in` walks the prototype
|
|
6907
6907
|
// chain, so a name matching an Object.prototype member reports as present on
|
|
6908
6908
|
// any plain object. ALLOWED_QUERY_PARAMS contains no such name, which was the
|
|
6909
|
-
// only thing making `in` safe here
|
|
6909
|
+
// only thing making `in` safe here \u2014 and it stops being a safe assumption the
|
|
6910
6910
|
// moment this list can be extended from configuration.
|
|
6911
6911
|
var capturedNames = function capturedNames(params) {
|
|
6912
6912
|
return ALLOWED_QUERY_PARAMS.filter(function (name) {
|
|
@@ -6915,12 +6915,12 @@ var mParticle = (function () {
|
|
|
6915
6915
|
};
|
|
6916
6916
|
// The dedup key: pathname plus the allowlisted params in a fixed order, so that
|
|
6917
6917
|
// reordering the query string is not a new page. Params outside the allowlist
|
|
6918
|
-
// never make it into `page.params` and so cannot key a view
|
|
6918
|
+
// never make it into `page.params` and so cannot key a view \u2014 nor can the hash.
|
|
6919
6919
|
//
|
|
6920
6920
|
// Values are re-encoded because queryStringParser hands them back DECODED. A
|
|
6921
6921
|
// value holding the pair delimiters would otherwise serialize exactly like two
|
|
6922
|
-
// separate params
|
|
6923
|
-
// `q=a&search=b`
|
|
6922
|
+
// separate params \u2014 `{q: 'a&search=b'}` and `{q: 'a', search: 'b'}` both becoming
|
|
6923
|
+
// `q=a&search=b` \u2014 and dedup would treat a real navigation between them as the
|
|
6924
6924
|
// same page and drop the view. `q`, `search` and `redirect_uri` carry `&` and `=`
|
|
6925
6925
|
// routinely, so this is reachable rather than theoretical.
|
|
6926
6926
|
var pageKey = function pageKey(page) {
|
|
@@ -7036,7 +7036,7 @@ var mParticle = (function () {
|
|
|
7036
7036
|
};
|
|
7037
7037
|
};
|
|
7038
7038
|
// Log-safe description of a page: the path, plus the NAMES of the captured
|
|
7039
|
-
// params. Values are deliberately omitted
|
|
7039
|
+
// params. Values are deliberately omitted \u2014 verbose logging goes to the console,
|
|
7040
7040
|
// and session-replay tooling ships console output off-domain, which is not a
|
|
7041
7041
|
// place for an OAuth code or a consumer's search terms.
|
|
7042
7042
|
// Only reachable before init() assigns lastPage, which is ahead of any navigation
|
|
@@ -7084,7 +7084,7 @@ var mParticle = (function () {
|
|
|
7084
7084
|
// Take over from whichever tracker is currently active: one left behind by
|
|
7085
7085
|
// a previous module load, or this same tracker on a repeat
|
|
7086
7086
|
// mParticle.init(). Their pending navigations are transferred rather than
|
|
7087
|
-
// dropped
|
|
7087
|
+
// dropped \u2014 a route change may have queued a deferred fire that has not
|
|
7088
7088
|
// flushed yet, and dropping it loses a page view entirely.
|
|
7089
7089
|
var active = getActiveTracker();
|
|
7090
7090
|
var inheritedPages = this.retire(active);
|
|
@@ -7124,7 +7124,7 @@ var mParticle = (function () {
|
|
|
7124
7124
|
if (!outgoing) {
|
|
7125
7125
|
return [];
|
|
7126
7126
|
}
|
|
7127
|
-
this.log(outgoing === this ? '[init] retiring this tracker for a repeat mParticle.init()
|
|
7127
|
+
this.log(outgoing === this ? '[init] retiring this tracker for a repeat mParticle.init() \u2014 transferring pending navigations and tearing down' : '[init] retiring a tracker from a previous module load \u2014 transferring pending navigations and tearing down');
|
|
7128
7128
|
var pages = outgoing.takePendingNavigations();
|
|
7129
7129
|
outgoing.teardown();
|
|
7130
7130
|
return pages;
|
|
@@ -7287,7 +7287,7 @@ var mParticle = (function () {
|
|
|
7287
7287
|
};
|
|
7288
7288
|
// The auto page view for the landing page. The SPA navigations that follow it
|
|
7289
7289
|
// come from PageViewTracker instead, so both emitters attach the same
|
|
7290
|
-
// allowlisted query params
|
|
7290
|
+
// allowlisted query params \u2014 and this is the one that matters for campaign
|
|
7291
7291
|
// attribution, since utm_*/gclid live on the entry URL.
|
|
7292
7292
|
this.logPageView = function (options) {
|
|
7293
7293
|
self.logEvent({
|
|
@@ -8432,8 +8432,8 @@ var mParticle = (function () {
|
|
|
8432
8432
|
if (isEmpty(readyQueue)) {
|
|
8433
8433
|
return [];
|
|
8434
8434
|
}
|
|
8435
|
-
// Without draining first, sync re-entry (cache-hit identify
|
|
8436
|
-
// parseIdentityResponse
|
|
8435
|
+
// Without draining first, sync re-entry (cache-hit identify \u2192
|
|
8436
|
+
// parseIdentityResponse \u2192 processReadyQueue) re-iterates the same array:
|
|
8437
8437
|
// callers only replace `_preInit.readyQueue` with [] after we return, so the
|
|
8438
8438
|
// nested call still sees every entry. That duplicates Identity/event calls
|
|
8439
8439
|
// and can nest "Unable to compute proper mParticle function" wraps.
|
|
@@ -8511,7 +8511,7 @@ var mParticle = (function () {
|
|
|
8511
8511
|
mpInstance.Logger.verbose(Messages$2.InformationMessages.StartingLogEvent + ': ' + method);
|
|
8512
8512
|
// First, remove any falsy identity values and warn about them
|
|
8513
8513
|
var removedFalsyIdentityData = mpInstance._Helpers.Validators.removeFalsyIdentityValues(identityApiData, mpInstance.Logger);
|
|
8514
|
-
// Normalize convenience aliases (email_sha256
|
|
8514
|
+
// Normalize convenience aliases (email_sha256 \u2192 other, mobile_sha256 \u2192 other2)
|
|
8515
8515
|
var cleanedIdentityApiData = (removedFalsyIdentityData === null || removedFalsyIdentityData === void 0 ? void 0 : removedFalsyIdentityData.userIdentities) ? __assign(__assign({}, removedFalsyIdentityData), {
|
|
8516
8516
|
userIdentities: normalizeUserIdentityKeys(removedFalsyIdentityData.userIdentities)
|
|
8517
8517
|
}) : removedFalsyIdentityData;
|
|
@@ -9694,7 +9694,7 @@ var mParticle = (function () {
|
|
|
9694
9694
|
* Add a GDPR Consent State to the consent state object
|
|
9695
9695
|
*
|
|
9696
9696
|
* @method addGDPRConsentState
|
|
9697
|
-
* @param purpose [String] Data processing purpose that describes the type of processing done on the data subject
|
|
9697
|
+
* @param purpose [String] Data processing purpose that describes the type of processing done on the data subject\u2019s data
|
|
9698
9698
|
* @param gdprConsent [Object] A GDPR consent object created via mParticle.Consent.createGDPRConsent(...)
|
|
9699
9699
|
*/
|
|
9700
9700
|
function addGDPRConsentState(purpose, gdprConsent) {
|
|
@@ -9730,7 +9730,7 @@ var mParticle = (function () {
|
|
|
9730
9730
|
* Remove a GDPR Consent State to the consent state object
|
|
9731
9731
|
*
|
|
9732
9732
|
* @method removeGDPRConsentState
|
|
9733
|
-
* @param purpose [String] Data processing purpose that describes the type of processing done on the data subject
|
|
9733
|
+
* @param purpose [String] Data processing purpose that describes the type of processing done on the data subject\u2019s data
|
|
9734
9734
|
*/
|
|
9735
9735
|
function removeGDPRConsentState(purpose) {
|
|
9736
9736
|
var normalizedPurpose = canonicalizeForDeduplication(purpose);
|
|
@@ -10785,7 +10785,7 @@ var mParticle = (function () {
|
|
|
10785
10785
|
RoktManager.prototype.isCheckoutIntentSuppressed = function () {
|
|
10786
10786
|
var _a, _b;
|
|
10787
10787
|
var flags = (_b = (_a = this.store) === null || _a === void 0 ? void 0 : _a.SDKConfig) === null || _b === void 0 ? void 0 : _b.flags;
|
|
10788
|
-
if (!flags || flags[Constants.FeatureFlags.
|
|
10788
|
+
if (!flags || flags[Constants.FeatureFlags.AutoButtonTracking] !== true || !this.store.isEnabled) {
|
|
10789
10789
|
return true;
|
|
10790
10790
|
}
|
|
10791
10791
|
var options = this.launcherOptions || {};
|
|
@@ -10922,7 +10922,7 @@ var mParticle = (function () {
|
|
|
10922
10922
|
if (isEmpty(newIdentities_1)) {
|
|
10923
10923
|
this.setUserAttributes(this.currentUser, userAttributes_1);
|
|
10924
10924
|
} else {
|
|
10925
|
-
// Fire-and-forget identify
|
|
10925
|
+
// Fire-and-forget identify \u2014 best-effort, does not block selectPlacements
|
|
10926
10926
|
try {
|
|
10927
10927
|
this.identityService.identify({
|
|
10928
10928
|
userIdentities: __assign(__assign({}, currentUserIdentities), newIdentities_1)
|
|
@@ -11074,7 +11074,7 @@ var mParticle = (function () {
|
|
|
11074
11074
|
/**
|
|
11075
11075
|
* Tears down the current Rokt launcher and removes the placements it rendered.
|
|
11076
11076
|
*
|
|
11077
|
-
* Intended for hosts that cannot simply destroy the container element
|
|
11077
|
+
* Intended for hosts that cannot simply destroy the container element \u2014
|
|
11078
11078
|
* SPA route changes and confirmation pages, for example.
|
|
11079
11079
|
*
|
|
11080
11080
|
* Unlike the other proxied methods, a call made before the kit is ready is
|
|
@@ -11459,21 +11459,66 @@ var mParticle = (function () {
|
|
|
11459
11459
|
return LoggingDispatcher;
|
|
11460
11460
|
}();
|
|
11461
11461
|
|
|
11462
|
-
|
|
11463
|
-
var
|
|
11464
|
-
|
|
11465
|
-
var
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
//
|
|
11469
|
-
var
|
|
11462
|
+
// Marks an automatically logged button click, like `is_auto_page_view`.
|
|
11463
|
+
var AUTO_BUTTON_ATTRIBUTE = 'is_auto_button_click';
|
|
11464
|
+
// Specific enough not to merge with a customer's own 'Button Click' event.
|
|
11465
|
+
var BUTTON_CLICK_EVENT_NAME = 'Auto Button Click';
|
|
11466
|
+
// One custom event per click, logged like logLink() with the auto marker and the
|
|
11467
|
+
// page fields that auto page views carry. No intent: classifying clicks is left
|
|
11468
|
+
// to whoever reads the data.
|
|
11469
|
+
var buildButtonClickEvent = function buildButtonClickEvent(click, pathname) {
|
|
11470
|
+
var _a;
|
|
11471
|
+
var data = (_a = {
|
|
11472
|
+
label_source: click.labelSource,
|
|
11473
|
+
element: click.element,
|
|
11474
|
+
type: click.type,
|
|
11475
|
+
path: pathname,
|
|
11476
|
+
hostname: window.location.hostname
|
|
11477
|
+
}, _a[AUTO_BUTTON_ATTRIBUTE] = true, _a);
|
|
11478
|
+
// Optional fields are left out when the button has no safe value for them.
|
|
11479
|
+
var optional = {
|
|
11480
|
+
label: click.label,
|
|
11481
|
+
aria_label: click.ariaLabel,
|
|
11482
|
+
icon: click.icon,
|
|
11483
|
+
element_id: click.elementId,
|
|
11484
|
+
element_name: click.elementName,
|
|
11485
|
+
test_id: click.testId,
|
|
11486
|
+
controls: click.controls,
|
|
11487
|
+
form: click.form
|
|
11488
|
+
};
|
|
11489
|
+
for (var _i = 0, _b = Object.keys(optional); _i < _b.length; _i++) {
|
|
11490
|
+
var key = _b[_i];
|
|
11491
|
+
if (optional[key]) {
|
|
11492
|
+
data[key] = optional[key];
|
|
11493
|
+
}
|
|
11494
|
+
}
|
|
11495
|
+
return {
|
|
11496
|
+
messageType: MessageType$1.PageEvent,
|
|
11497
|
+
name: BUTTON_CLICK_EVENT_NAME,
|
|
11498
|
+
data: data,
|
|
11499
|
+
eventType: EventType.Other
|
|
11500
|
+
};
|
|
11501
|
+
};
|
|
11502
|
+
|
|
11503
|
+
// Finds the control a click landed on, for both checkout intent and button
|
|
11504
|
+
// descriptions. Rokt's own elements, disabled controls and anything under
|
|
11505
|
+
// data-mp-no-track are never returned.
|
|
11470
11506
|
var CONTROL_SELECTOR = 'button, input[type="submit"], input[type="button"], input[type="image"], [role="button"]';
|
|
11471
|
-
|
|
11472
|
-
|
|
11507
|
+
// closest() over the composed tree: slots, parents, then shadow hosts.
|
|
11508
|
+
function hasComposedAncestor(element, selector) {
|
|
11509
|
+
var node = element;
|
|
11510
|
+
while (node) {
|
|
11511
|
+
if (node.matches(selector)) {
|
|
11512
|
+
return true;
|
|
11513
|
+
}
|
|
11514
|
+
var root = isFunction(node.getRootNode) ? node.getRootNode() : null;
|
|
11515
|
+
node = node.assignedSlot || node.parentElement || root && root.host || null;
|
|
11516
|
+
}
|
|
11517
|
+
return false;
|
|
11473
11518
|
}
|
|
11474
11519
|
// Rokt's own placements and frames never count as partner checkout controls.
|
|
11475
11520
|
function isRoktElement(element) {
|
|
11476
|
-
if (element
|
|
11521
|
+
if (hasComposedAncestor(element, '[data-core-type], #rokt-controller-frame')) {
|
|
11477
11522
|
return true;
|
|
11478
11523
|
}
|
|
11479
11524
|
var src = element.getAttribute('src');
|
|
@@ -11491,31 +11536,310 @@ var mParticle = (function () {
|
|
|
11491
11536
|
function isWalletElement(element) {
|
|
11492
11537
|
return element.matches('apple-pay-button, shop-pay-button, .gpay-button, #AmazonPayButton, [data-amazon-pay-button]');
|
|
11493
11538
|
}
|
|
11539
|
+
// Walks at most 12 entries of an event's composed path for the nearest control.
|
|
11540
|
+
// Rokt elements, disabled controls and anything under data-mp-no-track are skipped.
|
|
11541
|
+
function findControl(path) {
|
|
11542
|
+
var control;
|
|
11543
|
+
for (var _i = 0, _a = path.slice(0, 12); _i < _a.length; _i++) {
|
|
11544
|
+
var target = _a[_i];
|
|
11545
|
+
if (!(target instanceof Element)) {
|
|
11546
|
+
continue;
|
|
11547
|
+
}
|
|
11548
|
+
if (isRoktElement(target) || target.matches('[data-mp-no-track]')) {
|
|
11549
|
+
return undefined;
|
|
11550
|
+
}
|
|
11551
|
+
if (!control && (target.matches(CONTROL_SELECTOR + ', a[href]') || isWalletElement(target))) {
|
|
11552
|
+
control = target;
|
|
11553
|
+
}
|
|
11554
|
+
}
|
|
11555
|
+
if (!control || isRoktElement(control) || hasComposedAncestor(control, '[data-mp-no-track]') || control.matches(':disabled, [aria-disabled="true"]')) {
|
|
11556
|
+
return undefined;
|
|
11557
|
+
}
|
|
11558
|
+
return control;
|
|
11559
|
+
}
|
|
11560
|
+
var EDITABLE = '[contenteditable]:not([contenteditable="false"])';
|
|
11561
|
+
// Text that may hold what a shopper typed or what the page opted out: form
|
|
11562
|
+
// fields, editable regions, and anything under data-mp-no-track.
|
|
11563
|
+
function isUnsafeTextSource(element) {
|
|
11564
|
+
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);
|
|
11565
|
+
}
|
|
11566
|
+
|
|
11567
|
+
// Masks a button label before it is logged. Button text can carry personal data,
|
|
11568
|
+
// so this is the privacy boundary for every label and aria-label.
|
|
11569
|
+
// Masking needs \p{Nd} to see every script's digits. Browsers without Unicode
|
|
11570
|
+
// property escapes send no labels at all.
|
|
11571
|
+
function createDigitPatterns() {
|
|
11572
|
+
try {
|
|
11573
|
+
return {
|
|
11574
|
+
run: new RegExp('\\p{Nd}{6,}', 'u'),
|
|
11575
|
+
number: new RegExp('\\p{Nd}+(?:[.,\u060C\u066B\u066C]\\p{Nd}+)*', 'gu')
|
|
11576
|
+
};
|
|
11577
|
+
} catch (e) {
|
|
11578
|
+
return undefined;
|
|
11579
|
+
}
|
|
11580
|
+
}
|
|
11581
|
+
var digitPatterns = createDigitPatterns();
|
|
11582
|
+
// The label as logged: lower case, at most 64 characters, digits and amounts
|
|
11583
|
+
// masked. Dropped when it looks like an email, phone or card number.
|
|
11584
|
+
function maskLabel(raw) {
|
|
11585
|
+
if (!raw || raw.length > 128 || !digitPatterns) {
|
|
11586
|
+
return undefined;
|
|
11587
|
+
}
|
|
11588
|
+
var text = raw.replace(/\s+/g, ' ').trim().toLowerCase();
|
|
11589
|
+
if (!text || text.indexOf('@') !== -1 || digitPatterns.run.test(text.replace(/[\s()\-\u2010-\u2015]/g, ''))) {
|
|
11590
|
+
return undefined;
|
|
11591
|
+
}
|
|
11592
|
+
var masked = text.replace(digitPatterns.number, '#').slice(0, 64).trim();
|
|
11593
|
+
return masked || undefined;
|
|
11594
|
+
}
|
|
11595
|
+
|
|
11596
|
+
function elementKind(control) {
|
|
11597
|
+
if (isWalletElement(control)) {
|
|
11598
|
+
return 'wallet';
|
|
11599
|
+
}
|
|
11600
|
+
var tag = control.tagName.toLowerCase();
|
|
11601
|
+
return tag === 'button' || tag === 'input' ? tag : 'role';
|
|
11602
|
+
}
|
|
11603
|
+
function textOf(element) {
|
|
11604
|
+
return element && !isUnsafeTextSource(element) && element.textContent ? element.textContent.trim() : '';
|
|
11605
|
+
}
|
|
11606
|
+
function nonBlank(value) {
|
|
11607
|
+
return value && value.trim() ? value : undefined;
|
|
11608
|
+
}
|
|
11609
|
+
// The button's name as a screen reader would read it, simplified: the first of
|
|
11610
|
+
// aria-labelledby, aria-label, own text (or an inner image's alt), title, and for
|
|
11611
|
+
// inputs their value. The text sources are skipped for controls that hold form
|
|
11612
|
+
// fields or more than four children, so a typed value is never read.
|
|
11613
|
+
function accessibleName(control) {
|
|
11614
|
+
var labelledBy = control.getAttribute('aria-labelledby');
|
|
11615
|
+
if (labelledBy) {
|
|
11616
|
+
var root_1 = isFunction(control.getRootNode) ? control.getRootNode() : document;
|
|
11617
|
+
var text = labelledBy.split(/\s+/).map(function (id) {
|
|
11618
|
+
return textOf(root_1.getElementById ? root_1.getElementById(id) : null);
|
|
11619
|
+
}).filter(function (part) {
|
|
11620
|
+
return !!part;
|
|
11621
|
+
}).join(' ');
|
|
11622
|
+
if (text) {
|
|
11623
|
+
return {
|
|
11624
|
+
raw: text,
|
|
11625
|
+
source: 'labelledby'
|
|
11626
|
+
};
|
|
11627
|
+
}
|
|
11628
|
+
}
|
|
11629
|
+
var aria = nonBlank(control.getAttribute('aria-label'));
|
|
11630
|
+
if (aria) {
|
|
11631
|
+
return {
|
|
11632
|
+
raw: aria,
|
|
11633
|
+
source: 'aria'
|
|
11634
|
+
};
|
|
11635
|
+
}
|
|
11636
|
+
var readable = control.children.length <= 4 && !isUnsafeTextSource(control);
|
|
11637
|
+
if (control instanceof HTMLInputElement) {
|
|
11638
|
+
// The browser's normalised type: an unknown value reads as 'text'.
|
|
11639
|
+
var type = control.type;
|
|
11640
|
+
if (type === 'image') {
|
|
11641
|
+
var alt = nonBlank(control.getAttribute('alt'));
|
|
11642
|
+
if (alt) {
|
|
11643
|
+
return {
|
|
11644
|
+
raw: alt,
|
|
11645
|
+
source: 'alt'
|
|
11646
|
+
};
|
|
11647
|
+
}
|
|
11648
|
+
} else if (type === 'submit' || type === 'button' || type === 'reset') {
|
|
11649
|
+
var value = nonBlank(control.value);
|
|
11650
|
+
if (value) {
|
|
11651
|
+
return {
|
|
11652
|
+
raw: value,
|
|
11653
|
+
source: 'value'
|
|
11654
|
+
};
|
|
11655
|
+
}
|
|
11656
|
+
if (type !== 'button') {
|
|
11657
|
+
// What the browser shows on an input without a value.
|
|
11658
|
+
return {
|
|
11659
|
+
raw: type,
|
|
11660
|
+
source: 'value'
|
|
11661
|
+
};
|
|
11662
|
+
}
|
|
11663
|
+
}
|
|
11664
|
+
} else if (readable) {
|
|
11665
|
+
var text = textOf(control);
|
|
11666
|
+
if (text) {
|
|
11667
|
+
return {
|
|
11668
|
+
raw: text,
|
|
11669
|
+
source: 'text'
|
|
11670
|
+
};
|
|
11671
|
+
}
|
|
11672
|
+
var image = control.querySelector('img[alt]');
|
|
11673
|
+
var alt = image ? nonBlank(image.getAttribute('alt')) : undefined;
|
|
11674
|
+
if (alt) {
|
|
11675
|
+
return {
|
|
11676
|
+
raw: alt,
|
|
11677
|
+
source: 'alt'
|
|
11678
|
+
};
|
|
11679
|
+
}
|
|
11680
|
+
}
|
|
11681
|
+
var title = nonBlank(control.getAttribute('title'));
|
|
11682
|
+
if (title) {
|
|
11683
|
+
return {
|
|
11684
|
+
raw: title,
|
|
11685
|
+
source: 'title'
|
|
11686
|
+
};
|
|
11687
|
+
}
|
|
11688
|
+
return {
|
|
11689
|
+
source: 'none'
|
|
11690
|
+
};
|
|
11691
|
+
}
|
|
11692
|
+
var ICON_CLASS = /^(?:fa|fas|far|fal|icon|bi|glyphicon|ti|mdi|ri|la|lucide|ion|feather|ph)-([a-z][a-z-]{1,31})$/;
|
|
11693
|
+
// Size, style and animation classes that share the icon prefixes.
|
|
11694
|
+
var ICON_MODIFIER = /^(?:solid|regular|light|thin|duotone|brands|sharp|fw|lg|xs|sm|xl|spin|pulse|border|inverse|stack|flip(?:-[a-z]+)?|rotate(?:-[a-z]+)?|pull-[a-z]+)$/;
|
|
11695
|
+
function iconToken(candidate) {
|
|
11696
|
+
if (!candidate) {
|
|
11697
|
+
return undefined;
|
|
11698
|
+
}
|
|
11699
|
+
var token = candidate.toLowerCase().replace(/^icon-/, '');
|
|
11700
|
+
return /^[a-z][a-z-]{1,31}$/.test(token) ? token : undefined;
|
|
11701
|
+
}
|
|
11702
|
+
// An icon name from an SVG sprite reference or an icon-font class, for buttons
|
|
11703
|
+
// whose only content is an icon. Letters and hyphens only.
|
|
11704
|
+
function iconHint(control) {
|
|
11705
|
+
var allowed = function allowed(element) {
|
|
11706
|
+
return !hasComposedAncestor(element, '[data-mp-no-track]');
|
|
11707
|
+
};
|
|
11708
|
+
var use = Array.from(control.querySelectorAll('use')).filter(allowed)[0];
|
|
11709
|
+
if (use) {
|
|
11710
|
+
var href = use.getAttribute('href') || use.getAttribute('xlink:href') || '';
|
|
11711
|
+
var hash = href.indexOf('#');
|
|
11712
|
+
var sprite = iconToken(hash === -1 ? null : href.slice(hash + 1));
|
|
11713
|
+
if (sprite) {
|
|
11714
|
+
return sprite;
|
|
11715
|
+
}
|
|
11716
|
+
}
|
|
11717
|
+
var candidates = [control].concat(Array.from(control.querySelectorAll('i, span, svg'))).filter(allowed).slice(0, 5);
|
|
11718
|
+
for (var _i = 0, candidates_1 = candidates; _i < candidates_1.length; _i++) {
|
|
11719
|
+
var element = candidates_1[_i];
|
|
11720
|
+
var classes = (element.getAttribute('class') || '').split(/\s+/);
|
|
11721
|
+
for (var _a = 0, classes_1 = classes; _a < classes_1.length; _a++) {
|
|
11722
|
+
var name_1 = classes_1[_a];
|
|
11723
|
+
var match = ICON_CLASS.exec(name_1.toLowerCase());
|
|
11724
|
+
if (match && !ICON_MODIFIER.test(match[1])) {
|
|
11725
|
+
return match[1];
|
|
11726
|
+
}
|
|
11727
|
+
}
|
|
11728
|
+
}
|
|
11729
|
+
return undefined;
|
|
11730
|
+
}
|
|
11731
|
+
// Words of letters, each optionally ending in up to three digits, joined by
|
|
11732
|
+
// hyphens or underscores: `add-to-cart`, `btnCheckout`, `step_2`. Generated ids
|
|
11733
|
+
// (`ember1234`, `a8f3e2c1`, `radix-:r1:`) and long numbers don't match.
|
|
11734
|
+
var HAND_WRITTEN_ID = /^[A-Za-z]+[0-9]{0,3}(?:[-_](?:[A-Za-z]+[0-9]{0,3}|[0-9]{1,3}))*$/;
|
|
11735
|
+
// A developer-written identifier, or nothing.
|
|
11736
|
+
function stableIdentifier(value) {
|
|
11737
|
+
if (!value) {
|
|
11738
|
+
return undefined;
|
|
11739
|
+
}
|
|
11740
|
+
var id = value.trim();
|
|
11741
|
+
// At most three digits in all, so numbers split into groups don't pass.
|
|
11742
|
+
var digits = id.replace(/[^0-9]/g, '').length;
|
|
11743
|
+
return id.length <= 64 && digits <= 3 && HAND_WRITTEN_ID.test(id) ? id : undefined;
|
|
11744
|
+
}
|
|
11745
|
+
var TEST_ID_ATTRIBUTES = ['data-testid', 'data-test-id', 'data-test', 'data-qa', 'data-cy'];
|
|
11746
|
+
// The first of these attributes that holds a developer-written identifier.
|
|
11747
|
+
function firstIdentifier(control, attributes) {
|
|
11748
|
+
for (var _i = 0, attributes_1 = attributes; _i < attributes_1.length; _i++) {
|
|
11749
|
+
var attribute = attributes_1[_i];
|
|
11750
|
+
var id = stableIdentifier(control.getAttribute(attribute));
|
|
11751
|
+
if (id) {
|
|
11752
|
+
return id;
|
|
11753
|
+
}
|
|
11754
|
+
}
|
|
11755
|
+
return undefined;
|
|
11756
|
+
}
|
|
11757
|
+
// What the button opens or acts on: a menu, drawer or dialog. aria-controls can
|
|
11758
|
+
// list several ids, so only the first is used.
|
|
11759
|
+
function controlsIdentifier(control) {
|
|
11760
|
+
var ariaControls = control.getAttribute('aria-controls');
|
|
11761
|
+
return stableIdentifier(ariaControls ? ariaControls.trim().split(/\s+/)[0] : null) || firstIdentifier(control, ['popovertarget', 'commandfor']);
|
|
11762
|
+
}
|
|
11763
|
+
// The id of the form a button or input actually submits, which the browser
|
|
11764
|
+
// resolves from its form attribute or its owning form. getAttribute, because a
|
|
11765
|
+
// field named "id" shadows form.id.
|
|
11766
|
+
function formIdentifier(control) {
|
|
11767
|
+
var form = control instanceof HTMLButtonElement || control instanceof HTMLInputElement ? control.form : null;
|
|
11768
|
+
return form ? stableIdentifier(form.getAttribute('id')) : undefined;
|
|
11769
|
+
}
|
|
11770
|
+
// The browser's normalised type: a button defaults to 'submit' and an unknown
|
|
11771
|
+
// input type reads as 'text'. Wallet and role buttons are just 'button'.
|
|
11772
|
+
function controlType(control, element) {
|
|
11773
|
+
return element === 'button' || element === 'input' ? control.type : 'button';
|
|
11774
|
+
}
|
|
11775
|
+
// Describes a clicked control for auto button tracking. Links are left to page
|
|
11776
|
+
// views, so a link click is not described.
|
|
11777
|
+
function describeButtonClick(control) {
|
|
11778
|
+
if (control.matches('a[href]:not([role="button"])')) {
|
|
11779
|
+
return undefined;
|
|
11780
|
+
}
|
|
11781
|
+
var element = elementKind(control);
|
|
11782
|
+
var name = accessibleName(control);
|
|
11783
|
+
var label = maskLabel(name.raw);
|
|
11784
|
+
return {
|
|
11785
|
+
label: label,
|
|
11786
|
+
labelSource: label ? name.source : 'none',
|
|
11787
|
+
// Kept on its own as well: it often says more than the visible text,
|
|
11788
|
+
// such as which item a remove button removes.
|
|
11789
|
+
ariaLabel: maskLabel(control.getAttribute('aria-label')),
|
|
11790
|
+
icon: iconHint(control),
|
|
11791
|
+
elementId: stableIdentifier(control.getAttribute('id')),
|
|
11792
|
+
elementName: stableIdentifier(control.getAttribute('name')),
|
|
11793
|
+
testId: firstIdentifier(control, TEST_ID_ATTRIBUTES),
|
|
11794
|
+
controls: controlsIdentifier(control),
|
|
11795
|
+
form: formIdentifier(control),
|
|
11796
|
+
element: element,
|
|
11797
|
+
type: controlType(control, element)
|
|
11798
|
+
};
|
|
11799
|
+
}
|
|
11800
|
+
|
|
11801
|
+
var checkoutPath = /(?:^|\/)(?:checkouts?|payment|order|kasse|paiement|commander?|pago)(?:\/|$)/i;
|
|
11802
|
+
var exclusions = new RegExp(['coupon|promo|newsletter|sign in|add to cart|gift card|pay later|pay in|payment plan|learn more', 'gutschein|anmelden|warenkorb|bon cadeau|connexion|panier|cup\u00F3n|iniciar sesi\u00F3n|carrito', 'carrello|codice sconto|accedi|buono regalo|winkelwagen|kortingscode|inloggen|cadeaubon|achteraf betalen', '\u30AB\u30FC\u30C8|\u30AF\u30FC\u30DD\u30F3|\u30ED\u30B0\u30A4\u30F3|\u4F1A\u54E1\u767B\u9332|\u30AE\u30D5\u30C8|\u5F8C\u6255\u3044|\u30E1\u30EB\u30DE\u30AC'].join('|'));
|
|
11803
|
+
var commits = new RegExp('^(?:' + ['(?:place|submit|complete|confirm|finali[sz]e)(?!(?: [^ ]+){0,2} (?:another|new|next)(?: |$))(?: [^ ]+){0,2} (?:order|purchase|booking|reservation|payment|checkout)', 'pay(?: securely)?(?: now)?|confirm and pay|order and pay|order with obligation to pay', '(?:jetzt )?(?:zahlungs|kosten)pflichtig (?:bestellen|buchen)|(?:jetzt )?bezahlen|kauf abschlie\u00DFen|bestellung abschlie\u00DFen', 'commander et payer|payer(?: maintenant)?|(?:confirmer|finaliser) (?:ma |la )?commande', "valider et payer|confirmer et payer|commande avec obligation de paiement|finaliser l'achat", '(?:realizar|confirmar|completar) (?:el |mi |la )?(?:pedido|compra|reserva)|finalizar (?:el |mi )?pedido|pagar(?: ahora)?', 'pedido con obligaci\u00F3n de pago', "(?:effettua|conferma|concludi|completa) (?:l'|il )?(?:ordine|acquisto)|ordine con obbligo di pagamento", 'paga(?: ora| adesso)?|ordina e paga', '(?:nu )?betalen|bestellen en betalen|bestelling plaatsen|plaats bestelling|bestelling afronden', 'bestelling met betalingsverplichting', '(?:\u3053\u306E\u5185\u5BB9\u3067|\u4E0A\u8A18\u306E?\u5185\u5BB9\u3067)?\u3054?(?:\u6CE8\u6587|\u8CFC\u5165|\u4E88\u7D04|\u6C7A\u6E08|\u304A?\u652F\u6255\u3044?)\u3092?(?:\u78BA\u5B9A|\u5B8C\u4E86)(?:\u3059\u308B)?', '(?:\u3053\u306E\u5185\u5BB9\u3067|\u4E0A\u8A18\u306E?\u5185\u5BB9\u3067)\u3054?(?:\u6CE8\u6587|\u8CFC\u5165|\u4E88\u7D04)\u3059\u308B|\u3054?\u6CE8\u6587\u3059\u308B|\u6C7A\u6E08\u3059\u308B|(?:\u4ECA\u3059\u3050|\u3092)?\u652F\u6255\u3046'].join('|') + ')$');
|
|
11804
|
+
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)$');
|
|
11805
|
+
var steps = new RegExp('^(?:' + ['checkout|check out|check-out|continue to payment|proceed to checkout', '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('|') + ')$');
|
|
11806
|
+
var wallets = /^(?:apple pay|google pay|paypal|venmo|amazon pay|shop pay|klarna|afterpay|affirm)$/;
|
|
11807
|
+
// Exact HTTPS hosts of hosted wallet and payment frames.
|
|
11808
|
+
var frameHosts = new Set(['www.paypal.com', 'www.sandbox.paypal.com', 'pay.google.com', 'applepay.cdn-apple.com', 'js.stripe.com', 'checkoutshopper-live.adyen.com', 'payments.amazon.com', 'pay.shopify.com']);
|
|
11809
|
+
// Keep these classes ASCII-only in source bytes to avoid mojibake parse failures
|
|
11810
|
+
// when a host page forces non-UTF-8 decoding before JavaScript parse.
|
|
11811
|
+
var TYPOGRAPHIC_APOSTROPHES = /[\u2019\u2018]/g;
|
|
11812
|
+
var CURRENCY_AND_NUMBER_CHARS = /[0-9\uFF10-\uFF19$\u20AC\u00A3\u00A5\uFFE5\u20B9\u5186.,\uFF0C]/g;
|
|
11813
|
+
function getIntentRouteClass(pathname) {
|
|
11814
|
+
return checkoutPath.test(pathname) ? 'checkout_path' : 'other';
|
|
11815
|
+
}
|
|
11494
11816
|
function normalize(text) {
|
|
11495
11817
|
if (!text || text.length > 128) {
|
|
11496
11818
|
return undefined;
|
|
11497
11819
|
}
|
|
11498
|
-
return text.toLowerCase().replace(
|
|
11820
|
+
return text.toLowerCase().replace(TYPOGRAPHIC_APOSTROPHES, "'").replace(CURRENCY_AND_NUMBER_CHARS, '').replace(/\s+/g, ' ').trim();
|
|
11499
11821
|
}
|
|
11500
11822
|
// Labels come from aria-label then visible text. Only submit and button inputs
|
|
11501
|
-
// have their value read, so a typed field value is never touched.
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
if (element.tagName.toLowerCase() === 'input') {
|
|
11508
|
-
var typeAttr = element.getAttribute('type');
|
|
11509
|
-
var type = typeAttr ? typeAttr.toLowerCase() : typeAttr;
|
|
11823
|
+
// have their value read, so a typed field value is never touched. Other text
|
|
11824
|
+
// follows the same rules as button descriptions.
|
|
11825
|
+
function labelSources(element) {
|
|
11826
|
+
if (element instanceof HTMLInputElement) {
|
|
11827
|
+
var type = element.type;
|
|
11828
|
+
var text = null;
|
|
11510
11829
|
if (type === 'submit' || type === 'button') {
|
|
11511
11830
|
text = element.value;
|
|
11512
11831
|
} else if (type === 'image') {
|
|
11513
11832
|
text = element.getAttribute('alt');
|
|
11514
11833
|
}
|
|
11515
|
-
|
|
11516
|
-
|
|
11834
|
+
return [element.getAttribute('aria-label'), text];
|
|
11835
|
+
}
|
|
11836
|
+
if (element.children.length > 4 || isUnsafeTextSource(element)) {
|
|
11837
|
+
return [];
|
|
11517
11838
|
}
|
|
11518
|
-
return [
|
|
11839
|
+
return [element.getAttribute('aria-label'), element.textContent];
|
|
11840
|
+
}
|
|
11841
|
+
function labels(element) {
|
|
11842
|
+
return labelSources(element).map(normalize).filter(function (label) {
|
|
11519
11843
|
return !!label;
|
|
11520
11844
|
});
|
|
11521
11845
|
}
|
|
@@ -11531,24 +11855,8 @@ var mParticle = (function () {
|
|
|
11531
11855
|
}
|
|
11532
11856
|
return undefined;
|
|
11533
11857
|
}
|
|
11534
|
-
//
|
|
11535
|
-
function classifyIntentControl(
|
|
11536
|
-
var control;
|
|
11537
|
-
for (var _i = 0, _a = path.slice(0, 12); _i < _a.length; _i++) {
|
|
11538
|
-
var target = _a[_i];
|
|
11539
|
-
if (!(target instanceof Element)) {
|
|
11540
|
-
continue;
|
|
11541
|
-
}
|
|
11542
|
-
if (isRoktElement(target)) {
|
|
11543
|
-
return undefined;
|
|
11544
|
-
}
|
|
11545
|
-
if (!control && (target.matches(CONTROL_SELECTOR + ', a[href]') || isWalletElement(target))) {
|
|
11546
|
-
control = target;
|
|
11547
|
-
}
|
|
11548
|
-
}
|
|
11549
|
-
if (!control || isRoktElement(control)) {
|
|
11550
|
-
return undefined;
|
|
11551
|
-
}
|
|
11858
|
+
// Classifies a clicked or submitting control found by findControl.
|
|
11859
|
+
function classifyIntentControl(control, pathname) {
|
|
11552
11860
|
var texts = labels(control);
|
|
11553
11861
|
if (texts.some(function (text) {
|
|
11554
11862
|
return exclusions.test(text);
|
|
@@ -11562,8 +11870,8 @@ var mParticle = (function () {
|
|
|
11562
11870
|
if (button && isWalletElement(control)) {
|
|
11563
11871
|
return 'wallet';
|
|
11564
11872
|
}
|
|
11565
|
-
for (var
|
|
11566
|
-
var text = texts_1[
|
|
11873
|
+
for (var _i = 0, texts_1 = texts; _i < texts_1.length; _i++) {
|
|
11874
|
+
var text = texts_1[_i];
|
|
11567
11875
|
var kind = classifyLabel(text, button, pathname);
|
|
11568
11876
|
if (kind) {
|
|
11569
11877
|
return kind;
|
|
@@ -11591,30 +11899,44 @@ var mParticle = (function () {
|
|
|
11591
11899
|
}
|
|
11592
11900
|
|
|
11593
11901
|
// State lives on `window`, like APV, so a re-executed bundle never doubles the
|
|
11594
|
-
// listeners. Inspect `window.
|
|
11595
|
-
var
|
|
11902
|
+
// listeners. Inspect `window.__mpBtn__` in a console to see if one is live.
|
|
11903
|
+
var WIN_BTN_KEY = '__mpBtn__';
|
|
11596
11904
|
var THROTTLE_MS = 2000;
|
|
11597
11905
|
var SUBMIT_AFTER_COMMIT_CLICK_MS = 1000;
|
|
11598
11906
|
var PATH_LIMIT = 12;
|
|
11599
|
-
|
|
11907
|
+
// A ceiling, not a dedupe: a held Enter key or browser automation fires a
|
|
11908
|
+
// trusted click per repeat, and each one is forwarded to every kit.
|
|
11909
|
+
var PAGE_EVENT_LIMIT = 100;
|
|
11910
|
+
var btnWindow = function btnWindow() {
|
|
11600
11911
|
return typeof window === 'undefined' ? null : window;
|
|
11601
11912
|
};
|
|
11602
|
-
var
|
|
11603
|
-
var win =
|
|
11604
|
-
var state = win ? win[
|
|
11913
|
+
var getActiveButtonTracker = function getActiveButtonTracker() {
|
|
11914
|
+
var win = btnWindow();
|
|
11915
|
+
var state = win ? win[WIN_BTN_KEY] : undefined;
|
|
11605
11916
|
return state ? state.tracker : undefined;
|
|
11606
11917
|
};
|
|
11607
11918
|
// Stops whichever tracker is active, including one from an earlier bundle load.
|
|
11608
|
-
var
|
|
11609
|
-
var win =
|
|
11919
|
+
var resetButtonTracking = function resetButtonTracking() {
|
|
11920
|
+
var win = btnWindow();
|
|
11610
11921
|
if (!win) {
|
|
11611
11922
|
return;
|
|
11612
11923
|
}
|
|
11613
|
-
var active =
|
|
11924
|
+
var active = getActiveButtonTracker();
|
|
11614
11925
|
if (active) {
|
|
11615
11926
|
active.teardown();
|
|
11616
11927
|
}
|
|
11617
|
-
win[
|
|
11928
|
+
win[WIN_BTN_KEY] = {};
|
|
11929
|
+
};
|
|
11930
|
+
// Runs once the browser has painted the page's response to the interaction, so
|
|
11931
|
+
// describing and logging a click never delays that paint.
|
|
11932
|
+
var afterNextPaint = function afterNextPaint(fn) {
|
|
11933
|
+
if (isFunction(window.requestAnimationFrame) && document.visibilityState !== 'hidden') {
|
|
11934
|
+
requestAnimationFrame(function () {
|
|
11935
|
+
setTimeout(fn, 0);
|
|
11936
|
+
});
|
|
11937
|
+
} else {
|
|
11938
|
+
setTimeout(fn, 0);
|
|
11939
|
+
}
|
|
11618
11940
|
};
|
|
11619
11941
|
var CAPTURE_PASSIVE = {
|
|
11620
11942
|
capture: true,
|
|
@@ -11623,16 +11945,37 @@ var mParticle = (function () {
|
|
|
11623
11945
|
var PASSIVE = {
|
|
11624
11946
|
passive: true
|
|
11625
11947
|
};
|
|
11626
|
-
//
|
|
11627
|
-
// frozen {kind, t}
|
|
11628
|
-
var
|
|
11629
|
-
function
|
|
11948
|
+
// Logs every button click as an mParticle event, and hands checkout intent to the
|
|
11949
|
+
// Rokt kit as a frozen {kind, t}. Submits and wallet frame focus feed the kit only.
|
|
11950
|
+
var ButtonTracker = /** @class */function () {
|
|
11951
|
+
function ButtonTracker(mpInstance) {
|
|
11630
11952
|
var _this = this;
|
|
11631
11953
|
this.active = false;
|
|
11954
|
+
this.hasRoktKit = false;
|
|
11632
11955
|
// Bumped on reset so classification queued before it is dropped.
|
|
11633
11956
|
this.generation = 0;
|
|
11634
11957
|
this.lastCommitClick = -Infinity;
|
|
11635
11958
|
this.lastSent = {};
|
|
11959
|
+
this.pagePath = null;
|
|
11960
|
+
this.pageEvents = 0;
|
|
11961
|
+
// Clicks read at dispatch and waiting for the next paint.
|
|
11962
|
+
this.pending = [];
|
|
11963
|
+
this.drain = function () {
|
|
11964
|
+
var queue = _this.pending;
|
|
11965
|
+
_this.pending = [];
|
|
11966
|
+
queue.forEach(function (delivery) {
|
|
11967
|
+
return delivery();
|
|
11968
|
+
});
|
|
11969
|
+
};
|
|
11970
|
+
// A click that navigates away can unload the page before the next paint, so
|
|
11971
|
+
// anything waiting is delivered as the page is hidden or left. The capture
|
|
11972
|
+
// listeners run before the SDK's own upload on the same events, including
|
|
11973
|
+
// beforeunload, the first of them.
|
|
11974
|
+
this.onHide = function (event) {
|
|
11975
|
+
if (event.type === 'beforeunload' || event.type === 'pagehide' || document.visibilityState === 'hidden') {
|
|
11976
|
+
_this.drain();
|
|
11977
|
+
}
|
|
11978
|
+
};
|
|
11636
11979
|
this.onPageShow = function (event) {
|
|
11637
11980
|
// A page restored from the back-forward cache starts fresh.
|
|
11638
11981
|
if (event.persisted) {
|
|
@@ -11648,48 +11991,55 @@ var mParticle = (function () {
|
|
|
11648
11991
|
};
|
|
11649
11992
|
this.mpInstance = mpInstance;
|
|
11650
11993
|
}
|
|
11651
|
-
Object.defineProperty(
|
|
11994
|
+
Object.defineProperty(ButtonTracker.prototype, "isActive", {
|
|
11652
11995
|
get: function get() {
|
|
11653
11996
|
return this.active;
|
|
11654
11997
|
},
|
|
11655
11998
|
enumerable: false,
|
|
11656
11999
|
configurable: true
|
|
11657
12000
|
});
|
|
11658
|
-
|
|
11659
|
-
var win =
|
|
12001
|
+
ButtonTracker.prototype.init = function (options) {
|
|
12002
|
+
var win = btnWindow();
|
|
11660
12003
|
if (!win) {
|
|
11661
12004
|
return;
|
|
11662
12005
|
}
|
|
11663
|
-
var previous =
|
|
12006
|
+
var previous = getActiveButtonTracker();
|
|
11664
12007
|
if (previous) {
|
|
11665
12008
|
previous.teardown();
|
|
11666
12009
|
}
|
|
11667
12010
|
if (this.active) {
|
|
11668
12011
|
this.teardown();
|
|
11669
12012
|
}
|
|
11670
|
-
|
|
11671
|
-
|
|
12013
|
+
this.hasRoktKit = options.hasRoktKit;
|
|
12014
|
+
if (!this.eventsEnabled() && this.isKitSuppressed()) {
|
|
12015
|
+
this.log('opted out, not starting');
|
|
11672
12016
|
return;
|
|
11673
12017
|
}
|
|
11674
12018
|
win.document.addEventListener('click', this.onEvent, CAPTURE_PASSIVE);
|
|
11675
12019
|
win.document.addEventListener('submit', this.onEvent, CAPTURE_PASSIVE);
|
|
11676
12020
|
win.addEventListener('blur', this.onEvent, PASSIVE);
|
|
11677
12021
|
win.addEventListener('pageshow', this.onPageShow, PASSIVE);
|
|
12022
|
+
win.addEventListener('beforeunload', this.onHide, CAPTURE_PASSIVE);
|
|
12023
|
+
win.addEventListener('pagehide', this.onHide, CAPTURE_PASSIVE);
|
|
12024
|
+
win.document.addEventListener('visibilitychange', this.onHide, CAPTURE_PASSIVE);
|
|
11678
12025
|
this.active = true;
|
|
11679
|
-
if (!win[
|
|
11680
|
-
win[
|
|
12026
|
+
if (!win[WIN_BTN_KEY]) {
|
|
12027
|
+
win[WIN_BTN_KEY] = {};
|
|
11681
12028
|
}
|
|
11682
|
-
win[
|
|
12029
|
+
win[WIN_BTN_KEY].tracker = this;
|
|
11683
12030
|
this.log('listening');
|
|
11684
12031
|
};
|
|
11685
|
-
|
|
11686
|
-
var win =
|
|
12032
|
+
ButtonTracker.prototype.teardown = function () {
|
|
12033
|
+
var win = btnWindow();
|
|
11687
12034
|
if (win) {
|
|
11688
12035
|
win.document.removeEventListener('click', this.onEvent, true);
|
|
11689
12036
|
win.document.removeEventListener('submit', this.onEvent, true);
|
|
11690
12037
|
win.removeEventListener('blur', this.onEvent);
|
|
11691
12038
|
win.removeEventListener('pageshow', this.onPageShow);
|
|
11692
|
-
|
|
12039
|
+
win.removeEventListener('beforeunload', this.onHide, true);
|
|
12040
|
+
win.removeEventListener('pagehide', this.onHide, true);
|
|
12041
|
+
win.document.removeEventListener('visibilitychange', this.onHide, true);
|
|
12042
|
+
var state = win[WIN_BTN_KEY];
|
|
11693
12043
|
if (state && state.tracker === this) {
|
|
11694
12044
|
state.tracker = undefined;
|
|
11695
12045
|
}
|
|
@@ -11700,64 +12050,110 @@ var mParticle = (function () {
|
|
|
11700
12050
|
};
|
|
11701
12051
|
// Drops queued classification, commit timing and buffered signals, so
|
|
11702
12052
|
// nothing captured before an opt-out is delivered after an opt-in.
|
|
11703
|
-
|
|
12053
|
+
ButtonTracker.prototype.clearPending = function () {
|
|
11704
12054
|
this.reset();
|
|
11705
12055
|
var roktManager = this.mpInstance._RoktManager;
|
|
11706
12056
|
if (roktManager) {
|
|
11707
12057
|
roktManager.discardCheckoutIntents();
|
|
11708
12058
|
}
|
|
11709
12059
|
};
|
|
11710
|
-
|
|
12060
|
+
ButtonTracker.prototype.reset = function () {
|
|
11711
12061
|
this.generation++;
|
|
12062
|
+
this.pending = [];
|
|
11712
12063
|
this.lastCommitClick = -Infinity;
|
|
11713
12064
|
this.lastSent = {};
|
|
12065
|
+
this.pagePath = null;
|
|
12066
|
+
this.pageEvents = 0;
|
|
12067
|
+
};
|
|
12068
|
+
ButtonTracker.prototype.enqueue = function (delivery) {
|
|
12069
|
+
this.pending.push(delivery);
|
|
12070
|
+
if (this.pending.length === 1) {
|
|
12071
|
+
afterNextPaint(this.drain);
|
|
12072
|
+
}
|
|
11714
12073
|
};
|
|
11715
|
-
|
|
12074
|
+
ButtonTracker.prototype.observe = function (event) {
|
|
11716
12075
|
var _this = this;
|
|
11717
|
-
if (!this.active || !event.isTrusted
|
|
12076
|
+
if (!this.active || !event.isTrusted) {
|
|
12077
|
+
return;
|
|
12078
|
+
}
|
|
12079
|
+
var layer = event.type;
|
|
12080
|
+
var logsEvents = layer === 'click' && this.eventsEnabled();
|
|
12081
|
+
var signalsKit = !this.isKitSuppressed();
|
|
12082
|
+
if (!logsEvents && !signalsKit) {
|
|
11718
12083
|
return;
|
|
11719
12084
|
}
|
|
11720
12085
|
var t = Date.now();
|
|
11721
12086
|
var pathname = window.location.pathname;
|
|
11722
|
-
|
|
11723
|
-
//
|
|
11724
|
-
|
|
11725
|
-
|
|
11726
|
-
|
|
11727
|
-
|
|
11728
|
-
|
|
11729
|
-
|
|
11730
|
-
//
|
|
11731
|
-
|
|
11732
|
-
|
|
11733
|
-
|
|
12087
|
+
// The button is read now, while the click is still being dispatched:
|
|
12088
|
+
// this capture listener runs before the page's own handlers, so a
|
|
12089
|
+
// button that disables or relabels itself is seen as it was clicked.
|
|
12090
|
+
// Logging and the kit hand-off wait for the next paint.
|
|
12091
|
+
var click;
|
|
12092
|
+
var kind;
|
|
12093
|
+
var unconfirmedCommit = false;
|
|
12094
|
+
if (layer === 'click') {
|
|
12095
|
+
// The composed path is only populated during dispatch.
|
|
12096
|
+
var control = findControl(isFunction(event.composedPath) ? event.composedPath().slice(0, PATH_LIMIT) : []);
|
|
12097
|
+
if (control) {
|
|
12098
|
+
click = logsEvents ? describeButtonClick(control) : undefined;
|
|
12099
|
+
// Checkout intent is only worked out when the kit can use it.
|
|
12100
|
+
kind = signalsKit ? classifyIntentControl(control, pathname) : undefined;
|
|
12101
|
+
}
|
|
12102
|
+
} else if (layer === 'submit') {
|
|
12103
|
+
var submitter = event.submitter;
|
|
12104
|
+
var control = submitter ? findControl([submitter]) : undefined;
|
|
12105
|
+
// A form submitted without a submitter only counts right after a
|
|
12106
|
+
// commit click, which is known once that click is delivered.
|
|
12107
|
+
if (!submitter) {
|
|
12108
|
+
kind = 'commit';
|
|
12109
|
+
} else if (control) {
|
|
12110
|
+
kind = classifyIntentControl(control, pathname);
|
|
12111
|
+
}
|
|
12112
|
+
unconfirmedCommit = !submitter;
|
|
11734
12113
|
}
|
|
11735
12114
|
var generation = this.generation;
|
|
11736
|
-
|
|
12115
|
+
this.enqueue(function () {
|
|
11737
12116
|
if (generation !== _this.generation) {
|
|
11738
12117
|
return;
|
|
11739
12118
|
}
|
|
11740
12119
|
try {
|
|
11741
|
-
var kind = void 0;
|
|
11742
12120
|
if (layer === 'blur') {
|
|
12121
|
+
// Read after the blur settles: some browsers have not moved
|
|
12122
|
+
// focus into the frame yet when the window blurs.
|
|
11743
12123
|
kind = classifyIntentFrame(document.activeElement, window);
|
|
11744
|
-
} else if (
|
|
11745
|
-
|
|
11746
|
-
|
|
11747
|
-
|
|
11748
|
-
|
|
11749
|
-
kind = classifyIntentControl(layer === 'submit' ? [target] : path, pathname);
|
|
12124
|
+
} else if (unconfirmedCommit && t - _this.lastCommitClick > SUBMIT_AFTER_COMMIT_CLICK_MS) {
|
|
12125
|
+
kind = undefined;
|
|
12126
|
+
}
|
|
12127
|
+
if (click && logsEvents) {
|
|
12128
|
+
_this.logClick(click, pathname);
|
|
11750
12129
|
}
|
|
11751
12130
|
if (kind) {
|
|
11752
12131
|
_this.emit(kind, layer, t, pathname);
|
|
11753
12132
|
}
|
|
11754
12133
|
} catch (e) {
|
|
11755
|
-
_this.log('[error]
|
|
12134
|
+
_this.log('[error] delivery threw: ' + e);
|
|
11756
12135
|
}
|
|
11757
|
-
}
|
|
12136
|
+
});
|
|
12137
|
+
};
|
|
12138
|
+
// Every real click is one event, repeats included, up to a ceiling per page.
|
|
12139
|
+
ButtonTracker.prototype.logClick = function (click, pathname) {
|
|
12140
|
+
if (!this.eventsEnabled()) {
|
|
12141
|
+
return;
|
|
12142
|
+
}
|
|
12143
|
+
if (pathname !== this.pagePath) {
|
|
12144
|
+
this.pagePath = pathname;
|
|
12145
|
+
this.pageEvents = 0;
|
|
12146
|
+
}
|
|
12147
|
+
if (this.pageEvents >= PAGE_EVENT_LIMIT) {
|
|
12148
|
+
return;
|
|
12149
|
+
}
|
|
12150
|
+
this.pageEvents++;
|
|
12151
|
+
// Restarts an expired session, as public logEvent() and page views do.
|
|
12152
|
+
this.mpInstance._SessionManager.resetSessionTimer();
|
|
12153
|
+
this.mpInstance._Events.logEvent(buildButtonClickEvent(click, pathname));
|
|
11758
12154
|
};
|
|
11759
|
-
|
|
11760
|
-
if (this.
|
|
12155
|
+
ButtonTracker.prototype.emit = function (kind, layer, t, pathname) {
|
|
12156
|
+
if (this.isKitSuppressed()) {
|
|
11761
12157
|
return;
|
|
11762
12158
|
}
|
|
11763
12159
|
if (kind === 'commit' && layer === 'click') {
|
|
@@ -11776,16 +12172,21 @@ var mParticle = (function () {
|
|
|
11776
12172
|
t: t
|
|
11777
12173
|
}), pathname);
|
|
11778
12174
|
};
|
|
11779
|
-
//
|
|
11780
|
-
|
|
11781
|
-
|
|
12175
|
+
// Events follow the SDK's opt-out like any other event.
|
|
12176
|
+
ButtonTracker.prototype.eventsEnabled = function () {
|
|
12177
|
+
var store = this.mpInstance._Store;
|
|
12178
|
+
return !!store && store.isEnabled;
|
|
12179
|
+
};
|
|
12180
|
+
// The Rokt manager owns the kit's privacy gates: flag, opt-out, launcher
|
|
12181
|
+
// options and Global Privacy Control.
|
|
12182
|
+
ButtonTracker.prototype.isKitSuppressed = function () {
|
|
11782
12183
|
var roktManager = this.mpInstance._RoktManager;
|
|
11783
|
-
return !roktManager || roktManager.isCheckoutIntentSuppressed();
|
|
12184
|
+
return !this.hasRoktKit || !roktManager || roktManager.isCheckoutIntentSuppressed();
|
|
11784
12185
|
};
|
|
11785
|
-
|
|
11786
|
-
this.mpInstance.Logger.verbose('mParticle
|
|
12186
|
+
ButtonTracker.prototype.log = function (message) {
|
|
12187
|
+
this.mpInstance.Logger.verbose('mParticle button tracking: ' + message);
|
|
11787
12188
|
};
|
|
11788
|
-
return
|
|
12189
|
+
return ButtonTracker;
|
|
11789
12190
|
}();
|
|
11790
12191
|
|
|
11791
12192
|
var Messages = Constants.Messages,
|
|
@@ -11921,10 +12322,10 @@ var mParticle = (function () {
|
|
|
11921
12322
|
this.reset = function (instance) {
|
|
11922
12323
|
try {
|
|
11923
12324
|
instance._Persistence.resetPersistence();
|
|
11924
|
-
// The Rokt manager keeps its own store reference, so stop
|
|
11925
|
-
//
|
|
11926
|
-
|
|
11927
|
-
instance.
|
|
12325
|
+
// The Rokt manager keeps its own store reference, so stop button
|
|
12326
|
+
// tracking here rather than relying on the deleted store.
|
|
12327
|
+
resetButtonTracking();
|
|
12328
|
+
instance._ButtonTracker = undefined;
|
|
11928
12329
|
if (instance._Store) {
|
|
11929
12330
|
delete instance._Store;
|
|
11930
12331
|
}
|
|
@@ -11946,8 +12347,8 @@ var mParticle = (function () {
|
|
|
11946
12347
|
instance._Events.stopTracking();
|
|
11947
12348
|
resetPageViewTracking();
|
|
11948
12349
|
instance._PageViewTracker = undefined;
|
|
11949
|
-
|
|
11950
|
-
instance.
|
|
12350
|
+
resetButtonTracking();
|
|
12351
|
+
instance._ButtonTracker = undefined;
|
|
11951
12352
|
if (!keepPersistence) {
|
|
11952
12353
|
instance._Persistence.resetPersistence();
|
|
11953
12354
|
}
|
|
@@ -12547,8 +12948,8 @@ var mParticle = (function () {
|
|
|
12547
12948
|
self._SessionManager.resetSessionTimer();
|
|
12548
12949
|
self._Store.isEnabled = !isOptingOut;
|
|
12549
12950
|
if (isOptingOut) {
|
|
12550
|
-
if (self.
|
|
12551
|
-
self.
|
|
12951
|
+
if (self._ButtonTracker) {
|
|
12952
|
+
self._ButtonTracker.clearPending();
|
|
12552
12953
|
}
|
|
12553
12954
|
self._RoktManager.discardCheckoutIntents();
|
|
12554
12955
|
}
|
|
@@ -12720,7 +13121,7 @@ var mParticle = (function () {
|
|
|
12720
13121
|
var getFeatureFlag = mpInstance._Helpers.getFeatureFlag;
|
|
12721
13122
|
var _e = Constants.FeatureFlags,
|
|
12722
13123
|
AutoLogPageView = _e.AutoLogPageView,
|
|
12723
|
-
|
|
13124
|
+
AutoButtonTracking = _e.AutoButtonTracking;
|
|
12724
13125
|
// Destroy previous batch uploader to prevent leaked timers and event listeners
|
|
12725
13126
|
if ((_a = mpInstance._APIClient) === null || _a === void 0 ? void 0 : _a.uploader) {
|
|
12726
13127
|
mpInstance._APIClient.uploader.destroy();
|
|
@@ -12736,8 +13137,8 @@ var mParticle = (function () {
|
|
|
12736
13137
|
// persistence or Identity directly.
|
|
12737
13138
|
if (mpInstance._Store.webviewBridgeEnabled) {
|
|
12738
13139
|
mpInstance._NativeSdkHelpers.initializeSessionAttributes(apiKey);
|
|
12739
|
-
//
|
|
12740
|
-
|
|
13140
|
+
// Button tracking never runs as a native passthrough.
|
|
13141
|
+
resetButtonTracking();
|
|
12741
13142
|
} else {
|
|
12742
13143
|
// Main SDK initialization flow
|
|
12743
13144
|
// Load any settings/identities/attributes from cookie or localStorage
|
|
@@ -12817,17 +13218,19 @@ var mParticle = (function () {
|
|
|
12817
13218
|
// so it stops listening. Re-created if the flag is re-enabled later.
|
|
12818
13219
|
mpInstance._PageViewTracker.teardown();
|
|
12819
13220
|
}
|
|
12820
|
-
//
|
|
12821
|
-
//
|
|
12822
|
-
if (getFeatureFlag(
|
|
12823
|
-
if (!mpInstance.
|
|
12824
|
-
mpInstance.
|
|
13221
|
+
// Button clicks are logged for any workspace that opts in. Checkout
|
|
13222
|
+
// intent also goes to the Rokt kit when this init configures one.
|
|
13223
|
+
if (getFeatureFlag(AutoButtonTracking)) {
|
|
13224
|
+
if (!mpInstance._ButtonTracker) {
|
|
13225
|
+
mpInstance._ButtonTracker = new ButtonTracker(mpInstance);
|
|
12825
13226
|
}
|
|
12826
|
-
mpInstance.
|
|
13227
|
+
mpInstance._ButtonTracker.init({
|
|
13228
|
+
hasRoktKit: !!roktConfig
|
|
13229
|
+
});
|
|
12827
13230
|
} else {
|
|
12828
13231
|
// Also retires a tracker left by an earlier bundle load. Like APV,
|
|
12829
13232
|
// this assumes a single active SDK instance.
|
|
12830
|
-
|
|
13233
|
+
resetButtonTracking();
|
|
12831
13234
|
}
|
|
12832
13235
|
processIdentityCallback(mpInstance, currentUser, currentUserMPID, currentUserIdentities);
|
|
12833
13236
|
}
|
|
@@ -12922,8 +13325,8 @@ var mParticle = (function () {
|
|
|
12922
13325
|
mpInstance._LoggingDispatcher.logger = mpInstance.Logger;
|
|
12923
13326
|
mpInstance._Store = new Store(config, mpInstance, apiKey);
|
|
12924
13327
|
window.mParticle.Store = mpInstance._Store;
|
|
12925
|
-
//
|
|
12926
|
-
|
|
13328
|
+
// Button tracking stops until this init's config decides whether it runs.
|
|
13329
|
+
resetButtonTracking();
|
|
12927
13330
|
mpInstance.Logger.verbose(StartingInitialization);
|
|
12928
13331
|
// Initialize CookieConsentManager with privacy flags from launcherOptions
|
|
12929
13332
|
var _a = normalizeRoktLauncherOptions(config === null || config === void 0 ? void 0 : config.launcherOptions),
|