{"version":3,"sources":["webpack://mfModules.[name]/./src/mobile.special.nearby.scripts/LocationProvider.js","webpack://mfModules.[name]/./src/mobile.special.nearby.scripts/Nearby.js","webpack://mfModules.[name]/./src/mobile.special.nearby.scripts/NearbyGateway.js","webpack://mfModules.[name]/./src/mobile.special.nearby.scripts/mobile.special.nearby.scripts.js"],"names":["LocationProvider","browser","require","getSingleton","util","isAvailable","supportsGeoLocation","getCurrentPosition","result","Deferred","navigator","geolocation","geo","resolve","latitude","coords","longitude","err","error","code","PERMISSION_DENIED","TIMEOUT","POSITION_UNAVAILABLE","reject","timeout","enableHighAccuracy","module","exports","MessageBox","NearbyGateway","WatchstarPageList","Nearby","options","_super","this","range","mw","config","get","source","nearbyApi","api","eventBus","errorType","errorOptions","_errorOptions","onItemClick","apply","arguments","mfExtend","errorMessages","empty","heading","msg","hasHeading","http","incompatible","templatePartials","extend","prototype","pageList","template","messageBox","defaults","undefined","_find","self","pagesSuccess","pages","length","_isLoading","pagesError","getPages","exclude","then","pageTitle","getPagesAroundPage","key","message","className","postRender","$el","find","removeClass","_postRenderLinks","emit","each","i","attr","on","refresh","addClass","call","Error","Page","ns","extendSearchParams","_distanceMessage","d","Math","ceil","language","convertNumber","toFixed","_search","ggscoord","page","ggspage","params","requestParams","colimit","prop","generator","ggsradius","ggsnamespace","ggslimit","codistancefrompoint","codistancefrompage","ajax","resp","query","map","p","newFromJSON","anchor","coordinates","dist","lat","lon","proximity","title","filter","sort","a","b","nearby","Api","NEARBY_EVENT_POST_RENDER","loadingOverlay","router","loader","$infoContainer","$","OO","EventEmitter","el","funnel","ev","isModifiedEvent","fragment","match","isPageOrCoordFragment","getPath","navigate","overlay","hideInitialScreen","remove","opt","indexOf","isFragmentIdentifier","nodeType","window","scrollTop","offset","top","hide","route","Uri","decode","checkRoute","show","catch","alert"],"mappings":"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","file":"mobile.special.nearby.scripts.js","sourcesContent":["var LocationProvider,\n\tbrowser = require( '../mobile.startup/Browser' ).getSingleton(),\n\tutil = require( '../mobile.startup/util' );\n\n/**\n * API for retrieving location from user device\n * @class LocationProvider\n */\nLocationProvider = {\n\t/**\n\t * Detect if browser supports geolocation\n\t * @memberof LocationProvider\n\t * @instance\n\t * @return {boolean}\n\t */\n\tisAvailable: function () {\n\t\treturn browser.supportsGeoLocation();\n\t},\n\n\t/**\n\t * Obtain users current location and return a deferred object with the\n\t * longitude and latitude values\n\t * Resolve return object with 'incompatible' if browser doesn't support geo location\n\t * @memberof LocationProvider\n\t * @instance\n\t * @return {jQuery.Deferred}\n\t */\n\tgetCurrentPosition: function () {\n\t\tvar result = util.Deferred();\n\t\tif ( LocationProvider.isAvailable() ) {\n\t\t\tnavigator.geolocation.getCurrentPosition(\n\t\t\t\tfunction ( geo ) {\n\t\t\t\t\tresult.resolve( {\n\t\t\t\t\t\tlatitude: geo.coords.latitude,\n\t\t\t\t\t\tlongitude: geo.coords.longitude\n\t\t\t\t\t} );\n\t\t\t\t},\n\t\t\t\tfunction ( err ) {\n\t\t\t\t\tvar error;\n\t\t\t\t\tswitch ( err.code ) {\n\t\t\t\t\t\tcase err.PERMISSION_DENIED:\n\t\t\t\t\t\t\terror = 'permission';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase err.TIMEOUT:\n\t\t\t\t\t\t\terror = 'timeout';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase err.POSITION_UNAVAILABLE:\n\t\t\t\t\t\t\terror = 'location';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\terror = 'unknown';\n\t\t\t\t\t}\n\t\t\t\t\tresult.reject( error );\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttimeout: 10000,\n\t\t\t\t\tenableHighAccuracy: true\n\t\t\t\t}\n\t\t\t);\n\t\t} else {\n\t\t\tresult.reject( 'incompatible' );\n\t\t}\n\t\treturn result;\n\t}\n};\n\nmodule.exports = LocationProvider;\n","/** @event */\nvar\n\tNEARBY_EVENT_POST_RENDER = 'Nearby-postRender',\n\tMessageBox = require( '../mobile.startup/MessageBox' ),\n\tNearbyGateway = require( './NearbyGateway' ),\n\tutil = require( '../mobile.startup/util' ),\n\tWatchstarPageList = require( '../mobile.startup/watchstar/WatchstarPageList.js' ),\n\tmfExtend = require( '../mobile.startup/mfExtend' );\n\n/**\n * List of nearby pages\n * @class Nearby\n * @uses NearbyGateway\n * @extends WatchstarPageList\n *\n * @param {Object} options Configuration options\n * @param {OO.EventEmitter} options.eventBus Object used to emit Nearby-postRender events\n * @param {Function} [options.onItemClick] Callback invoked when a result is\n *                                         clicked. Defaults to nop.\n */\nfunction Nearby( options ) {\n\tvar self = this,\n\t\t_super = WatchstarPageList;\n\n\tthis.range = options.range || mw.config.get( 'wgMFNearbyRange' ) || 1000;\n\tthis.source = options.source || 'nearby';\n\tthis.nearbyApi = new NearbyGateway( {\n\t\tapi: options.api\n\t} );\n\tthis.eventBus = options.eventBus;\n\n\tif ( options.errorType ) {\n\t\toptions.errorOptions = self._errorOptions( options.errorType );\n\t}\n\n\tthis.onItemClick = options.onItemClick;\n\n\t_super.apply( this, arguments );\n}\n\nmfExtend( Nearby, WatchstarPageList, {\n\t/**\n\t * @memberof Nearby\n\t * @instance\n\t */\n\terrorMessages: {\n\t\tempty: {\n\t\t\theading: mw.msg( 'mobile-frontend-nearby-noresults' ),\n\t\t\thasHeading: true,\n\t\t\tmsg: mw.msg( 'mobile-frontend-nearby-noresults-guidance' )\n\t\t},\n\t\thttp: {\n\t\t\theading: mw.msg( 'mobile-frontend-nearby-error' ),\n\t\t\thasHeading: true,\n\t\t\tmsg: mw.msg( 'mobile-frontend-nearby-error-guidance' )\n\t\t},\n\t\tincompatible: {\n\t\t\theading: mw.msg( 'mobile-frontend-nearby-requirements' ),\n\t\t\thasHeading: true,\n\t\t\tmsg: mw.msg( 'mobile-frontend-nearby-requirements-guidance' )\n\t\t}\n\t},\n\t/**\n\t * @memberof Nearby\n\t * @instance\n\t */\n\ttemplatePartials: util.extend( {}, WatchstarPageList.prototype.templatePartials, {\n\t\tpageList: WatchstarPageList.prototype.template,\n\t\tmessageBox: MessageBox.prototype.template\n\t} ),\n\t/**\n\t * @memberof Nearby\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.special.nearby.scripts', 'Nearby.hogan' ),\n\t/**\n\t * @memberof Nearby\n\t * @instance\n\t * @mixes WatchstarPageList#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {mw.Api} defaults.api\n\t * @property {Object} defaults.errorOptions options to pass to a messagebox template\n\t * tells the user that their location is being looked up\n\t */\n\tdefaults: util.extend( {}, WatchstarPageList.prototype.defaults, {\n\t\terrorOptions: undefined\n\t} ),\n\t/**\n\t * Request pages from api based on provided options.\n\t * When options.longitude and options.latitude set getPages near that location.\n\t * If those are not present use options.title to find pages near that title.\n\t * If no valid options given resolve return object with error message.\n\t * @memberof Nearby\n\t * @instance\n\t * @param {Object} options Configuration options\n\t * @return {jQuery.Deferred}\n\t * @private\n\t */\n\t_find: function ( options ) {\n\t\tvar result = util.Deferred(),\n\t\t\tself = this;\n\n\t\t/**\n\t\t * Handler for successful query\n\t\t * @param {Array} pages as passed by then callback of Nearby##getPages\n\t\t */\n\t\tfunction pagesSuccess( pages ) {\n\t\t\toptions.pages = pages;\n\t\t\tif ( pages && pages.length === 0 ) {\n\t\t\t\toptions.errorOptions = self._errorOptions( 'empty' );\n\t\t\t}\n\t\t\tself._isLoading = false;\n\t\t\tresult.resolve( options );\n\t\t}\n\n\t\t/**\n\t\t * Handler for failed query\n\t\t *\n\t\t * @param {string} code Error Code\n\t\t */\n\t\tfunction pagesError( code ) {\n\t\t\tself._isLoading = false;\n\t\t\toptions.errorOptions = self._errorOptions( code );\n\t\t\tresult.resolve( options );\n\t\t}\n\n\t\tif ( options.latitude && options.longitude ) {\n\t\t\tthis.nearbyApi.getPages(\n\t\t\t\t{\n\t\t\t\t\tlatitude: options.latitude,\n\t\t\t\t\tlongitude: options.longitude\n\t\t\t\t},\n\t\t\t\tthis.range, options.exclude\n\t\t\t).then( pagesSuccess, pagesError );\n\t\t} else if ( options.pageTitle ) {\n\t\t\tthis.nearbyApi.getPagesAroundPage( options.pageTitle, this.range )\n\t\t\t\t.then( pagesSuccess, pagesError );\n\t\t} else {\n\t\t\tif ( options.errorType ) {\n\t\t\t\toptions.errorOptions = this._errorOptions( options.errorType );\n\t\t\t}\n\t\t\tresult.resolve( options );\n\t\t}\n\t\treturn result;\n\t},\n\t/**\n\t * Generate a list of options that can be passed to a messagebox template.\n\t * @memberof Nearby\n\t * @instance\n\t * @private\n\t * @param {string} key to a defined error message\n\t * @param {string} msg Message to use, instead of a mapped error message\n\t *  from this.errorMessages\n\t * @return {Object}\n\t */\n\t_errorOptions: function ( key ) {\n\t\tvar message = this.errorMessages[ key ] || this.errorMessages.http;\n\t\treturn util.extend( {\n\t\t\tclassName: 'errorbox'\n\t\t}, message );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof Nearby\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tvar self = this;\n\n\t\tif ( !this._isLoading ) {\n\t\t\tthis.$el.find( '.page-list' ).removeClass( 'hidden' );\n\t\t}\n\t\tWatchstarPageList.prototype.postRender.apply( this );\n\t\tthis._postRenderLinks();\n\t\t// FIXME: This should probably just be $( function () {} )\n\t\tthis.$el.find( function () {\n\t\t\t// todo: use the local emitter when refresh() doesn't recreate the\n\t\t\t//       OO.EventEmitter by calling the super's constructor.\n\t\t\tself.eventBus.emit( NEARBY_EVENT_POST_RENDER );\n\t\t} );\n\t},\n\t/**\n\t * Hijack links to apply several customisations to them:\n\t * Ensure that when clicked they register an uploads funnel.\n\t * Ensure that when a user navigates back to the page their page position is restored using\n\t * fragment identifier trickery.\n\t * @private\n\t * @memberof Nearby\n\t * @instance\n\t */\n\t_postRenderLinks: function () {\n\t\tvar self = this;\n\t\tthis.$el.find( 'a' ).each( function ( i ) {\n\t\t\t// FIXME: not unique if multiple Nearby objects on same page\n\t\t\tself.$el.find( this ).attr( 'id', 'nearby-page-list-item-' + i );\n\t\t} ).on( 'click', this.onItemClick );\n\t},\n\t/**\n\t * Refresh the list of the nearby articles depending on the options.\n\t * The current location, latitude/longitude, or page title can be used\n\t * to find the articles.\n\t * @memberof Nearby\n\t * @instance\n\t * @param {Object} options Configuration options\n\t * @throws {Error} If Nearby has not been initialised correctly.\n\t * @return {jQuery.Deferred}\n\t */\n\trefresh: function ( options ) {\n\t\tvar self = this,\n\t\t\t_super = WatchstarPageList;\n\n\t\tthis.$el.find( '.page-list' ).addClass( 'hidden' );\n\t\t// Run it once for loader etc\n\t\tthis._isLoading = true;\n\t\tif ( ( options.latitude && options.longitude ) || options.pageTitle ) {\n\t\t\t// Flush any existing list of pages\n\t\t\toptions.pages = [];\n\n\t\t\t// Get some new pages\n\t\t\treturn this._find( options ).then( function ( options ) {\n\t\t\t\t_super.call( self, options );\n\t\t\t}, function ( errorType ) {\n\t\t\t\toptions.errorOptions = self._errorOptions( errorType );\n\t\t\t\tself._isLoading = false;\n\t\t\t\t_super.call( self, options );\n\t\t\t} );\n\t\t} else {\n\t\t\tthrow new Error( 'No title or longitude, latitude options have been passed' );\n\t\t}\n\t}\n} );\n\nmodule.exports = Nearby;\n","var limit = 50,\n\tPage = require( '../mobile.startup/Page' ),\n\tns = mw.config.get( 'wgContentNamespaces' ),\n\tutil = require( '../mobile.startup/util' ),\n\textendSearchParams = require( '../mobile.startup/extendSearchParams' );\n\n/**\n * API for retrieving nearby pages\n * @class NearbyGateway\n * @param {Object} options Configuration options\n * @param {mw.Api} options.api\n */\nfunction NearbyGateway( options ) {\n\tthis.api = options.api;\n}\n\nNearbyGateway.prototype = {\n\t/**\n\t * Returns a human readable string stating the distance in meters or kilometers\n\t * depending on size.\n\t * @memberof NearbyGateway\n\t * @instance\n\t * @private\n\t * @param {number} d The distance in meters.\n\t * @return {string} message stating how far the user is from the point of interest.\n\t */\n\t_distanceMessage: function ( d ) {\n\t\tif ( d < 1 ) {\n\t\t\td *= 100;\n\t\t\td = Math.ceil( d ) * 10;\n\t\t\tif ( d === 1000 ) {\n\t\t\t\td = 1;\n\t\t\t} else {\n\t\t\t\treturn mw.msg( 'mobile-frontend-nearby-distance-meters', mw.language.convertNumber( d ) );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( d > 2 ) {\n\t\t\t\td *= 10;\n\t\t\t\td = Math.ceil( d ) / 10;\n\t\t\t\td = d.toFixed( 1 );\n\t\t\t} else {\n\t\t\t\td *= 100;\n\t\t\t\td = Math.ceil( d ) / 100;\n\t\t\t\td = d.toFixed( 2 );\n\t\t\t}\n\t\t}\n\t\treturn mw.msg( 'mobile-frontend-nearby-distance', mw.language.convertNumber( d ) );\n\t},\n\t/**\n\t * Returns a list of pages around a given point\n\t * @memberof NearbyGateway\n\t * @instance\n\t * @param {Object} coords In form { latitude: 0, longitude: 2 }\n\t * @param {number} range Number of meters to perform a geosearch for\n\t * @param {string} exclude Name of a title to exclude from the list of results\n\t * @return {jQuery.Deferred} Object taking list of pages as argument\n\t */\n\tgetPages: function ( coords, range, exclude ) {\n\t\treturn this._search( {\n\t\t\tggscoord: [ coords.latitude, coords.longitude ]\n\t\t}, range, exclude );\n\t},\n\n\t/**\n\t * Gets the pages around a page. It excludes itself from the search\n\t * @memberof NearbyGateway\n\t * @instance\n\t * @param {string} page Page title like \"W_San_Francisco\"\n\t * @param {number} range Number of meters to perform a geosearch for\n\t * @return {jQuery.Deferred} Object taking list of pages as argument\n\t */\n\tgetPagesAroundPage: function ( page, range ) {\n\t\treturn this._search( {\n\t\t\tggspage: page\n\t\t}, range, page );\n\t},\n\n\t/**\n\t * Searches for pages nearby\n\t * @memberof NearbyGateway\n\t * @instance\n\t * @private\n\t * @param {Object} params Parameters to use for searching\n\t * @param {number} range Number of meters to perform a geosearch for\n\t * @param {string} exclude Name of a title to exclude from the list of results\n\t * @return {jQuery.Deferred} Object taking list of pages as argument\n\t */\n\t_search: function ( params, range, exclude ) {\n\t\tvar requestParams,\n\t\t\td = util.Deferred(),\n\t\t\tself = this;\n\n\t\trequestParams = extendSearchParams( 'nearby', {\n\t\t\tcolimit: 'max',\n\t\t\tprop: [ 'coordinates' ],\n\t\t\tgenerator: 'geosearch',\n\t\t\tggsradius: range,\n\t\t\tggsnamespace: ns,\n\t\t\tggslimit: limit\n\t\t}, params );\n\n\t\tif ( params.ggscoord ) {\n\t\t\trequestParams.codistancefrompoint = params.ggscoord;\n\t\t} else if ( params.ggspage ) {\n\t\t\trequestParams.codistancefrompage = params.ggspage;\n\t\t}\n\n\t\tthis.api.ajax( requestParams ).then( function ( resp ) {\n\t\t\tvar pages;\n\n\t\t\t// resp.query.pages is an Array<Page> instead of a map like in other\n\t\t\t// API requests\n\t\t\tif ( resp.query ) {\n\t\t\t\tpages = resp.query.pages || [];\n\t\t\t} else {\n\t\t\t\tpages = [];\n\t\t\t}\n\n\t\t\tpages = pages.map( function ( page, i ) {\n\t\t\t\tvar coords, p;\n\t\t\t\tp = Page.newFromJSON( page );\n\t\t\t\tp.anchor = 'item_' + i;\n\n\t\t\t\t// protect against declined bug T49133\n\t\t\t\tif ( page.coordinates ) {\n\t\t\t\t\tcoords = page.coordinates[0];\n\t\t\t\t\t// FIXME: Make part of the Page object\n\t\t\t\t\tp.dist = coords.dist / 1000;\n\t\t\t\t\tp.latitude = coords.lat;\n\t\t\t\t\tp.longitude = coords.lon;\n\t\t\t\t\tp.proximity = self._distanceMessage( p.dist );\n\t\t\t\t} else {\n\t\t\t\t\tp.dist = 0;\n\t\t\t\t}\n\t\t\t\tif ( exclude !== page.title ) {\n\t\t\t\t\treturn p;\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} ).filter( function ( page ) { return !!page; } );\n\n\t\t\tpages.sort( function ( a, b ) {\n\t\t\t\treturn a.dist > b.dist ? 1 : -1;\n\t\t\t} );\n\t\t\td.resolve( pages );\n\t\t}, function ( error ) {\n\t\t\td.reject( error );\n\t\t} );\n\t\treturn d;\n\t}\n};\n\nmodule.exports = NearbyGateway;\n","/* global $ */\n/** @event */\nvar\n\tapi = new mw.Api(),\n\tNEARBY_EVENT_POST_RENDER = 'Nearby-postRender',\n\tLocationProvider = require( './LocationProvider' ),\n\tloadingOverlay = require( '../mobile.startup/loadingOverlay' ),\n\trouter = mw.loader.require( 'mediawiki.router' ),\n\tNearby = require( './Nearby' ),\n\tutil = require( '../mobile.startup/util' ),\n\t$infoContainer = $( '#mf-nearby-info-holder' ),\n\teventBus = new OO.EventEmitter(),\n\tnearby,\n\toptions = {\n\t\teventBus: eventBus,\n\t\tel: $( '#mw-mf-nearby' ),\n\t\tfunnel: 'nearby',\n\t\tonItemClick: function ( ev ) {\n\t\t\tif ( !util.isModifiedEvent( ev ) && !isPageOrCoordFragment( router.getPath() ) ) {\n\t\t\t\t// Change the URL fragment to the clicked element so that back\n\t\t\t\t// navigation can retain the item position. This behavior is\n\t\t\t\t// unwanted for results displayed around a page or coordinate since\n\t\t\t\t// that information is stored in the hash and would be overwritten.\n\t\t\t\trouter.navigate( $( this ).attr( 'id' ) );\n\t\t\t}\n\t\t}\n\t},\n\toverlay = loadingOverlay();\n\n/**\n * Show the title and hide the info container\n */\nfunction hideInitialScreen() {\n\t$infoContainer.remove();\n\t$( 'body' ).removeClass( 'nearby-accept-pending' );\n}\n/**\n * @param {string} fragment The URL fragment.\n * @return {boolean} True if the current URL is based around page or\n *                   coordinates (as opposed to current location or search).\n *                   e.g.: Special:Nearby#/page/San_Francisco and\n *                   Special:Nearby#/coord/0,0.\n */\nfunction isPageOrCoordFragment( fragment ) {\n\treturn fragment.match( /^(\\/page|\\/coord)/ );\n}\n\n/**\n * @param {string} fragment The URL fragment.\n * @return {boolean} True if the current URL doesn't contain an invalid\n *                   identifier expression, such as the slash in\n *                   Special:Nearby#/search, and probably contains the\n *                   target identifier to scroll to.\n */\nfunction isFragmentIdentifier( fragment ) {\n\treturn fragment && fragment.indexOf( '/' ) === -1;\n}\n\n/**\n * Initialize or instantiate Nearby with options\n * @param {Object} opt\n * @param {mw.Api} opt.api instance\n */\nfunction refresh( opt ) {\n\t// make sure, that the api object (if created above) is added to the options object used\n\t// in the Nearby module\n\topt = util.extend( {}, opt, options );\n\n\tif ( !nearby ) {\n\t\tnearby = new Nearby( opt );\n\t\t// todo: use the local emitter when refresh() doesn't recreate the\n\t\t//       OO.EventEmitter by calling the super's constructor.\n\t\teventBus.on( NEARBY_EVENT_POST_RENDER, function () {\n\t\t\tvar fragment = router.getPath(), el;\n\t\t\tif ( isFragmentIdentifier( fragment ) ) {\n\t\t\t\t// The hash is expected to be an identifier selector (unless the\n\t\t\t\t// user entered rubbish).\n\t\t\t\tel = nearby.$el.find( '#' + fragment );\n\t\t\t\tif ( el[0] && el[0].nodeType ) {\n\t\t\t\t\t$( window ).scrollTop( el.offset().top );\n\t\t\t\t}\n\t\t\t}\n\t\t\toverlay.hide();\n\t\t} );\n\t}\n\tnearby.refresh( opt );\n}\n\n// Routing on the nearby view\n\n/*\n * #/coords/lat,long\n */\nrouter.route( /^\\/coord\\/(-?\\d+(?:\\.\\d+)?),(-?\\d+(?:\\.\\d+)?)/, function ( lat, lon ) {\n\t// TODO this is bad, route shouldn't have side effects but otherwise mediawiki router\n\t// cannot refresh the page. We need to store those so when user hits $refreshButton\n\t// we reload the results\n\toptions.latitude = lat;\n\toptions.longitude = lon;\n\n\thideInitialScreen();\n\t// Search with coordinates\n\trefresh( util.extend( options, { api: api } ) );\n} );\n\n/*\n * #/page/PageTitle\n */\nrouter.route( /^\\/page\\/(.+)$/, function ( pageTitle ) {\n\thideInitialScreen();\n\toverlay.hide();\n\trefresh( util.extend( {}, options, {\n\t\tapi: api,\n\t\tpageTitle: mw.Uri.decode( pageTitle )\n\t} ) );\n} );\n\nrouter.checkRoute();\n$( '#showArticles' ).on( 'click', function () {\n\toverlay.show();\n\tLocationProvider.getCurrentPosition().then( function ( geo ) {\n\t\trouter.navigate( '#/coord/' + geo.latitude + ',' + geo.longitude );\n\t} ).catch( function ( error ) {\n\t\toverlay.hide();\n\t\t// We want to show the Alert dialog to make sure user sees it\n\t\tswitch ( error ) {\n\t\t\tcase 'permission':\n\t\t\t\talert( mw.msg( 'mobile-frontend-nearby-permission-denied' ) );\n\t\t\t\tbreak;\n\t\t\tcase 'location':\n\t\t\t\talert( mw.msg( 'mobile-frontend-nearby-location-unavailable' ) );\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// timeout or undefined, do nothing for now\n\t\t}\n\t} );\n} );\n"],"sourceRoot":""}