Phuedx has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/192788

Change subject: Add the MobileViewBannerImageRepository
......................................................................

Add the MobileViewBannerImageRepository

The pageimages API returns images that have one dimension - sometimes
height - equal to the target width. So use the mobileview API instead.

Also, both the pageimages and mobileview APIs return one image. Update
the BannerImage class and the repository classes to reflect this.

Change-Id: I0143e4b835311bf45fa3521d1335e23586043297
---
M includes/Resources.php
M javascripts/modules/bannerImage/BannerImage.js
A javascripts/modules/bannerImage/MobileViewBannerImageRepository.js
M javascripts/modules/bannerImage/PageImagesBannerImageRepository.js
M javascripts/modules/bannerImage/init.js
A tests/qunit/modules/bannerImage/test_MobileViewBannerImageRepository.js
M tests/qunit/modules/bannerImage/test_PageImagesBannerImageRepository.js
7 files changed, 220 insertions(+), 75 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend 
refs/changes/88/192788/1

diff --git a/includes/Resources.php b/includes/Resources.php
index 6215f80..3c4b55a 100644
--- a/includes/Resources.php
+++ b/includes/Resources.php
@@ -1245,6 +1245,7 @@
                'scripts' => array(
                        'javascripts/modules/bannerImage/Image.js',
                        
'javascripts/modules/bannerImage/PageImagesBannerImageRepository.js',
+                       
'javascripts/modules/bannerImage/MobileViewBannerImageRepository.js',
                        'javascripts/modules/bannerImage/BannerImage.js',
                ),
                'styles' => array(
diff --git a/javascripts/modules/bannerImage/BannerImage.js 
b/javascripts/modules/bannerImage/BannerImage.js
index 0acf277..aabfc42 100644
--- a/javascripts/modules/bannerImage/BannerImage.js
+++ b/javascripts/modules/bannerImage/BannerImage.js
@@ -5,51 +5,6 @@
                ratio = ( browser.isWideScreen() ) ? 21 / 9 : 16 / 9;
 
        /**
-        * Tries to load one image from a list of images.
-        *
-        * The first image from the list is loaded. If it loads, then it is 
returned, otherwise the next
-        * image in the list is loaded. If the list of images is exhausted then 
the loading has
-        * completely failed and nothing is returned.
-        *
-        * @param {Array} images A list of images
-        * @returns {jQuery.Promise}
-        */
-       function loadOneImage( images ) {
-
-               /**
-                * @ignore
-                *
-                * @param {Array} images
-                * @param {Number} index
-                * @param {jQuery.Deferred} deferred
-                */
-               function loadOneImageAcc( images, index, deferred ) {
-                       var image;
-
-                       if ( index >= images.length ) {
-                               deferred.reject();
-
-                               return;
-                       }
-
-                       image = images[ index ];
-                       image.load()
-                               .done( function () {
-                                       deferred.resolve( image );
-                               } )
-                               .fail( function () {
-                                       loadOneImageAcc( images, ++index, 
deferred );
-                               } );
-               }
-
-               var deferred = $.Deferred();
-
-               loadOneImageAcc( images, 0, deferred );
-
-               return deferred.promise();
-       }
-
-       /**
         * A banner image at the head of the page
         * @class BannerImage
         * @extends View
@@ -88,14 +43,11 @@
                                targetWidth = $( window ).width();
 
                        self.repository.getImages( targetWidth )
-                               .then( function ( images ) {
-                                       loadOneImage( images )
-                                               .done( function ( image ) {
-                                                       self.onImageLoaded( 
image );
-                                               } )
-                                               .fail( function () {
-                                                       self.remove();
-                                               } );
+                               .then( function ( image ) {
+                                       self.onImageLoaded( image );
+                               } )
+                               .fail( function () {
+                                       self.remove();
                                } );
                },
 
diff --git a/javascripts/modules/bannerImage/MobileViewBannerImageRepository.js 
b/javascripts/modules/bannerImage/MobileViewBannerImageRepository.js
new file mode 100644
index 0000000..33ebb68
--- /dev/null
+++ b/javascripts/modules/bannerImage/MobileViewBannerImageRepository.js
@@ -0,0 +1,88 @@
+ ( function ( M, $ ) {
+
+       var Class = M.require( 'Class' ),
+               Image = M.require( 'modules/bannerImage/Image' ),
+               MobileViewBannerImageRepository;
+
+       /**
+        * Uses the PageImages API to get images that can be used as banner 
images
+        * for a page.
+        *
+        * @class
+        */
+       MobileViewBannerImageRepository = Class.extend( {
+
+               /**
+                * @constructor
+                * @param {mw.Api} api A MediaWiki API client
+                * @param {String} title The title of the page
+                */
+               initialize: function ( api, title ) {
+                       this.api = api;
+                       this.title = title;
+                       this.cache = {};
+               },
+
+               /**
+                * Gets images that can be used as banner images.
+                *
+                * @param {Number} targetWidth The target width of the image
+                * @return {$.Promise} A promise that resolves with an array of 
Image objects if the
+                *  MediaWiki API request was successful or rejects otherwise.
+                */
+               getImages: function ( targetWidth ) {
+                       var deferred = $.Deferred(),
+                               promise = deferred.promise(),
+                               self = this;
+
+                       if ( self.cache.hasOwnProperty( targetWidth ) ) {
+                               deferred.resolve( self.cache[targetWidth] );
+
+                               return promise;
+                       }
+
+                       self.api.get( {
+                               action: 'mobileview',
+                               prop: 'thumb',
+                               page: self.title,
+                               thumbwidth: targetWidth
+                       } )
+                       .then( function ( data ) {
+                               var thumb,
+                                       image;
+
+                               // Page doesn't exist.
+                               if ( data.hasOwnProperty( 'error' ) ) {
+                                       deferred.reject( data.error );
+
+                                       return;
+                               }
+
+                               // Page exists but doesn't have thumbnail.
+                               if ( !data.mobileview.hasOwnProperty( 'thumb' ) 
) {
+                                       // TODO: Should this reject with an 
error?
+                                       deferred.reject();
+
+                                       return;
+                               }
+
+                               thumb = data.mobileview.thumb;
+                               image = new Image(
+                                       thumb.url,
+                                       thumb.width,
+                                       thumb.height
+                               );
+
+                               self.cache[targetWidth] = image;
+
+                               deferred.resolve( image );
+                       } )
+                       .fail( deferred.reject );
+
+                       return promise;
+               }
+       } );
+
+       M.define( 'modules/bannerImage/MobileViewBannerImageRepository', 
MobileViewBannerImageRepository );
+
+} ( mw.mobileFrontend, jQuery ) );
diff --git a/javascripts/modules/bannerImage/PageImagesBannerImageRepository.js 
b/javascripts/modules/bannerImage/PageImagesBannerImageRepository.js
index 5dbd640..84f0cea 100644
--- a/javascripts/modules/bannerImage/PageImagesBannerImageRepository.js
+++ b/javascripts/modules/bannerImage/PageImagesBannerImageRepository.js
@@ -47,33 +47,39 @@
                                pithumbsize: targetWidth
                        } )
                        .then( function ( data ) {
-                               var images = [];
+                               var image;
 
                                // Page doesn't exist.
                                if ( data.query.pages.hasOwnProperty( '-1' ) ) {
-                                       deferred.resolve( images );
+                                       deferred.reject();
 
                                        return;
                                }
 
+                               // TODO: Do we have an IE8 Object.keys polyfill 
available?
+                               // If so, then get rid of this iterator.
                                $.each( data.query.pages, function ( key, value 
) {
                                        var thumbnail = value.thumbnail;
 
                                        // Page exists but doesn't have 
thumbnail.
                                        if ( !thumbnail ) {
-                                               return;
+                                               deferred.reject();
+
+                                               return false;
                                        }
 
-                                       images.push( new Image(
+                                       image = new Image(
                                                thumbnail.source,
                                                thumbnail.width,
                                                thumbnail.height
-                                       ) );
+                                       );
+
+                                       return false;
                                } );
 
-                               self.cache[targetWidth] = images;
+                               self.cache[targetWidth] = image;
 
-                               deferred.resolve( images );
+                               deferred.resolve( image );
                        } )
                        .fail( deferred.reject );
 
