Jdlrobson has uploaded a new change for review.

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


Change subject: Refactor nearby into reuseable modules
......................................................................

Refactor nearby into reuseable modules

Change-Id: I10680d1f11e22ba0941a8c192bf3e8ee53d91a1c
---
M includes/Resources.php
A javascripts/modules/NearbyApi.js
M javascripts/specials/nearby.js
A javascripts/widgets/Nearby.js
M tests/javascripts/specials/test_nearby.js
5 files changed, 224 insertions(+), 187 deletions(-)


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

diff --git a/includes/Resources.php b/includes/Resources.php
index 31d3ab4..8d7ff07 100644
--- a/includes/Resources.php
+++ b/includes/Resources.php
@@ -614,6 +614,8 @@
                        'mobile-frontend-nearby-directions',
                ),
                'scripts' => array(
+                       'javascripts/modules/NearbyApi.js',
+                       'javascripts/widgets/Nearby.js',
                        'javascripts/specials/nearby.js',
                ),
                // stop flash of unstyled content when loading from cache
diff --git a/javascripts/modules/NearbyApi.js b/javascripts/modules/NearbyApi.js
new file mode 100644
index 0000000..7e566e4
--- /dev/null
+++ b/javascripts/modules/NearbyApi.js
@@ -0,0 +1,28 @@
+( function( M ) {
+       var
+               endpoint = mw.config.get( 'wgMFNearbyEndpoint' ),
+               limit = 50,
+               Api = M.require( 'api' ).Api,
+               NearbyApi = Api.extend( {
+                       getPages: function( lat, lng, range ) {
+                               return this.get( {
+                                       action: 'query',
+                                       colimit: 'max',
+                                       prop: 'pageimages|coordinates',
+                                       pithumbsize: 180,
+                                       pilimit: limit,
+                                       generator: 'geosearch',
+                                       ggscoord: [ lat, lng ],
+                                       ggsradius: range,
+                                       ggsnamespace: 0,
+                                       ggslimit: limit
+                               },
+                               {
+                                       dataType: endpoint ? 'jsonp' : 'json',
+                                       url: endpoint || M.getApiUrl()
+                               } );
+                       }
+               } );
+
+       M.define( 'NearbyApi', NearbyApi );
+}( mw.mobileFrontend ) );
\ No newline at end of file
diff --git a/javascripts/specials/nearby.js b/javascripts/specials/nearby.js
index 2c56eca..1406db0 100644
--- a/javascripts/specials/nearby.js
+++ b/javascripts/specials/nearby.js
@@ -1,199 +1,23 @@
 ( function( M, $ ) {
 var CACHE_KEY_RESULTS = 'mfNearbyLastSearchResult',
        endpoint = mw.config.get( 'wgMFNearbyEndpoint' ),
-       overlay,
+       widget,
+       range = mw.config.get( 'wgMFNearbyRange' ),
        CACHE_KEY_LAST_LOCATION = 'mfNearbyLastKnownLocation';
 
 function getOverlay() {
-       return overlay;
-}
-
-function distanceMessage( d ) {
-       var msg = 'mobile-frontend-nearby-distance';
-       if ( d < 1 ) {
-               d *= 100;
-               d = Math.ceil( d ) * 10;
-               if ( d === 1000 ) {
-                       d = 1;
-               } else {
-                       msg = 'mobile-frontend-nearby-distance-meters';
-               }
-               d = d + '';
-       } else {
-               if ( d > 2 ) {
-                       d *= 10;
-                       d = Math.ceil( d ) / 10;
-                       d = d.toFixed( 1 );
-               } else {
-                       d *= 100;
-                       d = Math.ceil( d ) / 100;
-                       d = d.toFixed( 2 );
-               }
-       }
-       return mw.msg( msg, d );
+       return widget;
 }
 
 $( function() {
        var supported = M.supportsGeoLocation(),
-               View = M.require( 'view' ),
                $userBtn = $( '#user-button' ),
-               errorMessages = {
-                       empty: {
-                               heading: mw.msg( 
'mobile-frontend-nearby-noresults' ),
-                               guidance: mw.msg( 
'mobile-frontend-nearby-noresults-guidance' )
-                       },
-                       location: {
-                               heading: mw.msg( 
'mobile-frontend-nearby-lookup-ui-error' ),
-                               guidance: mw.msg( 
'mobile-frontend-nearby-lookup-ui-error-guidance' )
-                       },
-                       server: {
-                               heading: mw.msg( 'mobile-frontend-nearby-error' 
),
-                               guidance: mw.msg( 
'mobile-frontend-nearby-error-guidance' )
-                       },
-                       // recycle it's already in html
-                       incompatible: {
-                               heading: $( '#mw-mf-nearby .noscript h2' 
).text(),
-                               guidance: $( '#mw-mf-nearby .noscript p' 
).text()
-                       }
-               },
                curLocation,
                lastKnownLocation = M.settings.getUserSetting( 
CACHE_KEY_LAST_LOCATION ),
                cache = M.settings.saveUserSetting,
                lastSearchResult = M.settings.getUserSetting( CACHE_KEY_RESULTS 
),
-               Nearby = View.extend( {
-                       template: M.template.get( 'articleList' ),
-                       /**
-                        * Renders an error in the existing view
-                        *
-                        * @param {String} type A string that identifies a 
particular type of error message
-                        */
-                       renderError: function( type ) {
-                               this.render( { error: errorMessages[ type ] } );
-                       },
-                       openPage: function( ev ) {
-                               // help back button work
-                               window.location.hash = '#' + $( 
ev.currentTarget ).attr( 'name' );
-                               window.location = $( ev.currentTarget ).attr( 
'href' );
-                       },
-                       postRender: function() {
-                               var self = this;
-                               this.$( 'a' ).on( 'mousedown', function( ev ) {
-                                       // name funnel for watchlists to catch 
subsequent uploads
-                                       $.cookie( 'mwUploadsFunnel', 'nearby', 
{ expires: new Date( new Date().getTime() + 60000) } );
-                                       self.openPage( ev );
-                               } );
-                               self.emit( 'rendered', this.$el );
-                       }
-               } ),
+               Nearby = M.require( 'widgets/nearby' ),
                pendingQuery = false, btn;
-
-               overlay = new Nearby( {
-                       el: $( '#mw-mf-nearby' )
-               } );
-
-       // FIXME: Api should surely know this and return it in response to save 
us the hassle
-       // haversine formula ( http://en.wikipedia.org/wiki/Haversine_formula )
-       function calculateDistance( from, to ) {
-               var distance, a,
-                       toRadians = Math.PI / 180,
-                       deltaLat, deltaLng,
-                       startLat, endLat,
-                       haversinLat, haversinLng,
-                       radius = 6378; // radius of Earth in km
-
-               if( from.latitude === to.latitude && from.longitude === 
to.longitude ) {
-                       distance = 0;
-               } else {
-                       deltaLat = ( to.longitude - from.longitude ) * 
toRadians;
-                       deltaLng = ( to.latitude - from.latitude ) * toRadians;
-                       startLat = from.latitude * toRadians;
-                       endLat = to.latitude * toRadians;
-
-                       haversinLat = Math.sin( deltaLat / 2 ) * Math.sin( 
deltaLat / 2 );
-                       haversinLng = Math.sin( deltaLng / 2 ) * Math.sin( 
deltaLng / 2 );
-
-                       a = haversinLat + Math.cos( startLat ) * Math.cos( 
endLat ) * haversinLng;
-                       return 2 * radius * Math.asin( Math.sqrt( a ) );
-               }
-               return distance;
-       }
-
-       function render( $content, pages ) {
-               cache( CACHE_KEY_RESULTS, $.toJSON( pages ) ); // cache result
-               pages = $.map( pages, function( page, i ) {
-                       var coords, lngLat, thumb;
-
-                       if ( page.thumbnail ) {
-                               thumb = page.thumbnail;
-                               page.listThumbStyleAttribute = 
'background-image: url(' + thumb.source + ')';
-                               page.pageimageClass = thumb.width > 
thumb.height ? 'listThumbH' : 'listThumbV';
-                       } else {
-                               page.pageimageClass = 'needsPhoto';
-                       }
-                       page.anchor = 'item_' + i;
-                       page.url = M.history.getArticleUrl( page.title );
-                       if ( page.coordinates ) { // FIXME: protect against bug 
47133 (remove when resolved)
-                               coords = page.coordinates[0],
-                               lngLat = { latitude: coords.lat, longitude: 
coords.lon };
-                               page.dist = calculateDistance( curLocation, 
lngLat );
-                               page.latitude = coords.lat;
-                               page.longitude = coords.lon;
-                               page.proximity = distanceMessage( page.dist );
-                       }
-                       page.heading = page.title;
-                       pages.push( page );
-                       return page;
-               } );
-               pages.sort( function( a, b ) {
-                       return a.dist > b.dist ? 1 : -1;
-               } );
-
-               overlay.render( {
-                       pages: pages
-               } );
-       }
-
-       function findResults( lat, lng ) {
-               var $content = $( '#mw-mf-nearby' ), range = mw.config.get( 
'wgMFNearbyRange' ),
-                       limit = 50;
-
-               $.ajax( {
-                       dataType: endpoint ? 'jsonp' : 'json',
-                       url: endpoint || M.getApiUrl(),
-                       data: {
-                               action: 'query',
-                               colimit: 'max',
-                               prop: 'pageimages|coordinates',
-                               pithumbsize: 180,
-                               pilimit: limit,
-                               generator: 'geosearch',
-                               format: 'json',
-                               ggscoord: lat + '|' + lng,
-                               ggsradius: range,
-                               ggsnamespace: 0,
-                               ggslimit: limit
-                       }
-               } ).done( function( data ) {
-                       var pages;
-                       // FIXME: API bug 48512
-                       if ( data.query ) {
-                               pages = data.query.pages || {};
-                       } else {
-                               pages = {};
-                       }
-                       // FIXME: API returns object when array would make much 
sense
-                       pages = $.map( pages , function( i ) {
-                               return i;
-                       } );
-                       if ( pages.length > 0 ) {
-                               render( $content, pages );
-                       } else {
-                               overlay.renderError( 'empty' );
-                       }
-               } ).fail( function() {
-                       overlay.renderError( 'server' );
-               } );
-       }
 
        function completeRefresh() {
                $( 'button.refresh' ).removeClass( 'refreshing' );
@@ -202,17 +26,20 @@
 
        function init() {
                var $content = $( '#mw-mf-nearby' ).empty();
+
                $( '<div class="content loading"> ').text(
                        mw.msg( 'mobile-frontend-nearby-loading' ) ).appendTo( 
$content );
                navigator.geolocation.getCurrentPosition( function( geo ) {
                        var lat = geo.coords.latitude, lng = 
geo.coords.longitude;
                        curLocation = { latitude: lat, longitude: lng }; // 
save as json so it can be cached bug 48268
                        cache( CACHE_KEY_LAST_LOCATION, $.toJSON( curLocation ) 
);
-                       findResults( lat, lng );
+                       widget.load( lat, lng, curLocation ).done( function( 
pages ) {
+                               cache( CACHE_KEY_RESULTS, $.toJSON( pages ) ); 
// cache result
+                       } );
                        completeRefresh();
                },
                function() {
-                       overlay.renderError( 'location' );
+                       widget.renderError( 'location' );
                        completeRefresh();
                },
                {
@@ -239,12 +66,24 @@
                        }
                }
                if ( lastSearchResult && window.location.hash ) {
-                       render( $( '#content' ), $.parseJSON( lastSearchResult 
) );
+                       widget = new Nearby( {
+                               el: $( '#mw-mf-nearby' ),
+                               range: range,
+                               pages: $.parseJSON( lastSearchResult )
+                       } );
                } else {
+                       widget = new Nearby( {
+                               range: range,
+                               el: $( '#mw-mf-nearby' )
+                       } );
                        init();
                }
        } else {
-               overlay.renderError( 'incompatible' );
+               widget = new Nearby( {
+                       range: range,
+                       el: $( '#mw-mf-nearby' )
+               } );
+               widget.renderError( 'incompatible' );
        }
 
        if ( $userBtn.length ) {
@@ -255,7 +94,6 @@
 } );
 
 M.define( 'nearby', {
-       distanceMessage: distanceMessage,
        endpoint: endpoint,
        getOverlay: getOverlay
 } );
diff --git a/javascripts/widgets/Nearby.js b/javascripts/widgets/Nearby.js
new file mode 100644
index 0000000..1d7ed82
--- /dev/null
+++ b/javascripts/widgets/Nearby.js
@@ -0,0 +1,168 @@
+( function( M, $ ) {
+       var NearbyApi = M.require( 'NearbyApi' ),
+               View = M.require( 'view' ),
+               NearbyWidget = View.extend( {
+                       template: M.template.get( 'articleList' ),
+                       errorMessages: {
+                               empty: {
+                                       heading: mw.msg( 
'mobile-frontend-nearby-noresults' ),
+                                       guidance: mw.msg( 
'mobile-frontend-nearby-noresults-guidance' )
+                               },
+                               location: {
+                                       heading: mw.msg( 
'mobile-frontend-nearby-lookup-ui-error' ),
+                                       guidance: mw.msg( 
'mobile-frontend-nearby-lookup-ui-error-guidance' )
+                               },
+                               server: {
+                                       heading: mw.msg( 
'mobile-frontend-nearby-error' ),
+                                       guidance: mw.msg( 
'mobile-frontend-nearby-error-guidance' )
+                               },
+                               // recycle it's already in html
+                               incompatible: {
+                                       heading: $( '#mw-mf-nearby .noscript 
h2' ).text(),
+                                       guidance: $( '#mw-mf-nearby .noscript 
p' ).text()
+                               }
+                       },
+                       initialize: function( options ) {
+                               this._super( options );
+                               this.range = options.range;
+                               this.api = new NearbyApi();
+                       },
+                       // FIXME: Api should surely know this and return it in 
response to save us the hassle
+                       // haversine formula ( 
http://en.wikipedia.org/wiki/Haversine_formula )
+                       calculateDistance: function( from, to ) {
+                               var distance, a,
+                                       toRadians = Math.PI / 180,
+                                       deltaLat, deltaLng,
+                                       startLat, endLat,
+                                       haversinLat, haversinLng,
+                                       radius = 6378; // radius of Earth in km
+
+                               if( from.latitude === to.latitude && 
from.longitude === to.longitude ) {
+                                       distance = 0;
+                               } else {
+                                       deltaLat = ( to.longitude - 
from.longitude ) * toRadians;
+                                       deltaLng = ( to.latitude - 
from.latitude ) * toRadians;
+                                       startLat = from.latitude * toRadians;
+                                       endLat = to.latitude * toRadians;
+
+                                       haversinLat = Math.sin( deltaLat / 2 ) 
* Math.sin( deltaLat / 2 );
+                                       haversinLng = Math.sin( deltaLng / 2 ) 
* Math.sin( deltaLng / 2 );
+
+                                       a = haversinLat + Math.cos( startLat ) 
* Math.cos( endLat ) * haversinLng;
+                                       return 2 * radius * Math.asin( 
Math.sqrt( a ) );
+                               }
+                               return distance;
+                       },
+                       /**
+                        * Renders an error in the existing view
+                        *
+                        * @param {String} type A string that identifies a 
particular type of error message
+                        */
+                       renderError: function( type ) {
+                               this.render( { error: this.errorMessages[ type 
] } );
+                       },
+                       openPage: function( ev ) {
+                               // help back button work
+                               window.location.hash = '#' + $( 
ev.currentTarget ).attr( 'name' );
+                               window.location = $( ev.currentTarget ).attr( 
'href' );
+                       },
+                       _distanceMessage: function( d ) {
+                               var msg = 'mobile-frontend-nearby-distance';
+                               if ( d < 1 ) {
+                                       d *= 100;
+                                       d = Math.ceil( d ) * 10;
+                                       if ( d === 1000 ) {
+                                               d = 1;
+                                       } else {
+                                               msg = 
'mobile-frontend-nearby-distance-meters';
+                                       }
+                                       d = d + '';
+                               } else {
+                                       if ( d > 2 ) {
+                                               d *= 10;
+                                               d = Math.ceil( d ) / 10;
+                                               d = d.toFixed( 1 );
+                                       } else {
+                                               d *= 100;
+                                               d = Math.ceil( d ) / 100;
+                                               d = d.toFixed( 2 );
+                                       }
+                               }
+                               return mw.msg( msg, d );
+                       },
+                       _render: function( pages, curLocation ) {
+                               var self = this;
+
+                               pages = $.map( pages, function( page, i ) {
+                                       var coords, lngLat, thumb;
+
+                                       if ( page.thumbnail ) {
+                                               thumb = page.thumbnail;
+                                               page.listThumbStyleAttribute = 
'background-image: url(' + thumb.source + ')';
+                                               page.pageimageClass = 
thumb.width > thumb.height ? 'listThumbH' : 'listThumbV';
+                                       } else {
+                                               page.pageimageClass = 
'needsPhoto';
+                                       }
+                                       page.anchor = 'item_' + i;
+                                       page.url = M.history.getArticleUrl( 
page.title );
+                                       if ( page.coordinates ) { // FIXME: 
protect against bug 47133 (remove when resolved)
+                                               coords = page.coordinates[0],
+                                               lngLat = { latitude: 
coords.lat, longitude: coords.lon };
+                                               page.dist = 
self.calculateDistance( curLocation, lngLat );
+                                               page.latitude = coords.lat;
+                                               page.longitude = coords.lon;
+                                               page.proximity = 
self._distanceMessage( page.dist );
+                                       }
+                                       page.heading = page.title;
+                                       pages.push( page );
+                                       return page;
+                               } );
+
+                               pages.sort( function( a, b ) {
+                                       return a.dist > b.dist ? 1 : -1;
+                               } );
+
+                               self.render( {
+                                       pages: pages
+                               } );
+                               return pages;
+                       },
+                       load: function( lat, lng, curLocation ) {
+                               var self = this, d = $.Deferred();
+                               this.api.getPages( lat, lng, this.range ).done( 
function( data ) {
+                                       var pages;
+                                       // FIXME: API bug 48512
+                                       if ( data.query ) {
+                                               pages = data.query.pages || {};
+                                       } else {
+                                               pages = {};
+                                       }
+                                       // FIXME: API returns object when array 
would make much sense
+                                       pages = $.map( pages , function( i ) {
+                                               return i;
+                                       } );
+                                       if ( pages.length > 0 ) {
+                                               self._render( pages, 
curLocation );
+                                               d.resolve( pages );
+                                       } else {
+                                               self.renderError( 'empty' );
+                                       }
+                               } ).fail( function() {
+                                       self.renderError( 'server' );
+                               } );
+                               return d;
+                       },
+                       postRender: function() {
+                               var self = this;
+                               this.$( 'a' ).on( 'mousedown', function( ev ) {
+                                       // name funnel for watchlists to catch 
subsequent uploads
+                                       $.cookie( 'mwUploadsFunnel', 'nearby', 
{ expires: new Date( new Date().getTime() + 60000) } );
+                                       self.openPage( ev );
+                               } );
+                               self.emit( 'rendered', this.$el );
+                       }
+               } );
+
+       M.define( 'widgets/nearby', NearbyWidget );
+
+}( mw.mobileFrontend, jQuery ) );
\ No newline at end of file
diff --git a/tests/javascripts/specials/test_nearby.js 
b/tests/javascripts/specials/test_nearby.js
index 109efe5..ef2e607 100644
--- a/tests/javascripts/specials/test_nearby.js
+++ b/tests/javascripts/specials/test_nearby.js
@@ -1,6 +1,7 @@
 ( function ( M, $ ) {
 
-var m = M.require( 'nearby' );
+var Nearby = M.require( 'widgets/nearby-pages' ),
+       m = new Nearby();
 
 QUnit.module( 'MobileFrontend Nearby', {
        setup: function() {
@@ -27,7 +28,7 @@
 
        QUnit.expect( tests.length );
        $( tests ).each( function( i ) {
-               m.distanceMessage( this[0] );
+               m._distanceMessage( this[0] );
                strictEqual( mw.msg.getCall( i ).calledWith( this[1], this[2] 
), true, 'failed test ' + i );
        } );
 } );

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

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

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

Reply via email to