Phuedx has uploaded a new change for review. https://gerrit.wikimedia.org/r/325287
Change subject: Increment preview count ...................................................................... Increment preview count Action changes: * Add the PREVIEW_SHOW action. Reducer changes: * Increment the user's preview count in the eventLogging reducer. Changes: * Add the previewCount change listener, which is responsible for persisting the user's preview count to storage. * Call the change listener factories individually in #registerChangeListeners as their signatures aren't consistent. Bug: T152223 Change-Id: Ifb493c5bff66712a25614ebb905251e43375420a --- M extension.json M resources/ext.popups/actions.js M resources/ext.popups/boot.js A resources/ext.popups/previewCountChangeListener.js M resources/ext.popups/reducers.js M resources/ext.popups/renderChangeListener.js A tests/qunit/ext.popups/previewCountChangeListener.test.js M tests/qunit/ext.popups/reducers.eventLogging.test.js A tests/qunit/ext.popups/renderChangeListener.test.js 9 files changed, 219 insertions(+), 12 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Popups refs/changes/87/325287/1 diff --git a/extension.json b/extension.json index 264ae1b..9408bd2 100644 --- a/extension.json +++ b/extension.json @@ -71,6 +71,7 @@ "resources/ext.popups/linkTitleChangeListener.js", "resources/ext.popups/renderer.js", "resources/ext.popups/renderChangeListener.js", + "resources/ext.popups/previewCountChangeListener.js", "resources/ext.popups/boot.js" ], "templates": { diff --git a/resources/ext.popups/actions.js b/resources/ext.popups/actions.js index 838f901..bea886a 100644 --- a/resources/ext.popups/actions.js +++ b/resources/ext.popups/actions.js @@ -15,6 +15,7 @@ PREVIEW_ABANDON_END: 'PREVIEW_ABANDON_END', PREVIEW_ANIMATING: 'PREVIEW_ANIMATING', PREVIEW_INTERACTIVE: 'PREVIEW_INTERACTIVE', + PREVIEW_SHOW: 'PREVIEW_SHOW', PREVIEW_CLICK: 'PREVIEW_CLICK', COG_CLICK: 'COG_CLICK', SETTINGS_DIALOG_RENDERED: 'SETTINGS_DIALOG_RENDERED', @@ -174,7 +175,7 @@ }; /** - * Represents the user dwelling on a preivew with their mouse. + * Represents the user dwelling on a preview with their mouse. * * @return {Object} */ @@ -206,6 +207,20 @@ }; /** + * Represents a preview being shown to the user. + * + * This action is dispatched by the `mw.popups.changeListeners.render` change + * listener. + * + * @return {Object} + */ + actions.previewShow = function () { + return { + type: 'PREVIEW_SHOW' + }; + }; + + /** * Represents the user clicking either the "Enable previews" footer menu link, * or the "cog" icon that's present on each preview. * diff --git a/resources/ext.popups/boot.js b/resources/ext.popups/boot.js index 05c077e..6729599 100644 --- a/resources/ext.popups/boot.js +++ b/resources/ext.popups/boot.js @@ -1,4 +1,4 @@ -( function ( mw, Redux, ReduxThunk, $ ) { +( function ( mw, Redux, ReduxThunk ) { var BLACKLISTED_LINKS = [ '.extiw', '.image', @@ -28,13 +28,19 @@ * `mw.popups.changeListeners`. * * @param {Redux.Store} store + * @param {Object} actions + * @param {ext.popups.UserSettings} userSettings */ - function registerChangeListeners( store, actions ) { - $.each( mw.popups.changeListeners, function ( _, changeListenerFactory ) { - var changeListener = changeListenerFactory( actions ); + function registerChangeListeners( store, actions, userSettings ) { - mw.popups.registerChangeListener( store, changeListener ); - } ); + // Sugar. + var changeListeners = mw.popups.changeListeners, + registerChangeListener = mw.popups.registerChangeListener; + + registerChangeListener( store, changeListeners.footerLink( actions ) ); + registerChangeListener( store, changeListeners.linkTitle() ); + registerChangeListener( store, changeListeners.render( actions ) ); + registerChangeListener( store, changeListeners.previewCount( userSettings ) ); } /** @@ -84,7 +90,7 @@ ) ) ); actions = createBoundActions( store ); - registerChangeListeners( store, actions ); + registerChangeListeners( store, actions, userSettings ); actions.boot( isUserInCondition, @@ -118,4 +124,4 @@ } ); } ); -}( mediaWiki, Redux, ReduxThunk, jQuery ) ); +}( mediaWiki, Redux, ReduxThunk ) ); diff --git a/resources/ext.popups/previewCountChangeListener.js b/resources/ext.popups/previewCountChangeListener.js new file mode 100644 index 0000000..40d7b37 --- /dev/null +++ b/resources/ext.popups/previewCountChangeListener.js @@ -0,0 +1,38 @@ +( function ( mw ) { + + /** + * Creates an instance of the preview count change listener. + * + * When the user dwells on a link for long enough that a preview is shown, + * then their preview count will be incremented (see + * `mw.popups.reducers.eventLogging`, and is persisted to local storage. + * + * @return {ext.popups.ChangeListener} + */ + mw.popups.changeListeners.previewCount = function ( userSettings ) { + + /** + * FIXME: This kind of function, one that selects the specific part(s) of + * the state tree that a change listener will use, is a common pattern and + * should be extracted. + * + * @param {Object} state + * @return {Number} + */ + function getPreviewCount( state ) { + return state.eventLogging.baseData.previewCount; + } + + return function ( prevState, state ) { + var previewCount = getPreviewCount( state ); + + if ( + prevState && + previewCount > getPreviewCount( prevState ) + ) { + userSettings.setPreviewCount( previewCount ); + } + }; + }; + +}( mediaWiki ) ); diff --git a/resources/ext.popups/reducers.js b/resources/ext.popups/reducers.js index 9a80a77..89ac525 100644 --- a/resources/ext.popups/reducers.js +++ b/resources/ext.popups/reducers.js @@ -127,7 +127,8 @@ * @return {Object} The state as a result of processing the action */ mw.popups.reducers.eventLogging = function ( state, action ) { - var nextQueue; + var nextQueue, + nextCount; if ( state === undefined ) { state = { @@ -153,11 +154,23 @@ popupEnabled: action.isUserInCondition, pageToken: action.pageToken, sessionToken: action.sessionToken, - editCountBucket: counts.getEditCountBucket( action.user.editCount ) + editCountBucket: counts.getEditCountBucket( action.user.editCount ), + previewCount: action.user.previewCount, + previewCountBucket: counts.getPreviewCountBucket( action.user.previewCount ) }, queue: nextQueue } ); + case mw.popups.actionTypes.PREVIEW_SHOW: + nextCount = state.baseData.previewCount + 1; + + return nextState( state, { + baseData: nextState( state.baseData, { + previewCount: nextCount, + previewCountBucket: counts.getPreviewCountBucket( nextCount ) + } ) + } ); + default: return state; } diff --git a/resources/ext.popups/renderChangeListener.js b/resources/ext.popups/renderChangeListener.js index 99fd821..99c9ccb 100644 --- a/resources/ext.popups/renderChangeListener.js +++ b/resources/ext.popups/renderChangeListener.js @@ -12,7 +12,8 @@ return function ( prevState, state ) { if ( state.preview.shouldShow && !preview ) { preview = mw.popups.renderer.render( state.preview.fetchResponse ); - preview.show( state.preview.activeEvent, boundActions ); + preview.show( state.preview.activeEvent, boundActions ) + .done( boundActions.previewShow ); } else if ( !state.preview.shouldShow && preview ) { preview.hide() .done( function () { diff --git a/tests/qunit/ext.popups/previewCountChangeListener.test.js b/tests/qunit/ext.popups/previewCountChangeListener.test.js new file mode 100644 index 0000000..7c5ce09 --- /dev/null +++ b/tests/qunit/ext.popups/previewCountChangeListener.test.js @@ -0,0 +1,63 @@ +( function ( mw, $ ) { + + QUnit.module( 'ext.popups/previewCountChangeListener', { + setup: function () { + this.userSettings = { + setPreviewCount: this.sandbox.spy() + }; + + this.changeListener = mw.popups.changeListeners.previewCount( this.userSettings ); + } + } ); + + QUnit.test( + 'it shouldn\'t update the storage if the preview count hasn\'t changed', + function ( assert ) { + var state, + prevState; + + assert.expect( 1 ); + + state = { + eventLogging: { + baseData: { + previewCount: 222 + } + } + }; + + this.changeListener( undefined, state ); + + // --- + + prevState = $.extend( true, {}, state ); + + this.changeListener( prevState, state ); + + assert.notOk( this.userSettings.setPreviewCount.called ); + } + ); + + QUnit.test( 'it should update the storage', function ( assert ) { + var prevState, + state; + + assert.expect( 1 ); + + prevState = { + eventLogging: { + baseData: { + previewCount: 222 + } + } + }; + + state = $.extend( true, {}, prevState ); + ++state.eventLogging.baseData.previewCount; + + this.changeListener( prevState, state ); + + assert.ok( this.userSettings.setPreviewCount.calledWith( 223 ) ); + } ); + +}( mediaWiki, jQuery ) ); diff --git a/tests/qunit/ext.popups/reducers.eventLogging.test.js b/tests/qunit/ext.popups/reducers.eventLogging.test.js index 28b7047..f758c18 100644 --- a/tests/qunit/ext.popups/reducers.eventLogging.test.js +++ b/tests/qunit/ext.popups/reducers.eventLogging.test.js @@ -57,4 +57,35 @@ ); } ); + QUnit.test( 'PREVIEW_SHOW', function ( assert ) { + var state, + count = 22, + action, + expectedCount = count + 1; + + state = { + baseData: { + previewCount: count, + previewCountBucket: counts.getPreviewCountBucket( count ) + }, + queue: [] + }; + + action = { + type: 'PREVIEW_SHOW' + }; + + assert.deepEqual( + mw.popups.reducers.eventLogging( state, action ), + { + baseData: { + previewCount: expectedCount, + previewCountBucket: counts.getPreviewCountBucket( expectedCount ) + }, + queue: [] + }, + 'It increments the user\'s preview count and re-buckets that count.' + ); + } ); + }( mediaWiki ) ); diff --git a/tests/qunit/ext.popups/renderChangeListener.test.js b/tests/qunit/ext.popups/renderChangeListener.test.js new file mode 100644 index 0000000..7b65dc7 --- /dev/null +++ b/tests/qunit/ext.popups/renderChangeListener.test.js @@ -0,0 +1,39 @@ +( function ( mw, $ ) { + + // Since mw.popups.changeListeners.render manipulates the DOM, this test is, + // by necessity, an integration test. + QUnit.module( 'ext.popups/renderChangeListener @integration' ); + + QUnit.test( + 'it should call the showPreview action creator when the preview is shown', + function ( assert ) { + var boundActions, + changeListener, + state; + + boundActions = { + previewShow: this.sandbox.spy() + }; + + this.sandbox.stub( mw.popups.renderer, 'render', function () { + return { + show: function () { + return $.Deferred().resolve(); + } + }; + } ); + + state = { + preview: { + shouldShow: true + } + }; + + changeListener = mw.popups.changeListeners.render( boundActions ); + changeListener( undefined, state ); + + assert.ok( boundActions.previewShow.called ); + } + ); + +}( mediaWiki, jQuery ) ); -- To view, visit https://gerrit.wikimedia.org/r/325287 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ifb493c5bff66712a25614ebb905251e43375420a Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Popups Gerrit-Branch: mpga Gerrit-Owner: Phuedx <samsm...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits