Phuedx has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/323524

Change subject: Don't always render after the API request resolves
......................................................................

Don't always render after the API request resolves

If the user abandons the link after the API request delay (500 ms) but
before the it resolves (~10e3 ms), then the preview shouldn't be
rendered.

Changes:
* actions: Include the link in the FETCH_START, FETCH_FAILED, and
  FETCH_END actions.
* reducers: If the active link has changed, then FETCH_END is a NOOP.

Supporting changes:
* reducers: Signal that a preview should be rendered and shown with
  preview.shouldShow.

Change-Id: I3dd1c0c566ec63de515174c14845d7927583ce93
---
M resources/ext.popups/actions.js
M resources/ext.popups/reducers.js
M resources/ext.popups/renderChangeListener.js
M tests/qunit/ext.popups/actions.test.js
M tests/qunit/ext.popups/reducers.test.js
5 files changed, 111 insertions(+), 30 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Popups 
refs/changes/24/323524/1

diff --git a/resources/ext.popups/actions.js b/resources/ext.popups/actions.js
index e51c4b3..95389b3 100644
--- a/resources/ext.popups/actions.js
+++ b/resources/ext.popups/actions.js
@@ -48,25 +48,30 @@
         * Represents Page Previews fetching data via the 
[gateway](./gateway.js).
         *
         * @param {ext.popups.Gateway} gateway
-        * @param {String} title
+        * @param {Element} el
         * @return {Redux.Thunk}
         */
-       function fetch( gateway, title ) {
+       function fetch( gateway, el ) {
+               var title = $( el ).data( 'page-previews-title' );
+
                return function ( dispatch ) {
                        dispatch( {
                                type: types.FETCH_START,
+                               el: el,
                                title: title
                        } );
 
                        gateway( title )
                                .fail( function () {
                                        dispatch( {
-                                               type: types.FETCH_FAILED
+                                               type: types.FETCH_FAILED,
+                                               el: el
                                        } );
                                } )
                                .done( function ( result ) {
                                        dispatch( {
                                                type: types.FETCH_END,
+                                               el: el,
                                                result: result
                                        } );
                                } );
@@ -94,7 +99,7 @@
                        mw.popups.wait( FETCH_START_DELAY )
                                .then( function () {
                                        if ( getState().preview.activeLink === 
el ) {
-                                               dispatch( fetch( gateway, $( el 
).data( 'page-previews-title' ) ) );
+                                               dispatch( fetch( gateway, el ) 
);
                                        }
                                } );
                };
diff --git a/resources/ext.popups/reducers.js b/resources/ext.popups/reducers.js
index 395ad7e..4c6aaee 100644
--- a/resources/ext.popups/reducers.js
+++ b/resources/ext.popups/reducers.js
@@ -44,7 +44,8 @@
                                linkInteractionToken: undefined,
                                activeLink: undefined,
                                activeEvent: undefined,
-                               interactionStarted: undefined
+                               interactionStarted: undefined,
+                               shouldShow: false
                        };
                }
 
@@ -68,16 +69,22 @@
                                        activeEvent: undefined,
                                        interactionStarted: undefined,
                                        linkInteractionToken: undefined,
-                                       fetchResponse: undefined
+                                       fetchResponse: undefined,
+                                       shouldShow: false
                                } );
                        case mw.popups.actionTypes.FETCH_START:
                                return nextState( state, {
                                        fetchResponse: undefined
                                } );
                        case mw.popups.actionTypes.FETCH_END:
-                               return nextState( state, {
-                                       fetchResponse: action.result
-                               } );
+                               if ( action.el === state.activeLink ) {
+                                       return nextState( state, {
+                                               fetchResponse: action.result,
+                                               shouldShow: true
+                                       } );
+                               }
+
+                               /* falls through */
                        default:
                                return state;
                }
