@mparticle/web-sdk 3.23.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.common.js +1 -1688
- package/dist/mparticle.esm.js +1 -1688
- package/dist/mparticle.js +1015 -253
- package/dist/types/src/buttonTracking/buttonClickEvent.d.ts +7 -0
- package/dist/types/src/buttonTracking/buttonDescription.d.ts +10 -3
- package/dist/types/src/buttonTracking/buttonTracker.d.ts +8 -0
- package/dist/types/src/buttonTracking/checkoutIntent.d.ts +8 -3
- package/dist/types/src/buttonTracking/controls.d.ts +8 -4
- package/dist/types/src/buttonTracking/labelMasking.d.ts +1 -0
- package/dist/types/src/configAPIClient.d.ts +1 -0
- package/dist/types/src/constants.d.ts +1 -0
- package/dist/types/src/cookieConsentManager.d.ts +17 -3
- package/dist/types/src/forwarder-utils.d.ts +3 -0
- package/dist/types/src/pageViewTracker.d.ts +19 -3
- package/dist/types/src/roktLauncherOptions.d.ts +1 -0
- package/dist/types/src/roktManager.d.ts +13 -2
- package/dist/types/src/sdkRuntimeModels.d.ts +1 -0
- package/dist/types/src/store.d.ts +3 -0
- package/package.json +21 -14
- package/src/buttonTracking/buttonClickEvent.ts +126 -8
- package/src/buttonTracking/buttonDescription.ts +336 -53
- package/src/buttonTracking/buttonTracker.ts +231 -19
- package/src/buttonTracking/checkoutIntent.ts +117 -23
- package/src/buttonTracking/controls.ts +169 -55
- package/src/buttonTracking/labelMasking.ts +4 -1
- package/src/configAPIClient.ts +1 -0
- package/src/constants.ts +1 -0
- package/src/cookieConsentManager.ts +23 -3
- package/src/cookieSyncManager.ts +11 -3
- package/src/events.ts +9 -3
- package/src/forwarder-utils.ts +38 -0
- package/src/forwarders.ts +2 -28
- package/src/mp-instance.ts +41 -7
- package/src/pageUrl.ts +43 -2
- package/src/pageViewTracker.ts +193 -111
- package/src/roktLauncherOptions.ts +1 -0
- package/src/roktManager.ts +66 -11
- package/src/sdkRuntimeModels.ts +1 -0
- package/src/store.ts +17 -0
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.25.0";
|
|
208
208
|
|
|
209
209
|
var Constants = {
|
|
210
210
|
sdkVersion: version,
|
|
@@ -315,7 +315,6 @@ var mParticle = (function () {
|
|
|
315
315
|
aliasMaxWindow: 90,
|
|
316
316
|
uploadInterval: 0 // Maximum milliseconds in between batch uploads, below 500 will mean immediate upload. The server returns this as a string, but we are using it as a number internally
|
|
317
317
|
},
|
|
318
|
-
|
|
319
318
|
DefaultBaseUrls: {
|
|
320
319
|
v1SecureServiceUrl: 'jssdks.mparticle.com/v1/JS/',
|
|
321
320
|
v2SecureServiceUrl: 'jssdks.mparticle.com/v2/JS/',
|
|
@@ -380,7 +379,8 @@ var mParticle = (function () {
|
|
|
380
379
|
CaptureIntegrationSpecificIdsV2: 'captureIntegrationSpecificIds.V2',
|
|
381
380
|
AstBackgroundEvents: 'astBackgroundEvents',
|
|
382
381
|
AutoLogPageView: 'autoLogPageView',
|
|
383
|
-
AutoButtonTracking: 'autoButtonTracking'
|
|
382
|
+
AutoButtonTracking: 'autoButtonTracking',
|
|
383
|
+
AutoLinkTracking: 'autoLinkTracking'
|
|
384
384
|
},
|
|
385
385
|
DefaultInstance: 'default_instance',
|
|
386
386
|
CCPAPurpose: 'data_sale_opt_out',
|
|
@@ -601,14 +601,13 @@ var mParticle = (function () {
|
|
|
601
601
|
// @ts-ignore
|
|
602
602
|
randomValue = window.crypto.getRandomValues(new Uint8Array(1)); // eslint-disable-line no-undef
|
|
603
603
|
}
|
|
604
|
-
|
|
605
604
|
if (randomValue) {
|
|
606
605
|
// @ts-ignore
|
|
607
606
|
return (a ^ randomValue[0] % 16 >> a / 4).toString(16);
|
|
608
607
|
}
|
|
609
608
|
return (a ^ Math.random() * 16 >> a / 4).toString(16);
|
|
610
609
|
};
|
|
611
|
-
var
|
|
610
|
+
var _generateUniqueId = function generateUniqueId(a) {
|
|
612
611
|
// https://gist.github.com/jed/982883
|
|
613
612
|
// Added support for crypto for better random
|
|
614
613
|
if (a === void 0) {
|
|
@@ -624,7 +623,7 @@ var mParticle = (function () {
|
|
|
624
623
|
// -1e11 -> //-100000000000,
|
|
625
624
|
"".concat(1e7, "-").concat(1e3, "-").concat(4e3, "-").concat(8e3, "-").concat(1e11).replace(/[018]/g,
|
|
626
625
|
// zeroes, ones, and eights with
|
|
627
|
-
|
|
626
|
+
_generateUniqueId // random hex digits
|
|
628
627
|
);
|
|
629
628
|
};
|
|
630
629
|
/**
|
|
@@ -930,7 +929,7 @@ var mParticle = (function () {
|
|
|
930
929
|
* obfuscateData({ tags: ['premium', 'verified'] })
|
|
931
930
|
* // Returns: { tags: ['string', 'string'] }
|
|
932
931
|
*/
|
|
933
|
-
var
|
|
932
|
+
var _obfuscateData = function obfuscateData(value) {
|
|
934
933
|
// Preserve null and undefined
|
|
935
934
|
if (value === null || value === undefined) {
|
|
936
935
|
return value;
|
|
@@ -938,7 +937,7 @@ var mParticle = (function () {
|
|
|
938
937
|
// Handle arrays - recursively obfuscate each element
|
|
939
938
|
if (Array.isArray(value)) {
|
|
940
939
|
return value.map(function (item) {
|
|
941
|
-
return
|
|
940
|
+
return _obfuscateData(item);
|
|
942
941
|
});
|
|
943
942
|
}
|
|
944
943
|
// Handle objects - recursively obfuscate each property
|
|
@@ -946,7 +945,7 @@ var mParticle = (function () {
|
|
|
946
945
|
var obfuscated = {};
|
|
947
946
|
for (var key in value) {
|
|
948
947
|
if (value.hasOwnProperty(key)) {
|
|
949
|
-
obfuscated[key] =
|
|
948
|
+
obfuscated[key] = _obfuscateData(value[key]);
|
|
950
949
|
}
|
|
951
950
|
}
|
|
952
951
|
return obfuscated;
|
|
@@ -970,7 +969,7 @@ var mParticle = (function () {
|
|
|
970
969
|
* // Returns: { email: 'string' }
|
|
971
970
|
*/
|
|
972
971
|
var obfuscateDevData = function obfuscateDevData(data, isDevelopmentMode) {
|
|
973
|
-
return isDevelopmentMode ? data :
|
|
972
|
+
return isDevelopmentMode ? data : _obfuscateData(data);
|
|
974
973
|
};
|
|
975
974
|
// Standalone version of jQuery.extend, from https://github.com/dansdom/extend
|
|
976
975
|
// https://go.mparticle.com/work/SQDSDKS-6047
|
|
@@ -2183,7 +2182,7 @@ var mParticle = (function () {
|
|
|
2183
2182
|
application_info: {
|
|
2184
2183
|
application_version: lastEvent.AppVersion,
|
|
2185
2184
|
application_name: lastEvent.AppName,
|
|
2186
|
-
|
|
2185
|
+
package: lastEvent.Package,
|
|
2187
2186
|
sideloaded_kits_count: mpInstance._Store.sideloadedKitsCount
|
|
2188
2187
|
},
|
|
2189
2188
|
device_info: {
|
|
@@ -2523,7 +2522,6 @@ var mParticle = (function () {
|
|
|
2523
2522
|
//note: External Events DTO does not support the session mpids array as of this time.
|
|
2524
2523
|
//spanning_mpids: sdkEvent.SessionMpids
|
|
2525
2524
|
};
|
|
2526
|
-
|
|
2527
2525
|
sessionEndEventData = Object.assign(sessionEndEventData, commonEventData);
|
|
2528
2526
|
return {
|
|
2529
2527
|
event_type: dist.EventTypeEnum.sessionEnd,
|
|
@@ -2652,7 +2650,7 @@ var mParticle = (function () {
|
|
|
2652
2650
|
var commonEventData = convertBaseEventData(sdkEvent);
|
|
2653
2651
|
var userAttributeChangeEvent = {
|
|
2654
2652
|
user_attribute_name: sdkEvent.UserAttributeChanges.UserAttributeName,
|
|
2655
|
-
|
|
2653
|
+
new: sdkEvent.UserAttributeChanges.New,
|
|
2656
2654
|
old: sdkEvent.UserAttributeChanges.Old,
|
|
2657
2655
|
deleted: sdkEvent.UserAttributeChanges.Deleted,
|
|
2658
2656
|
is_new_attribute: sdkEvent.UserAttributeChanges.IsNewAttribute
|
|
@@ -2666,7 +2664,7 @@ var mParticle = (function () {
|
|
|
2666
2664
|
function convertUserIdentityChangeEvent(sdkEvent) {
|
|
2667
2665
|
var commonEventData = convertBaseEventData(sdkEvent);
|
|
2668
2666
|
var userIdentityChangeEvent = {
|
|
2669
|
-
|
|
2667
|
+
new: {
|
|
2670
2668
|
identity_type: convertUserIdentityTypeToServerIdentityType(sdkEvent.UserIdentityChanges.New.IdentityType),
|
|
2671
2669
|
identity: sdkEvent.UserIdentityChanges.New.Identity || null,
|
|
2672
2670
|
timestamp_unixtime_ms: sdkEvent.Timestamp,
|
|
@@ -2886,23 +2884,9 @@ var mParticle = (function () {
|
|
|
2886
2884
|
// Nothing has to be deleted, and there is no ordering in which half the state
|
|
2887
2885
|
// survives the reset.
|
|
2888
2886
|
var WIN_APV_KEY = '__mpApv__';
|
|
2889
|
-
//
|
|
2890
|
-
//
|
|
2891
|
-
// none of those should reach the event stream because someone forgot to exclude
|
|
2892
|
-
// them. Anything absent from this list is dropped.
|
|
2893
|
-
//
|
|
2894
|
-
// SECURITY: `code`, `state` and `nonce` are the OAuth 2.0 / OIDC authorization
|
|
2895
|
-
// code and the CSRF/replay tokens. They are credentials until redeemed, and
|
|
2896
|
-
// attaching them here persists them in the event store and forwards them to
|
|
2897
|
-
// every configured kit. They are on the list by explicit product decision \u2014
|
|
2898
|
-
// deleting that line is the whole of the fix if that decision is revisited.
|
|
2887
|
+
// Parameters that identify which page a view is of. Authorization-flow and campaign
|
|
2888
|
+
// attribution parameters are deliberately absent; an input can add them explicitly.
|
|
2899
2889
|
var ALLOWED_QUERY_PARAMS = [
|
|
2900
|
-
// Campaign attribution
|
|
2901
|
-
'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_id', 'utm_source_platform', 'utm_creative_format', 'utm_marketing_tactic', 'gad_source', 'gad_campaignid', 'mc_cid',
|
|
2902
|
-
// Ad-network click ids
|
|
2903
|
-
'gclid', 'gbraid', 'wbraid', 'fbclid', 'msclkid', 'ttclid', 'twclid', 'li_fat_id', 'dclid', 'srsltid', 'epik', 'ScCid', 'irclickid', 'rtid', 'rclid',
|
|
2904
|
-
// OAuth / OIDC \u2014 see the SECURITY note above
|
|
2905
|
-
'client_id', 'redirect_uri', 'response_type', 'scope', 'state', 'code', 'nonce',
|
|
2906
2890
|
// Pagination
|
|
2907
2891
|
'page', 'limit', 'offset', 'cursor', 'per_page',
|
|
2908
2892
|
// Site search term, as the common platforms spell it. Matching is
|
|
@@ -2916,6 +2900,22 @@ var mParticle = (function () {
|
|
|
2916
2900
|
'category',
|
|
2917
2901
|
// Referral
|
|
2918
2902
|
'ref', 'referrer'];
|
|
2903
|
+
var AUTO_PAGE_VIEW_ATTRIBUTE = 'is_auto_page_view';
|
|
2904
|
+
var CORE_EVENT_FIELDS = ['hostname', 'title', 'path', AUTO_PAGE_VIEW_ATTRIBUTE];
|
|
2905
|
+
var PROTOTYPE_MEMBER_NAMES = ['constructor', '__proto__', 'prototype'];
|
|
2906
|
+
// Server flag values are the strings 'True' and 'False', so these get typed here by habit.
|
|
2907
|
+
var FLAG_VALUE_NAMES = ['true', 'false'];
|
|
2908
|
+
var RESERVED_QUERY_PARAMS = CORE_EVENT_FIELDS.concat(PROTOTYPE_MEMBER_NAMES, FLAG_VALUE_NAMES);
|
|
2909
|
+
var BUILT_IN_NAMES = ALLOWED_QUERY_PARAMS.map(function (name) {
|
|
2910
|
+
return name.toLowerCase();
|
|
2911
|
+
});
|
|
2912
|
+
var isBuiltIn = function isBuiltIn(name) {
|
|
2913
|
+
return BUILT_IN_NAMES.indexOf(name.toLowerCase()) !== -1;
|
|
2914
|
+
};
|
|
2915
|
+
// Excludes `&`, `=`, `%` and whitespace, which would distort the dedup key.
|
|
2916
|
+
var QUERY_PARAM_NAME = /^[a-z0-9_][a-z0-9_.-]{0,63}$/;
|
|
2917
|
+
var MAX_CUSTOM_QUERY_PARAMS = 25;
|
|
2918
|
+
var MAX_CUSTOM_QUERY_PARAM_VALUE_LENGTH = 512;
|
|
2919
2919
|
// Params matched by name prefix, for platforms that put a per-product id in the
|
|
2920
2920
|
// name. Salesforce Commerce Cloud spells a variant choice
|
|
2921
2921
|
// `dwvar_<productId>_<attribute>`, e.g. `dwvar_12345_color=navy`.
|
|
@@ -2925,34 +2925,113 @@ var mParticle = (function () {
|
|
|
2925
2925
|
return name.indexOf(prefix) === 0;
|
|
2926
2926
|
});
|
|
2927
2927
|
};
|
|
2928
|
-
|
|
2929
|
-
return name.toLowerCase();
|
|
2930
|
-
});
|
|
2931
|
-
// Whether a query param name, in any case, is one an auto page view captures.
|
|
2928
|
+
// Whether a query param name, in any case, is one an auto page view captures by default.
|
|
2932
2929
|
var isAllowedQueryParam = function isAllowedQueryParam(name) {
|
|
2933
|
-
|
|
2934
|
-
return ALLOWED_QUERY_PARAMS_LOWER.indexOf(lower) !== -1 || hasAllowedPrefix(lower);
|
|
2930
|
+
return isBuiltIn(name) || hasAllowedPrefix(name.toLowerCase());
|
|
2935
2931
|
};
|
|
2936
2932
|
// ---------------------------------------------------------------------------
|
|
2937
2933
|
// Pure helpers. No `this`, no globals, no side effects \u2014 callable and assertable
|
|
2938
2934
|
// on their own, which is where the interesting rules live.
|
|
2939
2935
|
// ---------------------------------------------------------------------------
|
|
2940
|
-
//
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2936
|
+
// Validated here as well as in the dashboard, because remote config is untrusted input.
|
|
2937
|
+
var parseQueryParamAllowlist = function parseQueryParamAllowlist(configured) {
|
|
2938
|
+
var allowed = [];
|
|
2939
|
+
var rejectedPositions = [];
|
|
2940
|
+
var overLimit = 0;
|
|
2941
|
+
if (!configured) {
|
|
2942
|
+
return {
|
|
2943
|
+
allowed: allowed,
|
|
2944
|
+
rejectedPositions: rejectedPositions,
|
|
2945
|
+
overLimit: overLimit
|
|
2946
|
+
};
|
|
2947
|
+
}
|
|
2948
|
+
var entries = Array.isArray(configured) ? configured : String(configured).split(',');
|
|
2949
|
+
entries.forEach(function (entry, index) {
|
|
2950
|
+
var position = index + 1;
|
|
2951
|
+
var name = String(entry).trim().toLowerCase();
|
|
2952
|
+
if (!name) {
|
|
2953
|
+
return;
|
|
2954
|
+
}
|
|
2955
|
+
if (!QUERY_PARAM_NAME.test(name) || RESERVED_QUERY_PARAMS.indexOf(name) !== -1) {
|
|
2956
|
+
rejectedPositions.push(position);
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2959
|
+
if (isBuiltIn(name) || allowed.indexOf(name) !== -1) {
|
|
2960
|
+
return;
|
|
2961
|
+
}
|
|
2962
|
+
if (allowed.length >= MAX_CUSTOM_QUERY_PARAMS) {
|
|
2963
|
+
overLimit++;
|
|
2964
|
+
return;
|
|
2965
|
+
}
|
|
2966
|
+
allowed.push(name);
|
|
2967
|
+
});
|
|
2968
|
+
return {
|
|
2969
|
+
allowed: allowed,
|
|
2970
|
+
rejectedPositions: rejectedPositions,
|
|
2971
|
+
overLimit: overLimit
|
|
2972
|
+
};
|
|
2973
|
+
};
|
|
2974
|
+
// Not localeCompare: this order feeds the dedup key, so it must be identical in every
|
|
2975
|
+
// browser, and localeCompare is locale-dependent.
|
|
2976
|
+
var byName = function byName(a, b) {
|
|
2977
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
2978
|
+
};
|
|
2979
|
+
// Built-ins keep their positions and additions sort after them, so a dedup key depends on
|
|
2980
|
+
// which params are configured, not the order they were typed.
|
|
2981
|
+
var effectiveAllowlist = function effectiveAllowlist(extras) {
|
|
2982
|
+
if (extras === void 0) {
|
|
2983
|
+
extras = [];
|
|
2984
|
+
}
|
|
2985
|
+
return ALLOWED_QUERY_PARAMS.concat(extras.filter(function (name) {
|
|
2986
|
+
return !isBuiltIn(name);
|
|
2987
|
+
}).sort(byName));
|
|
2988
|
+
};
|
|
2989
|
+
// Over-long custom values are dropped rather than truncated: two truncated values could
|
|
2990
|
+
// share a dedup key and swallow a real page view.
|
|
2991
|
+
var isWithinValueLimit = function isWithinValueLimit(name, value) {
|
|
2992
|
+
return isBuiltIn(name) || value.length <= MAX_CUSTOM_QUERY_PARAM_VALUE_LENGTH;
|
|
2993
|
+
};
|
|
2994
|
+
// A prefix match is a platform name, not a configured extra, so the custom
|
|
2995
|
+
// value limit does not apply. A name already on the allowlist keeps that
|
|
2996
|
+
// position instead of being appended again.
|
|
2997
|
+
var prefixMatchedParams = function prefixMatchedParams(href, allowlist) {
|
|
2947
2998
|
var allParams = queryStringParser(href);
|
|
2948
|
-
Object.keys(allParams).filter(function (name) {
|
|
2949
|
-
return hasAllowedPrefix(name) && allParams[name];
|
|
2950
|
-
}).
|
|
2951
|
-
|
|
2999
|
+
return Object.keys(allParams).filter(function (name) {
|
|
3000
|
+
return hasAllowedPrefix(name) && allParams[name] && allowlist.indexOf(name) === -1;
|
|
3001
|
+
}).sort(byName).map(function (name) {
|
|
3002
|
+
return {
|
|
3003
|
+
name: name,
|
|
3004
|
+
value: allParams[name]
|
|
3005
|
+
};
|
|
2952
3006
|
});
|
|
2953
|
-
return params;
|
|
2954
3007
|
};
|
|
2955
|
-
var
|
|
3008
|
+
var allowedQueryParams = function allowedQueryParams(href, extras) {
|
|
3009
|
+
if (extras === void 0) {
|
|
3010
|
+
extras = [];
|
|
3011
|
+
}
|
|
3012
|
+
var allowlist = effectiveAllowlist(extras);
|
|
3013
|
+
var found = queryStringParser(href, allowlist);
|
|
3014
|
+
var listed = allowlist.filter(function (name) {
|
|
3015
|
+
return hasOwnProp(found, name);
|
|
3016
|
+
}).filter(function (name) {
|
|
3017
|
+
return isWithinValueLimit(name, found[name]);
|
|
3018
|
+
}).map(function (name) {
|
|
3019
|
+
return {
|
|
3020
|
+
name: name,
|
|
3021
|
+
value: found[name]
|
|
3022
|
+
};
|
|
3023
|
+
});
|
|
3024
|
+
return listed.concat(prefixMatchedParams(href, allowlist));
|
|
3025
|
+
};
|
|
3026
|
+
var paramsToAttributes = function paramsToAttributes(params) {
|
|
3027
|
+
var attributes = {};
|
|
3028
|
+
params.forEach(function (_a) {
|
|
3029
|
+
var name = _a.name,
|
|
3030
|
+
value = _a.value;
|
|
3031
|
+
attributes[name] = value;
|
|
3032
|
+
});
|
|
3033
|
+
return attributes;
|
|
3034
|
+
};
|
|
2956
3035
|
// Absent rather than false on a manual page view, so the attribute is only ever
|
|
2957
3036
|
// added by the automatic emitters. Shared by both of them so the key and that
|
|
2958
3037
|
// rule have one definition instead of two that can drift.
|
|
@@ -2960,33 +3039,13 @@ var mParticle = (function () {
|
|
|
2960
3039
|
var _a;
|
|
2961
3040
|
return isAutoPageView ? (_a = {}, _a[AUTO_PAGE_VIEW_ATTRIBUTE] = true, _a) : {};
|
|
2962
3041
|
};
|
|
2963
|
-
//
|
|
2964
|
-
//
|
|
2965
|
-
// string cannot produce a different key.
|
|
2966
|
-
//
|
|
2967
|
-
// Membership is an own-property check, not `in`. `in` walks the prototype
|
|
2968
|
-
// chain, so a name matching an Object.prototype member reports as present on
|
|
2969
|
-
// any plain object. ALLOWED_QUERY_PARAMS contains no such name, which was the
|
|
2970
|
-
// only thing making `in` safe here \u2014 and it stops being a safe assumption the
|
|
2971
|
-
// moment this list can be extended from configuration.
|
|
2972
|
-
var capturedNames = function capturedNames(params) {
|
|
2973
|
-
return ALLOWED_QUERY_PARAMS.filter(function (name) {
|
|
2974
|
-
return hasOwnProp(params, name);
|
|
2975
|
-
}).concat(Object.keys(params).filter(hasAllowedPrefix).sort());
|
|
2976
|
-
};
|
|
2977
|
-
// The dedup key: pathname plus the allowlisted params in a fixed order, so that
|
|
2978
|
-
// reordering the query string is not a new page. Params outside the allowlist
|
|
2979
|
-
// never make it into `page.params` and so cannot key a view \u2014 nor can the hash.
|
|
2980
|
-
//
|
|
2981
|
-
// Values are re-encoded because queryStringParser hands them back DECODED. A
|
|
2982
|
-
// value holding the pair delimiters would otherwise serialize exactly like two
|
|
2983
|
-
// separate params \u2014 `{q: 'a&search=b'}` and `{q: 'a', search: 'b'}` both becoming
|
|
2984
|
-
// `q=a&search=b` \u2014 and dedup would treat a real navigation between them as the
|
|
2985
|
-
// same page and drop the view. `q`, `search` and `redirect_uri` carry `&` and `=`
|
|
2986
|
-
// routinely, so this is reachable rather than theoretical.
|
|
3042
|
+
// Values are re-encoded because they arrive decoded: `{q: 'a&search=b'}` would otherwise
|
|
3043
|
+
// key the same as `{q: 'a', search: 'b'}` and dedup a real navigation away.
|
|
2987
3044
|
var pageKey = function pageKey(page) {
|
|
2988
|
-
var query =
|
|
2989
|
-
|
|
3045
|
+
var query = page.params.map(function (_a) {
|
|
3046
|
+
var name = _a.name,
|
|
3047
|
+
value = _a.value;
|
|
3048
|
+
return "".concat(name, "=").concat(encodeURIComponent(value));
|
|
2990
3049
|
}).join('&');
|
|
2991
3050
|
return query ? "".concat(page.path, "?").concat(query) : page.path;
|
|
2992
3051
|
};
|
|
@@ -3011,7 +3070,7 @@ var mParticle = (function () {
|
|
|
3011
3070
|
// Params spread first, then the core fields by name, so a core field always
|
|
3012
3071
|
// wins. No allowlist entry collides with hostname/title/path today; naming
|
|
3013
3072
|
// them here is what keeps a later addition from silently overwriting one.
|
|
3014
|
-
data: __assign(__assign(__assign({}, params), {
|
|
3073
|
+
data: __assign(__assign(__assign({}, paramsToAttributes(params)), {
|
|
3015
3074
|
hostname: hostname,
|
|
3016
3075
|
title: title,
|
|
3017
3076
|
path: path
|
|
@@ -3090,10 +3149,10 @@ var mParticle = (function () {
|
|
|
3090
3149
|
state.tracker = undefined;
|
|
3091
3150
|
}
|
|
3092
3151
|
};
|
|
3093
|
-
var currentPage = function currentPage() {
|
|
3152
|
+
var currentPage = function currentPage(extras) {
|
|
3094
3153
|
return {
|
|
3095
3154
|
path: window.location.pathname,
|
|
3096
|
-
params: allowedQueryParams(getHref())
|
|
3155
|
+
params: allowedQueryParams(getHref(), extras)
|
|
3097
3156
|
};
|
|
3098
3157
|
};
|
|
3099
3158
|
// Log-safe description of a page: the path, plus the NAMES of the captured
|
|
@@ -3106,7 +3165,10 @@ var mParticle = (function () {
|
|
|
3106
3165
|
if (!page) {
|
|
3107
3166
|
return '';
|
|
3108
3167
|
}
|
|
3109
|
-
var names =
|
|
3168
|
+
var names = page.params.map(function (_a) {
|
|
3169
|
+
var name = _a.name;
|
|
3170
|
+
return name;
|
|
3171
|
+
});
|
|
3110
3172
|
return names.length ? "".concat(page.path, " (params: ").concat(names.join(), ")") : page.path;
|
|
3111
3173
|
};
|
|
3112
3174
|
// ---------------------------------------------------------------------------
|
|
@@ -3119,6 +3181,7 @@ var mParticle = (function () {
|
|
|
3119
3181
|
function PageViewTracker(mpInstance, options) {
|
|
3120
3182
|
this.lastPage = null;
|
|
3121
3183
|
this.active = false;
|
|
3184
|
+
this.customQueryParams = [];
|
|
3122
3185
|
this.pendingNavigations = [];
|
|
3123
3186
|
this.undoHistoryPatch = null;
|
|
3124
3187
|
this.mpInstance = mpInstance;
|
|
@@ -3153,7 +3216,8 @@ var mParticle = (function () {
|
|
|
3153
3216
|
inheritedPages = inheritedPages.concat(this.retire(this));
|
|
3154
3217
|
}
|
|
3155
3218
|
this.active = true;
|
|
3156
|
-
this.
|
|
3219
|
+
this.customQueryParams = this.readCustomQueryParams();
|
|
3220
|
+
this.lastPage = currentPage(this.customQueryParams);
|
|
3157
3221
|
this.log("[init] seeded lastPage: ".concat(describePage(this.lastPage)));
|
|
3158
3222
|
this.undoHistoryPatch = subscribeToRouteChange('pageView', function (source) {
|
|
3159
3223
|
return _this.safeHandleNavigation(source);
|
|
@@ -3178,6 +3242,25 @@ var mParticle = (function () {
|
|
|
3178
3242
|
this.active = false;
|
|
3179
3243
|
clearActiveTracker(this);
|
|
3180
3244
|
};
|
|
3245
|
+
PageViewTracker.prototype.readCustomQueryParams = function () {
|
|
3246
|
+
var _a = this.mpInstance._Store.SDKConfig.autoLogPageViewQueryParams || {},
|
|
3247
|
+
_b = _a.allowed,
|
|
3248
|
+
allowed = _b === void 0 ? [] : _b,
|
|
3249
|
+
_c = _a.rejectedPositions,
|
|
3250
|
+
rejectedPositions = _c === void 0 ? [] : _c,
|
|
3251
|
+
_d = _a.overLimit,
|
|
3252
|
+
overLimit = _d === void 0 ? 0 : _d;
|
|
3253
|
+
if (rejectedPositions.length) {
|
|
3254
|
+
this.mpInstance.Logger.warning('mParticle APV: ignoring invalid additional page view query ' + "parameters at positions ".concat(rejectedPositions.join(', ')));
|
|
3255
|
+
}
|
|
3256
|
+
if (overLimit) {
|
|
3257
|
+
this.mpInstance.Logger.warning("mParticle APV: ignoring ".concat(overLimit, " additional page view ") + "query parameters beyond the limit of " + "".concat(MAX_CUSTOM_QUERY_PARAMS));
|
|
3258
|
+
}
|
|
3259
|
+
if (allowed.length) {
|
|
3260
|
+
this.log("[init] additional query params: ".concat(allowed.join()));
|
|
3261
|
+
}
|
|
3262
|
+
return allowed;
|
|
3263
|
+
};
|
|
3181
3264
|
// Stops the outgoing tracker and returns the pages it had queued so this
|
|
3182
3265
|
// tracker can re-schedule them once it is active. Private, but reachable
|
|
3183
3266
|
// across instances: the handoff protocol stays internal to the class.
|
|
@@ -3219,7 +3302,7 @@ var mParticle = (function () {
|
|
|
3219
3302
|
}
|
|
3220
3303
|
};
|
|
3221
3304
|
PageViewTracker.prototype.handleNavigation = function (source) {
|
|
3222
|
-
var candidate = currentPage();
|
|
3305
|
+
var candidate = currentPage(this.customQueryParams);
|
|
3223
3306
|
var lastKey = this.lastPage ? pageKey(this.lastPage) : null;
|
|
3224
3307
|
this.log("[detect] navigation signal (source: ".concat(source, ", candidate: ").concat(describePage(candidate), ", last: ").concat(describePage(this.lastPage), ")"));
|
|
3225
3308
|
if (!isNewPage(lastKey, pageKey(candidate))) {
|
|
@@ -3271,11 +3354,21 @@ var mParticle = (function () {
|
|
|
3271
3354
|
|
|
3272
3355
|
// The one rule for a URL that leaves the SDK, shared with kits through
|
|
3273
3356
|
// `mParticle._cleanUrl`. `path` keeps scheme, host and path. `full` adds the
|
|
3274
|
-
// query params an auto page view
|
|
3357
|
+
// query params an auto page view captures by default and the campaign
|
|
3358
|
+
// attribution params, then the fragment.
|
|
3275
3359
|
var UrlMode = {
|
|
3276
3360
|
Path: 'path',
|
|
3277
3361
|
Full: 'full'
|
|
3278
3362
|
};
|
|
3363
|
+
// Campaign attribution and ad-network click ids. URLs keep them; an auto page view
|
|
3364
|
+
// carries one as an attribute only when an input configures it.
|
|
3365
|
+
var URL_ATTRIBUTION_QUERY_PARAMS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_id', 'utm_source_platform', 'utm_creative_format', 'utm_marketing_tactic', 'gad_source', 'gad_campaignid', 'mc_cid', 'gclid', 'gbraid', 'wbraid', 'fbclid', 'msclkid', 'ttclid', 'twclid', 'li_fat_id', 'dclid', 'srsltid', 'epik', 'ScCid', 'irclickid', 'rtid', 'rclid'];
|
|
3366
|
+
var URL_ATTRIBUTION_QUERY_PARAMS_LOWER = URL_ATTRIBUTION_QUERY_PARAMS.map(function (name) {
|
|
3367
|
+
return name.toLowerCase();
|
|
3368
|
+
});
|
|
3369
|
+
var isUrlQueryParam = function isUrlQueryParam(name) {
|
|
3370
|
+
return isAllowedQueryParam(name) || URL_ATTRIBUTION_QUERY_PARAMS_LOWER.indexOf(name.toLowerCase()) !== -1;
|
|
3371
|
+
};
|
|
3279
3372
|
// OAuth 2.0 / OIDC authorization-flow params. They stay off URLs even where the
|
|
3280
3373
|
// page view allowlist admits them, because a URL travels on every event.
|
|
3281
3374
|
var EXCLUDED_URL_QUERY_PARAMS = ['client_id', 'redirect_uri', 'response_type', 'scope', 'state', 'code', 'nonce'];
|
|
@@ -3297,7 +3390,7 @@ var mParticle = (function () {
|
|
|
3297
3390
|
return null;
|
|
3298
3391
|
}
|
|
3299
3392
|
var lowerName = name.toLowerCase();
|
|
3300
|
-
if (!name || !
|
|
3393
|
+
if (!name || !isUrlQueryParam(name) || EXCLUDED_URL_QUERY_PARAMS.indexOf(lowerName) !== -1) {
|
|
3301
3394
|
return null;
|
|
3302
3395
|
}
|
|
3303
3396
|
if (separator === -1 || URL_VALUED_QUERY_PARAMS.indexOf(lowerName) === -1) {
|
|
@@ -3745,7 +3838,7 @@ var mParticle = (function () {
|
|
|
3745
3838
|
var event = {
|
|
3746
3839
|
AppName: SDKConfig.appName,
|
|
3747
3840
|
AppVersion: SDKConfig.appVersion,
|
|
3748
|
-
Package: SDKConfig
|
|
3841
|
+
Package: SDKConfig.package,
|
|
3749
3842
|
EventDataType: MessageType$1.AppStateTransition,
|
|
3750
3843
|
Timestamp: now,
|
|
3751
3844
|
SessionId: sessionId,
|
|
@@ -3976,7 +4069,7 @@ var mParticle = (function () {
|
|
|
3976
4069
|
});
|
|
3977
4070
|
batchesToUpload.forEach(function (batch) {
|
|
3978
4071
|
if (retriedIds.indexOf(batch.source_request_id) === -1) {
|
|
3979
|
-
_this_1.batchOrder
|
|
4072
|
+
_this_1.batchOrder.delete(batch.source_request_id);
|
|
3980
4073
|
}
|
|
3981
4074
|
});
|
|
3982
4075
|
// Batches that do not successfully upload are added back to the process queue
|
|
@@ -4003,7 +4096,6 @@ var mParticle = (function () {
|
|
|
4003
4096
|
});
|
|
4004
4097
|
});
|
|
4005
4098
|
};
|
|
4006
|
-
|
|
4007
4099
|
BatchUploader.prototype.storeBatchesQueuedForProcessing = function () {
|
|
4008
4100
|
var _this_1 = this;
|
|
4009
4101
|
var _a;
|
|
@@ -4271,7 +4363,6 @@ var mParticle = (function () {
|
|
|
4271
4363
|
logger.error('search called without a callback function; skipping request.');
|
|
4272
4364
|
return [2 /*return*/];
|
|
4273
4365
|
}
|
|
4274
|
-
|
|
4275
4366
|
safeInvoke = function safeInvoke(result) {
|
|
4276
4367
|
try {
|
|
4277
4368
|
callback(result);
|
|
@@ -4301,7 +4392,6 @@ var mParticle = (function () {
|
|
|
4301
4392
|
});
|
|
4302
4393
|
return [2 /*return*/];
|
|
4303
4394
|
}
|
|
4304
|
-
|
|
4305
4395
|
_a.label = 1;
|
|
4306
4396
|
case 1:
|
|
4307
4397
|
_a.trys.push([1, 9,, 10]);
|
|
@@ -4604,7 +4694,7 @@ var mParticle = (function () {
|
|
|
4604
4694
|
sdk_version: Constants.sdkVersion
|
|
4605
4695
|
},
|
|
4606
4696
|
environment: environment,
|
|
4607
|
-
request_id:
|
|
4697
|
+
request_id: _generateUniqueId(),
|
|
4608
4698
|
request_timestamp_ms: Date.now()
|
|
4609
4699
|
};
|
|
4610
4700
|
};
|
|
@@ -5058,7 +5148,7 @@ var mParticle = (function () {
|
|
|
5058
5148
|
this.decoded = decoded;
|
|
5059
5149
|
this.parseStringOrNumber = parseStringOrNumber;
|
|
5060
5150
|
this.generateHash = generateHash;
|
|
5061
|
-
this.generateUniqueId =
|
|
5151
|
+
this.generateUniqueId = _generateUniqueId;
|
|
5062
5152
|
// Imported Validators
|
|
5063
5153
|
this.Validators = Validators;
|
|
5064
5154
|
}
|
|
@@ -5260,9 +5350,13 @@ var mParticle = (function () {
|
|
|
5260
5350
|
if (requiresConsent && mpidIsNotInCookies) {
|
|
5261
5351
|
return;
|
|
5262
5352
|
}
|
|
5263
|
-
// For Rokt, block cookie sync
|
|
5264
|
-
|
|
5265
|
-
|
|
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
|
+
}
|
|
5266
5360
|
}
|
|
5267
5361
|
var isEnabledForUserConsent = mpInstance._Consent.isEnabledForUserConsent;
|
|
5268
5362
|
if (!isEnabledForUserConsent(filteringConsentRuleValues, mpInstance.Identity.getCurrentUser())) {
|
|
@@ -6144,6 +6238,7 @@ var mParticle = (function () {
|
|
|
6144
6238
|
this.SDKConfig.flags = {};
|
|
6145
6239
|
}
|
|
6146
6240
|
this.SDKConfig.flags = processFlags(config);
|
|
6241
|
+
this.SDKConfig.autoLogPageViewQueryParams = parseQueryParamAllowlist(config.autoLogPageViewQueryParams);
|
|
6147
6242
|
if (config.deviceId) {
|
|
6148
6243
|
this.deviceId = config.deviceId;
|
|
6149
6244
|
}
|
|
@@ -6178,7 +6273,7 @@ var mParticle = (function () {
|
|
|
6178
6273
|
this.SDKConfig.appName = config.appName;
|
|
6179
6274
|
}
|
|
6180
6275
|
if (config.hasOwnProperty('package')) {
|
|
6181
|
-
this.SDKConfig
|
|
6276
|
+
this.SDKConfig.package = config.package;
|
|
6182
6277
|
}
|
|
6183
6278
|
if (config.hasOwnProperty('integrationDelayTimeout')) {
|
|
6184
6279
|
this.SDKConfig.integrationDelayTimeout = config.integrationDelayTimeout;
|
|
@@ -6420,6 +6515,9 @@ var mParticle = (function () {
|
|
|
6420
6515
|
if (config.flags) {
|
|
6421
6516
|
_this.SDKConfig.flags = processFlags(config);
|
|
6422
6517
|
}
|
|
6518
|
+
// Stored whole: the tracker reports the rejections, and cannot recover them by
|
|
6519
|
+
// re-parsing a list that has already had them removed.
|
|
6520
|
+
_this.SDKConfig.autoLogPageViewQueryParams = parseQueryParamAllowlist(config.autoLogPageViewQueryParams);
|
|
6423
6521
|
var baseUrls = processBaseUrls(config, _this.SDKConfig.flags, apiKey);
|
|
6424
6522
|
for (var baseUrlKeys in baseUrls) {
|
|
6425
6523
|
_this.SDKConfig[baseUrlKeys] = baseUrls[baseUrlKeys];
|
|
@@ -6452,7 +6550,8 @@ var mParticle = (function () {
|
|
|
6452
6550
|
CaptureIntegrationSpecificIdsV2 = _a.CaptureIntegrationSpecificIdsV2,
|
|
6453
6551
|
AstBackgroundEvents = _a.AstBackgroundEvents,
|
|
6454
6552
|
AutoLogPageView = _a.AutoLogPageView,
|
|
6455
|
-
AutoButtonTracking = _a.AutoButtonTracking
|
|
6553
|
+
AutoButtonTracking = _a.AutoButtonTracking,
|
|
6554
|
+
AutoLinkTracking = _a.AutoLinkTracking;
|
|
6456
6555
|
if (!config.flags) {
|
|
6457
6556
|
return {};
|
|
6458
6557
|
}
|
|
@@ -6470,6 +6569,7 @@ var mParticle = (function () {
|
|
|
6470
6569
|
flags[AstBackgroundEvents] = config.flags[AstBackgroundEvents] === 'True';
|
|
6471
6570
|
flags[AutoLogPageView] = config.flags[AutoLogPageView] === 'True';
|
|
6472
6571
|
flags[AutoButtonTracking] = config.flags[AutoButtonTracking] === 'True';
|
|
6572
|
+
flags[AutoLinkTracking] = config.flags[AutoLinkTracking] === 'True';
|
|
6473
6573
|
return flags;
|
|
6474
6574
|
}
|
|
6475
6575
|
function processBaseUrls(config, flags, apiKey) {
|
|
@@ -7438,13 +7538,13 @@ var mParticle = (function () {
|
|
|
7438
7538
|
};
|
|
7439
7539
|
// The auto page view for the landing page. The SPA navigations that follow it
|
|
7440
7540
|
// come from PageViewTracker instead, so both emitters attach the same
|
|
7441
|
-
// allowlisted query params
|
|
7442
|
-
// attribution, since utm_*/gclid live on the entry URL.
|
|
7541
|
+
// allowlisted query params.
|
|
7443
7542
|
this.logPageView = function (options) {
|
|
7543
|
+
var _a;
|
|
7444
7544
|
self.logEvent({
|
|
7445
7545
|
messageType: Types.MessageType.PageView,
|
|
7446
7546
|
name: 'PageView',
|
|
7447
|
-
data: __assign(__assign(__assign({}, allowedQueryParams(getHref())), {
|
|
7547
|
+
data: __assign(__assign(__assign({}, paramsToAttributes(allowedQueryParams(getHref(), (_a = mpInstance._Store.SDKConfig.autoLogPageViewQueryParams) === null || _a === void 0 ? void 0 : _a.allowed))), {
|
|
7448
7548
|
hostname: window.location.hostname,
|
|
7449
7549
|
title: window.document.title
|
|
7450
7550
|
}), autoPageViewAttribute(options && options.isAutoPageView)),
|
|
@@ -7738,6 +7838,19 @@ var mParticle = (function () {
|
|
|
7738
7838
|
}
|
|
7739
7839
|
return false;
|
|
7740
7840
|
}
|
|
7841
|
+
// sendEventToForwarders passes no kitBlocker: apiClient has already applied
|
|
7842
|
+
// the data plan by then.
|
|
7843
|
+
function isEventForwarded(event, forwarder, kitBlocker) {
|
|
7844
|
+
var plannedEvent = kitBlocker && kitBlocker.kitBlockingEnabled ? kitBlocker.createBlockedEvent(event) : event;
|
|
7845
|
+
if (!plannedEvent) {
|
|
7846
|
+
return false;
|
|
7847
|
+
}
|
|
7848
|
+
if (isBlockedByForwardingRule(plannedEvent.EventDataType, plannedEvent.EventAttributes, forwarder)) {
|
|
7849
|
+
return false;
|
|
7850
|
+
}
|
|
7851
|
+
var eventCategory = plannedEvent.EventCategory;
|
|
7852
|
+
return !isBlockedByEventFilter(plannedEvent.EventDataType, KitFilterHelper.hashEventName(plannedEvent.EventName, eventCategory), KitFilterHelper.hashEventType(eventCategory), forwarder);
|
|
7853
|
+
}
|
|
7741
7854
|
function filterEventAttributes(messageType, eventCategory, eventName, attributes, forwarder) {
|
|
7742
7855
|
if (!attributes) {
|
|
7743
7856
|
return attributes;
|
|
@@ -7888,17 +8001,12 @@ var mParticle = (function () {
|
|
|
7888
8001
|
if (mpInstance._Store.webviewBridgeEnabled || !mpInstance._Store.activeForwarders) {
|
|
7889
8002
|
return;
|
|
7890
8003
|
}
|
|
7891
|
-
var hashedEventName = KitFilterHelper.hashEventName(event.EventName, event.EventCategory);
|
|
7892
|
-
var hashedEventType = KitFilterHelper.hashEventType(event.EventCategory);
|
|
7893
8004
|
var forwardEvent = function forwardEvent(forwarder) {
|
|
7894
|
-
if (
|
|
8005
|
+
if (!isEventForwarded(event, forwarder)) {
|
|
7895
8006
|
return;
|
|
7896
8007
|
}
|
|
7897
8008
|
// Clone the event object, as we could be sending different attributes to each forwarder
|
|
7898
8009
|
var clonedEvent = extend(true, {}, event);
|
|
7899
|
-
if (isBlockedByEventFilter(event.EventDataType, hashedEventName, hashedEventType, forwarder)) {
|
|
7900
|
-
return;
|
|
7901
|
-
}
|
|
7902
8010
|
clonedEvent.EventAttributes = filterEventAttributes(event.EventDataType, event.EventCategory, event.EventName, clonedEvent.EventAttributes, forwarder);
|
|
7903
8011
|
// Check user identity filtering rules
|
|
7904
8012
|
clonedEvent.UserIdentities = filterUserIdentities(clonedEvent.UserIdentities, forwarder.userIdentityFilters);
|
|
@@ -8346,7 +8454,7 @@ var mParticle = (function () {
|
|
|
8346
8454
|
ExpandedEventCount: 0,
|
|
8347
8455
|
AppVersion: mpInstance.getAppVersion(),
|
|
8348
8456
|
AppName: mpInstance.getAppName(),
|
|
8349
|
-
Package: mpInstance._Store.SDKConfig
|
|
8457
|
+
Package: mpInstance._Store.SDKConfig.package,
|
|
8350
8458
|
ClientGeneratedId: mpInstance._Store.clientId,
|
|
8351
8459
|
DeviceId: mpInstance._Store.deviceId,
|
|
8352
8460
|
IntegrationAttributes: integrationAttributes,
|
|
@@ -8575,7 +8683,6 @@ var mParticle = (function () {
|
|
|
8575
8683
|
});
|
|
8576
8684
|
});
|
|
8577
8685
|
};
|
|
8578
|
-
|
|
8579
8686
|
return AudienceManager;
|
|
8580
8687
|
}();
|
|
8581
8688
|
|
|
@@ -10614,7 +10721,6 @@ var mParticle = (function () {
|
|
|
10614
10721
|
});
|
|
10615
10722
|
});
|
|
10616
10723
|
};
|
|
10617
|
-
|
|
10618
10724
|
this.sendIdentityRequest = function (identityApiRequest, method, callback, originalIdentityApiData, parseIdentityResponse, mpid, knownIdentities) {
|
|
10619
10725
|
var _a, _b, _c, _d;
|
|
10620
10726
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -10634,13 +10740,11 @@ var mParticle = (function () {
|
|
|
10634
10740
|
Logger.error(Messages$1.ErrorMessages.APIRequestEmpty);
|
|
10635
10741
|
return [2 /*return*/];
|
|
10636
10742
|
}
|
|
10637
|
-
|
|
10638
10743
|
Logger.verbose(Messages$1.InformationMessages.SendIdentityHttp);
|
|
10639
10744
|
if (mpInstance._Store.identityCallInFlight) {
|
|
10640
10745
|
invokeCallback(callback, HTTPCodes$1.activeIdentityRequest, 'There is currently an Identity request processing. Please wait for this to return before requesting again');
|
|
10641
10746
|
return [2 /*return*/];
|
|
10642
10747
|
}
|
|
10643
|
-
|
|
10644
10748
|
previousMPID = mpid || null;
|
|
10645
10749
|
uploadUrl = this.getUploadUrl(method, mpid);
|
|
10646
10750
|
uploader = window.fetch ? new FetchUploader(uploadUrl) : new XHRUploader(uploadUrl);
|
|
@@ -10698,7 +10802,7 @@ var mParticle = (function () {
|
|
|
10698
10802
|
responseToLog = responseText;
|
|
10699
10803
|
if (!isDevelopmentMode && (responseText === null || responseText === void 0 ? void 0 : responseText.matched_identities)) {
|
|
10700
10804
|
responseToLog = __assign(__assign({}, responseText), {
|
|
10701
|
-
matched_identities:
|
|
10805
|
+
matched_identities: _obfuscateData(responseText.matched_identities)
|
|
10702
10806
|
});
|
|
10703
10807
|
}
|
|
10704
10808
|
message = 'Received Identity Response from server: ' + JSON.stringify(responseToLog);
|
|
@@ -10753,7 +10857,6 @@ var mParticle = (function () {
|
|
|
10753
10857
|
});
|
|
10754
10858
|
});
|
|
10755
10859
|
};
|
|
10756
|
-
|
|
10757
10860
|
this.getUploadUrl = function (method, mpid) {
|
|
10758
10861
|
var uploadServiceUrl = mpInstance._Helpers.createServiceUrl(mpInstance._Store.SDKConfig.identityUrl);
|
|
10759
10862
|
var uploadUrl = method === Modify ? uploadServiceUrl + mpid + '/' + method : uploadServiceUrl + method;
|
|
@@ -10778,7 +10881,8 @@ var mParticle = (function () {
|
|
|
10778
10881
|
}
|
|
10779
10882
|
|
|
10780
10883
|
var PASSBACK_CONVERSION_TRACKING_ID = 'passbackconversiontrackingid';
|
|
10781
|
-
|
|
10884
|
+
// One signal per kind (commit, wallet, checkout_step, frame and cart), so a new kind never evicts another.
|
|
10885
|
+
var CHECKOUT_INTENT_BUFFER_LIMIT = 5;
|
|
10782
10886
|
var CHECKOUT_INTENT_MAX_AGE_MS = 30000;
|
|
10783
10887
|
var ON_SHOPPABLE_ADS_READY_METHOD = 'onShoppableAdsReady';
|
|
10784
10888
|
// The purpose of this class is to create a link between the Core mParticle SDK and the
|
|
@@ -10807,6 +10911,8 @@ var mParticle = (function () {
|
|
|
10807
10911
|
this.stopRouteChangeWatch = null;
|
|
10808
10912
|
// Checkout intent raised before the kit attached: latest per kind.
|
|
10809
10913
|
this.pendingCheckoutIntents = [];
|
|
10914
|
+
// Off until SDK init finds the Rokt connection receives auto button clicks.
|
|
10915
|
+
this.autoButtonClicksForwarded = false;
|
|
10810
10916
|
}
|
|
10811
10917
|
/**
|
|
10812
10918
|
* Sets a callback to be invoked when RoktManager becomes ready
|
|
@@ -10933,21 +11039,31 @@ var mParticle = (function () {
|
|
|
10933
11039
|
(_c = this.logger) === null || _c === void 0 ? void 0 : _c.error("RoktManager: Error in onRouteChange: ".concat(getErrorMessage(e)));
|
|
10934
11040
|
}
|
|
10935
11041
|
};
|
|
10936
|
-
|
|
10937
|
-
|
|
10938
|
-
|
|
10939
|
-
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
}
|
|
11042
|
+
RoktManager.prototype.setAutoButtonClicksForwarded = function (forwarded) {
|
|
11043
|
+
this.autoButtonClicksForwarded = forwarded;
|
|
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 () {
|
|
10944
11049
|
var options = this.launcherOptions || {};
|
|
10945
|
-
if (options.
|
|
11050
|
+
if (options.noTargeting || options.doNotShareOrSell) {
|
|
10946
11051
|
return true;
|
|
10947
11052
|
}
|
|
10948
11053
|
var nav = typeof navigator === 'undefined' ? undefined : navigator;
|
|
10949
11054
|
return !!nav && nav.globalPrivacyControl === true;
|
|
10950
11055
|
};
|
|
11056
|
+
// Checkout intent is off unless the flag is on, and under opt-out, any Rokt
|
|
11057
|
+
// privacy launcher option, Global Privacy Control, or a Rokt connection that
|
|
11058
|
+
// does not receive auto button clicks.
|
|
11059
|
+
RoktManager.prototype.isCheckoutIntentSuppressed = function () {
|
|
11060
|
+
var _a, _b, _c;
|
|
11061
|
+
var flags = (_b = (_a = this.store) === null || _a === void 0 ? void 0 : _a.SDKConfig) === null || _b === void 0 ? void 0 : _b.flags;
|
|
11062
|
+
if (!flags || flags[Constants.FeatureFlags.AutoButtonTracking] !== true || !this.store.isEnabled || !this.autoButtonClicksForwarded) {
|
|
11063
|
+
return true;
|
|
11064
|
+
}
|
|
11065
|
+
return !!((_c = this.launcherOptions) === null || _c === void 0 ? void 0 : _c.noFunctional) || this.hasTargetingOptOut();
|
|
11066
|
+
};
|
|
10951
11067
|
// True when the kit can wait for the shopper's confirm click: signals are not
|
|
10952
11068
|
// suppressed and the browser exposes the composed path the detector reads.
|
|
10953
11069
|
// Decided from config alone, so tracker setup and teardown never change it.
|
|
@@ -10988,6 +11104,23 @@ var mParticle = (function () {
|
|
|
10988
11104
|
RoktManager.prototype.discardCheckoutIntents = function () {
|
|
10989
11105
|
this.pendingCheckoutIntents = [];
|
|
10990
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
|
+
};
|
|
10991
11124
|
// Replays recent buffered signals raised on the current page, oldest first.
|
|
10992
11125
|
RoktManager.prototype.flushCheckoutIntents = function () {
|
|
10993
11126
|
var _this = this;
|
|
@@ -11006,6 +11139,8 @@ var mParticle = (function () {
|
|
|
11006
11139
|
return _this.notifyCheckoutIntent(signal);
|
|
11007
11140
|
});
|
|
11008
11141
|
};
|
|
11142
|
+
// The Rokt kit reads this to tell core's page views, whose title and utm
|
|
11143
|
+
// attributes a filter may have removed, from ones logged by hand.
|
|
11009
11144
|
RoktManager.prototype.isAutoLogPageViewEnabled = function () {
|
|
11010
11145
|
var _a, _b, _c;
|
|
11011
11146
|
return ((_c = (_b = (_a = this.store) === null || _a === void 0 ? void 0 : _a.SDKConfig) === null || _b === void 0 ? void 0 : _b.flags) === null || _c === void 0 ? void 0 : _c[Constants.FeatureFlags.AutoLogPageView]) === true;
|
|
@@ -11153,7 +11288,6 @@ var mParticle = (function () {
|
|
|
11153
11288
|
});
|
|
11154
11289
|
});
|
|
11155
11290
|
};
|
|
11156
|
-
|
|
11157
11291
|
RoktManager.prototype.logFilteredIdentity = function (identityType) {
|
|
11158
11292
|
var _a;
|
|
11159
11293
|
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.verbose("mParticle.Rokt selectPlacements did not add the ".concat(identityType, " user identity to the attributes because the Rokt connection does not allow it"));
|
|
@@ -11223,7 +11357,6 @@ var mParticle = (function () {
|
|
|
11223
11357
|
});
|
|
11224
11358
|
});
|
|
11225
11359
|
};
|
|
11226
|
-
|
|
11227
11360
|
RoktManager.prototype.setExtensionData = function (extensionData) {
|
|
11228
11361
|
if (!this.isReady()) {
|
|
11229
11362
|
this.deferredCall('setExtensionData', extensionData);
|
|
@@ -11272,12 +11405,10 @@ var mParticle = (function () {
|
|
|
11272
11405
|
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.verbose('mParticle.Rokt.terminate called before the Rokt kit was ready. Nothing to terminate.');
|
|
11273
11406
|
return [2 /*return*/];
|
|
11274
11407
|
}
|
|
11275
|
-
|
|
11276
11408
|
if (!isFunction(this.kit.terminate)) {
|
|
11277
11409
|
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.error('mParticle.Rokt.terminate is not supported by the attached Rokt Kit version.');
|
|
11278
11410
|
return [2 /*return*/];
|
|
11279
11411
|
}
|
|
11280
|
-
|
|
11281
11412
|
_d.label = 1;
|
|
11282
11413
|
case 1:
|
|
11283
11414
|
_d.trys.push([1, 3,, 4]);
|
|
@@ -11295,7 +11426,6 @@ var mParticle = (function () {
|
|
|
11295
11426
|
});
|
|
11296
11427
|
});
|
|
11297
11428
|
};
|
|
11298
|
-
|
|
11299
11429
|
RoktManager.prototype.onShoppableAdsReady = function (callback) {
|
|
11300
11430
|
if (!this.kit || !this.isShoppableAdsLoaded) {
|
|
11301
11431
|
this.deferredCall('onShoppableAdsReady', callback);
|
|
@@ -11318,7 +11448,7 @@ var mParticle = (function () {
|
|
|
11318
11448
|
} catch (e) {
|
|
11319
11449
|
(_a = _this.logger) === null || _a === void 0 ? void 0 : _a.error('RoktManager: Error flushing onShoppableAdsReady: ' + e);
|
|
11320
11450
|
}
|
|
11321
|
-
_this.messageQueue
|
|
11451
|
+
_this.messageQueue.delete(key);
|
|
11322
11452
|
}
|
|
11323
11453
|
});
|
|
11324
11454
|
this.isShoppableAdsLoaded = true;
|
|
@@ -11357,7 +11487,6 @@ var mParticle = (function () {
|
|
|
11357
11487
|
});
|
|
11358
11488
|
});
|
|
11359
11489
|
};
|
|
11360
|
-
|
|
11361
11490
|
RoktManager.prototype.getLocalSessionAttributes = function () {
|
|
11362
11491
|
return this.store.getLocalSessionAttributes();
|
|
11363
11492
|
};
|
|
@@ -11463,7 +11592,7 @@ var mParticle = (function () {
|
|
|
11463
11592
|
if (resolve) {
|
|
11464
11593
|
resolve(resolvedResult);
|
|
11465
11594
|
}
|
|
11466
|
-
})
|
|
11595
|
+
}).catch(handleError);
|
|
11467
11596
|
} catch (error) {
|
|
11468
11597
|
handleError(error);
|
|
11469
11598
|
}
|
|
@@ -11475,7 +11604,7 @@ var mParticle = (function () {
|
|
|
11475
11604
|
RoktManager.prototype.deferredCall = function (methodName, payload) {
|
|
11476
11605
|
var _this = this;
|
|
11477
11606
|
return new Promise(function (resolve, reject) {
|
|
11478
|
-
var messageId = "".concat(methodName, "_").concat(
|
|
11607
|
+
var messageId = "".concat(methodName, "_").concat(_generateUniqueId());
|
|
11479
11608
|
_this.queueMessage({
|
|
11480
11609
|
messageId: messageId,
|
|
11481
11610
|
methodName: methodName,
|
|
@@ -11538,24 +11667,21 @@ var mParticle = (function () {
|
|
|
11538
11667
|
if (!currentValue) {
|
|
11539
11668
|
return true; // New value exists but no current value
|
|
11540
11669
|
}
|
|
11541
|
-
|
|
11542
11670
|
if (currentValue !== newValue) {
|
|
11543
11671
|
return true; // Values are different
|
|
11544
11672
|
}
|
|
11545
|
-
|
|
11546
11673
|
return false; // Values are the same
|
|
11547
11674
|
};
|
|
11548
|
-
|
|
11549
11675
|
return RoktManager;
|
|
11550
11676
|
}();
|
|
11551
11677
|
|
|
11552
11678
|
/**
|
|
11553
|
-
* CookieConsentManager handles storage and access of consent flags (noFunctional, noTargeting
|
|
11554
|
-
* 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.
|
|
11555
11681
|
*
|
|
11556
11682
|
* These flags allow Rokt integration to respect user privacy choices.
|
|
11557
11683
|
*
|
|
11558
|
-
* Default behavior:
|
|
11684
|
+
* Default behavior: All flags default to false, meaning all features are allowed
|
|
11559
11685
|
* unless explicitly opted out by the user.
|
|
11560
11686
|
*/
|
|
11561
11687
|
var CookieConsentManager = /** @class */function () {
|
|
@@ -11563,7 +11689,8 @@ var mParticle = (function () {
|
|
|
11563
11689
|
this.flags = flags;
|
|
11564
11690
|
this.flags = {
|
|
11565
11691
|
noFunctional: flags.noFunctional === true,
|
|
11566
|
-
noTargeting: flags.noTargeting === true
|
|
11692
|
+
noTargeting: flags.noTargeting === true,
|
|
11693
|
+
doNotShareOrSell: flags.doNotShareOrSell === true
|
|
11567
11694
|
};
|
|
11568
11695
|
}
|
|
11569
11696
|
/**
|
|
@@ -11580,6 +11707,13 @@ var mParticle = (function () {
|
|
|
11580
11707
|
CookieConsentManager.prototype.getNoFunctional = function () {
|
|
11581
11708
|
return this.flags.noFunctional;
|
|
11582
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
|
+
};
|
|
11583
11717
|
CookieConsentManager.prototype.syncNoTargetingAttribute = function (user) {
|
|
11584
11718
|
if (!user) return;
|
|
11585
11719
|
if (this.flags.noTargeting) {
|
|
@@ -11637,19 +11771,20 @@ var mParticle = (function () {
|
|
|
11637
11771
|
var AUTO_BUTTON_ATTRIBUTE = 'is_auto_button_click';
|
|
11638
11772
|
// Specific enough not to merge with a customer's own 'Button Click' event.
|
|
11639
11773
|
var BUTTON_CLICK_EVENT_NAME = 'Auto Button Click';
|
|
11640
|
-
//
|
|
11641
|
-
|
|
11642
|
-
|
|
11643
|
-
|
|
11644
|
-
|
|
11645
|
-
|
|
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 = {
|
|
11646
11781
|
label_source: click.labelSource,
|
|
11647
11782
|
element: click.element,
|
|
11648
11783
|
type: click.type,
|
|
11649
11784
|
path: pathname,
|
|
11650
11785
|
hostname: window.location.hostname
|
|
11651
|
-
}
|
|
11652
|
-
// Optional fields are left out when the
|
|
11786
|
+
};
|
|
11787
|
+
// Optional fields are left out when the control has no safe value for them.
|
|
11653
11788
|
var optional = {
|
|
11654
11789
|
label: click.label,
|
|
11655
11790
|
aria_label: click.ariaLabel,
|
|
@@ -11663,8 +11798,8 @@ var mParticle = (function () {
|
|
|
11663
11798
|
link_domain: click.linkDomain,
|
|
11664
11799
|
file_extension: click.fileExtension
|
|
11665
11800
|
};
|
|
11666
|
-
for (var _i = 0,
|
|
11667
|
-
var key =
|
|
11801
|
+
for (var _i = 0, _a = Object.keys(optional); _i < _a.length; _i++) {
|
|
11802
|
+
var key = _a[_i];
|
|
11668
11803
|
if (optional[key]) {
|
|
11669
11804
|
data[key] = optional[key];
|
|
11670
11805
|
}
|
|
@@ -11672,6 +11807,12 @@ var mParticle = (function () {
|
|
|
11672
11807
|
if (click.checked !== undefined) {
|
|
11673
11808
|
data.checked = click.checked;
|
|
11674
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;
|
|
11675
11816
|
return {
|
|
11676
11817
|
messageType: MessageType$1.PageEvent,
|
|
11677
11818
|
name: BUTTON_CLICK_EVENT_NAME,
|
|
@@ -11679,23 +11820,95 @@ var mParticle = (function () {
|
|
|
11679
11820
|
eventType: EventType.Other
|
|
11680
11821
|
};
|
|
11681
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
|
+
};
|
|
11841
|
+
// Every attribute buildButtonClickEvent can set apart from the marker and the
|
|
11842
|
+
// hostname, which is the same on every click on this page. A spec checks the
|
|
11843
|
+
// two stay in step.
|
|
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'];
|
|
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
|
+
}
|
|
11854
|
+
var rule = forwarder.filteringEventAttributeValue;
|
|
11855
|
+
if (rule && rule.eventAttributeValue && CLICK_ATTRIBUTES.some(function (name) {
|
|
11856
|
+
return KitFilterHelper.hashAttributeConditionalForwarding(name) === rule.eventAttributeName;
|
|
11857
|
+
})) {
|
|
11858
|
+
return 'forwarding rule';
|
|
11859
|
+
}
|
|
11860
|
+
var attributes = {
|
|
11861
|
+
hostname: window.location.hostname
|
|
11862
|
+
};
|
|
11863
|
+
attributes[link ? AUTO_LINK_ATTRIBUTE : AUTO_BUTTON_ATTRIBUTE] = true;
|
|
11864
|
+
var click = {
|
|
11865
|
+
EventName: link ? LINK_CLICK_EVENT_NAME : BUTTON_CLICK_EVENT_NAME,
|
|
11866
|
+
EventCategory: EventType.Other,
|
|
11867
|
+
EventDataType: MessageType$1.PageEvent,
|
|
11868
|
+
EventAttributes: attributes
|
|
11869
|
+
};
|
|
11870
|
+
var checks = [['data plan', {}], ['forwarding rule', {
|
|
11871
|
+
filteringEventAttributeValue: rule
|
|
11872
|
+
}], ['event name filter', {
|
|
11873
|
+
eventNameFilters: forwarder.eventNameFilters
|
|
11874
|
+
}], ['event type filter', {
|
|
11875
|
+
eventTypeFilters: forwarder.eventTypeFilters
|
|
11876
|
+
}]];
|
|
11877
|
+
var failed = checks.find(function (_a) {
|
|
11878
|
+
var filters = _a[1];
|
|
11879
|
+
return !isEventForwarded(click, filters, kitBlocker);
|
|
11880
|
+
});
|
|
11881
|
+
return failed ? failed[0] : undefined;
|
|
11882
|
+
};
|
|
11682
11883
|
|
|
11683
11884
|
// Finds the control a click landed on, for both checkout intent and button
|
|
11684
11885
|
// descriptions. Rokt's own elements, disabled controls and anything under
|
|
11685
11886
|
// data-mp-no-track are never returned.
|
|
11686
11887
|
var CONTROL_SELECTOR = 'button, input[type="submit"], input[type="button"], input[type="image"], [role="button"]';
|
|
11687
|
-
|
|
11688
|
-
|
|
11888
|
+
var EDITABLE = '[contenteditable]:not([contenteditable="false"])';
|
|
11889
|
+
// One step up the composed tree: the slot, the parent, then the shadow host.
|
|
11890
|
+
function composedParent(node) {
|
|
11891
|
+
var root = isFunction(node.getRootNode) ? node.getRootNode() : null;
|
|
11892
|
+
return node.assignedSlot || node.parentElement || root && root.host || null;
|
|
11893
|
+
}
|
|
11894
|
+
// Tests the element and its ancestors over the composed tree: slots, parents,
|
|
11895
|
+
// then shadow hosts. With `until`, stops before reaching that ancestor.
|
|
11896
|
+
function someComposedAncestor(element, test, until) {
|
|
11689
11897
|
var node = element;
|
|
11690
|
-
while (node) {
|
|
11691
|
-
if (node
|
|
11898
|
+
while (node && node !== until) {
|
|
11899
|
+
if (test(node)) {
|
|
11692
11900
|
return true;
|
|
11693
11901
|
}
|
|
11694
|
-
|
|
11695
|
-
node = node.assignedSlot || node.parentElement || root && root.host || null;
|
|
11902
|
+
node = composedParent(node);
|
|
11696
11903
|
}
|
|
11697
11904
|
return false;
|
|
11698
11905
|
}
|
|
11906
|
+
// closest() over the composed tree, starting at the element itself.
|
|
11907
|
+
function hasComposedAncestor(element, selector) {
|
|
11908
|
+
return someComposedAncestor(element, function (node) {
|
|
11909
|
+
return node.matches(selector);
|
|
11910
|
+
});
|
|
11911
|
+
}
|
|
11699
11912
|
var ROKT_SELECTOR = '[data-core-type], #rokt-controller-frame';
|
|
11700
11913
|
// A Rokt frame or script is served from a /wsdk/ path.
|
|
11701
11914
|
function hasRoktSrc(element) {
|
|
@@ -11741,8 +11954,27 @@ var mParticle = (function () {
|
|
|
11741
11954
|
}
|
|
11742
11955
|
return host.matches(CARD_FORM_BUTTON) ? 'checkout_step' : 'wallet';
|
|
11743
11956
|
}
|
|
11957
|
+
// A merchant-built wallet button that names its wallet in an id or test id, such
|
|
11958
|
+
// as `venmo-pay-btn` or `applePayButton`. The name must also say button and not
|
|
11959
|
+
// name a part or a wrapper of one, so a wallet's logo, label or container never
|
|
11960
|
+
// counts, nor a button that only chooses a wallet. Affirm is also an English
|
|
11961
|
+
// verb, so it counts only beside a payment word. Only the element's own
|
|
11962
|
+
// attributes are read.
|
|
11963
|
+
var WALLET_IN_NAME = /(?:^| )(?:apple ?pay|google ?pay|g ?pay|amazon ?pay|cash ?app|venmo|pay ?pal|shop ?pay|klarna|after ?pay|clear ?pay|sezzle|samsung ?pay)(?= |$)/;
|
|
11964
|
+
var AFFIRM_IN_NAME = /(?:^| )affirm(?= |$)/;
|
|
11965
|
+
var PAYMENT_IN_NAME = /(?:^| )(?:pay|payment|checkout)(?= |$)/;
|
|
11966
|
+
var BUTTON_IN_NAME = /(?:^| )(?:btn|button)(?= |$)/;
|
|
11967
|
+
var PART_IN_NAME = /(?:^| )(?:logo|icon|image|img|label|text|caption|message|messaging|info|tooltip|help|learn|terms|promo|banner|container|wrapper|wrap|placeholder|form|section|panel|modal|list|group|select|option|tab|toggle|radio|choice|method)(?= |$)/;
|
|
11968
|
+
function nameWords(value) {
|
|
11969
|
+
return (value || '').slice(0, 64).replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[^A-Za-z0-9]+/g, ' ').trim().toLowerCase();
|
|
11970
|
+
}
|
|
11971
|
+
function isWalletNamed(element) {
|
|
11972
|
+
return [element.getAttribute('id'), element.getAttribute('data-testid')].map(nameWords).some(function (words) {
|
|
11973
|
+
return (WALLET_IN_NAME.test(words) || AFFIRM_IN_NAME.test(words) && PAYMENT_IN_NAME.test(words)) && BUTTON_IN_NAME.test(words) && !PART_IN_NAME.test(words);
|
|
11974
|
+
});
|
|
11975
|
+
}
|
|
11744
11976
|
function isWalletElement(element) {
|
|
11745
|
-
return vendorButtonKind(element) === 'wallet';
|
|
11977
|
+
return vendorButtonKind(element) === 'wallet' || isWalletNamedControl(element);
|
|
11746
11978
|
}
|
|
11747
11979
|
// Pickers and toggles choose a payment method or open a panel; they never pay.
|
|
11748
11980
|
var PICKER = 'input[type="radio"], input[type="checkbox"], label, [role="radio"], [role="tab"], [role="option"], ' + '[role="checkbox"], [role="switch"], [role="menuitemradio"], [role="menuitemcheckbox"], [aria-checked], [aria-selected]';
|
|
@@ -11750,25 +11982,53 @@ var mParticle = (function () {
|
|
|
11750
11982
|
// Pay-later and financing messages link to details rather than pay.
|
|
11751
11983
|
var MESSAGING = 'klarna-placement, afterpay-placement, square-placement, .affirm-as-low-as, .affirm-site-modal, ' + '.affirm-product-modal, [data-pp-message]';
|
|
11752
11984
|
// A control that is still logged as a click but never counts as checkout intent.
|
|
11753
|
-
|
|
11985
|
+
// A cart button can open a flyout, so aria-expanded alone never quiets one.
|
|
11986
|
+
function isQuietIntentControl(control, isVendorWallet, isCart) {
|
|
11987
|
+
if (isCart === void 0) {
|
|
11988
|
+
isCart = false;
|
|
11989
|
+
}
|
|
11754
11990
|
if (control.matches(PICKER)) {
|
|
11755
11991
|
return true;
|
|
11756
11992
|
}
|
|
11757
11993
|
if (hasComposedAncestor(control, PICKER_GROUP)) {
|
|
11758
11994
|
return true;
|
|
11759
11995
|
}
|
|
11760
|
-
if (!isVendorWallet && (control.hasAttribute('aria-expanded') || control.hasAttribute('aria-pressed'))) {
|
|
11996
|
+
if (!isVendorWallet && (!isCart && control.hasAttribute('aria-expanded') || control.hasAttribute('aria-pressed'))) {
|
|
11761
11997
|
return true;
|
|
11762
11998
|
}
|
|
11763
11999
|
return hasComposedAncestor(control, MESSAGING);
|
|
11764
12000
|
}
|
|
11765
12001
|
// A checkbox or radio is a control of its own only when no button or link
|
|
11766
|
-
// around it takes the click, so a tappable row
|
|
12002
|
+
// around it takes the click, so a tappable row stays the control.
|
|
11767
12003
|
var OPTION_INPUT = 'input[type="checkbox"], input[type="radio"]';
|
|
11768
|
-
//
|
|
11769
|
-
//
|
|
11770
|
-
//
|
|
11771
|
-
|
|
12004
|
+
// Anything that chooses, toggles or takes typing. One between a click's target
|
|
12005
|
+
// and a wallet-named element, or inside that element, keeps it from becoming
|
|
12006
|
+
// the tap. Hidden inputs and button-like inputs are not fields.
|
|
12007
|
+
var NAME_BARRIER = PICKER + ', ' + PICKER_GROUP + ', input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="image"]), ' + 'select, textarea, option, optgroup, datalist, [aria-expanded], [aria-pressed], ' + EDITABLE;
|
|
12008
|
+
// What owns a click on anything inside it: a picker, a real control or link,
|
|
12009
|
+
// a toggle, or an editable region.
|
|
12010
|
+
var NAME_HOLDER = PICKER + ', ' + CONTROL_SELECTOR + ', a[href], ' + VENDOR_BUTTON + ', [aria-expanded], [aria-pressed], ' + EDITABLE;
|
|
12011
|
+
// A wallet-named element that may stand as a control by its name alone: not
|
|
12012
|
+
// itself a picker, toggle or form field; not inside a picker, a real button or
|
|
12013
|
+
// link, a toggle, an editable region or another wallet-named element, which own
|
|
12014
|
+
// the click with their own state; and holding no picker or field, in its open
|
|
12015
|
+
// shadow root either, so a payment-method row with its own radio or select
|
|
12016
|
+
// never becomes a wallet tap.
|
|
12017
|
+
function isWalletNamedControl(element) {
|
|
12018
|
+
if (!isWalletNamed(element) || element.matches(NAME_BARRIER)) {
|
|
12019
|
+
return false;
|
|
12020
|
+
}
|
|
12021
|
+
for (var node = composedParent(element); node; node = composedParent(node)) {
|
|
12022
|
+
if (node.matches(NAME_HOLDER) || isWalletNamed(node)) {
|
|
12023
|
+
return false;
|
|
12024
|
+
}
|
|
12025
|
+
}
|
|
12026
|
+
var shadow = element.shadowRoot;
|
|
12027
|
+
return !element.querySelector(NAME_BARRIER) && !(shadow && shadow.querySelector(NAME_BARRIER));
|
|
12028
|
+
}
|
|
12029
|
+
// Whether a click is never tracked: it has no element, or lands on a Rokt
|
|
12030
|
+
// element or under data-mp-no-track. Reads at most 12 entries of the path.
|
|
12031
|
+
function isExcludedPath(path) {
|
|
11772
12032
|
var entries = path.slice(0, 12);
|
|
11773
12033
|
var first;
|
|
11774
12034
|
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
|
|
@@ -11779,40 +12039,63 @@ var mParticle = (function () {
|
|
|
11779
12039
|
}
|
|
11780
12040
|
}
|
|
11781
12041
|
if (!first || hasComposedAncestor(first, ROKT_SELECTOR + ', [data-mp-no-track]')) {
|
|
12042
|
+
return true;
|
|
12043
|
+
}
|
|
12044
|
+
for (var _a = 0, entries_2 = entries; _a < entries_2.length; _a++) {
|
|
12045
|
+
var target = entries_2[_a];
|
|
12046
|
+
if (target instanceof Element && hasRoktSrc(target)) {
|
|
12047
|
+
return true;
|
|
12048
|
+
}
|
|
12049
|
+
}
|
|
12050
|
+
return false;
|
|
12051
|
+
}
|
|
12052
|
+
// Walks at most 12 entries of an event's composed path for the nearest control.
|
|
12053
|
+
// A wallet-named element counts as one unless a picker, toggle or form field
|
|
12054
|
+
// lies between it and the target or a picker holds it, so choosing an option in
|
|
12055
|
+
// or around it never becomes its tap. Excluded clicks give nothing; disabled controls are skipped, a
|
|
12056
|
+
// wallet-named one also by its `disabled` class. A caller that has already
|
|
12057
|
+
// found the path not excluded passes `included` so the walk runs once.
|
|
12058
|
+
function findControl(path, included) {
|
|
12059
|
+
if (included === void 0) {
|
|
12060
|
+
included = false;
|
|
12061
|
+
}
|
|
12062
|
+
if (!included && isExcludedPath(path)) {
|
|
11782
12063
|
return undefined;
|
|
11783
12064
|
}
|
|
11784
12065
|
var control;
|
|
11785
12066
|
var option;
|
|
11786
|
-
|
|
11787
|
-
|
|
12067
|
+
var picked = false;
|
|
12068
|
+
for (var _i = 0, _a = path.slice(0, 12); _i < _a.length; _i++) {
|
|
12069
|
+
var target = _a[_i];
|
|
12070
|
+
if (control) {
|
|
12071
|
+
break;
|
|
12072
|
+
}
|
|
11788
12073
|
if (!(target instanceof Element)) {
|
|
11789
12074
|
continue;
|
|
11790
12075
|
}
|
|
11791
|
-
if (
|
|
11792
|
-
return undefined;
|
|
11793
|
-
}
|
|
11794
|
-
if (!control && target.matches(CONTROL_SELECTOR + ', a[href], ' + VENDOR_BUTTON)) {
|
|
12076
|
+
if (target.matches(CONTROL_SELECTOR + ', a[href], ' + VENDOR_BUTTON) || !picked && isWalletNamedControl(target)) {
|
|
11795
12077
|
control = target;
|
|
11796
|
-
} else
|
|
11797
|
-
option
|
|
12078
|
+
} else {
|
|
12079
|
+
if (!option && target.matches(OPTION_INPUT)) {
|
|
12080
|
+
option = target;
|
|
12081
|
+
}
|
|
12082
|
+
picked = picked || target.matches(NAME_BARRIER);
|
|
11798
12083
|
}
|
|
11799
12084
|
}
|
|
11800
12085
|
control = control || option;
|
|
11801
|
-
if (!control || control.matches(':disabled, [aria-disabled="true"]')) {
|
|
12086
|
+
if (!control || control.matches(':disabled, [aria-disabled="true"]') || control.classList.contains('disabled') && isWalletNamed(control)) {
|
|
11802
12087
|
return undefined;
|
|
11803
12088
|
}
|
|
11804
12089
|
return control;
|
|
11805
12090
|
}
|
|
11806
|
-
var EDITABLE = '[contenteditable]:not([contenteditable="false"])';
|
|
11807
12091
|
// Text that may hold what a shopper typed or what the page opted out: form
|
|
11808
|
-
// fields, editable regions, and anything under data-mp-no-track.
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
11813
|
-
|
|
11814
|
-
|
|
11815
|
-
return !!label.querySelector('input:not([type="checkbox"]):not([type="radio"]), select, textarea, [data-mp-no-track], ' + EDITABLE) || hasComposedAncestor(label, '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);
|
|
11816
12099
|
}
|
|
11817
12100
|
|
|
11818
12101
|
// Masks a button label before it is logged. Button text can carry personal data,
|
|
@@ -11830,10 +12113,12 @@ var mParticle = (function () {
|
|
|
11830
12113
|
}
|
|
11831
12114
|
}
|
|
11832
12115
|
var digitPatterns = createDigitPatterns();
|
|
12116
|
+
// Longer raw labels are dropped, not cut short.
|
|
12117
|
+
var MAX_RAW_LABEL_LENGTH = 128;
|
|
11833
12118
|
// The label as logged: lower case, at most 64 characters, digits and amounts
|
|
11834
12119
|
// masked. Dropped when it looks like an email, phone or card number.
|
|
11835
12120
|
function maskLabel(raw) {
|
|
11836
|
-
if (!raw || raw.length >
|
|
12121
|
+
if (!raw || raw.length > MAX_RAW_LABEL_LENGTH || !digitPatterns) {
|
|
11837
12122
|
return undefined;
|
|
11838
12123
|
}
|
|
11839
12124
|
var text = raw.replace(/\s+/g, ' ').trim().toLowerCase();
|
|
@@ -11855,24 +12140,139 @@ var mParticle = (function () {
|
|
|
11855
12140
|
}
|
|
11856
12141
|
return control.matches('a[href]:not([role="button"])') ? 'link' : 'role';
|
|
11857
12142
|
}
|
|
12143
|
+
var NOT_RENDERED = 'script, style, template, [hidden], [aria-hidden="true"], [inert]';
|
|
12144
|
+
// The most nodes read for one label source, and images looked at for one
|
|
12145
|
+
// button. Each costs a style lookup in the click handler.
|
|
12146
|
+
var MAX_READS = 64;
|
|
12147
|
+
function assignedNodes(element) {
|
|
12148
|
+
var slot = element;
|
|
12149
|
+
return isFunction(slot.assignedNodes) ? slot.assignedNodes() : [];
|
|
12150
|
+
}
|
|
12151
|
+
// Left out of what is drawn by its parent: a light child of an open shadow host
|
|
12152
|
+
// that no slot takes, or a slot's own child while nodes are assigned to the
|
|
12153
|
+
// slot. A closed shadow root can't be seen, so its host's children count.
|
|
12154
|
+
function isUnslotted(node) {
|
|
12155
|
+
var parent = node.parentElement;
|
|
12156
|
+
if (!parent) {
|
|
12157
|
+
return false;
|
|
12158
|
+
}
|
|
12159
|
+
return parent.shadowRoot ? !node.assignedSlot : assignedNodes(parent).length > 0;
|
|
12160
|
+
}
|
|
12161
|
+
// Hides the element and all it holds, whatever their own style says.
|
|
12162
|
+
// Screen-reader-only text is clipped rather than hidden, so it is not. An SVG
|
|
12163
|
+
// title is never drawn but names its icon, so it is not either.
|
|
12164
|
+
function hidesSubtree(element) {
|
|
12165
|
+
if (element.matches(NOT_RENDERED) || isUnslotted(element)) {
|
|
12166
|
+
return true;
|
|
12167
|
+
}
|
|
12168
|
+
return !(element instanceof SVGTitleElement) && window.getComputedStyle(element).display === 'none';
|
|
12169
|
+
}
|
|
12170
|
+
// Visibility is inherited and a child can set it back to visible, so only the
|
|
12171
|
+
// element's own counts.
|
|
12172
|
+
function isVisible(element) {
|
|
12173
|
+
var visibility = window.getComputedStyle(element).visibility;
|
|
12174
|
+
return visibility !== 'hidden' && visibility !== 'collapse';
|
|
12175
|
+
}
|
|
12176
|
+
function isShown(element, until) {
|
|
12177
|
+
return !someComposedAncestor(element, hidesSubtree, until);
|
|
12178
|
+
}
|
|
12179
|
+
// A shadow host shows a light child only through a slot, and only while
|
|
12180
|
+
// nothing from that slot up to the host hides it.
|
|
12181
|
+
function isShownThroughSlot(node, host) {
|
|
12182
|
+
var slot = node.assignedSlot;
|
|
12183
|
+
return !!slot && isShown(slot, host);
|
|
12184
|
+
}
|
|
12185
|
+
// Whitespace hides nothing, so a node holding only whitespace is taken as it
|
|
12186
|
+
// is, without a style lookup: an icon's paths cost nothing. A slot's text can
|
|
12187
|
+
// sit in the nodes assigned to it, so a slot is never blank.
|
|
12188
|
+
function isBlank(node) {
|
|
12189
|
+
return !/\S/.test(node.textContent || '') && !(node instanceof Element && (node.matches('slot') || !!node.querySelector('slot')));
|
|
12190
|
+
}
|
|
12191
|
+
// The text a sighted user or a screen reader gets from an element, whitespace
|
|
12192
|
+
// collapsed. Undefined when that runs past what maskLabel keeps, takes more
|
|
12193
|
+
// than MAX_READS nodes to read, or takes in a form field through a slot, so a
|
|
12194
|
+
// label is never cut short at a node boundary.
|
|
12195
|
+
function renderedText(root) {
|
|
12196
|
+
var text = '';
|
|
12197
|
+
var reads = 0;
|
|
12198
|
+
var append = function append(value) {
|
|
12199
|
+
text = (text + value).replace(/\s+/g, ' ');
|
|
12200
|
+
};
|
|
12201
|
+
var _read = function read(element) {
|
|
12202
|
+
if (hidesSubtree(element)) {
|
|
12203
|
+
return true;
|
|
12204
|
+
}
|
|
12205
|
+
var assigned = assignedNodes(element);
|
|
12206
|
+
var nodes = assigned.length ? assigned : element.childNodes;
|
|
12207
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
12208
|
+
var node = nodes[i];
|
|
12209
|
+
var isText = node.nodeType === Node.TEXT_NODE;
|
|
12210
|
+
if (!isText && !(node instanceof Element)) {
|
|
12211
|
+
continue;
|
|
12212
|
+
}
|
|
12213
|
+
if (isBlank(node)) {
|
|
12214
|
+
append(node.textContent);
|
|
12215
|
+
continue;
|
|
12216
|
+
}
|
|
12217
|
+
if (++reads > MAX_READS) {
|
|
12218
|
+
return false;
|
|
12219
|
+
}
|
|
12220
|
+
if (element.shadowRoot && !isShownThroughSlot(node, element)) {
|
|
12221
|
+
continue;
|
|
12222
|
+
}
|
|
12223
|
+
if (isText) {
|
|
12224
|
+
if (isVisible(node.assignedSlot || element)) {
|
|
12225
|
+
append(node.nodeValue);
|
|
12226
|
+
}
|
|
12227
|
+
} else if (
|
|
12228
|
+
// Assigned nodes sit outside the label source, where its own
|
|
12229
|
+
// form field check never looked.
|
|
12230
|
+
assigned.length && isUnsafeTextSource(node) || !_read(node)) {
|
|
12231
|
+
return false;
|
|
12232
|
+
}
|
|
12233
|
+
if (text.trim().length > MAX_RAW_LABEL_LENGTH) {
|
|
12234
|
+
return false;
|
|
12235
|
+
}
|
|
12236
|
+
}
|
|
12237
|
+
return true;
|
|
12238
|
+
};
|
|
12239
|
+
return _read(root) ? text.trim() : undefined;
|
|
12240
|
+
}
|
|
12241
|
+
// '' when the element can't name the button, undefined when its text can't be
|
|
12242
|
+
// read in full.
|
|
11858
12243
|
function textOf(element) {
|
|
11859
|
-
return element && !isUnsafeTextSource(element) && element
|
|
12244
|
+
return element && !isUnsafeTextSource(element) && isShown(element) ? renderedText(element) : '';
|
|
12245
|
+
}
|
|
12246
|
+
// The control itself is already known to be shown.
|
|
12247
|
+
function shownImageAlt(control) {
|
|
12248
|
+
var images = control.querySelectorAll('img[alt]');
|
|
12249
|
+
for (var i = 0; i < images.length && i < MAX_READS; i++) {
|
|
12250
|
+
if (isShown(images[i], control) && isVisible(images[i])) {
|
|
12251
|
+
return nonBlank(images[i].getAttribute('alt'));
|
|
12252
|
+
}
|
|
12253
|
+
}
|
|
12254
|
+
return undefined;
|
|
11860
12255
|
}
|
|
11861
12256
|
function nonBlank(value) {
|
|
11862
12257
|
return value && value.trim() ? value : undefined;
|
|
11863
12258
|
}
|
|
11864
12259
|
// The button's name as a screen reader would read it, simplified: the first of
|
|
11865
|
-
// aria-labelledby, aria-label, own text (or an inner image's alt), title,
|
|
11866
|
-
// inputs their value
|
|
11867
|
-
//
|
|
11868
|
-
// children, so a typed value is never read.
|
|
12260
|
+
// aria-labelledby, aria-label, own text (or an inner image's alt), title, and
|
|
12261
|
+
// for inputs their value. The text sources are skipped for controls that hold
|
|
12262
|
+
// form fields or more than four children, so a typed value is never read.
|
|
11869
12263
|
function accessibleName(control) {
|
|
11870
12264
|
var labelledBy = control.getAttribute('aria-labelledby');
|
|
11871
12265
|
if (labelledBy) {
|
|
11872
12266
|
var root_1 = isFunction(control.getRootNode) ? control.getRootNode() : document;
|
|
11873
|
-
var
|
|
12267
|
+
var parts = labelledBy.split(/\s+/).map(function (id) {
|
|
11874
12268
|
return textOf(root_1.getElementById ? root_1.getElementById(id) : null);
|
|
11875
|
-
})
|
|
12269
|
+
});
|
|
12270
|
+
if (parts.indexOf(undefined) !== -1) {
|
|
12271
|
+
return {
|
|
12272
|
+
source: 'none'
|
|
12273
|
+
};
|
|
12274
|
+
}
|
|
12275
|
+
var text = parts.filter(function (part) {
|
|
11876
12276
|
return !!part;
|
|
11877
12277
|
}).join(' ');
|
|
11878
12278
|
if (text) {
|
|
@@ -11916,27 +12316,21 @@ var mParticle = (function () {
|
|
|
11916
12316
|
source: 'value'
|
|
11917
12317
|
};
|
|
11918
12318
|
}
|
|
11919
|
-
} else if (type === 'checkbox' || type === 'radio') {
|
|
11920
|
-
// The label the browser ties to the box, never the box's value.
|
|
11921
|
-
var label = control.labels ? control.labels[0] : undefined;
|
|
11922
|
-
var text = label && !isUnsafeLabelSource(label) && label.textContent ? label.textContent.trim() : '';
|
|
11923
|
-
if (text) {
|
|
11924
|
-
return {
|
|
11925
|
-
raw: text,
|
|
11926
|
-
source: 'label'
|
|
11927
|
-
};
|
|
11928
|
-
}
|
|
11929
12319
|
}
|
|
11930
|
-
} else if (readable) {
|
|
11931
|
-
var text =
|
|
12320
|
+
} else if (readable && isShown(control)) {
|
|
12321
|
+
var text = renderedText(control);
|
|
12322
|
+
if (text === undefined) {
|
|
12323
|
+
return {
|
|
12324
|
+
source: 'none'
|
|
12325
|
+
};
|
|
12326
|
+
}
|
|
11932
12327
|
if (text) {
|
|
11933
12328
|
return {
|
|
11934
12329
|
raw: text,
|
|
11935
12330
|
source: 'text'
|
|
11936
12331
|
};
|
|
11937
12332
|
}
|
|
11938
|
-
var
|
|
11939
|
-
var alt = image ? nonBlank(image.getAttribute('alt')) : undefined;
|
|
12333
|
+
var alt = shownImageAlt(control);
|
|
11940
12334
|
if (alt) {
|
|
11941
12335
|
return {
|
|
11942
12336
|
raw: alt,
|
|
@@ -12034,13 +12428,16 @@ var mParticle = (function () {
|
|
|
12034
12428
|
return form ? stableIdentifier(form.getAttribute('id')) : undefined;
|
|
12035
12429
|
}
|
|
12036
12430
|
// The browser's normalised type: a button defaults to 'submit' and an unknown
|
|
12037
|
-
// input type reads as 'text'.
|
|
12038
|
-
|
|
12039
|
-
|
|
12431
|
+
// input type reads as 'text'. A native button or input reports its own type, a
|
|
12432
|
+
// wallet-named one included; any other control, such as a role button or a
|
|
12433
|
+
// vendor's wallet element, reads as 'button'.
|
|
12434
|
+
function controlType(control) {
|
|
12435
|
+
var tag = control.tagName.toLowerCase();
|
|
12436
|
+
return tag === 'button' || tag === 'input' ? control.type : 'button';
|
|
12040
12437
|
}
|
|
12041
12438
|
// Reads the link's own resolved URL parts, never its full href: only the hostname of
|
|
12042
|
-
// a link that leaves the site and the extension of a file it downloads travel.
|
|
12043
|
-
//
|
|
12439
|
+
// a link that leaves the site and the extension of a file it downloads travel.
|
|
12440
|
+
// mailto:, tel: and other schemes give undefined.
|
|
12044
12441
|
function describeLink(link) {
|
|
12045
12442
|
var href = (link.getAttribute('href') || '').trim();
|
|
12046
12443
|
if (!href || href.charAt(0) === '#') {
|
|
@@ -12077,43 +12474,149 @@ var mParticle = (function () {
|
|
|
12077
12474
|
}
|
|
12078
12475
|
return link.pathname === window.location.pathname && link.search === window.location.search ? {
|
|
12079
12476
|
type: 'same_page'
|
|
12080
|
-
} :
|
|
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';
|
|
12081
12485
|
}
|
|
12082
|
-
//
|
|
12083
|
-
//
|
|
12084
|
-
|
|
12486
|
+
// Checkboxes and radios, and the roles that act as them. A role can list
|
|
12487
|
+
// fallbacks, so any of its tokens counts.
|
|
12488
|
+
var CHOICE = 'input[type="checkbox"], input[type="radio"], [role~="checkbox"], [role~="radio"], ' + '[role~="switch"], [role~="menuitemcheckbox"], [role~="menuitemradio"]';
|
|
12489
|
+
var RADIO_ROLE = '[role~="radio"], [role~="menuitemradio"]';
|
|
12490
|
+
function boxOf(element) {
|
|
12491
|
+
var box = element instanceof HTMLLabelElement ? element.control : element;
|
|
12492
|
+
return box && box.matches(CHOICE) ? box : null;
|
|
12493
|
+
}
|
|
12494
|
+
function isRadio(choice) {
|
|
12495
|
+
return choice instanceof HTMLInputElement ? choice.type === 'radio' : !!choice && choice.matches(RADIO_ROLE);
|
|
12496
|
+
}
|
|
12497
|
+
// The box a click on this control picks. One the click passed through below
|
|
12498
|
+
// the control comes first: querySelector can't reach a slotted box, a box in a
|
|
12499
|
+
// shadow root or the box of a label inside the control, and a row can hold
|
|
12500
|
+
// more than one box. Else the control itself, the box it labels, or the first
|
|
12501
|
+
// one it wraps, as on an option row whose name repeats the option's text.
|
|
12502
|
+
function choiceOf(control, path) {
|
|
12503
|
+
for (var _i = 0, path_1 = path; _i < path_1.length; _i++) {
|
|
12504
|
+
var target = path_1[_i];
|
|
12505
|
+
if (target === control) {
|
|
12506
|
+
break;
|
|
12507
|
+
}
|
|
12508
|
+
var box = target instanceof Element ? boxOf(target) : null;
|
|
12509
|
+
if (box) {
|
|
12510
|
+
return box;
|
|
12511
|
+
}
|
|
12512
|
+
}
|
|
12513
|
+
return boxOf(control) || control.querySelector(CHOICE);
|
|
12514
|
+
}
|
|
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.
|
|
12518
|
+
function describeButtonClick(control, path) {
|
|
12519
|
+
if (path === void 0) {
|
|
12520
|
+
path = [];
|
|
12521
|
+
}
|
|
12085
12522
|
var link;
|
|
12086
12523
|
if (control.matches('a[href]:not([role="button"])')) {
|
|
12087
12524
|
link = describeLink(control);
|
|
12088
12525
|
if (!link) {
|
|
12089
12526
|
return undefined;
|
|
12090
12527
|
}
|
|
12528
|
+
} else if (control.matches('a[href]')) {
|
|
12529
|
+
link = describeLink(control);
|
|
12530
|
+
if (link && link.type === 'same_page') {
|
|
12531
|
+
link = undefined;
|
|
12532
|
+
}
|
|
12091
12533
|
}
|
|
12092
12534
|
var element = elementKind(control);
|
|
12093
|
-
var
|
|
12094
|
-
|
|
12535
|
+
var box = control instanceof HTMLInputElement && (control.type === 'checkbox' || control.type === 'radio') ? control : undefined;
|
|
12536
|
+
// A box's text sent with its state is the shopper's answer, and the text
|
|
12537
|
+
// can be a name, an address or a sensitive choice, so a box goes by its
|
|
12538
|
+
// hand-written identifiers alone. So does a control acting as one or
|
|
12539
|
+
// wrapping one, and a label, whose click the browser passes on to its box
|
|
12540
|
+
// as a second event.
|
|
12541
|
+
var choice = box || choiceOf(control, path);
|
|
12542
|
+
// A checkbox's identifiers name its question, which its state answers. A
|
|
12543
|
+
// radio's id, test id and the panel it opens name the option picked, so
|
|
12544
|
+
// only the name of its input, the question, goes with it. A wrapper's own
|
|
12545
|
+
// name, or a role radio's, can name the option instead.
|
|
12546
|
+
var radio = isRadio(choice);
|
|
12547
|
+
var named = !radio ? control : choice instanceof HTMLInputElement ? choice : null;
|
|
12548
|
+
var name = choice ? undefined : accessibleName(control);
|
|
12549
|
+
var label = name ? maskLabel(name.raw) : undefined;
|
|
12095
12550
|
return {
|
|
12096
12551
|
label: label,
|
|
12097
12552
|
labelSource: label ? name.source : 'none',
|
|
12098
12553
|
// Kept on its own as well: it often says more than the visible text,
|
|
12099
12554
|
// such as which item a remove button removes.
|
|
12100
|
-
ariaLabel: maskLabel(control.getAttribute('aria-label')),
|
|
12101
|
-
icon: iconHint(control),
|
|
12102
|
-
elementId: stableIdentifier(control.getAttribute('id')),
|
|
12103
|
-
elementName: stableIdentifier(
|
|
12104
|
-
testId: firstIdentifier(control, TEST_ID_ATTRIBUTES),
|
|
12105
|
-
controls: controlsIdentifier(control),
|
|
12555
|
+
ariaLabel: choice ? undefined : maskLabel(control.getAttribute('aria-label')),
|
|
12556
|
+
icon: choice ? undefined : iconHint(control),
|
|
12557
|
+
elementId: radio ? undefined : stableIdentifier(control.getAttribute('id')),
|
|
12558
|
+
elementName: stableIdentifier(named && named.getAttribute('name')),
|
|
12559
|
+
testId: radio ? undefined : firstIdentifier(control, TEST_ID_ATTRIBUTES),
|
|
12560
|
+
controls: radio ? undefined : controlsIdentifier(control),
|
|
12106
12561
|
form: formIdentifier(control),
|
|
12107
12562
|
element: element,
|
|
12108
|
-
type: controlType(control
|
|
12563
|
+
type: controlType(control),
|
|
12109
12564
|
linkType: link ? link.type : undefined,
|
|
12110
12565
|
linkDomain: link ? link.domain : undefined,
|
|
12111
12566
|
fileExtension: link ? link.fileExtension : undefined,
|
|
12112
12567
|
// The box as the click left it: the browser toggles it before the click
|
|
12113
12568
|
// reaches listeners, and puts it back if the click is cancelled.
|
|
12114
|
-
checked:
|
|
12569
|
+
checked: box ? box.checked : undefined
|
|
12115
12570
|
};
|
|
12116
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
|
+
}
|
|
12117
12620
|
|
|
12118
12621
|
var checkoutPath = /(?:^|\/)(?:checkouts?|payment|order|kasse|paiement|commander?|pago)(?:\/|$)/i;
|
|
12119
12622
|
// English look-alikes are whole words; the other languages stay substring
|
|
@@ -12128,6 +12631,12 @@ var mParticle = (function () {
|
|
|
12128
12631
|
var linkCommits = new RegExp('^(?:(?:place|submit|complete)(?!(?: [^ ]+){0,2} (?:another|new|next)(?: |$))(?: [^ ]+){0,2} (?:order|purchase)|' + otherCommits + ')$');
|
|
12129
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)$');
|
|
12130
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('|') + ')$');
|
|
12634
|
+
var CART_NOUN = '(?:(?:my|your|the) )?(?:shopping )?(?:cart|bag|basket)';
|
|
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 + ')$');
|
|
12131
12640
|
var WALLET_NAMES = 'apple pay|google pay|paypal|venmo|amazon pay|shop pay|klarna|afterpay|clearpay|cash app(?: pay)?|affirm|sezzle|samsung pay';
|
|
12132
12641
|
var WALLET_VERBS = 'pay|buy|purchase|order|book|donate|subscribe|check ?out|checkout|express checkout|continue|proceed|' + 'complete purchase|place (?:my |your )?order';
|
|
12133
12642
|
// "Pay with Klarna", "Buy with GPay", "Continue to PayPal".
|
|
@@ -12135,14 +12644,27 @@ var mParticle = (function () {
|
|
|
12135
12644
|
// A wallet's own name on a button: "PayPal", "Klarna checkout", "Apple Pay logo".
|
|
12136
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))*)?$');
|
|
12137
12646
|
// Exact HTTPS hosts of hosted wallet button frames.
|
|
12138
|
-
var
|
|
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
|
+
};
|
|
12139
12653
|
// PayPal serves its buttons and its card fields and pay-later messages from
|
|
12140
12654
|
// the same hosts; only the button frames are wallet taps.
|
|
12141
12655
|
var paypalFrameHosts = new Set(['www.paypal.com', 'www.sandbox.paypal.com']);
|
|
12142
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)__/;
|
|
12143
12662
|
// Stripe's quick-pay button frames; its other frames are card and form fields.
|
|
12144
12663
|
var STRIPE_WALLET_FRAME = /\/elements-inner-(?:payment-request|express-checkout)-/;
|
|
12664
|
+
var STRIPE_CARD_FRAME = /\/elements-inner-card\b/;
|
|
12145
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.
|
|
12146
12668
|
var CARD_FRAME_DOMAINS = ['adyen.com', 'braintreegateway.com', 'cybersource.com', 'squarecdn.com', 'checkout.com'];
|
|
12147
12669
|
// Keep these classes ASCII-only in source bytes to avoid mojibake parse failures
|
|
12148
12670
|
// when a host page forces non-UTF-8 decoding before JavaScript parse.
|
|
@@ -12203,6 +12725,22 @@ var mParticle = (function () {
|
|
|
12203
12725
|
return !!label;
|
|
12204
12726
|
});
|
|
12205
12727
|
}
|
|
12728
|
+
// A cart button is often a bare icon, so its title names it when nothing else
|
|
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.
|
|
12732
|
+
function isCartControl(control, cores) {
|
|
12733
|
+
var title = cores.length ? undefined : normalize(control.getAttribute('title'));
|
|
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);
|
|
12742
|
+
});
|
|
12743
|
+
}
|
|
12206
12744
|
// "Buy now" and "Purchase" count only on a checkout route, and never on a plain
|
|
12207
12745
|
// link, which is navigation.
|
|
12208
12746
|
function isCommitLabel(text, isLink, pathname) {
|
|
@@ -12214,20 +12752,33 @@ var mParticle = (function () {
|
|
|
12214
12752
|
// Classifies a clicked or submitting control found by findControl, in order:
|
|
12215
12753
|
// pickers, toggles and pay-later messages never count; a vendor's own wallet
|
|
12216
12754
|
// button counts before any label rule; a confirm label on any source counts
|
|
12217
|
-
// before the look-alike exclusions veto; then wallet
|
|
12755
|
+
// before the look-alike exclusions veto; then a wallet-named control, wallet
|
|
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.
|
|
12218
12758
|
function classifyIntent(control, pathname) {
|
|
12219
12759
|
var vendor = vendorButtonKind(control);
|
|
12220
|
-
if (
|
|
12760
|
+
if (vendor === 'none') {
|
|
12221
12761
|
return undefined;
|
|
12222
12762
|
}
|
|
12223
12763
|
if (vendor) {
|
|
12224
|
-
return {
|
|
12764
|
+
return isQuietIntentControl(control, vendor === 'wallet') ? undefined : {
|
|
12225
12765
|
kind: vendor,
|
|
12226
12766
|
source: 'vendor'
|
|
12227
12767
|
};
|
|
12228
12768
|
}
|
|
12229
12769
|
var texts = labels(control);
|
|
12230
12770
|
var cores = texts.map(coreLabel);
|
|
12771
|
+
var cart = isCartControl(control, cores) ? {
|
|
12772
|
+
kind: 'cart',
|
|
12773
|
+
source: 'label'
|
|
12774
|
+
} : undefined;
|
|
12775
|
+
if (isQuietIntentControl(control, false, !!cart)) {
|
|
12776
|
+
return undefined;
|
|
12777
|
+
}
|
|
12778
|
+
// A bag button that opens a flyout counts only as a cart click.
|
|
12779
|
+
if (cart && control.hasAttribute('aria-expanded')) {
|
|
12780
|
+
return cart;
|
|
12781
|
+
}
|
|
12231
12782
|
var isLink = control.matches('a[href]:not([role="button"])');
|
|
12232
12783
|
if (cores.some(function (text) {
|
|
12233
12784
|
return isCommitLabel(text, isLink, pathname);
|
|
@@ -12240,7 +12791,13 @@ var mParticle = (function () {
|
|
|
12240
12791
|
if (texts.concat(cores).some(function (text) {
|
|
12241
12792
|
return englishExclusions.test(text) || otherExclusions.test(text);
|
|
12242
12793
|
})) {
|
|
12243
|
-
return
|
|
12794
|
+
return cart;
|
|
12795
|
+
}
|
|
12796
|
+
if (isWalletNamedControl(control)) {
|
|
12797
|
+
return {
|
|
12798
|
+
kind: 'wallet',
|
|
12799
|
+
source: 'name'
|
|
12800
|
+
};
|
|
12244
12801
|
}
|
|
12245
12802
|
var isButton = !isLink && control.matches(CONTROL_SELECTOR);
|
|
12246
12803
|
for (var _i = 0, cores_1 = cores; _i < cores_1.length; _i++) {
|
|
@@ -12264,37 +12821,73 @@ var mParticle = (function () {
|
|
|
12264
12821
|
};
|
|
12265
12822
|
}
|
|
12266
12823
|
}
|
|
12267
|
-
return
|
|
12824
|
+
return cart;
|
|
12268
12825
|
}
|
|
12269
12826
|
// The host is the domain or one of its subdomains, never a look-alike suffix.
|
|
12270
12827
|
function isOnDomain(host, domain) {
|
|
12271
12828
|
return host === domain || host.length > domain.length && host.slice(host.length - domain.length - 1) === '.' + domain;
|
|
12272
12829
|
}
|
|
12273
12830
|
// Focus moving into a visible hosted wallet button counts as a wallet click;
|
|
12274
|
-
// focus into hosted card fields or messages is only a frame.
|
|
12275
|
-
|
|
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) {
|
|
12276
12836
|
if (win.document.visibilityState !== 'visible' || !(target instanceof HTMLIFrameElement)) {
|
|
12277
12837
|
return undefined;
|
|
12278
12838
|
}
|
|
12279
12839
|
if (isRoktElement(target) || hasComposedAncestor(target, '[data-mp-no-track]')) {
|
|
12280
12840
|
return undefined;
|
|
12281
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
|
+
}
|
|
12282
12850
|
try {
|
|
12283
12851
|
var url = new URL(target.src);
|
|
12284
12852
|
var host_1 = url.protocol === 'https:' ? url.hostname : '';
|
|
12285
12853
|
if (paypalFrameHosts.has(host_1)) {
|
|
12286
|
-
|
|
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
|
+
};
|
|
12287
12865
|
}
|
|
12288
|
-
if (
|
|
12289
|
-
return
|
|
12866
|
+
if (Object.prototype.hasOwnProperty.call(walletFrameFamilies, host_1)) {
|
|
12867
|
+
return {
|
|
12868
|
+
kind: 'wallet',
|
|
12869
|
+
family: walletFrameFamilies[host_1]
|
|
12870
|
+
};
|
|
12290
12871
|
}
|
|
12291
12872
|
if (host_1 === 'js.stripe.com') {
|
|
12292
|
-
|
|
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
|
+
};
|
|
12293
12884
|
}
|
|
12294
12885
|
if (CARD_FRAME_DOMAINS.some(function (domain) {
|
|
12295
12886
|
return isOnDomain(host_1, domain);
|
|
12296
12887
|
})) {
|
|
12297
|
-
return
|
|
12888
|
+
return {
|
|
12889
|
+
kind: 'frame'
|
|
12890
|
+
};
|
|
12298
12891
|
}
|
|
12299
12892
|
} catch (e) {
|
|
12300
12893
|
// An unparseable frame src is not a wallet frame.
|
|
@@ -12307,6 +12900,8 @@ var mParticle = (function () {
|
|
|
12307
12900
|
var WIN_BTN_KEY = '__mpBtn__';
|
|
12308
12901
|
var THROTTLE_MS = 2000;
|
|
12309
12902
|
var SUBMIT_AFTER_COMMIT_CLICK_MS = 1000;
|
|
12903
|
+
// Apple Pay must begin inside the tap's own handler, so the tap is this recent.
|
|
12904
|
+
var APPLE_PAY_AFTER_CLICK_MS = 1000;
|
|
12310
12905
|
var PATH_LIMIT = 12;
|
|
12311
12906
|
// A ceiling, not a dedupe: a held Enter key or browser automation fires a
|
|
12312
12907
|
// trusted click per repeat, and each one is forwarded to every kit.
|
|
@@ -12345,6 +12940,63 @@ var mParticle = (function () {
|
|
|
12345
12940
|
setTimeout(fn, 0);
|
|
12346
12941
|
}
|
|
12347
12942
|
};
|
|
12943
|
+
// Apple Pay's session opens only from a shopper's tap, whatever button the page
|
|
12944
|
+
// draws for it, so its opening is a wallet tap no label or name rule can miss.
|
|
12945
|
+
// The wrapper keeps the page's own begin under this key, to put it back.
|
|
12946
|
+
var APPLE_PAY_HOOK = '__mpApplePayHook__';
|
|
12947
|
+
var applePayPrototype = function applePayPrototype(win) {
|
|
12948
|
+
var session = win['ApplePaySession'];
|
|
12949
|
+
return session && session.prototype;
|
|
12950
|
+
};
|
|
12951
|
+
// Wraps ApplePaySession.prototype.begin once per window, so the active tracker
|
|
12952
|
+
// hears that a session began. The wrapper reads no arguments and no payment
|
|
12953
|
+
// data, and returns or throws exactly what the original does. Nothing here can
|
|
12954
|
+
// throw into SDK init: a throwing getter or a frozen prototype leaves Apple Pay
|
|
12955
|
+
// as it was.
|
|
12956
|
+
var hookApplePay = function hookApplePay(win) {
|
|
12957
|
+
try {
|
|
12958
|
+
var prototype = applePayPrototype(win);
|
|
12959
|
+
var begin_1 = prototype && prototype.begin;
|
|
12960
|
+
if (!isFunction(begin_1) || begin_1[APPLE_PAY_HOOK]) {
|
|
12961
|
+
return;
|
|
12962
|
+
}
|
|
12963
|
+
var opened = function opened() {
|
|
12964
|
+
var args = [];
|
|
12965
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
12966
|
+
args[_i] = arguments[_i];
|
|
12967
|
+
}
|
|
12968
|
+
var result = begin_1.apply(this, args);
|
|
12969
|
+
try {
|
|
12970
|
+
var tracker = getActiveButtonTracker();
|
|
12971
|
+
if (tracker) {
|
|
12972
|
+
tracker.onApplePayBegin();
|
|
12973
|
+
}
|
|
12974
|
+
} catch (e) {
|
|
12975
|
+
// A session the page began is never disturbed by tracking.
|
|
12976
|
+
}
|
|
12977
|
+
return result;
|
|
12978
|
+
};
|
|
12979
|
+
// Not enumerable, so the marker doesn't show among the method's own keys.
|
|
12980
|
+
Object.defineProperty(opened, APPLE_PAY_HOOK, {
|
|
12981
|
+
value: begin_1
|
|
12982
|
+
});
|
|
12983
|
+
prototype.begin = opened;
|
|
12984
|
+
} catch (e) {
|
|
12985
|
+
// Apple Pay stays as the page set it up.
|
|
12986
|
+
}
|
|
12987
|
+
};
|
|
12988
|
+
// Puts the page's own begin back, unless another script has wrapped it since.
|
|
12989
|
+
var unhookApplePay = function unhookApplePay(win) {
|
|
12990
|
+
try {
|
|
12991
|
+
var prototype = applePayPrototype(win);
|
|
12992
|
+
var begin = prototype && prototype.begin;
|
|
12993
|
+
if (isFunction(begin) && isFunction(begin[APPLE_PAY_HOOK])) {
|
|
12994
|
+
prototype.begin = begin[APPLE_PAY_HOOK];
|
|
12995
|
+
}
|
|
12996
|
+
} catch (e) {
|
|
12997
|
+
// Apple Pay stays as it is.
|
|
12998
|
+
}
|
|
12999
|
+
};
|
|
12348
13000
|
var CAPTURE_PASSIVE = {
|
|
12349
13001
|
capture: true,
|
|
12350
13002
|
passive: true
|
|
@@ -12352,16 +13004,22 @@ var mParticle = (function () {
|
|
|
12352
13004
|
var PASSIVE = {
|
|
12353
13005
|
passive: true
|
|
12354
13006
|
};
|
|
12355
|
-
// Logs
|
|
12356
|
-
// 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.
|
|
12357
13010
|
var ButtonTracker = /** @class */function () {
|
|
12358
13011
|
function ButtonTracker(mpInstance) {
|
|
12359
13012
|
var _this = this;
|
|
12360
13013
|
this.active = false;
|
|
12361
13014
|
this.hasRoktKit = false;
|
|
13015
|
+
this.logButtons = false;
|
|
13016
|
+
this.logLinks = false;
|
|
12362
13017
|
// Bumped on reset so classification queued before it is dropped.
|
|
12363
13018
|
this.generation = 0;
|
|
12364
13019
|
this.lastCommitClick = -Infinity;
|
|
13020
|
+
// The latest trusted click: whether the page excluded it, and the intent it
|
|
13021
|
+
// already carries to the kit, with its source, if any.
|
|
13022
|
+
this.lastClick = null;
|
|
12365
13023
|
this.lastSent = {};
|
|
12366
13024
|
this.pagePath = null;
|
|
12367
13025
|
this.pageEvents = 0;
|
|
@@ -12429,7 +13087,9 @@ var mParticle = (function () {
|
|
|
12429
13087
|
this.teardown();
|
|
12430
13088
|
}
|
|
12431
13089
|
this.hasRoktKit = options.hasRoktKit;
|
|
12432
|
-
|
|
13090
|
+
this.logButtons = options.logButtons;
|
|
13091
|
+
this.logLinks = options.logLinks;
|
|
13092
|
+
if ((!(this.logButtons || this.logLinks) || !this.eventsEnabled()) && this.isKitSuppressed()) {
|
|
12433
13093
|
this.log('opted out, not starting');
|
|
12434
13094
|
return;
|
|
12435
13095
|
}
|
|
@@ -12445,8 +13105,40 @@ var mParticle = (function () {
|
|
|
12445
13105
|
win[WIN_BTN_KEY] = {};
|
|
12446
13106
|
}
|
|
12447
13107
|
win[WIN_BTN_KEY].tracker = this;
|
|
13108
|
+
// Only where checkout intent can reach the kit; a shopper who opts back in mid-page gets no session
|
|
13109
|
+
// signal until the next page load.
|
|
13110
|
+
if (!this.isKitSuppressed()) {
|
|
13111
|
+
hookApplePay(win);
|
|
13112
|
+
}
|
|
12448
13113
|
this.log('listening');
|
|
12449
13114
|
};
|
|
13115
|
+
// An Apple Pay session begun right after a tracked tap counts as a wallet
|
|
13116
|
+
// tap for the kit; one begun with no such tap, or from a tap the page
|
|
13117
|
+
// excluded, does not. A tap that reads as a confirm tap reaches the kit as
|
|
13118
|
+
// one. It is delivered on a timer, not after the next paint, since the
|
|
13119
|
+
// payment sheet may hold painting back: a tap that already reads as a
|
|
13120
|
+
// wallet goes now under its own rule, and the throttle drops the copy
|
|
13121
|
+
// queued for the paint.
|
|
13122
|
+
ButtonTracker.prototype.onApplePayBegin = function () {
|
|
13123
|
+
var _this = this;
|
|
13124
|
+
var t = Date.now();
|
|
13125
|
+
var click = this.lastClick;
|
|
13126
|
+
if (!this.active || !click || click.excluded || click.kind === 'commit' || t - click.t > APPLE_PAY_AFTER_CLICK_MS || this.isKitSuppressed()) {
|
|
13127
|
+
return;
|
|
13128
|
+
}
|
|
13129
|
+
var pathname = window.location.pathname;
|
|
13130
|
+
var generation = this.generation;
|
|
13131
|
+
setTimeout(function () {
|
|
13132
|
+
if (generation !== _this.generation) {
|
|
13133
|
+
return;
|
|
13134
|
+
}
|
|
13135
|
+
try {
|
|
13136
|
+
_this.emit('wallet', click.kind === 'wallet' ? click.source : 'api', 'apple_pay', t, pathname);
|
|
13137
|
+
} catch (e) {
|
|
13138
|
+
_this.log('[error] Apple Pay delivery threw: ' + e);
|
|
13139
|
+
}
|
|
13140
|
+
}, 0);
|
|
13141
|
+
};
|
|
12450
13142
|
ButtonTracker.prototype.teardown = function () {
|
|
12451
13143
|
var win = btnWindow();
|
|
12452
13144
|
if (win) {
|
|
@@ -12460,6 +13152,7 @@ var mParticle = (function () {
|
|
|
12460
13152
|
var state = win[WIN_BTN_KEY];
|
|
12461
13153
|
if (state && state.tracker === this) {
|
|
12462
13154
|
state.tracker = undefined;
|
|
13155
|
+
unhookApplePay(win);
|
|
12463
13156
|
}
|
|
12464
13157
|
}
|
|
12465
13158
|
this.active = false;
|
|
@@ -12479,6 +13172,7 @@ var mParticle = (function () {
|
|
|
12479
13172
|
this.generation++;
|
|
12480
13173
|
this.pending = [];
|
|
12481
13174
|
this.lastCommitClick = -Infinity;
|
|
13175
|
+
this.lastClick = null;
|
|
12482
13176
|
this.lastSent = {};
|
|
12483
13177
|
this.pagePath = null;
|
|
12484
13178
|
this.pageEvents = 0;
|
|
@@ -12496,7 +13190,7 @@ var mParticle = (function () {
|
|
|
12496
13190
|
return;
|
|
12497
13191
|
}
|
|
12498
13192
|
var layer = event.type;
|
|
12499
|
-
var logsEvents = layer === 'click' && this.eventsEnabled();
|
|
13193
|
+
var logsEvents = layer === 'click' && (this.logButtons || this.logLinks) && this.eventsEnabled() && !this.hasTargetingOptOut();
|
|
12500
13194
|
var signalsKit = !this.isKitSuppressed();
|
|
12501
13195
|
if (!logsEvents && !signalsKit) {
|
|
12502
13196
|
return;
|
|
@@ -12508,15 +13202,31 @@ var mParticle = (function () {
|
|
|
12508
13202
|
// button that disables or relabels itself is seen as it was clicked.
|
|
12509
13203
|
// Logging and the kit hand-off wait for the next paint.
|
|
12510
13204
|
var click;
|
|
13205
|
+
var asLink = false;
|
|
12511
13206
|
var box;
|
|
12512
13207
|
var kind;
|
|
12513
13208
|
var source;
|
|
13209
|
+
var choice;
|
|
13210
|
+
var family;
|
|
12514
13211
|
var unconfirmedCommit = false;
|
|
12515
13212
|
if (layer === 'click') {
|
|
12516
13213
|
// The composed path is only populated during dispatch.
|
|
12517
|
-
var
|
|
13214
|
+
var path = isFunction(event.composedPath) ? event.composedPath().slice(0, PATH_LIMIT) : [];
|
|
13215
|
+
var excluded = isExcludedPath(path);
|
|
13216
|
+
var control = excluded ? undefined : findControl(path, true);
|
|
12518
13217
|
if (control) {
|
|
12519
|
-
|
|
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
|
+
}
|
|
12520
13230
|
if (click && click.checked !== undefined) {
|
|
12521
13231
|
box = control;
|
|
12522
13232
|
}
|
|
@@ -12524,7 +13234,14 @@ var mParticle = (function () {
|
|
|
12524
13234
|
var intent = signalsKit ? classifyIntent(control, pathname) : undefined;
|
|
12525
13235
|
kind = intent ? intent.kind : undefined;
|
|
12526
13236
|
source = intent ? intent.source : undefined;
|
|
13237
|
+
choice = signalsKit ? describePaymentChoice(control, path) : undefined;
|
|
12527
13238
|
}
|
|
13239
|
+
this.lastClick = {
|
|
13240
|
+
t: t,
|
|
13241
|
+
excluded: excluded,
|
|
13242
|
+
kind: kind,
|
|
13243
|
+
source: source
|
|
13244
|
+
};
|
|
12528
13245
|
} else if (layer === 'submit') {
|
|
12529
13246
|
var submitter = event.submitter;
|
|
12530
13247
|
var control = submitter ? findControl([submitter]) : undefined;
|
|
@@ -12549,7 +13266,9 @@ var mParticle = (function () {
|
|
|
12549
13266
|
if (layer === 'blur') {
|
|
12550
13267
|
// Read after the blur settles: some browsers have not moved
|
|
12551
13268
|
// focus into the frame yet when the window blurs.
|
|
12552
|
-
|
|
13269
|
+
var frame = classifyPaymentFrame(document.activeElement, window);
|
|
13270
|
+
kind = frame ? frame.kind : undefined;
|
|
13271
|
+
family = frame ? frame.family : undefined;
|
|
12553
13272
|
source = 'frame';
|
|
12554
13273
|
} else if (unconfirmedCommit && t - _this.lastCommitClick > SUBMIT_AFTER_COMMIT_CLICK_MS) {
|
|
12555
13274
|
kind = undefined;
|
|
@@ -12563,7 +13282,14 @@ var mParticle = (function () {
|
|
|
12563
13282
|
if (box && event.defaultPrevented) {
|
|
12564
13283
|
click.checked = box.type === 'checkbox' ? !click.checked : box.checked;
|
|
12565
13284
|
}
|
|
12566
|
-
_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);
|
|
12567
13293
|
}
|
|
12568
13294
|
if (kind) {
|
|
12569
13295
|
_this.emit(kind, source, layer, t, pathname);
|
|
@@ -12574,8 +13300,8 @@ var mParticle = (function () {
|
|
|
12574
13300
|
});
|
|
12575
13301
|
};
|
|
12576
13302
|
// Every real click is one event, repeats included, up to a ceiling per page.
|
|
12577
|
-
ButtonTracker.prototype.logClick = function (click, pathname) {
|
|
12578
|
-
if (!this.eventsEnabled()) {
|
|
13303
|
+
ButtonTracker.prototype.logClick = function (click, pathname, asLink) {
|
|
13304
|
+
if (!this.eventsEnabled() || this.hasTargetingOptOut()) {
|
|
12579
13305
|
return;
|
|
12580
13306
|
}
|
|
12581
13307
|
if (pathname !== this.pagePath) {
|
|
@@ -12589,7 +13315,7 @@ var mParticle = (function () {
|
|
|
12589
13315
|
// Restarts an expired session, as public logEvent() and page views do.
|
|
12590
13316
|
this.mpInstance._SessionManager.resetSessionTimer();
|
|
12591
13317
|
var queued = this.queuedForUpload();
|
|
12592
|
-
this.mpInstance._Events.logEvent(buildButtonClickEvent(click, pathname));
|
|
13318
|
+
this.mpInstance._Events.logEvent(asLink ? buildLinkClickEvent(click, pathname) : buildButtonClickEvent(click, pathname));
|
|
12593
13319
|
// Only a click waiting for the batch interval is sent early: a held
|
|
12594
13320
|
// one goes out when released, and with batching off it already has.
|
|
12595
13321
|
// A checkbox or radio waits for the batch, since choosing an option
|
|
@@ -12651,11 +13377,29 @@ var mParticle = (function () {
|
|
|
12651
13377
|
pathname: pathname
|
|
12652
13378
|
}), pathname);
|
|
12653
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
|
+
};
|
|
12654
13391
|
// Events follow the SDK's opt-out like any other event.
|
|
12655
13392
|
ButtonTracker.prototype.eventsEnabled = function () {
|
|
12656
13393
|
var store = this.mpInstance._Store;
|
|
12657
13394
|
return !!store && store.isEnabled;
|
|
12658
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
|
+
};
|
|
12659
13403
|
// The Rokt manager owns the kit's privacy gates: flag, opt-out, launcher
|
|
12660
13404
|
// options and Global Privacy Control.
|
|
12661
13405
|
ButtonTracker.prototype.isKitSuppressed = function () {
|
|
@@ -13600,7 +14344,8 @@ var mParticle = (function () {
|
|
|
13600
14344
|
var getFeatureFlag = mpInstance._Helpers.getFeatureFlag;
|
|
13601
14345
|
var _e = Constants.FeatureFlags,
|
|
13602
14346
|
AutoLogPageView = _e.AutoLogPageView,
|
|
13603
|
-
AutoButtonTracking = _e.AutoButtonTracking
|
|
14347
|
+
AutoButtonTracking = _e.AutoButtonTracking,
|
|
14348
|
+
AutoLinkTracking = _e.AutoLinkTracking;
|
|
13604
14349
|
// Destroy previous batch uploader to prevent leaked timers and event listeners
|
|
13605
14350
|
if ((_a = mpInstance._APIClient) === null || _a === void 0 ? void 0 : _a.uploader) {
|
|
13606
14351
|
mpInstance._APIClient.uploader.destroy();
|
|
@@ -13618,6 +14363,7 @@ var mParticle = (function () {
|
|
|
13618
14363
|
mpInstance._NativeSdkHelpers.initializeSessionAttributes(apiKey);
|
|
13619
14364
|
// Button tracking never runs as a native passthrough.
|
|
13620
14365
|
resetButtonTracking();
|
|
14366
|
+
mpInstance._RoktManager.setAutoButtonClicksForwarded(false);
|
|
13621
14367
|
} else {
|
|
13622
14368
|
// Main SDK initialization flow
|
|
13623
14369
|
// Load any settings/identities/attributes from cookie or localStorage
|
|
@@ -13662,6 +14408,20 @@ var mParticle = (function () {
|
|
|
13662
14408
|
// https://go.mparticle.com/work/SQDSDKS-7339
|
|
13663
14409
|
mpInstance._RoktManager.init(roktConfig_1, createRoktFilteredUser(currentUserMPID), mpInstance.Identity, mpInstance._Store, mpInstance.Logger, roktOptions, mpInstance.captureTiming, mpInstance._ErrorReportingDispatcher, mpInstance._LoggingDispatcher, mpInstance._IntegrationCapture, createRoktFilteredUser);
|
|
13664
14410
|
}
|
|
14411
|
+
// Checkout intent comes from the shopper's clicks, so it goes to the
|
|
14412
|
+
// Rokt kit only when that kit receives them. Set before
|
|
14413
|
+
// processForwarders: the kit can read it during this init, from its own
|
|
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.
|
|
14419
|
+
var buttonClickBlocker = roktConfig_1 ? getButtonClickBlocker(roktConfig_1, kitBlocker) : undefined;
|
|
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."));
|
|
14423
|
+
}
|
|
14424
|
+
mpInstance._RoktManager.setAutoButtonClicksForwarded(!!roktConfig_1 && !buttonClickBlocker && !linkClickBlocker);
|
|
13665
14425
|
mpInstance._Forwarders.processForwarders(config, mpInstance._APIClient.prepareForwardingStats);
|
|
13666
14426
|
mpInstance._Forwarders.processPixelConfigs(config);
|
|
13667
14427
|
// Checks if session is created, resumed, or needs to be ended
|
|
@@ -13696,14 +14456,14 @@ var mParticle = (function () {
|
|
|
13696
14456
|
// so it stops listening. Re-created if the flag is re-enabled later.
|
|
13697
14457
|
mpInstance._PageViewTracker.teardown();
|
|
13698
14458
|
}
|
|
13699
|
-
|
|
13700
|
-
// intent also goes to the Rokt kit when this init configures one.
|
|
13701
|
-
if (getFeatureFlag(AutoButtonTracking)) {
|
|
14459
|
+
if (logButtons || logLinks) {
|
|
13702
14460
|
if (!mpInstance._ButtonTracker) {
|
|
13703
14461
|
mpInstance._ButtonTracker = new ButtonTracker(mpInstance);
|
|
13704
14462
|
}
|
|
13705
14463
|
mpInstance._ButtonTracker.init({
|
|
13706
|
-
hasRoktKit: !!roktConfig_1
|
|
14464
|
+
hasRoktKit: !!roktConfig_1,
|
|
14465
|
+
logButtons: logButtons,
|
|
14466
|
+
logLinks: logLinks
|
|
13707
14467
|
});
|
|
13708
14468
|
} else {
|
|
13709
14469
|
// Also retires a tracker left by an earlier bundle load. Like APV,
|
|
@@ -13809,10 +14569,12 @@ var mParticle = (function () {
|
|
|
13809
14569
|
// Initialize CookieConsentManager with privacy flags from launcherOptions
|
|
13810
14570
|
var _a = normalizeRoktLauncherOptions(config === null || config === void 0 ? void 0 : config.launcherOptions),
|
|
13811
14571
|
noFunctional = _a.noFunctional,
|
|
13812
|
-
noTargeting = _a.noTargeting
|
|
14572
|
+
noTargeting = _a.noTargeting,
|
|
14573
|
+
doNotShareOrSell = _a.doNotShareOrSell;
|
|
13813
14574
|
mpInstance._CookieConsentManager = new CookieConsentManager({
|
|
13814
14575
|
noFunctional: noFunctional,
|
|
13815
|
-
noTargeting: noTargeting
|
|
14576
|
+
noTargeting: noTargeting,
|
|
14577
|
+
doNotShareOrSell: doNotShareOrSell
|
|
13816
14578
|
});
|
|
13817
14579
|
// Check to see if localStorage is available before main configuration runs
|
|
13818
14580
|
// since we will need this for the current implementation of user persistence
|
|
@@ -14308,8 +15070,8 @@ var mParticle = (function () {
|
|
|
14308
15070
|
this.configurePixel = function (settings) {
|
|
14309
15071
|
self.getInstance().configurePixel(settings);
|
|
14310
15072
|
};
|
|
14311
|
-
this._setIntegrationDelay = function (moduleId,
|
|
14312
|
-
self.getInstance()._setIntegrationDelay(moduleId,
|
|
15073
|
+
this._setIntegrationDelay = function (moduleId, boolean) {
|
|
15074
|
+
self.getInstance()._setIntegrationDelay(moduleId, boolean);
|
|
14313
15075
|
};
|
|
14314
15076
|
this._getIntegrationDelays = function () {
|
|
14315
15077
|
return self.getInstance()._getIntegrationDelays();
|