mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Popups
synced 2024-11-30 18:34:40 +00:00
reducers: Make LINK_CLICK finalize but not close
... the interaction. Following on from Iccba3c4c, LINK_CLICK shouldn't be considered the end of an interaction because the link or preview can still be abandoned by the user. Unlike ABANDON_END and LINK_DWELL, therefore, LINK_CLICK musn't destroy the interaction but indicate that no more events should be enqueued for the interaction. More concretely, if the user has clicked the link or the preview, then a "dwelledButAbandoned" or "dismissed" event shouldn't be logged. Changes: * Distinguish between "finalizing" and "closing" an interaction, where the latter is the current behavior of ABANDON_END, LINK_DWELL, and LINK_CLICK, in the eventLogging reducer and associated tests. * If the interaction is finalized, then either the "dwelledButAbandoned" or "dismissed" events shouldn't be logged. Bug: T162924 Change-Id: I09d8776da992053f89a77508e29a7cde3cfeeac6
This commit is contained in:
parent
9590284c70
commit
56aeeccb0d
BIN
resources/dist/index.js
vendored
BIN
resources/dist/index.js
vendored
Binary file not shown.
BIN
resources/dist/index.js.map
vendored
BIN
resources/dist/index.js.map
vendored
Binary file not shown.
|
@ -33,16 +33,26 @@ function getBaseData( bootAction ) {
|
||||||
* Creates an event that, when mixed into the base data (see `getBaseData`),
|
* Creates an event that, when mixed into the base data (see `getBaseData`),
|
||||||
* represents the user abandoning a link or preview.
|
* represents the user abandoning a link or preview.
|
||||||
*
|
*
|
||||||
|
* Since the event should be logged when the user has either abandoned a link or
|
||||||
|
* dwelled on a different link, we refer to these events as "closing" events as
|
||||||
|
* the link interaction has finished and a new one will be created later.
|
||||||
|
*
|
||||||
|
* If the link interaction is finalized, i.e. if an event has already been
|
||||||
|
* logged for the link interaction, then no closing event is created.
|
||||||
|
*
|
||||||
* @param {Object} interaction
|
* @param {Object} interaction
|
||||||
* @param {Number} endTimestamp
|
* @return {Object|undefined}
|
||||||
* @return {Object}
|
|
||||||
*/
|
*/
|
||||||
function createAbandonEvent( interaction ) {
|
function createClosingEvent( interaction ) {
|
||||||
var result = {
|
var result = {
|
||||||
linkInteractionToken: interaction.token,
|
linkInteractionToken: interaction.token,
|
||||||
totalInteractionTime: Math.round( interaction.finished - interaction.started )
|
totalInteractionTime: Math.round( interaction.finished - interaction.started )
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if ( interaction.finalized ) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// Has the preview been shown? If so, then, in the context of the
|
// Has the preview been shown? If so, then, in the context of the
|
||||||
// instrumentation, then the preview has been dismissed by the user
|
// instrumentation, then the preview has been dismissed by the user
|
||||||
// rather than the user has abandoned the link.
|
// rather than the user has abandoned the link.
|
||||||
|
@ -166,7 +176,7 @@ module.exports = function ( state, action ) {
|
||||||
|
|
||||||
// Was the user interacting with another link? If so, then log the
|
// Was the user interacting with another link? If so, then log the
|
||||||
// abandoned event.
|
// abandoned event.
|
||||||
event: state.interaction ? createAbandonEvent( state.interaction ) : undefined
|
event: state.interaction ? createClosingEvent( state.interaction ) : undefined
|
||||||
} );
|
} );
|
||||||
|
|
||||||
case actionTypes.PREVIEW_DWELL:
|
case actionTypes.PREVIEW_DWELL:
|
||||||
|
@ -178,7 +188,9 @@ module.exports = function ( state, action ) {
|
||||||
|
|
||||||
case actionTypes.LINK_CLICK:
|
case actionTypes.LINK_CLICK:
|
||||||
return nextState( state, {
|
return nextState( state, {
|
||||||
interaction: undefined,
|
interaction: {
|
||||||
|
finalized: true
|
||||||
|
},
|
||||||
event: {
|
event: {
|
||||||
action: 'opened',
|
action: 'opened',
|
||||||
linkInteractionToken: state.interaction.token,
|
linkInteractionToken: state.interaction.token,
|
||||||
|
@ -199,7 +211,7 @@ module.exports = function ( state, action ) {
|
||||||
if ( !state.interaction.isUserDwelling ) {
|
if ( !state.interaction.isUserDwelling ) {
|
||||||
return nextState( state, {
|
return nextState( state, {
|
||||||
interaction: undefined,
|
interaction: undefined,
|
||||||
event: createAbandonEvent( state.interaction )
|
event: createClosingEvent( state.interaction )
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,15 +221,16 @@ QUnit.test( 'LINK_DWELL doesn\'t start a new interaction under certain condition
|
||||||
QUnit.test(
|
QUnit.test(
|
||||||
'LINK_DWELL should enqueue a "dismissed" or "dwelledButAbandoned" event under certain conditions',
|
'LINK_DWELL should enqueue a "dismissed" or "dwelledButAbandoned" event under certain conditions',
|
||||||
function ( assert ) {
|
function ( assert ) {
|
||||||
var state,
|
var token = '0987654321',
|
||||||
now = Date.now();
|
now = Date.now(),
|
||||||
|
state;
|
||||||
|
|
||||||
// Read: The user dwells on link A, abandons it, and dwells on link B fewer
|
// Read: The user dwells on link A, abandons it, and dwells on link B fewer
|
||||||
// than 300 ms after (before the ABANDON_END action is reduced).
|
// than 300 ms after (before the ABANDON_END action is reduced).
|
||||||
state = eventLogging( undefined, {
|
state = eventLogging( undefined, {
|
||||||
type: 'LINK_DWELL',
|
type: 'LINK_DWELL',
|
||||||
el: this.link,
|
el: this.link,
|
||||||
token: '0987654321',
|
token: token,
|
||||||
timestamp: now
|
timestamp: now
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
@ -253,6 +254,33 @@ QUnit.test(
|
||||||
action: 'dwelledButAbandoned'
|
action: 'dwelledButAbandoned'
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
state = eventLogging( undefined, {
|
||||||
|
type: 'LINK_DWELL',
|
||||||
|
el: this.link,
|
||||||
|
token: token,
|
||||||
|
timestamp: now
|
||||||
|
} );
|
||||||
|
|
||||||
|
state = eventLogging( state, {
|
||||||
|
type: 'LINK_CLICK',
|
||||||
|
el: this.link
|
||||||
|
} );
|
||||||
|
|
||||||
|
state = eventLogging( state, {
|
||||||
|
type: 'LINK_DWELL',
|
||||||
|
el: $( '<a>' ),
|
||||||
|
token: 'banana',
|
||||||
|
timestamp: now + 500
|
||||||
|
} );
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
state.event,
|
||||||
|
undefined,
|
||||||
|
'It shouldn\'t enqueue either event if the interaction is finalized.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -286,8 +314,8 @@ QUnit.test( 'LINK_CLICK should enqueue an "opened" event', function ( assert ) {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
state.interaction,
|
state.interaction.finalized,
|
||||||
undefined,
|
true,
|
||||||
'It should finalize the interaction.'
|
'It should finalize the interaction.'
|
||||||
);
|
);
|
||||||
} );
|
} );
|
||||||
|
@ -504,7 +532,7 @@ QUnit.test( 'ABANDON_END should enqueue an event', function ( assert ) {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
state.interaction,
|
state.interaction,
|
||||||
undefined,
|
undefined,
|
||||||
'It should finalize the interaction.'
|
'It should close the interaction.'
|
||||||
);
|
);
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
@ -541,14 +569,16 @@ QUnit.test( 'ABANDON_END should enqueue an event', function ( assert ) {
|
||||||
} );
|
} );
|
||||||
|
|
||||||
QUnit.test( 'ABANDON_END doesn\'t enqueue an event under certain conditions', function ( assert ) {
|
QUnit.test( 'ABANDON_END doesn\'t enqueue an event under certain conditions', function ( assert ) {
|
||||||
var dwelledState,
|
var token = '0987654321',
|
||||||
|
now = Date.now(),
|
||||||
|
dwelledState,
|
||||||
state;
|
state;
|
||||||
|
|
||||||
dwelledState = eventLogging( undefined, {
|
dwelledState = eventLogging( undefined, {
|
||||||
type: 'LINK_DWELL',
|
type: 'LINK_DWELL',
|
||||||
el: this.link,
|
el: this.link,
|
||||||
token: '0987654321',
|
token: token,
|
||||||
timestamp: Date.now()
|
timestamp: now
|
||||||
} );
|
} );
|
||||||
|
|
||||||
state = eventLogging( dwelledState, {
|
state = eventLogging( dwelledState, {
|
||||||
|
@ -566,12 +596,35 @@ QUnit.test( 'ABANDON_END doesn\'t enqueue an event under certain conditions', fu
|
||||||
|
|
||||||
state = eventLogging( dwelledState, {
|
state = eventLogging( dwelledState, {
|
||||||
type: 'ABANDON_END',
|
type: 'ABANDON_END',
|
||||||
token: '0987654321'
|
token: token
|
||||||
} );
|
} );
|
||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
state.event,
|
state.event,
|
||||||
undefined,
|
undefined,
|
||||||
'It shouldn\'t enqueue an event if the use is dwelling on the preview or the link.'
|
'It shouldn\'t enqueue an event if the user is dwelling on the preview or the link.'
|
||||||
|
);
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
state = eventLogging( dwelledState, {
|
||||||
|
type: 'LINK_CLICK',
|
||||||
|
timestamp: now + 500
|
||||||
|
} );
|
||||||
|
|
||||||
|
state = eventLogging( state, {
|
||||||
|
type: 'ABANDON_START',
|
||||||
|
timestamp: now + 700
|
||||||
|
} );
|
||||||
|
|
||||||
|
state = eventLogging( state, {
|
||||||
|
type: 'ABANDON_END',
|
||||||
|
timestamp: now + 1000 // ABANDON_END_DELAY is 300 ms.
|
||||||
|
} );
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
state.event,
|
||||||
|
undefined,
|
||||||
|
'It shouldn\'t enqueue an event if the interaction is finalized.'
|
||||||
);
|
);
|
||||||
} );
|
} );
|
||||||
|
|
Loading…
Reference in a new issue