mediawiki-extensions-Popups/resources/ext.popups/boot.js
Sam Smith 0d300867ab Make API request after 500 ms
If the user has abandoned the link or dwelled on a different link, then
don't make the API request.

Changes:
* Fix a bug in the linkDwell reducer where the activeLink was always
  being set to undefined.
* Add the private fetch action creator.
* Make the linkDwell action dispatch the result of the fetch action
  creator after 500ms.

Supporting changes:
* Make the link* action creators take DOM elements rather than jQuery
  instances so that:
  1. Testing whether the state tree has changed is an identity
     comparison.
  2. jQuery instances are constructed only when required.
* Document the ext.popups.Gateway type.
* Document the Redux.Store type.
* Rename the "previews-page-title" data attribute to
  "page-previews-title" to avoid confusion.

Change-Id: I0b1cf3337a6f8d6450ad2bd127cb292ebb73af4f
2016-11-17 13:20:11 +00:00

128 lines
3 KiB
JavaScript

( function ( mw, Redux, ReduxThunk, $ ) {
var BLACKLISTED_LINKS = [
'.extiw',
'.image',
'.new',
'.internal',
'.external',
'.oo-ui-buttonedElement-button',
'.cancelLink a'
];
/**
* Creates an experiment with sensible values for the depenencies.
*
* See `mw.popups.createExperiment`.
*
* @return {Function}
*/
function isUserInCondition() {
var userSettings = mw.popups.createUserSettings( mw.storage, mw.user );
return mw.popups.createExperiment(
mw.config,
mw.user,
userSettings
);
}
/**
* Creates a gateway with sensible values for the dependencies.
*
* See `mw.popups.createGateway`.
*
* @return {ext.popups.Gateway}
*/
function createGateway() {
return mw.popups.createGateway( new mw.Api() );
}
/**
* Subscribes the registered change listeners to the
* [store](http://redux.js.org/docs/api/Store.html#store).
*
* Change listeners are registered by setting a property on
* `mw.popups.changeListeners`.
*
* @param {Redux.Store} store
*/
function registerChangeListeners( store, actions ) {
$.each( mw.popups.changeListeners, function ( _, changeListenerFactory ) {
var changeListener = changeListenerFactory( actions );
mw.popups.registerChangeListener( store, changeListener );
} );
}
/**
* Binds the actions (or "action creators") to the
* [store](http://redux.js.org/docs/api/Store.html#store).
*
* @param {Redux.Store} store
* @return {Object}
*/
function createBoundActions( store ) {
return Redux.bindActionCreators( mw.popups.actions, store.dispatch );
}
/**
* Root reducer for all actions
*
* @param {Object} global state before action
* @param {Object} action Redux action that modified state.
* Must have `type` property.
* @return {Object} global state after action
*/
mw.popups.reducers.rootReducer = Redux.combineReducers( mw.popups.reducers );
// FIXME: Needs doc (or at least one comment line)
mw.requestIdleCallback( function () {
var compose = Redux.compose,
store,
actions,
generateToken = mw.user.generateRandomSessionId,
gateway = createGateway();
// If debug mode is enabled, then enable Redux DevTools.
if ( mw.config.get( 'debug' ) === true ) {
compose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
}
store = Redux.createStore(
mw.popups.reducers.rootReducer,
compose( Redux.applyMiddleware(
ReduxThunk.default
) )
);
actions = createBoundActions( store );
registerChangeListeners( store, actions );
actions.boot(
isUserInCondition(),
mw.user.sessionId(),
generateToken
);
mw.hook( 'wikipage.content' ).add( function ( $container ) {
var previewLinks =
mw.popups.processLinks(
$container,
BLACKLISTED_LINKS
);
previewLinks
.on( 'mouseover focus', function () {
actions.linkDwell( this, gateway );
} )
.on( 'mouseout blur', function () {
actions.linkAbandon( this );
} )
.on( 'click', function () {
actions.linkClick( this );
} );
} );
} );
}( mediaWiki, Redux, ReduxThunk, jQuery ) );