mediawiki-extensions-Popups/resources/ext.popups/gateway.js
Sam Smith b2f9ffa9b0 previews: Add generic fallback preview
Changes:
* Make the gateway handle missing pages, which are characterised by the
  MediaWiki API response having both the missing property set to truthy
  and the page not having any revisions.
* Add the preview-empty template and associated "mwe-popups-is-empty"
  CSS class, which describe what an empty preview contains and how it
  should look.

Supporting changes:
* Move the original preview template into the ext.popups module.

Bug: T151054
Change-Id: Ife75bf9c6bafdfe0a6cc3e20eea853b4ac8f951b
2016-12-02 12:02:43 +00:00

186 lines
4.3 KiB
JavaScript

( function ( mw, $ ) {
// FIXME: These constants (and others like 'em) should be in some top-level
// configuration file.
var EXTRACT_LENGTH = 525,
THUMBNAIL_SIZE = 300 * $.bracketedDevicePixelRatio(),
CACHE_LIFETIME = 300, // Public and private cache lifetime (5 minutes)
ONE_DAY = 24 * 60 * 60 * 1000; // ms.
/**
* @typedef {Function} ext.popups.Gateway
* @param {String} title
*/
/**
* Creates a function that fetches all of the data required to give the user a
* preview of the page from the MediaWiki API given the title of the page (see
* `mw.popups.processLinks` for the definition of "title").
*
* If the API request fails or if the API response is empty, then the gateway
* will reject; otherwise, it'll resolve.
*
* @param {mw.Api} api
* @return {ext.popups.Gateway}
*/
mw.popups.createGateway = function ( api ) {
return function ( title ) {
return api.get( {
action: 'query',
prop: 'info|extracts|pageimages|revisions|info',
formatversion: 2,
redirects: true,
exintro: true,
exchars: EXTRACT_LENGTH,
// There is an added geometric limit on .mwe-popups-extract
// so that text does not overflow from the card.
explaintext: true,
piprop: 'thumbnail',
pithumbsize: THUMBNAIL_SIZE,
rvprop: 'timestamp',
inprop: 'url',
titles: title,
smaxage: CACHE_LIFETIME,
maxage: CACHE_LIFETIME,
uselang: 'content'
},
{
headers: {
'X-Analytics': 'preview=1'
}
} )
.then( function ( data ) {
// If the response is empty, i.e. data.query.pages is empty or isn't
// set, then reject rather than resolve.
if (
data.query &&
data.query.pages &&
data.query.pages.length
) {
return data.query.pages[0];
}
return $.Deferred().reject();
} )
.then( processPage );
};
};
/**
* Processes a page as represented by the MediaWiki API (including the
* additional data requested above).
*
* @param {Object} page
* @result {Object}
*/
function processPage( page ) {
var lastModified,
result;
result = {
title: page.title,
languageCode: page.pagelanguagehtmlcode,
languageDirection: page.pagelanguagedir,
url: page.canonicalurl,
extract: processExtract( page.extract )
};
if ( page.revisions && page.revisions.length ) {
lastModified = new Date( page.revisions[0].timestamp );
result.lastModified = lastModified;
result.isRecent = new Date() - lastModified < ONE_DAY;
}
if ( page.thumbnail ) {
result.thumbnail = page.thumbnail;
result.thumbnail.url = result.thumbnail.source;
delete( result.thumbnail.source );
}
return result;
}
/**
* Processes the extract returned by the TextExtracts MediaWiki API query
* module.
*
* @param {String|undefined} extract
* @return {String|undefined}
*/
function processExtract( extract ) {
var result;
if ( extract === undefined || extract === '' ) {
return undefined;
}
result = extract;
result = removeParentheticals( result );
result = removeEllipsis( result );
return result.length > 0 ? result : undefined;
}
/**
* Removes the trailing ellipsis from the extract, if it's there.
*
* This function was extracted from
* `mw.popups.renderer.article#removeEllipsis`.
*
* @param {String} extract
* @return {String}
*/
function removeEllipsis( extract ) {
return extract.replace( /\.\.\.$/, '' );
}
/**
* Removes parentheticals from the extract.
*
* If the parenthesis are unbalanced or out of order, then the extract is
* returned without further processing.
*
* This function was extracted from
* `mw.popups.renderer.article#removeParensFromText`.
*
* @param {String} extract
* @return {String}
*/
function removeParentheticals( extract ) {
var
ch,
result = '',
level = 0,
i = 0;
for ( i; i < extract.length; i++ ) {
ch = extract.charAt( i );
if ( ch === ')' && level === 0 ) {
return extract;
}
if ( ch === '(' ) {
level++;
continue;
} else if ( ch === ')' ) {
level--;
continue;
}
if ( level === 0 ) {
// Remove leading spaces before brackets
if ( ch === ' ' && extract.charAt( i + 1 ) === '(' ) {
continue;
}
result += ch;
}
}
return ( level === 0 ) ? result : extract;
}
}( mediaWiki, jQuery ) );