Merge "Resize thumbnails images returned by REST endpoint"

This commit is contained in:
jenkins-bot 2017-02-17 00:30:28 +00:00 committed by Gerrit Code Review
commit ade818e89e
8 changed files with 126 additions and 37 deletions

Binary file not shown.

Binary file not shown.

3
src/constants.js Normal file
View file

@ -0,0 +1,3 @@
module.exports = {
THUMBNAIL_SIZE: 300 * $.bracketedDevicePixelRatio()
};

View file

@ -1,7 +1,6 @@
( function ( mw, $ ) {
( function ( mw ) {
var EXTRACT_LENGTH = 525,
THUMBNAIL_SIZE = 300 * $.bracketedDevicePixelRatio(),
// Public and private cache lifetime (5 minutes)
CACHE_LIFETIME = 300;
@ -9,9 +8,10 @@
* MediaWiki API gateway factory
*
* @param {mw.Api} api
* @param {mw.ext.constants } config
* @returns {ext.popups.Gateway}
*/
function createMediaWikiApiGateway( api ) {
function createMediaWikiApiGateway( api, config ) {
/**
* Fetch page data from the API
@ -33,7 +33,7 @@
explaintext: true,
piprop: 'thumbnail',
pithumbsize: THUMBNAIL_SIZE,
pithumbsize: config.THUMBNAIL_SIZE,
rvprop: 'timestamp',
inprop: 'url',
titles: title,
@ -106,4 +106,4 @@
module.exports = createMediaWikiApiGateway;
}( mediaWiki, jQuery ) );
}( mediaWiki ) );

View file

@ -1,4 +1,4 @@
( function ( mw ) {
( function ( mw, $ ) {
var RESTBASE_ENDPOINT = '/api/rest_v1/page/summary/',
RESTBASE_PROFILE = 'https://www.mediawiki.org/wiki/Specs/Summary/1.0.0';
@ -7,9 +7,10 @@
* RESTBase gateway factory
*
* @param {Function} ajax function from jQuery for example
* @param {ext.popups.constants} config set of configuration values
* @returns {ext.popups.Gateway}
*/
function createRESTBaseGateway( ajax ) {
function createRESTBaseGateway( ajax, config ) {
/**
* Fetch page data from the API
@ -35,7 +36,9 @@
*/
function getPageSummary( title ) {
return fetch( title )
.then( convertPageToModel );
.then( function( page ) {
return convertPageToModel( page, config.THUMBNAIL_SIZE );
} );
}
return {
@ -45,23 +48,44 @@
};
}
/**
* Takes the original thumbnail and ensure it fits within limits of THUMBNAIL_SIZE
*
* @param {Object} original image
* @param {int} thumbSize expected thumbnail size
* @returns {Object}
*/
function generateThumbnailData( original, thumbSize ) {
var parts = original.source.split( '/' ),
filename = parts[ parts.length - 1 ];
if ( thumbSize > original.width && filename.indexOf( '.svg' ) === -1 ) {
thumbSize = original.width;
}
return $.extend( {}, original, {
source: parts.join( '/' ) + '/' + thumbSize + 'px-' + filename
} );
}
/**
* Transform the rest API response to a preview model
*
* @param {Object} page
* @param {int} thumbSize
* @returns {ext.popups.PreviewModel}
*/
function convertPageToModel( page ) {
function convertPageToModel( page, thumbSize ) {
return mw.popups.preview.createModel(
page.title,
new mw.Title( page.title ).getUrl(),
page.lang,
page.dir,
page.extract,
page.thumbnail
page.originalimage ? generateThumbnailData( page.originalimage, thumbSize ) : undefined
);
}
module.exports = createRESTBaseGateway;
}( mediaWiki ) );
}( mediaWiki, jQuery ) );

View file

@ -1,13 +1,14 @@
( function ( mw, popups, Redux, ReduxThunk, $ ) {
var BLACKLISTED_LINKS = [
'.extiw',
'.image',
'.new',
'.internal',
'.external',
'.oo-ui-buttonedElement-button',
'.cancelLink a'
];
'.extiw',
'.image',
'.new',
'.internal',
'.external',
'.oo-ui-buttonedElement-button',
'.cancelLink a'
],
constants = require( './constants' );
/**
* Creates a gateway with sensible values for the dependencies.
@ -17,9 +18,9 @@
*/
function createGateway( config ) {
if ( config.get( 'wgPopupsAPIUseRESTBase' ) ) {
return popups.gateway.createRESTBaseGateway( $.ajax );
return popups.gateway.createRESTBaseGateway( $.ajax, constants );
}
return popups.gateway.createMediaWikiApiGateway( new mw.Api() );
return popups.gateway.createMediaWikiApiGateway( new mw.Api(), constants );
}
/**

View file

@ -2,6 +2,9 @@
var createModel = mw.popups.preview.createModel,
createMediaWikiApiGateway = mw.popups.gateway.createMediaWikiApiGateway,
DEFAULT_CONSTANTS = {
THUMBNAIL_SIZE: 300
},
MEDIAWIKI_API_RESPONSE = {
query: {
pages: [
@ -52,7 +55,7 @@
api = {
get: spy
},
gateway = createMediaWikiApiGateway( api ),
gateway = createMediaWikiApiGateway( api, DEFAULT_CONSTANTS),
expectedOptions = {
action: 'query',
prop: 'info|extracts|pageimages|revisions|info',
@ -62,7 +65,7 @@
exchars: 525,
explaintext: true,
piprop: 'thumbnail',
pithumbsize: 300 * $.bracketedDevicePixelRatio(),
pithumbsize: DEFAULT_CONSTANTS.THUMBNAIL_SIZE,
rvprop: 'timestamp',
inprop: 'url',
titles: 'Test Title',
@ -86,7 +89,7 @@
var api = {
get: this.sandbox.stub()
},
gateway = createMediaWikiApiGateway( api ),
gateway = createMediaWikiApiGateway( api, DEFAULT_CONSTANTS ),
errorCases = [
{},
{
@ -142,7 +145,7 @@
api = {
get: this.sandbox.stub().returns( deferred.promise() )
},
gateway = createMediaWikiApiGateway( api ),
gateway = createMediaWikiApiGateway( api, DEFAULT_CONSTANTS ),
done = assert.async( 1 );
gateway.getPageSummary( 'Test Title' ).fail( function () {
@ -159,7 +162,7 @@
$.Deferred().resolve( MEDIAWIKI_API_RESPONSE ).promise()
)
},
gateway = createMediaWikiApiGateway( api ),
gateway = createMediaWikiApiGateway( api, DEFAULT_CONSTANTS ),
done = assert.async( 1 );
gateway.getPageSummary( 'Test Title' ).done( function ( result ) {
@ -198,7 +201,7 @@
$.Deferred().resolve( response ).promise()
)
},
gateway = createMediaWikiApiGateway( api ),
gateway = createMediaWikiApiGateway( api, DEFAULT_CONSTANTS),
done = assert.async( 1 );
gateway.getPageSummary( 'Test Title' ).done( function ( result ) {

View file

@ -2,14 +2,35 @@
var createModel = mw.popups.preview.createModel,
createRESTBaseGateway = mw.popups.gateway.createRESTBaseGateway,
DEFAULT_CONSTANTS = {
THUMBNAIL_SIZE: 512
},
SVG_ORIGINAL_IMAGE = {
source: "https://upload.wikimedia.org/wikipedia/commons/8/8d/Ceiling_cat.svg",
width: 800,
height: 1000
},
RESTBASE_RESPONSE = {
title: 'Barack Obama',
extract: 'Barack Hussein Obama II born August 4, 1961) ...',
thumbnail: {
source: 'https://upload.wikimedia.org/someImage.jpg',
width: 256,
height: 320
width: 200,
height: 250
},
originalimage: {
source: "https://upload.wikimedia.org/wikipedia/commons/8/8d/President_Barack_Obama.jpg",
width: 800,
height: 1000
},
lang: 'en',
dir: 'ltr',
timestamp: '2017-01-30T10:17:41Z',
description: '44th President of the United States of America'
},
RESTBASE_RESPONSE_WITHOUT_IMAGE = {
title: 'Barack Obama',
extract: 'Barack Hussein Obama II born August 4, 1961) ...',
lang: 'en',
dir: 'ltr',
timestamp: '2017-01-30T10:17:41Z',
@ -22,14 +43,12 @@
'ltr',
'Barack Hussein Obama II born August 4, 1961) ...',
{
source: 'https://upload.wikimedia.org/someImage.jpg',
width: 256,
height: 320
source: 'https://upload.wikimedia.org/wikipedia/commons/8/8d/President_Barack_Obama.jpg/512px-President_Barack_Obama.jpg',
width: 800,
height: 1000
}
);
QUnit.module( 'ext.popups/gateway/rest' );
QUnit.test( 'RESTBase gateway is called with correct arguments', function ( assert ) {
var getSpy = this.sandbox.spy(),
gateway = createRESTBaseGateway( getSpy ),
@ -50,11 +69,38 @@
var gateway = createRESTBaseGateway();
assert.deepEqual(
gateway.convertPageToModel( RESTBASE_RESPONSE ),
gateway.convertPageToModel( RESTBASE_RESPONSE, 512 ),
RESTBASE_RESPONSE_PREVIEW_MODEL
);
} );
QUnit.test( 'RESTBase gateway doesn\'t stretch thumbnails', function ( assert ) {
var model,
gateway = createRESTBaseGateway();
model = gateway.convertPageToModel( RESTBASE_RESPONSE, 2000);
assert.equal(
model.thumbnail.source,
'https://upload.wikimedia.org/wikipedia/commons/8/8d/President_Barack_Obama.jpg/800px-President_Barack_Obama.jpg',
'If the requested thumbnail size is bigger than the originalimage width the originalimage width is used'
);
} );
QUnit.test( 'RESTBase gateway stretches SVGs', function ( assert ) {
var model,
gateway = createRESTBaseGateway();
model = gateway.convertPageToModel( $.extend( {}, RESTBASE_RESPONSE, { originalimage: SVG_ORIGINAL_IMAGE } ),
2000 );
assert.equal(
model.thumbnail.source,
'https://upload.wikimedia.org/wikipedia/commons/8/8d/Ceiling_cat.svg/2000px-Ceiling_cat.svg',
'If the requested thumbnail size is bigger than the originalimage and its an SVG all is good'
);
} );
QUnit.test( 'RESTBase gateway handles the API failure', function ( assert ) {
var deferred = $.Deferred(),
api = this.sandbox.stub().returns( deferred.promise() ),
@ -73,7 +119,7 @@
var api = this.sandbox.stub().returns(
$.Deferred().resolve( RESTBASE_RESPONSE ).promise()
),
gateway = createRESTBaseGateway( api ),
gateway = createRESTBaseGateway( api, DEFAULT_CONSTANTS),
done = assert.async( 1 );
gateway.getPageSummary( 'Test Title' ).done( function ( result ) {
@ -82,6 +128,18 @@
} );
} );
QUnit.test( 'RESTBase gateway handles missing images ', function ( assert ) {
var model,
gateway = createRESTBaseGateway();
model = gateway.convertPageToModel( RESTBASE_RESPONSE_WITHOUT_IMAGE, 300 );
assert.equal(
model.originalimage,
undefined,
'If restbase handles missing image information'
);
} );
QUnit.test( 'RESTBase gateway handles missing pages ', function ( assert ) {
var response = {
type: 'https://mediawiki.org/wiki/HyperSwitch/errors/not_found',
@ -93,7 +151,7 @@
api = this.sandbox.stub().returns(
$.Deferred().rejectWith( response ).promise()
),
gateway = createRESTBaseGateway( api ),
gateway = createRESTBaseGateway( api, DEFAULT_CONSTANTS ),
done = assert.async( 1 );
gateway.getPageSummary( 'Missing Page' ).fail( function () {