@mparticle/web-sdk 3.19.1 → 3.21.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 +10 -7
- package/dist/mparticle.esm.js +10 -7
- package/dist/mparticle.js +62 -7
- package/dist/types/src/buttonTracking/buttonDescription.d.ts +5 -1
- package/package.json +4 -2
- package/src/buttonTracking/buttonClickEvent.ts +3 -0
- package/src/buttonTracking/buttonDescription.ts +68 -5
package/dist/mparticle.common.js
CHANGED
|
@@ -15,7 +15,7 @@ map:function map(a,b){var c,d,e;if(null===this)throw new TypeError(" this is nul
|
|
|
15
15
|
filter:function filter(a/*, thisArg*/){if(void 0===this||null===this)throw new TypeError;var b=Object(this),c=b.length>>>0;if("function"!=typeof a)throw new TypeError;for(var d=[],e=2<=arguments.length?arguments[1]:void 0,f=0;f<c;f++)if(f in b){var g=b[f];a.call(e,g,f,b)&&d.push(g);}return d},// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
|
|
16
16
|
isArray:function isArray(a){return "[object Array]"===Object.prototype.toString.call(a)},Base64:Base64$1};
|
|
17
17
|
|
|
18
|
-
var version = "3.
|
|
18
|
+
var version = "3.21.0";
|
|
19
19
|
|
|
20
20
|
var Constants={sdkVersion:version,sdkVendor:"mparticle",platform:"web",Messages:{DeprecationMessages:{MethodHasBeenDeprecated:"has been deprecated.",MethodMarkedForDeprecationPostfix:"is a deprecated method and will be removed in future releases.",AlternativeMethodPrefix:"Please use the alternate method:"},ErrorMessages:{NoToken:"A token must be specified.",EventNameInvalidType:"Event name must be a valid string value.",EventDataInvalidType:"Event data must be a valid object hash.",LoggingDisabled:"Event logging is currently disabled.",CookieParseError:"Could not parse cookie",EventEmpty:"Event object is null or undefined, cancelling send",APIRequestEmpty:"APIRequest is null or undefined, cancelling send",NoEventType:"Event type must be specified.",TransactionIdRequired:"Transaction ID is required",TransactionRequired:"A transaction attributes object is required",PromotionIdRequired:"Promotion ID is required",BadAttribute:"Attribute value cannot be object or array",BadKey:"Key value cannot be object or array",BadLogPurchase:"Transaction attributes and a product are both required to log a purchase, https://docs.mparticle.com/?javascript#measuring-transactions",AudienceAPINotEnabled:"Your workspace is not enabled to retrieve user audiences."},InformationMessages:{CookieSearch:"Searching for cookie",CookieFound:"Cookie found, parsing values",CookieNotFound:"Cookies not found",CookieSet:"Setting cookie",CookieSync:"Performing cookie sync",SendBegin:"Starting to send event",SendIdentityBegin:"Starting to send event to identity server",SendWindowsPhone:"Sending event to Windows Phone container",SendIOS:"Calling iOS path: ",SendAndroid:"Calling Android JS interface method: ",SendHttp:"Sending event to mParticle HTTP service",SendAliasHttp:"Sending alias request to mParticle HTTP service",SendIdentityHttp:"Sending event to mParticle HTTP service",StartingNewSession:"Starting new Session",StartingLogEvent:"Starting to log event",StartingLogOptOut:"Starting to log user opt in/out",StartingEndSession:"Starting to end session",StartingInitialization:"Starting to initialize",StartingLogCommerceEvent:"Starting to log commerce event",StartingAliasRequest:"Starting to Alias MPIDs",LoadingConfig:"Loading configuration options",AbandonLogEvent:"Cannot log event, logging disabled or developer token not set",AbandonAliasUsers:"Cannot Alias Users, logging disabled or developer token not set",AbandonStartSession:"Cannot start session, logging disabled or developer token not set",AbandonEndSession:"Cannot end session, logging disabled or developer token not set",NoSessionToEnd:"Cannot end session, no active session found"},ValidationMessages:{ModifyIdentityRequestUserIdentitiesPresent:"identityRequests to modify require userIdentities to be present. Request not sent to server. Please fix and try again",IdentityRequesetInvalidKey:"There is an invalid key on your identityRequest object. It can only contain a `userIdentities` object and a `onUserAlias` function. Request not sent to server. Please fix and try again.",OnUserAliasType:"The onUserAlias value must be a function.",UserIdentities:"The userIdentities key must be an object with keys of identityTypes and values of strings. Request not sent to server. Please fix and try again.",UserIdentitiesInvalidKey:"There is an invalid identity key on your `userIdentities` object within the identityRequest. Request not sent to server. Please fix and try again.",UserIdentitiesInvalidValues:"All user identity values must be strings or null. Request not sent to server. Please fix and try again.",AliasMissingMpid:"Alias Request must contain both a destinationMpid and a sourceMpid",AliasNonUniqueMpid:"Alias Request's destinationMpid and sourceMpid must be unique",AliasMissingTime:"Alias Request must have both a startTime and an endTime",AliasStartBeforeEndTime:"Alias Request's endTime must be later than its startTime"}},NativeSdkPaths:{LogEvent:"logEvent",SetUserTag:"setUserTag",RemoveUserTag:"removeUserTag",SetUserAttribute:"setUserAttribute",RemoveUserAttribute:"removeUserAttribute",SetSessionAttribute:"setSessionAttribute",LogOut:"logOut",SetUserAttributeList:"setUserAttributeList",RemoveAllUserAttributes:"removeAllUserAttributes",GetUserAttributesLists:"getUserAttributesLists",GetAllUserAttributes:"getAllUserAttributes",Identify:"identify",Logout:"logout",Login:"login",Modify:"modify",Alias:"aliasUsers",Upload:"upload"},StorageNames:{localStorageName:"mprtcl-api",localStorageNameV3:"mprtcl-v3",cookieName:"mprtcl-api",cookieNameV2:"mprtcl-v2",cookieNameV3:"mprtcl-v3",localStorageNameV4:"mprtcl-v4",cookieNameV4:"mprtcl-v4",currentStorageName:"mprtcl-v4"},DefaultConfig:{cookieDomain:null,cookieExpiration:365,logLevel:null,timeout:300,sessionTimeout:30,forwarderStatsTimeout:5e3,integrationDelayTimeout:5e3,maxCookieSize:3e3,aliasMaxWindow:90,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
|
|
21
21
|
},DefaultBaseUrls:{v1SecureServiceUrl:"jssdks.mparticle.com/v1/JS/",v2SecureServiceUrl:"jssdks.mparticle.com/v2/JS/",v3SecureServiceUrl:"jssdks.mparticle.com/v3/JS/",configUrl:"jssdkcdns.mparticle.com/JS/v2/",identityUrl:"identity.mparticle.com/v1/",aliasUrl:"jssdks.mparticle.com/v1/identity/",userAudienceUrl:"nativesdks.mparticle.com/v1/"},// These are the paths that are used to construct the CNAME urls
|
|
@@ -1364,7 +1364,7 @@ var BUTTON_CLICK_EVENT_NAME="Auto Button Click";// One custom event per click, l
|
|
|
1364
1364
|
// page fields that auto page views carry. No intent: classifying clicks is left
|
|
1365
1365
|
// to whoever reads the data.
|
|
1366
1366
|
var buildButtonClickEvent=function(a,b){// Optional fields are left out when the button has no safe value for them.
|
|
1367
|
-
for(var c,d,e=(c={label_source:a.labelSource,element:a.element,type:a.type,path:b,hostname:window.location.hostname},c[AUTO_BUTTON_ATTRIBUTE]=!0,c),f={label:a.label,aria_label:a.ariaLabel,icon:a.icon,element_id:a.elementId,element_name:a.elementName,test_id:a.testId,controls:a.controls,form:a.form},g=0,h=Object.keys(f);g<h.length;g++)d=h[g],f[d]&&(e[d]=f[d]);return {messageType:MessageType$1.PageEvent,name:BUTTON_CLICK_EVENT_NAME,data:e,eventType:EventType.Other}};
|
|
1367
|
+
for(var c,d,e=(c={label_source:a.labelSource,element:a.element,type:a.type,path:b,hostname:window.location.hostname},c[AUTO_BUTTON_ATTRIBUTE]=!0,c),f={label:a.label,aria_label:a.ariaLabel,icon:a.icon,element_id:a.elementId,element_name:a.elementName,test_id:a.testId,controls:a.controls,form:a.form,link_type:a.linkType,link_domain:a.linkDomain,file_extension:a.fileExtension},g=0,h=Object.keys(f);g<h.length;g++)d=h[g],f[d]&&(e[d]=f[d]);return {messageType:MessageType$1.PageEvent,name:BUTTON_CLICK_EVENT_NAME,data:e,eventType:EventType.Other}};
|
|
1368
1368
|
|
|
1369
1369
|
// descriptions. Rokt's own elements, disabled controls and anything under
|
|
1370
1370
|
// data-mp-no-track are never returned.
|
|
@@ -1384,7 +1384,7 @@ function createDigitPatterns(){try{return {run:/\p{Nd}{6,}/u,number:/\p{Nd}+(?:[
|
|
|
1384
1384
|
// masked. Dropped when it looks like an email, phone or card number.
|
|
1385
1385
|
function maskLabel(a){if(a&&!(128<a.length)&&digitPatterns){var b=a.replace(/\s+/g," ").trim().toLowerCase();if(b&&-1===b.indexOf("@")&&!digitPatterns.run.test(b.replace(/[\s()\-\u2010-\u2015]/g,""))){var c=b.replace(digitPatterns.number,"#").slice(0,64).trim();return c||void 0}}}
|
|
1386
1386
|
|
|
1387
|
-
function elementKind(a){if(isWalletElement(a))return "wallet";var b=a.tagName.toLowerCase();return "button"===b||"input"===b?b:"role"}function textOf(a){return a&&!isUnsafeTextSource(a)&&a.textContent?a.textContent.trim():""}function nonBlank(a){return a&&a.trim()?a:void 0}// The button's name as a screen reader would read it, simplified: the first of
|
|
1387
|
+
var DOWNLOAD_EXTENSIONS=/\.(pdf|zip|csv|txt|ics|docx?|xlsx?|pptx?|dmg|exe|apk|mp3|mp4)$/i;function elementKind(a){if(isWalletElement(a))return "wallet";var b=a.tagName.toLowerCase();return "button"===b||"input"===b?b:a.matches("a[href]:not([role=\"button\"])")?"link":"role"}function textOf(a){return a&&!isUnsafeTextSource(a)&&a.textContent?a.textContent.trim():""}function nonBlank(a){return a&&a.trim()?a:void 0}// The button's name as a screen reader would read it, simplified: the first of
|
|
1388
1388
|
// aria-labelledby, aria-label, own text (or an inner image's alt), title, and for
|
|
1389
1389
|
// inputs their value. The text sources are skipped for controls that hold form
|
|
1390
1390
|
// fields or more than four children, so a typed value is never read.
|
|
@@ -1406,11 +1406,14 @@ function controlsIdentifier(a){var b=a.getAttribute("aria-controls");return stab
|
|
|
1406
1406
|
// field named "id" shadows form.id.
|
|
1407
1407
|
function formIdentifier(a){var b=a instanceof HTMLButtonElement||a instanceof HTMLInputElement?a.form:null;return b?stableIdentifier(b.getAttribute("id")):void 0}// The browser's normalised type: a button defaults to 'submit' and an unknown
|
|
1408
1408
|
// input type reads as 'text'. Wallet and role buttons are just 'button'.
|
|
1409
|
-
function controlType(a,b){return "button"===b||"input"===b?a.type:"button"}//
|
|
1410
|
-
//
|
|
1411
|
-
|
|
1409
|
+
function controlType(a,b){return "button"===b||"input"===b?a.type:"button"}// Reads the link's own resolved URL parts, never its full href: only the hostname of
|
|
1410
|
+
// a link that leaves the site and the extension of a file it downloads travel. Navigation
|
|
1411
|
+
// within the site is left to page views, and mailto:, tel: and other schemes are skipped.
|
|
1412
|
+
function describeLink(a){var b=(a.getAttribute("href")||"").trim();if(!b||"#"===b.charAt(0))return {type:"same_page"};if(a instanceof HTMLAnchorElement){var c=a.protocol.toLowerCase();if("javascript:"===c)return {type:"same_page"};if("http:"===c||"https:"===c){var d=a.hostname===window.location.hostname?void 0:a.hostname.toLowerCase(),e=DOWNLOAD_EXTENSIONS.exec(a.pathname);return a.hasAttribute("download")||e?{type:"download",domain:d,fileExtension:e?e[1].toLowerCase():void 0}:d?{type:"outbound",domain:d}:a.pathname===window.location.pathname&&a.search===window.location.search?{type:"same_page"}:void 0}}}// Describes a clicked control for auto button tracking. A link counts only when page
|
|
1413
|
+
// views can't see the click, and carries its link type.
|
|
1414
|
+
function describeButtonClick(a){var b;if(!(a.matches("a[href]:not([role=\"button\"])")&&(b=describeLink(a),!b))){var c=elementKind(a),d=accessibleName(a),e=maskLabel(d.raw);return {label:e,labelSource:e?d.source:"none",// Kept on its own as well: it often says more than the visible text,
|
|
1412
1415
|
// such as which item a remove button removes.
|
|
1413
|
-
ariaLabel:maskLabel(a.getAttribute("aria-label")),icon:iconHint(a),elementId:stableIdentifier(a.getAttribute("id")),elementName:stableIdentifier(a.getAttribute("name")),testId:firstIdentifier(a,TEST_ID_ATTRIBUTES),controls:controlsIdentifier(a),form:formIdentifier(a),element:
|
|
1416
|
+
ariaLabel:maskLabel(a.getAttribute("aria-label")),icon:iconHint(a),elementId:stableIdentifier(a.getAttribute("id")),elementName:stableIdentifier(a.getAttribute("name")),testId:firstIdentifier(a,TEST_ID_ATTRIBUTES),controls:controlsIdentifier(a),form:formIdentifier(a),element:c,type:controlType(a,c),linkType:b?b.type:void 0,linkDomain:b?b.domain:void 0,fileExtension:b?b.fileExtension:void 0}}}
|
|
1414
1417
|
|
|
1415
1418
|
var checkoutPath=/(?:^|\/)(?:checkouts?|payment|order|kasse|paiement|commander?|pago)(?:\/|$)/i,exclusions=new RegExp("coupon|promo|newsletter|sign in|add to cart|gift card|pay later|pay in|payment plan|learn more|gutschein|anmelden|warenkorb|bon cadeau|connexion|panier|cup\xF3n|iniciar sesi\xF3n|carrito|carrello|codice sconto|accedi|buono regalo|winkelwagen|kortingscode|inloggen|cadeaubon|achteraf betalen|\u30AB\u30FC\u30C8|\u30AF\u30FC\u30DD\u30F3|\u30ED\u30B0\u30A4\u30F3|\u4F1A\u54E1\u767B\u9332|\u30AE\u30D5\u30C8|\u5F8C\u6255\u3044|\u30E1\u30EB\u30DE\u30AC"),commits=new RegExp("^(?:"+"(?:place|submit|complete|confirm|finali[sz]e)(?!(?: [^ ]+){0,2} (?:another|new|next)(?: |$))(?: [^ ]+){0,2} (?:order|purchase|booking|reservation|payment|checkout)|pay(?: securely)?(?: now)?|confirm and pay|order and pay|order with obligation to pay|(?:jetzt )?(?:zahlungs|kosten)pflichtig (?:bestellen|buchen)|(?:jetzt )?bezahlen|kauf abschlie\xDFen|bestellung abschlie\xDFen|commander et payer|payer(?: maintenant)?|(?:confirmer|finaliser) (?:ma |la )?commande|valider et payer|confirmer et payer|commande avec obligation de paiement|finaliser l'achat|(?:realizar|confirmar|completar) (?:el |mi |la )?(?:pedido|compra|reserva)|finalizar (?:el |mi )?pedido|pagar(?: ahora)?|pedido con obligaci\xF3n de pago|(?:effettua|conferma|concludi|completa) (?:l'|il )?(?:ordine|acquisto)|ordine con obbligo di pagamento|paga(?: ora| adesso)?|ordina e paga|(?:nu )?betalen|bestellen en betalen|bestelling plaatsen|plaats bestelling|bestelling afronden|bestelling met betalingsverplichting|(?:\u3053\u306E\u5185\u5BB9\u3067|\u4E0A\u8A18\u306E?\u5185\u5BB9\u3067)?\u3054?(?:\u6CE8\u6587|\u8CFC\u5165|\u4E88\u7D04|\u6C7A\u6E08|\u304A?\u652F\u6255\u3044?)\u3092?(?:\u78BA\u5B9A|\u5B8C\u4E86)(?:\u3059\u308B)?|(?:\u3053\u306E\u5185\u5BB9\u3067|\u4E0A\u8A18\u306E?\u5185\u5BB9\u3067)\u3054?(?:\u6CE8\u6587|\u8CFC\u5165|\u4E88\u7D04)\u3059\u308B|\u3054?\u6CE8\u6587\u3059\u308B|\u6C7A\u6E08\u3059\u308B|(?:\u4ECA\u3059\u3050|\u3092)?\u652F\u6255\u3046"+")$"),routeGatedCommits=/^(?: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)$/,steps=new RegExp("^(?:"+"checkout|check out|check-out|continue to payment|proceed to checkout|zur kasse|zur kasse gehen|auschecken|weiter zur zahlung|passer \xE0 la caisse|continuer vers le paiement|proc\xE9der 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)?"+")$"),wallets=/^(?:apple pay|google pay|paypal|venmo|amazon pay|shop pay|klarna|afterpay|affirm)$/,frameHosts=new Set(["www.paypal.com","www.sandbox.paypal.com","pay.google.com","applepay.cdn-apple.com","js.stripe.com","checkoutshopper-live.adyen.com","payments.amazon.com","pay.shopify.com"]),TYPOGRAPHIC_APOSTROPHES=/[\u2019\u2018]/g,CURRENCY_AND_NUMBER_CHARS=/[0-9\uFF10-\uFF19$\u20AC\u00A3\u00A5\uFFE5\u20B9\u5186.,\uFF0C]/g;// Exact HTTPS hosts of hosted wallet and payment frames.
|
|
1416
1419
|
// Keep these classes ASCII-only in source bytes to avoid mojibake parse failures
|
package/dist/mparticle.esm.js
CHANGED
|
@@ -15,7 +15,7 @@ map:function map(a,b){var c,d,e;if(null===this)throw new TypeError(" this is nul
|
|
|
15
15
|
filter:function filter(a/*, thisArg*/){if(void 0===this||null===this)throw new TypeError;var b=Object(this),c=b.length>>>0;if("function"!=typeof a)throw new TypeError;for(var d=[],e=2<=arguments.length?arguments[1]:void 0,f=0;f<c;f++)if(f in b){var g=b[f];a.call(e,g,f,b)&&d.push(g);}return d},// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
|
|
16
16
|
isArray:function isArray(a){return "[object Array]"===Object.prototype.toString.call(a)},Base64:Base64$1};
|
|
17
17
|
|
|
18
|
-
var version = "3.
|
|
18
|
+
var version = "3.21.0";
|
|
19
19
|
|
|
20
20
|
var Constants={sdkVersion:version,sdkVendor:"mparticle",platform:"web",Messages:{DeprecationMessages:{MethodHasBeenDeprecated:"has been deprecated.",MethodMarkedForDeprecationPostfix:"is a deprecated method and will be removed in future releases.",AlternativeMethodPrefix:"Please use the alternate method:"},ErrorMessages:{NoToken:"A token must be specified.",EventNameInvalidType:"Event name must be a valid string value.",EventDataInvalidType:"Event data must be a valid object hash.",LoggingDisabled:"Event logging is currently disabled.",CookieParseError:"Could not parse cookie",EventEmpty:"Event object is null or undefined, cancelling send",APIRequestEmpty:"APIRequest is null or undefined, cancelling send",NoEventType:"Event type must be specified.",TransactionIdRequired:"Transaction ID is required",TransactionRequired:"A transaction attributes object is required",PromotionIdRequired:"Promotion ID is required",BadAttribute:"Attribute value cannot be object or array",BadKey:"Key value cannot be object or array",BadLogPurchase:"Transaction attributes and a product are both required to log a purchase, https://docs.mparticle.com/?javascript#measuring-transactions",AudienceAPINotEnabled:"Your workspace is not enabled to retrieve user audiences."},InformationMessages:{CookieSearch:"Searching for cookie",CookieFound:"Cookie found, parsing values",CookieNotFound:"Cookies not found",CookieSet:"Setting cookie",CookieSync:"Performing cookie sync",SendBegin:"Starting to send event",SendIdentityBegin:"Starting to send event to identity server",SendWindowsPhone:"Sending event to Windows Phone container",SendIOS:"Calling iOS path: ",SendAndroid:"Calling Android JS interface method: ",SendHttp:"Sending event to mParticle HTTP service",SendAliasHttp:"Sending alias request to mParticle HTTP service",SendIdentityHttp:"Sending event to mParticle HTTP service",StartingNewSession:"Starting new Session",StartingLogEvent:"Starting to log event",StartingLogOptOut:"Starting to log user opt in/out",StartingEndSession:"Starting to end session",StartingInitialization:"Starting to initialize",StartingLogCommerceEvent:"Starting to log commerce event",StartingAliasRequest:"Starting to Alias MPIDs",LoadingConfig:"Loading configuration options",AbandonLogEvent:"Cannot log event, logging disabled or developer token not set",AbandonAliasUsers:"Cannot Alias Users, logging disabled or developer token not set",AbandonStartSession:"Cannot start session, logging disabled or developer token not set",AbandonEndSession:"Cannot end session, logging disabled or developer token not set",NoSessionToEnd:"Cannot end session, no active session found"},ValidationMessages:{ModifyIdentityRequestUserIdentitiesPresent:"identityRequests to modify require userIdentities to be present. Request not sent to server. Please fix and try again",IdentityRequesetInvalidKey:"There is an invalid key on your identityRequest object. It can only contain a `userIdentities` object and a `onUserAlias` function. Request not sent to server. Please fix and try again.",OnUserAliasType:"The onUserAlias value must be a function.",UserIdentities:"The userIdentities key must be an object with keys of identityTypes and values of strings. Request not sent to server. Please fix and try again.",UserIdentitiesInvalidKey:"There is an invalid identity key on your `userIdentities` object within the identityRequest. Request not sent to server. Please fix and try again.",UserIdentitiesInvalidValues:"All user identity values must be strings or null. Request not sent to server. Please fix and try again.",AliasMissingMpid:"Alias Request must contain both a destinationMpid and a sourceMpid",AliasNonUniqueMpid:"Alias Request's destinationMpid and sourceMpid must be unique",AliasMissingTime:"Alias Request must have both a startTime and an endTime",AliasStartBeforeEndTime:"Alias Request's endTime must be later than its startTime"}},NativeSdkPaths:{LogEvent:"logEvent",SetUserTag:"setUserTag",RemoveUserTag:"removeUserTag",SetUserAttribute:"setUserAttribute",RemoveUserAttribute:"removeUserAttribute",SetSessionAttribute:"setSessionAttribute",LogOut:"logOut",SetUserAttributeList:"setUserAttributeList",RemoveAllUserAttributes:"removeAllUserAttributes",GetUserAttributesLists:"getUserAttributesLists",GetAllUserAttributes:"getAllUserAttributes",Identify:"identify",Logout:"logout",Login:"login",Modify:"modify",Alias:"aliasUsers",Upload:"upload"},StorageNames:{localStorageName:"mprtcl-api",localStorageNameV3:"mprtcl-v3",cookieName:"mprtcl-api",cookieNameV2:"mprtcl-v2",cookieNameV3:"mprtcl-v3",localStorageNameV4:"mprtcl-v4",cookieNameV4:"mprtcl-v4",currentStorageName:"mprtcl-v4"},DefaultConfig:{cookieDomain:null,cookieExpiration:365,logLevel:null,timeout:300,sessionTimeout:30,forwarderStatsTimeout:5e3,integrationDelayTimeout:5e3,maxCookieSize:3e3,aliasMaxWindow:90,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
|
|
21
21
|
},DefaultBaseUrls:{v1SecureServiceUrl:"jssdks.mparticle.com/v1/JS/",v2SecureServiceUrl:"jssdks.mparticle.com/v2/JS/",v3SecureServiceUrl:"jssdks.mparticle.com/v3/JS/",configUrl:"jssdkcdns.mparticle.com/JS/v2/",identityUrl:"identity.mparticle.com/v1/",aliasUrl:"jssdks.mparticle.com/v1/identity/",userAudienceUrl:"nativesdks.mparticle.com/v1/"},// These are the paths that are used to construct the CNAME urls
|
|
@@ -1364,7 +1364,7 @@ var BUTTON_CLICK_EVENT_NAME="Auto Button Click";// One custom event per click, l
|
|
|
1364
1364
|
// page fields that auto page views carry. No intent: classifying clicks is left
|
|
1365
1365
|
// to whoever reads the data.
|
|
1366
1366
|
var buildButtonClickEvent=function(a,b){// Optional fields are left out when the button has no safe value for them.
|
|
1367
|
-
for(var c,d,e=(c={label_source:a.labelSource,element:a.element,type:a.type,path:b,hostname:window.location.hostname},c[AUTO_BUTTON_ATTRIBUTE]=!0,c),f={label:a.label,aria_label:a.ariaLabel,icon:a.icon,element_id:a.elementId,element_name:a.elementName,test_id:a.testId,controls:a.controls,form:a.form},g=0,h=Object.keys(f);g<h.length;g++)d=h[g],f[d]&&(e[d]=f[d]);return {messageType:MessageType$1.PageEvent,name:BUTTON_CLICK_EVENT_NAME,data:e,eventType:EventType.Other}};
|
|
1367
|
+
for(var c,d,e=(c={label_source:a.labelSource,element:a.element,type:a.type,path:b,hostname:window.location.hostname},c[AUTO_BUTTON_ATTRIBUTE]=!0,c),f={label:a.label,aria_label:a.ariaLabel,icon:a.icon,element_id:a.elementId,element_name:a.elementName,test_id:a.testId,controls:a.controls,form:a.form,link_type:a.linkType,link_domain:a.linkDomain,file_extension:a.fileExtension},g=0,h=Object.keys(f);g<h.length;g++)d=h[g],f[d]&&(e[d]=f[d]);return {messageType:MessageType$1.PageEvent,name:BUTTON_CLICK_EVENT_NAME,data:e,eventType:EventType.Other}};
|
|
1368
1368
|
|
|
1369
1369
|
// descriptions. Rokt's own elements, disabled controls and anything under
|
|
1370
1370
|
// data-mp-no-track are never returned.
|
|
@@ -1384,7 +1384,7 @@ function createDigitPatterns(){try{return {run:/\p{Nd}{6,}/u,number:/\p{Nd}+(?:[
|
|
|
1384
1384
|
// masked. Dropped when it looks like an email, phone or card number.
|
|
1385
1385
|
function maskLabel(a){if(a&&!(128<a.length)&&digitPatterns){var b=a.replace(/\s+/g," ").trim().toLowerCase();if(b&&-1===b.indexOf("@")&&!digitPatterns.run.test(b.replace(/[\s()\-\u2010-\u2015]/g,""))){var c=b.replace(digitPatterns.number,"#").slice(0,64).trim();return c||void 0}}}
|
|
1386
1386
|
|
|
1387
|
-
function elementKind(a){if(isWalletElement(a))return "wallet";var b=a.tagName.toLowerCase();return "button"===b||"input"===b?b:"role"}function textOf(a){return a&&!isUnsafeTextSource(a)&&a.textContent?a.textContent.trim():""}function nonBlank(a){return a&&a.trim()?a:void 0}// The button's name as a screen reader would read it, simplified: the first of
|
|
1387
|
+
var DOWNLOAD_EXTENSIONS=/\.(pdf|zip|csv|txt|ics|docx?|xlsx?|pptx?|dmg|exe|apk|mp3|mp4)$/i;function elementKind(a){if(isWalletElement(a))return "wallet";var b=a.tagName.toLowerCase();return "button"===b||"input"===b?b:a.matches("a[href]:not([role=\"button\"])")?"link":"role"}function textOf(a){return a&&!isUnsafeTextSource(a)&&a.textContent?a.textContent.trim():""}function nonBlank(a){return a&&a.trim()?a:void 0}// The button's name as a screen reader would read it, simplified: the first of
|
|
1388
1388
|
// aria-labelledby, aria-label, own text (or an inner image's alt), title, and for
|
|
1389
1389
|
// inputs their value. The text sources are skipped for controls that hold form
|
|
1390
1390
|
// fields or more than four children, so a typed value is never read.
|
|
@@ -1406,11 +1406,14 @@ function controlsIdentifier(a){var b=a.getAttribute("aria-controls");return stab
|
|
|
1406
1406
|
// field named "id" shadows form.id.
|
|
1407
1407
|
function formIdentifier(a){var b=a instanceof HTMLButtonElement||a instanceof HTMLInputElement?a.form:null;return b?stableIdentifier(b.getAttribute("id")):void 0}// The browser's normalised type: a button defaults to 'submit' and an unknown
|
|
1408
1408
|
// input type reads as 'text'. Wallet and role buttons are just 'button'.
|
|
1409
|
-
function controlType(a,b){return "button"===b||"input"===b?a.type:"button"}//
|
|
1410
|
-
//
|
|
1411
|
-
|
|
1409
|
+
function controlType(a,b){return "button"===b||"input"===b?a.type:"button"}// Reads the link's own resolved URL parts, never its full href: only the hostname of
|
|
1410
|
+
// a link that leaves the site and the extension of a file it downloads travel. Navigation
|
|
1411
|
+
// within the site is left to page views, and mailto:, tel: and other schemes are skipped.
|
|
1412
|
+
function describeLink(a){var b=(a.getAttribute("href")||"").trim();if(!b||"#"===b.charAt(0))return {type:"same_page"};if(a instanceof HTMLAnchorElement){var c=a.protocol.toLowerCase();if("javascript:"===c)return {type:"same_page"};if("http:"===c||"https:"===c){var d=a.hostname===window.location.hostname?void 0:a.hostname.toLowerCase(),e=DOWNLOAD_EXTENSIONS.exec(a.pathname);return a.hasAttribute("download")||e?{type:"download",domain:d,fileExtension:e?e[1].toLowerCase():void 0}:d?{type:"outbound",domain:d}:a.pathname===window.location.pathname&&a.search===window.location.search?{type:"same_page"}:void 0}}}// Describes a clicked control for auto button tracking. A link counts only when page
|
|
1413
|
+
// views can't see the click, and carries its link type.
|
|
1414
|
+
function describeButtonClick(a){var b;if(!(a.matches("a[href]:not([role=\"button\"])")&&(b=describeLink(a),!b))){var c=elementKind(a),d=accessibleName(a),e=maskLabel(d.raw);return {label:e,labelSource:e?d.source:"none",// Kept on its own as well: it often says more than the visible text,
|
|
1412
1415
|
// such as which item a remove button removes.
|
|
1413
|
-
ariaLabel:maskLabel(a.getAttribute("aria-label")),icon:iconHint(a),elementId:stableIdentifier(a.getAttribute("id")),elementName:stableIdentifier(a.getAttribute("name")),testId:firstIdentifier(a,TEST_ID_ATTRIBUTES),controls:controlsIdentifier(a),form:formIdentifier(a),element:
|
|
1416
|
+
ariaLabel:maskLabel(a.getAttribute("aria-label")),icon:iconHint(a),elementId:stableIdentifier(a.getAttribute("id")),elementName:stableIdentifier(a.getAttribute("name")),testId:firstIdentifier(a,TEST_ID_ATTRIBUTES),controls:controlsIdentifier(a),form:formIdentifier(a),element:c,type:controlType(a,c),linkType:b?b.type:void 0,linkDomain:b?b.domain:void 0,fileExtension:b?b.fileExtension:void 0}}}
|
|
1414
1417
|
|
|
1415
1418
|
var checkoutPath=/(?:^|\/)(?:checkouts?|payment|order|kasse|paiement|commander?|pago)(?:\/|$)/i,exclusions=new RegExp("coupon|promo|newsletter|sign in|add to cart|gift card|pay later|pay in|payment plan|learn more|gutschein|anmelden|warenkorb|bon cadeau|connexion|panier|cup\xF3n|iniciar sesi\xF3n|carrito|carrello|codice sconto|accedi|buono regalo|winkelwagen|kortingscode|inloggen|cadeaubon|achteraf betalen|\u30AB\u30FC\u30C8|\u30AF\u30FC\u30DD\u30F3|\u30ED\u30B0\u30A4\u30F3|\u4F1A\u54E1\u767B\u9332|\u30AE\u30D5\u30C8|\u5F8C\u6255\u3044|\u30E1\u30EB\u30DE\u30AC"),commits=new RegExp("^(?:"+"(?:place|submit|complete|confirm|finali[sz]e)(?!(?: [^ ]+){0,2} (?:another|new|next)(?: |$))(?: [^ ]+){0,2} (?:order|purchase|booking|reservation|payment|checkout)|pay(?: securely)?(?: now)?|confirm and pay|order and pay|order with obligation to pay|(?:jetzt )?(?:zahlungs|kosten)pflichtig (?:bestellen|buchen)|(?:jetzt )?bezahlen|kauf abschlie\xDFen|bestellung abschlie\xDFen|commander et payer|payer(?: maintenant)?|(?:confirmer|finaliser) (?:ma |la )?commande|valider et payer|confirmer et payer|commande avec obligation de paiement|finaliser l'achat|(?:realizar|confirmar|completar) (?:el |mi |la )?(?:pedido|compra|reserva)|finalizar (?:el |mi )?pedido|pagar(?: ahora)?|pedido con obligaci\xF3n de pago|(?:effettua|conferma|concludi|completa) (?:l'|il )?(?:ordine|acquisto)|ordine con obbligo di pagamento|paga(?: ora| adesso)?|ordina e paga|(?:nu )?betalen|bestellen en betalen|bestelling plaatsen|plaats bestelling|bestelling afronden|bestelling met betalingsverplichting|(?:\u3053\u306E\u5185\u5BB9\u3067|\u4E0A\u8A18\u306E?\u5185\u5BB9\u3067)?\u3054?(?:\u6CE8\u6587|\u8CFC\u5165|\u4E88\u7D04|\u6C7A\u6E08|\u304A?\u652F\u6255\u3044?)\u3092?(?:\u78BA\u5B9A|\u5B8C\u4E86)(?:\u3059\u308B)?|(?:\u3053\u306E\u5185\u5BB9\u3067|\u4E0A\u8A18\u306E?\u5185\u5BB9\u3067)\u3054?(?:\u6CE8\u6587|\u8CFC\u5165|\u4E88\u7D04)\u3059\u308B|\u3054?\u6CE8\u6587\u3059\u308B|\u6C7A\u6E08\u3059\u308B|(?:\u4ECA\u3059\u3050|\u3092)?\u652F\u6255\u3046"+")$"),routeGatedCommits=/^(?: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)$/,steps=new RegExp("^(?:"+"checkout|check out|check-out|continue to payment|proceed to checkout|zur kasse|zur kasse gehen|auschecken|weiter zur zahlung|passer \xE0 la caisse|continuer vers le paiement|proc\xE9der 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)?"+")$"),wallets=/^(?:apple pay|google pay|paypal|venmo|amazon pay|shop pay|klarna|afterpay|affirm)$/,frameHosts=new Set(["www.paypal.com","www.sandbox.paypal.com","pay.google.com","applepay.cdn-apple.com","js.stripe.com","checkoutshopper-live.adyen.com","payments.amazon.com","pay.shopify.com"]),TYPOGRAPHIC_APOSTROPHES=/[\u2019\u2018]/g,CURRENCY_AND_NUMBER_CHARS=/[0-9\uFF10-\uFF19$\u20AC\u00A3\u00A5\uFFE5\u20B9\u5186.,\uFF0C]/g;// Exact HTTPS hosts of hosted wallet and payment frames.
|
|
1416
1419
|
// Keep these classes ASCII-only in source bytes to avoid mojibake parse failures
|
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.21.0";
|
|
208
208
|
|
|
209
209
|
var Constants = {
|
|
210
210
|
sdkVersion: version,
|
|
@@ -11484,7 +11484,10 @@ var mParticle = (function () {
|
|
|
11484
11484
|
element_name: click.elementName,
|
|
11485
11485
|
test_id: click.testId,
|
|
11486
11486
|
controls: click.controls,
|
|
11487
|
-
form: click.form
|
|
11487
|
+
form: click.form,
|
|
11488
|
+
link_type: click.linkType,
|
|
11489
|
+
link_domain: click.linkDomain,
|
|
11490
|
+
file_extension: click.fileExtension
|
|
11488
11491
|
};
|
|
11489
11492
|
for (var _i = 0, _b = Object.keys(optional); _i < _b.length; _i++) {
|
|
11490
11493
|
var key = _b[_i];
|
|
@@ -11593,12 +11596,16 @@ var mParticle = (function () {
|
|
|
11593
11596
|
return masked || undefined;
|
|
11594
11597
|
}
|
|
11595
11598
|
|
|
11599
|
+
var DOWNLOAD_EXTENSIONS = /\.(pdf|zip|csv|txt|ics|docx?|xlsx?|pptx?|dmg|exe|apk|mp3|mp4)$/i;
|
|
11596
11600
|
function elementKind(control) {
|
|
11597
11601
|
if (isWalletElement(control)) {
|
|
11598
11602
|
return 'wallet';
|
|
11599
11603
|
}
|
|
11600
11604
|
var tag = control.tagName.toLowerCase();
|
|
11601
|
-
|
|
11605
|
+
if (tag === 'button' || tag === 'input') {
|
|
11606
|
+
return tag;
|
|
11607
|
+
}
|
|
11608
|
+
return control.matches('a[href]:not([role="button"])') ? 'link' : 'role';
|
|
11602
11609
|
}
|
|
11603
11610
|
function textOf(element) {
|
|
11604
11611
|
return element && !isUnsafeTextSource(element) && element.textContent ? element.textContent.trim() : '';
|
|
@@ -11772,11 +11779,56 @@ var mParticle = (function () {
|
|
|
11772
11779
|
function controlType(control, element) {
|
|
11773
11780
|
return element === 'button' || element === 'input' ? control.type : 'button';
|
|
11774
11781
|
}
|
|
11775
|
-
//
|
|
11776
|
-
//
|
|
11782
|
+
// Reads the link's own resolved URL parts, never its full href: only the hostname of
|
|
11783
|
+
// a link that leaves the site and the extension of a file it downloads travel. Navigation
|
|
11784
|
+
// within the site is left to page views, and mailto:, tel: and other schemes are skipped.
|
|
11785
|
+
function describeLink(link) {
|
|
11786
|
+
var href = (link.getAttribute('href') || '').trim();
|
|
11787
|
+
if (!href || href.charAt(0) === '#') {
|
|
11788
|
+
return {
|
|
11789
|
+
type: 'same_page'
|
|
11790
|
+
};
|
|
11791
|
+
}
|
|
11792
|
+
if (!(link instanceof HTMLAnchorElement)) {
|
|
11793
|
+
return undefined;
|
|
11794
|
+
}
|
|
11795
|
+
var protocol = link.protocol.toLowerCase();
|
|
11796
|
+
if (protocol === 'javascript:') {
|
|
11797
|
+
return {
|
|
11798
|
+
type: 'same_page'
|
|
11799
|
+
};
|
|
11800
|
+
}
|
|
11801
|
+
if (protocol !== 'http:' && protocol !== 'https:') {
|
|
11802
|
+
return undefined;
|
|
11803
|
+
}
|
|
11804
|
+
var domain = link.hostname !== window.location.hostname ? link.hostname.toLowerCase() : undefined;
|
|
11805
|
+
var extension = DOWNLOAD_EXTENSIONS.exec(link.pathname);
|
|
11806
|
+
if (link.hasAttribute('download') || extension) {
|
|
11807
|
+
return {
|
|
11808
|
+
type: 'download',
|
|
11809
|
+
domain: domain,
|
|
11810
|
+
fileExtension: extension ? extension[1].toLowerCase() : undefined
|
|
11811
|
+
};
|
|
11812
|
+
}
|
|
11813
|
+
if (domain) {
|
|
11814
|
+
return {
|
|
11815
|
+
type: 'outbound',
|
|
11816
|
+
domain: domain
|
|
11817
|
+
};
|
|
11818
|
+
}
|
|
11819
|
+
return link.pathname === window.location.pathname && link.search === window.location.search ? {
|
|
11820
|
+
type: 'same_page'
|
|
11821
|
+
} : undefined;
|
|
11822
|
+
}
|
|
11823
|
+
// Describes a clicked control for auto button tracking. A link counts only when page
|
|
11824
|
+
// views can't see the click, and carries its link type.
|
|
11777
11825
|
function describeButtonClick(control) {
|
|
11826
|
+
var link;
|
|
11778
11827
|
if (control.matches('a[href]:not([role="button"])')) {
|
|
11779
|
-
|
|
11828
|
+
link = describeLink(control);
|
|
11829
|
+
if (!link) {
|
|
11830
|
+
return undefined;
|
|
11831
|
+
}
|
|
11780
11832
|
}
|
|
11781
11833
|
var element = elementKind(control);
|
|
11782
11834
|
var name = accessibleName(control);
|
|
@@ -11794,7 +11846,10 @@ var mParticle = (function () {
|
|
|
11794
11846
|
controls: controlsIdentifier(control),
|
|
11795
11847
|
form: formIdentifier(control),
|
|
11796
11848
|
element: element,
|
|
11797
|
-
type: controlType(control, element)
|
|
11849
|
+
type: controlType(control, element),
|
|
11850
|
+
linkType: link ? link.type : undefined,
|
|
11851
|
+
linkDomain: link ? link.domain : undefined,
|
|
11852
|
+
fileExtension: link ? link.fileExtension : undefined
|
|
11798
11853
|
};
|
|
11799
11854
|
}
|
|
11800
11855
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export type ButtonElementKind = 'button' | 'input' | 'role' | 'wallet';
|
|
1
|
+
export type ButtonElementKind = 'button' | 'input' | 'role' | 'wallet' | 'link';
|
|
2
|
+
export type LinkType = 'same_page' | 'outbound' | 'download';
|
|
2
3
|
export type ButtonLabelSource = 'labelledby' | 'aria' | 'text' | 'alt' | 'title' | 'value' | 'none';
|
|
3
4
|
export interface IButtonClick {
|
|
4
5
|
label?: string;
|
|
@@ -12,5 +13,8 @@ export interface IButtonClick {
|
|
|
12
13
|
form?: string;
|
|
13
14
|
element: ButtonElementKind;
|
|
14
15
|
type: string;
|
|
16
|
+
linkType?: LinkType;
|
|
17
|
+
linkDomain?: string;
|
|
18
|
+
fileExtension?: string;
|
|
15
19
|
}
|
|
16
20
|
export declare function describeButtonClick(control: Element): IButtonClick | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mparticle/web-sdk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.21.0",
|
|
4
4
|
"description": "mParticle core SDK for web applications",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"bundle": "npm run uglify && npm run gzip",
|
|
95
95
|
"report:bundled": "ls -l dist/mparticle.min.js.gz | awk '{print $5}'",
|
|
96
96
|
"check:ascii:dist": "node scripts/check-ascii-dist.js",
|
|
97
|
+
"check:cdn-minifier": "node scripts/check-cdn-minifier.js",
|
|
97
98
|
"report:bundled:human": "ls -lh dist/mparticle.min.js.gz | awk '{print $5}'"
|
|
98
99
|
},
|
|
99
100
|
"pre-commit": [
|
|
@@ -119,7 +120,6 @@
|
|
|
119
120
|
"@semantic-release/exec": "^6.0.3",
|
|
120
121
|
"@semantic-release/git": "^10.0.1",
|
|
121
122
|
"@semantic-release/npm": "^13.1.2",
|
|
122
|
-
"semantic-release": "^24.2.0",
|
|
123
123
|
"@types/chai": "^4.2.3",
|
|
124
124
|
"@types/jest": "^29.5.1",
|
|
125
125
|
"@types/jest-expect-message": "^1.1.0",
|
|
@@ -139,6 +139,7 @@
|
|
|
139
139
|
"gts": "^5.0.1",
|
|
140
140
|
"jest": "^29.5.0",
|
|
141
141
|
"jest-environment-jsdom": "^29.5.0",
|
|
142
|
+
"jsdom": "20.0.3",
|
|
142
143
|
"karma": "^6.3.2",
|
|
143
144
|
"karma-browserstack-launcher": "^1.6.0",
|
|
144
145
|
"karma-chai": "^0.1.0",
|
|
@@ -154,6 +155,7 @@
|
|
|
154
155
|
"pre-commit": "^1.2.2",
|
|
155
156
|
"prettier": "1.18.2",
|
|
156
157
|
"rollup": "^2.75.7",
|
|
158
|
+
"semantic-release": "^24.2.0",
|
|
157
159
|
"shelljs": "^0.8.4",
|
|
158
160
|
"should": "^7.1.0",
|
|
159
161
|
"sinon": "^16.1.3",
|
|
@@ -33,6 +33,9 @@ export const buildButtonClickEvent = (
|
|
|
33
33
|
test_id: click.testId,
|
|
34
34
|
controls: click.controls,
|
|
35
35
|
form: click.form,
|
|
36
|
+
link_type: click.linkType,
|
|
37
|
+
link_domain: click.linkDomain,
|
|
38
|
+
file_extension: click.fileExtension,
|
|
36
39
|
};
|
|
37
40
|
for (const key of Object.keys(optional)) {
|
|
38
41
|
if (optional[key]) {
|
|
@@ -8,7 +8,12 @@ import { maskLabel } from './labelMasking';
|
|
|
8
8
|
|
|
9
9
|
// Describes a clicked button for auto button tracking: its masked name, icon,
|
|
10
10
|
// hand-written identifiers and kind. Never reads form field values.
|
|
11
|
-
export type ButtonElementKind = 'button' | 'input' | 'role' | 'wallet';
|
|
11
|
+
export type ButtonElementKind = 'button' | 'input' | 'role' | 'wallet' | 'link';
|
|
12
|
+
|
|
13
|
+
// The link clicks page views can't see: ones that stay on the page, leave the site or download a file.
|
|
14
|
+
export type LinkType = 'same_page' | 'outbound' | 'download';
|
|
15
|
+
|
|
16
|
+
const DOWNLOAD_EXTENSIONS = /\.(pdf|zip|csv|txt|ics|docx?|xlsx?|pptx?|dmg|exe|apk|mp3|mp4)$/i;
|
|
12
17
|
|
|
13
18
|
export type ButtonLabelSource =
|
|
14
19
|
| 'labelledby'
|
|
@@ -31,6 +36,9 @@ export interface IButtonClick {
|
|
|
31
36
|
form?: string;
|
|
32
37
|
element: ButtonElementKind;
|
|
33
38
|
type: string;
|
|
39
|
+
linkType?: LinkType;
|
|
40
|
+
linkDomain?: string;
|
|
41
|
+
fileExtension?: string;
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
function elementKind(control: Element): ButtonElementKind {
|
|
@@ -38,7 +46,10 @@ function elementKind(control: Element): ButtonElementKind {
|
|
|
38
46
|
return 'wallet';
|
|
39
47
|
}
|
|
40
48
|
const tag = control.tagName.toLowerCase();
|
|
41
|
-
|
|
49
|
+
if (tag === 'button' || tag === 'input') {
|
|
50
|
+
return tag;
|
|
51
|
+
}
|
|
52
|
+
return control.matches('a[href]:not([role="button"])') ? 'link' : 'role';
|
|
42
53
|
}
|
|
43
54
|
|
|
44
55
|
function textOf(element: Element | null): string {
|
|
@@ -230,13 +241,62 @@ function controlType(control: Element, element: ButtonElementKind): string {
|
|
|
230
241
|
: 'button';
|
|
231
242
|
}
|
|
232
243
|
|
|
233
|
-
|
|
234
|
-
|
|
244
|
+
interface ILinkDetails {
|
|
245
|
+
type: LinkType;
|
|
246
|
+
domain?: string;
|
|
247
|
+
fileExtension?: string;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Reads the link's own resolved URL parts, never its full href: only the hostname of
|
|
251
|
+
// a link that leaves the site and the extension of a file it downloads travel. Navigation
|
|
252
|
+
// within the site is left to page views, and mailto:, tel: and other schemes are skipped.
|
|
253
|
+
function describeLink(link: Element): ILinkDetails | undefined {
|
|
254
|
+
const href = (link.getAttribute('href') || '').trim();
|
|
255
|
+
if (!href || href.charAt(0) === '#') {
|
|
256
|
+
return { type: 'same_page' };
|
|
257
|
+
}
|
|
258
|
+
if (!(link instanceof HTMLAnchorElement)) {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
const protocol = link.protocol.toLowerCase();
|
|
262
|
+
if (protocol === 'javascript:') {
|
|
263
|
+
return { type: 'same_page' };
|
|
264
|
+
}
|
|
265
|
+
if (protocol !== 'http:' && protocol !== 'https:') {
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
const domain =
|
|
269
|
+
link.hostname !== window.location.hostname
|
|
270
|
+
? link.hostname.toLowerCase()
|
|
271
|
+
: undefined;
|
|
272
|
+
const extension = DOWNLOAD_EXTENSIONS.exec(link.pathname);
|
|
273
|
+
if (link.hasAttribute('download') || extension) {
|
|
274
|
+
return {
|
|
275
|
+
type: 'download',
|
|
276
|
+
domain,
|
|
277
|
+
fileExtension: extension ? extension[1].toLowerCase() : undefined,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
if (domain) {
|
|
281
|
+
return { type: 'outbound', domain };
|
|
282
|
+
}
|
|
283
|
+
return link.pathname === window.location.pathname &&
|
|
284
|
+
link.search === window.location.search
|
|
285
|
+
? { type: 'same_page' }
|
|
286
|
+
: undefined;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Describes a clicked control for auto button tracking. A link counts only when page
|
|
290
|
+
// views can't see the click, and carries its link type.
|
|
235
291
|
export function describeButtonClick(
|
|
236
292
|
control: Element
|
|
237
293
|
): IButtonClick | undefined {
|
|
294
|
+
let link: ILinkDetails | undefined;
|
|
238
295
|
if (control.matches('a[href]:not([role="button"])')) {
|
|
239
|
-
|
|
296
|
+
link = describeLink(control);
|
|
297
|
+
if (!link) {
|
|
298
|
+
return undefined;
|
|
299
|
+
}
|
|
240
300
|
}
|
|
241
301
|
const element = elementKind(control);
|
|
242
302
|
const name = accessibleName(control);
|
|
@@ -255,5 +315,8 @@ export function describeButtonClick(
|
|
|
255
315
|
form: formIdentifier(control),
|
|
256
316
|
element,
|
|
257
317
|
type: controlType(control, element),
|
|
318
|
+
linkType: link ? link.type : undefined,
|
|
319
|
+
linkDomain: link ? link.domain : undefined,
|
|
320
|
+
fileExtension: link ? link.fileExtension : undefined,
|
|
258
321
|
};
|
|
259
322
|
}
|