mediawiki-extensions-Popups/src/reducers/preview.js
Stephen Niedzielski 9114981380 Update: show placeholder preview for more failures
Functional changes

- Show the default / error preview for all extract request failures
  except those due to network circumstances (such as CORS) or no
  connectivity (offline). Previously, the error preview was displayed
  only for missing pages.

- FETCH_COMPLETE was previously only dispatched after FETCH_END. Now
  it's also dispatched after FETCH_FAILED. The additional "fetch
  complete" is not expected to impact logging. The states of success
  are: START, END, COMPLETE. The new failure states are consistent with
  success: START, FAILED, COMPLETE.

Testing

Errors may be stimulated in a number of ways including:

- Timeout: add a timeout field to RESTBaseGateway /
  MediaWikiGateway.fetch().

  http://api.jquery.com/jquery.ajax/

- Bad request: change MediaWikiGateway.fetch's action field to
  `Math.random() > 0.5 ? 'query' : 'fail'` and RESTBaseGateway.fetch's
  url field to
  `RESTBASE_ENDPOINT + ( Math.random() > 0.5 ? encodeURIComponent( title ) : '%%%' )`.

- Desired Gateway can be configured in Gateway#createGateway().

- Note: T184534 describes a circumstance where cached previews may not
  appear when offline. Disable browser caching to avoid confusion.

Bug: T183151
Bug: T184534
Change-Id: I7332284da0e0fb1ecd234a6f1e146ebd9ad8d81f
2018-01-16 18:44:00 -06:00

96 lines
2.2 KiB
JavaScript

import actionTypes from '../actionTypes';
import nextState from './nextState';
/**
* Reducer for actions that modify the state of the preview model
*
* @param {?Object} state before action
* @param {!Object} action Redux action that modified state.
* Must have `type` property.
* @return {!Object} state after action
*/
export default function preview( state, action ) {
if ( state === undefined ) {
state = {
enabled: undefined,
activeLink: undefined,
activeEvent: undefined,
activeToken: '',
shouldShow: false,
isUserDwelling: false
};
}
switch ( action.type ) {
case actionTypes.BOOT:
return nextState( state, {
enabled: action.isEnabled
} );
case actionTypes.SETTINGS_CHANGE:
return nextState( state, {
enabled: action.enabled
} );
case actionTypes.LINK_DWELL:
// New interaction
if ( action.el !== state.activeLink ) {
return nextState( state, {
activeLink: action.el,
activeEvent: action.event,
activeToken: action.token,
// When the user dwells on a link with their keyboard, a preview is
// renderered, and then dwells on another link, the ABANDON_END
// action will be ignored.
//
// Ensure that all the preview is hidden.
shouldShow: false,
isUserDwelling: true
} );
}
// Dwelling back into the same link
return nextState( state, {
isUserDwelling: true
} );
case actionTypes.ABANDON_END:
if ( action.token === state.activeToken && !state.isUserDwelling ) {
return nextState( state, {
activeLink: undefined,
activeToken: undefined,
activeEvent: undefined,
fetchResponse: undefined,
shouldShow: false
} );
}
return state;
case actionTypes.PREVIEW_DWELL:
return nextState( state, {
isUserDwelling: true
} );
case actionTypes.ABANDON_START:
return nextState( state, {
isUserDwelling: false
} );
case actionTypes.FETCH_START:
return nextState( state, {
fetchResponse: undefined
} );
case actionTypes.FETCH_COMPLETE:
if ( action.token === state.activeToken ) {
return nextState( state, {
fetchResponse: action.result,
shouldShow: state.isUserDwelling
} );
} // else fall through
default:
return state;
}
}