diff --git a/javascripts/modules/bannerImage/init.js 
b/javascripts/modules/bannerImage/init.js
index bbfd68a..a481d56 100644
--- a/javascripts/modules/bannerImage/init.js
+++ b/javascripts/modules/bannerImage/init.js
@@ -1,7 +1,7 @@
 ( function ( M ) {
        M.require( 'context' ).assertMode( [ 'alpha', 'beta' ] );
 
-       var PageImagesBannerImageRepository = M.require( 
'modules/bannerImage/PageImagesBannerImageRepository' ),
+       var MobileViewBannerImageRepository = M.require( 
'modules/bannerImage/MobileViewBannerImageRepository' ),
                BannerImage = M.require( 'modules/bannerImage/BannerImage' ),
                page = M.getCurrentPage(),
                repository,
@@ -12,7 +12,7 @@
                !page.isMainPage() &&
                page.getNamespaceId() === 0
        ) {
-               repository = new PageImagesBannerImageRepository( new mw.Api(), 
page.title );
+               repository = new MobileViewBannerImageRepository( new mw.Api(), 
page.title );
                bannerImage = new BannerImage( {
                        repository: repository
                } );
diff --git 
a/tests/qunit/modules/bannerImage/test_MobileViewBannerImageRepository.js 
b/tests/qunit/modules/bannerImage/test_MobileViewBannerImageRepository.js
new file mode 100644
index 0000000..8ddb430
--- /dev/null
+++ b/tests/qunit/modules/bannerImage/test_MobileViewBannerImageRepository.js
@@ -0,0 +1,100 @@
+( function ( M, mw, $ ) {
+
+       var MobileViewBannerImageRepository = M.require( 
'modules/bannerImage/MobileViewBannerImageRepository' ),
+               Image = M.require( 'modules/bannerImage/Image' );
+
+       QUnit.module( 'MobileFrontend 
modules/bannerImage/MobileViewBannerImageRepository', {
+               setup: function () {
+                       var api = new mw.Api();
+                       this.getDeferred = $.Deferred();
+                       this.getSpy = this.stub( api, 'get' ).returns( 
this.getDeferred.promise() );
+                       this.title = 'Samurai';
+                       this.repository = new MobileViewBannerImageRepository( 
api, this.title );
+               }
+       } );
+
+       QUnit.test( 'it should try to get the image at the target width', 1, 
function ( assert ) {
+               this.repository.getImages( 1234 );
+
+               assert.deepEqual( this.getSpy.lastCall.args[0], {
+                       action: 'mobileview',
+                       prop: 'thumb',
+                       page: this.title,
+                       thumbwidth: 1234
+               } );
+       } );
+
+       QUnit.test( 'it should reject if the page doesn\'t exist', 1, function 
( assert ) {
+               var error = {
+                       code: 'missingtitle',
+                       info: 'The page you requested doesn\'t exist',
+                       '*': 'See https://en.wikipedia.org/w/api.php for API 
usage'
+               };
+
+               this.getDeferred.resolve( {
+                       error: error
+               } );
+
+               this.repository.getImages( 1234 ).fail( function ( actualError 
) {
+                       assert.deepEqual( error, actualError );
+               } );
+       } );
+
+       QUnit.test( 'it should reject if there\'s an error getting the image', 
1, function ( assert ) {
+               var error = 'ERR0R!!!';
+
+               this.getDeferred.reject( error );
+
+               this.repository.getImages( 1234 ).fail( function ( actualError 
) {
+                       assert.deepEqual( error, actualError );
+               } );
+       } );
+
+       QUnit.test( 'it should return the image if there is one', 1, function ( 
assert ) {
+               this.getDeferred.resolve( {
+                       mobileview: {
+                               thumb: {
+                                       url: 'http://foo/bar/baz',
+                                       width: 1,
+                                       height: 1
+                               },
+                               sections: []
+                       }
+               } );
+
+               this.repository.getImages( 1234 ).then( function ( image ) {
+                       assert.deepEqual( image, new Image( 
'http://foo/bar/baz', 1, 1 ) );
+               } );
+       } );
+
+       QUnit.test( 'it should reject if there isn\'t a thumbnail', 1, function 
( assert ) {
+               this.getDeferred.resolve( {
+                       mobileview: {
+                               sections: []
+                       }
+               } );
+
+               this.repository.getImages( 1234 ).fail( function () {
+                       assert.strictEqual( true, true );
+               } );
+       } );
+
+       QUnit.test( 'it shouldn\'t try to get the image at the target width 
more than once', 1, function ( assert ) {
+               this.getDeferred.resolve( {
+                       mobileview: {
+                               thumb: {
+                                       url: 'http://foo/bar/baz',
+                                       width: 1,
+                                       height: 1
+                               },
+                               sections: []
+                       }
+               } );
+
+               this.repository.getImages( 1234 );
+               this.repository.getImages( 1234 );
+
+               assert.strictEqual( this.getSpy.callCount, 1 );
+       } );
+
+} ( mw.mobileFrontend, mw, jQuery ) );
diff --git 
a/tests/qunit/modules/bannerImage/test_PageImagesBannerImageRepository.js 
b/tests/qunit/modules/bannerImage/test_PageImagesBannerImageRepository.js
index 53d7de4..0a81b88 100644
--- a/tests/qunit/modules/bannerImage/test_PageImagesBannerImageRepository.js
+++ b/tests/qunit/modules/bannerImage/test_PageImagesBannerImageRepository.js
@@ -23,7 +23,7 @@
                } );
        } );
 
