@@ -14,7 +14,7 @@ import { applyFnToProps } from '../../../common/util/traverse'
1414import { UserActionsAggregator } from './user-actions/user-actions-aggregator'
1515import { isIFrameWindow } from '../../../common/dom/iframe'
1616import { isPureObject } from '../../../common/util/type-check'
17- import { getVersion2Attributes } from '../../../common/v2/utils'
17+ import { getVersion2Attributes , getVersion2DuplicationAttributes , shouldDuplicate } from '../../../common/v2/utils'
1818
1919export class Aggregate extends AggregateBase {
2020 static featureName = FEATURE_NAME
@@ -61,7 +61,7 @@ export class Aggregate extends AggregateBase {
6161
6262 let addUserAction = ( ) => { /** no-op */ }
6363 if ( isBrowserScope && agentRef . init . user_actions . enabled ) {
64- this . #userActionAggregator = new UserActionsAggregator ( )
64+ this . #userActionAggregator = new UserActionsAggregator ( this . agentRef )
6565 this . harvestOpts . beforeUnload = ( ) => addUserAction ?. ( this . #userActionAggregator. aggregationEvent )
6666
6767 addUserAction = ( aggregatedUserAction ) => {
@@ -70,50 +70,54 @@ export class Aggregate extends AggregateBase {
7070 * so we still need to validate that an event was given to this method before we try to add */
7171 if ( aggregatedUserAction ?. event ) {
7272 const { target, timeStamp, type } = aggregatedUserAction . event
73- const userActionEvent = {
74- eventType : 'UserAction' ,
75- timestamp : this . #toEpoch( timeStamp ) ,
76- action : type ,
77- actionCount : aggregatedUserAction . count ,
78- actionDuration : aggregatedUserAction . relativeMs [ aggregatedUserAction . relativeMs . length - 1 ] ,
79- actionMs : aggregatedUserAction . relativeMs ,
80- rageClick : aggregatedUserAction . rageClick ,
81- target : aggregatedUserAction . selectorPath ,
82- currentUrl : aggregatedUserAction . currentUrl ,
83- ...( isIFrameWindow ( window ) && { iframe : true } ) ,
84- ...( this . agentRef . init . user_actions . elementAttributes . reduce ( ( acc , field ) => {
73+
74+ aggregatedUserAction . targets . forEach ( mfeTarget => {
75+ const userActionEvent = {
76+ eventType : 'UserAction' ,
77+ timestamp : this . #toEpoch( timeStamp ) ,
78+ action : type ,
79+ actionCount : aggregatedUserAction . count ,
80+ actionDuration : aggregatedUserAction . relativeMs [ aggregatedUserAction . relativeMs . length - 1 ] ,
81+ actionMs : aggregatedUserAction . relativeMs ,
82+ rageClick : aggregatedUserAction . rageClick ,
83+ target : aggregatedUserAction . selectorPath ,
84+ currentUrl : aggregatedUserAction . currentUrl ,
85+ ...( isIFrameWindow ( window ) && { iframe : true } ) ,
86+ ...( this . agentRef . init . user_actions . elementAttributes . reduce ( ( acc , field ) => {
8587 /** prevent us from capturing an obscenely long value */
86- if ( canTrustTargetAttribute ( field ) ) acc [ targetAttrName ( field ) ] = String ( target [ field ] ) . trim ( ) . slice ( 0 , 128 )
87- return acc
88- } , { } ) ) ,
89- ...aggregatedUserAction . nearestTargetFields ,
90- ...( aggregatedUserAction . deadClick && { deadClick : true } ) ,
91- ...( aggregatedUserAction . errorClick && { errorClick : true } )
92- }
93- this . addEvent ( userActionEvent )
94- this . #trackUserActionSM( userActionEvent )
95-
96- /**
88+ if ( canTrustTargetAttribute ( field ) ) acc [ targetAttrName ( field ) ] = String ( target [ field ] ) . trim ( ) . slice ( 0 , 128 )
89+ return acc
90+ } , { } ) ) ,
91+ ...aggregatedUserAction . nearestTargetFields ,
92+ ...( aggregatedUserAction . deadClick && { deadClick : true } ) ,
93+ ...( aggregatedUserAction . errorClick && { errorClick : true } )
94+ }
95+ this . addEvent ( userActionEvent , mfeTarget )
96+
97+ this . #trackUserActionSM( userActionEvent )
98+
99+ /**
97100 * Returns the original target field name with `target` prepended and camelCased
98101 * @param {string } originalFieldName
99102 * @returns {string } the target field name
100103 */
101- function targetAttrName ( originalFieldName ) {
104+ function targetAttrName ( originalFieldName ) {
102105 /** preserve original renaming structure for pre-existing field maps */
103- if ( originalFieldName === 'tagName' ) originalFieldName = 'tag'
104- if ( originalFieldName === 'className' ) originalFieldName = 'class'
105- /** return the original field name, cap'd and prepended with target to match formatting */
106- return `target${ originalFieldName . charAt ( 0 ) . toUpperCase ( ) + originalFieldName . slice ( 1 ) } `
107- }
106+ if ( originalFieldName === 'tagName' ) originalFieldName = 'tag'
107+ if ( originalFieldName === 'className' ) originalFieldName = 'class'
108+ /** return the original field name, cap'd and prepended with target to match formatting */
109+ return `target${ originalFieldName . charAt ( 0 ) . toUpperCase ( ) + originalFieldName . slice ( 1 ) } `
110+ }
108111
109- /**
112+ /**
110113 * Only trust attributes that exist on HTML element targets, which excludes the window and the document targets
111114 * @param {string } attribute The attribute to check for on the target element
112115 * @returns {boolean } Whether the target element has the attribute and can be trusted
113116 */
114- function canTrustTargetAttribute ( attribute ) {
115- return ! ! ( aggregatedUserAction . selectorPath !== 'window' && aggregatedUserAction . selectorPath !== 'document' && target instanceof HTMLElement && target ?. [ attribute ] )
116- }
117+ function canTrustTargetAttribute ( attribute ) {
118+ return ! ! ( aggregatedUserAction . selectorPath !== 'window' && aggregatedUserAction . selectorPath !== 'document' && target instanceof HTMLElement && target ?. [ attribute ] )
119+ }
120+ } )
117121 }
118122 } catch ( e ) {
119123 // do nothing for now
@@ -314,9 +318,7 @@ export class Aggregate extends AggregateBase {
314318 timestamp : this . #toEpoch( now ( ) ) ,
315319 /** all generic events require pageUrl(s) */
316320 pageUrl : cleanURL ( '' + initialLocation ) ,
317- currentUrl : cleanURL ( '' + location ) ,
318- /** Specific attributes only supplied if harvesting to endpoint version 2 */
319- ...( getVersion2Attributes ( target , this ) )
321+ currentUrl : cleanURL ( '' + location )
320322 }
321323
322324 const eventAttributes = {
@@ -328,7 +330,8 @@ export class Aggregate extends AggregateBase {
328330 ...obj
329331 }
330332
331- this . events . add ( eventAttributes )
333+ this . events . add ( { ...eventAttributes , ...getVersion2Attributes ( target , this ) } )
334+ if ( shouldDuplicate ( target , this . agentRef ) ) this . addEvent ( { ...eventAttributes , ...getVersion2DuplicationAttributes ( target , this ) } )
332335 }
333336
334337 serializer ( eventBuffer ) {
0 commit comments