diff --git a/resources/ext.popups/renderChangeListener.js 
b/resources/ext.popups/renderChangeListener.js
index 1288e35..f0c13a1 100644
--- a/resources/ext.popups/renderChangeListener.js
+++ b/resources/ext.popups/renderChangeListener.js
@@ -9,10 +9,10 @@
                var preview;
 
                return function ( prevState, state ) {
-                       if ( state.preview.fetchResponse && !preview ) {
+                       if ( state.preview.shouldShow && !preview ) {
                                preview = mw.popups.renderer.render( 
state.preview.fetchResponse );
                                preview.show( state.preview.activeEvent );
-                       } else if ( prevState && 
prevState.preview.fetchResponse ) {
+                       } else if ( !state.preview.shouldShow && preview ) {
                                preview.hide()
                                        .done( function () {
                                                preview = undefined;
diff --git a/tests/qunit/ext.popups/actions.test.js 
b/tests/qunit/ext.popups/actions.test.js
index 45b80f0..5f9af0b 100644
--- a/tests/qunit/ext.popups/actions.test.js
+++ b/tests/qunit/ext.popups/actions.test.js
@@ -54,23 +54,24 @@
                        gateway = function () {
                                return gatewayDeferred;
                        },
+                       el = this.el,
                        fetchThunk,
                        result = {};
 
                this.sandbox.stub( mw, 'now' ).returns( new Date() );
 
-               mw.popups.actions.linkDwell( this.el, event, gateway )( 
dispatch, this.getState );
+               mw.popups.actions.linkDwell( el, event, gateway )( dispatch, 
this.getState );
 
                assert.ok( dispatch.calledWith( {
                        type: 'LINK_DWELL',
-                       el: this.el,
+                       el: el,
                        event: event,
                        interactionStarted: mw.now()
                } ) );
 
                // Stub the state tree being updated.
                this.state.preview = {
-                       activeLink: this.el
+                       activeLink: el
                };
 
                // ---
@@ -87,13 +88,17 @@
 
                        assert.ok( dispatch.calledWith( {
                                type: 'FETCH_START',
+                               el: el,
                                title: 'Foo'
                        } ) );
+
+                       // ---
 
                        gatewayDeferred.resolve( result );
 
                        assert.ok( dispatch.calledWith( {
                                type: 'FETCH_END',
+                               el: el,
                                result: result
                        } ) );
 
diff --git a/tests/qunit/ext.popups/reducers.test.js 
b/tests/qunit/ext.popups/reducers.test.js
index 4d2a590..5adf4d4 100644
--- a/tests/qunit/ext.popups/reducers.test.js
+++ b/tests/qunit/ext.popups/reducers.test.js
@@ -1,6 +1,10 @@
 ( function ( mw, $ ) {
 
-       QUnit.module( 'ext.popups/reducers' );
+       QUnit.module( 'ext.popups/reducers', {
+               setup: function () {
+                       this.el = $( '<a>' );
+               }
+       } );
 
        QUnit.test( '#rootReducer', function ( assert ) {
                var state = mw.popups.reducers.rootReducer( undefined, { type: 
'@@INIT' } );
@@ -17,7 +21,8 @@
                                        linkInteractionToken: undefined,
                                        activeLink: undefined,
                                        activeEvent: undefined,
-                                       interactionStarted: undefined
+                                       interactionStarted: undefined,
+                                       shouldShow: false
                                },
                                renderer: {
                                        isAnimating: false,
@@ -29,47 +34,106 @@
                );
        } );
 
-       QUnit.test( '#preview', function ( assert ) {
-               var state = mw.popups.reducers.preview( undefined, { type: 
'@@INIT' } ),
-                       action;
-
-               assert.expect( 2 );
-
-               action = {
+       QUnit.test( '#preview: BOOT', function ( assert ) {
+               var action = {
                        type: 'BOOT',
                        isUserInCondition: true,
                        sessionToken: '0123456789',
                        pageToken: '9876543210'
                };
 
+               assert.expect( 1 );
+
                assert.deepEqual(
-                       mw.popups.reducers.preview( state, action ),
+                       mw.popups.reducers.preview( {}, action ),
                        {
                                enabled: true,
                                sessionToken: '0123456789',
                                pageToken: '9876543210'
                        },
-                       'It should set enabled and the session tokens on the 
BOOT action'
+                       'It should set enabled and the session tokens.'
                );
+       } );
 
-               // ---
-               action = {
+       QUnit.test( '#preview: LINK_DWELL', function ( assert ) {
+               var action = {
                        type: 'LINK_DWELL',
-                       el: $( '<a>' ),
+                       el: this.el,
                        event: {},
                        interactionStarted: mw.now(),
                        linkInteractionToken: '0123456789'
                };
 
                assert.deepEqual(
-                       mw.popups.reducers.preview( state, action ),
+                       mw.popups.reducers.preview( {}, action ),
                        {
                                activeLink: action.el,
                                activeEvent: action.event,
                                interactionStarted: action.interactionStarted,
                                linkInteractionToken: 
action.linkInteractionToken
                        },
-                       'It should set active link and event as well as 
interaction info on the LINK_DWELL action'
+                       'It should set active link and event as well as 
interaction info.'
+               );
+       } );
+
+       QUnit.test( '#preview: LINK_ABANDON', function ( assert ) {
+               var action = {
+                       type: 'LINK_ABANDON',
+                       el: this.el
+               };
+
+               assert.deepEqual(
+                       mw.popups.reducers.preview( {}, action ),
+                       {
+                               activeLink: undefined,
+                               activeEvent: undefined,
+                               interactionStarted: undefined,
+                               linkInteractionToken: undefined,
+                               fetchResponse: undefined,
+                               shouldShow: false
+                       },
+                       'It should hide the preview and reset the interaction 
info.'
+               );
+       } );
+
+       QUnit.test( '#preview: FETCH_END', function ( assert ) {
+               var state = {
+                               activeLink: this.el
+                       },
+                       action = {
+                               type: 'FETCH_END',
+                               el: this.el,
+                               result: {}
+                       };
+
+               assert.expect( 2 );
+
+               assert.deepEqual(
+                       mw.popups.reducers.preview( state, action ),
+                       {
+                               activeLink: state.activeLink, // Previous state.
+
+                               fetchResponse: action.result,
+                               shouldShow: true
+                       },
+                       'It should store the result and signal that a preview 
should be rendered.'
+               );
+
+               // ---
+
+               state = {
+                       activeLink: $( '<a>' )
+               };
+               action = {
+                       type: 'FETCH_END',
+                       el: this.el,
+                       result: {}
+               };
+
+               assert.deepEqual(
+                       mw.popups.reducers.preview( state, action ),
+                       state,
+                       'It should NOOP if the user has interacted with another 
link since the request was dispatched via the gateway.'
                );
        } );
 

-- 
To view, visit https://gerrit.wikimedia.org/r/323524
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I3dd1c0c566ec63de515174c14845d7927583ce93
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Popups
Gerrit-Branch: mpga
Gerrit-Owner: Phuedx <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to