-       QUnit.test( 'it should resolve with an empty list if the page doesn\'t 
exist', 1, function ( assert ) {
+       QUnit.test( 'it should reject if the page doesn\'t exist', 1, function 
( assert ) {
                this.getDeferred.resolve( {
                        query: {
                                pages: {
@@ -32,12 +32,12 @@
                        }
                } );
 
-               this.repository.getImages( 1234 ).then( function ( images ) {
-                       assert.deepEqual( images, [] );
+               this.repository.getImages( 1234 ).fail( function () {
+                       assert.strictEqual( true, true );
                } );
        } );
 
-       QUnit.test( 'it should reject if there\'s an error getting the images', 
1, function ( assert ) {
+       QUnit.test( 'it should reject if there\'s an error getting the image', 
1, function ( assert ) {
                var error = 'ERR0R!!!';
 
                this.getDeferred.reject( error );
@@ -47,7 +47,7 @@
                } );
        } );
 
-       QUnit.test( 'it should return a list of images if there are any', 1, 
function ( assert ) {
+       QUnit.test( 'it should return an image if there is one', 1, function ( 
assert ) {
                this.getDeferred.resolve( {
                        query: {
                                pages: {
@@ -62,14 +62,12 @@
                        }
                } );
 
-               this.repository.getImages( 1234 ).then( function ( images ) {
-                       assert.deepEqual( images, [
-                               new Image( 'http://foo/bar/baz', 1, 1 )
-                       ] );
+               this.repository.getImages( 1234 ).then( function ( image ) {
+                       assert.deepEqual( image, new Image( 
'http://foo/bar/baz', 1, 1 ) );
                } );
        } );
 
-       QUnit.test( 'it shouldn\'t return an image if there isn\'t a 
thumbnail', 1, function ( assert ) {
+       QUnit.test( 'it shouldn reject image if there isn\'t a thumbnail', 1, 
function ( assert ) {
                this.getDeferred.resolve( {
                        query: {
                                pages: {
@@ -78,12 +76,12 @@
                        }
                } );
 
-               this.repository.getImages( 1234 ).then( function ( images ) {
-                       assert.deepEqual( images, [] );
+               this.repository.getImages( 1234 ).fail( function () {
+                       assert.strictEqual( true, true );
                } );
        } );
 
-       QUnit.test( 'it shouldn\'t try to get images at the target width more 
than once', 1, function ( assert ) {
+       QUnit.test( 'it shouldn\'t try to get an image at the target width more 
than once', 1, function ( assert ) {
                this.getDeferred.resolve( {
                        query: {
                                pages: {

-- 
To view, visit https://gerrit.wikimedia.org/r/192788
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0143e4b835311bf45fa3521d1335e23586043297
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Phuedx <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to