/* * Copyright (c) 2015-2017, Michael A. Updike All rights reserved. * Licensed under the BSD-3-Clause * https://opensource.org/licenses/BSD-3-Clause * https://github.com/opus1269/photo-screen-saver/blob/master/LICENSE.md */ window.app = window.app || {}; /** * Handle interaction the Google maps geocode API * @namespace */ app.Geo = (function() { 'use strict'; new ExceptionHandler(); /** * Path to Google's geocode api * @type {string} * @const * @default * @private * @memberOf app.Geo */ const _GEOCODE_API = 'http://maps.googleapis.com/maps/api/geocode/json'; /** * A Geo location * @typedef {Object} app.Geo.Location * @property {string} loc - descriptive location * @property {string} point - geo location 'lat lon' * @memberOf app.Geo */ /** * Cache of Geo Locations * @typedef {Object} app.Geo.Cache * @property {app.Geo.Location[]} entries - Array of locations * @property {int} maxSize - max entries to cache * @memberOf app.Geo */ /** * Location cache * @type {app.Geo.Cache} * @private * @memberOf app.Geo */ const _LOC_CACHE = { entries: [], maxSize: 100, }; /** * Try to get (@link app.Geo.Location} from cache * @param {string} point - a geolocation * @returns {app.Geo.Location|undefined} location, undefined if not cached * @memberOf app.Geo * @private */ function _getFromCache(point) { return _LOC_CACHE.entries.find((element) => { return (element.point === point); }); } /** * Try to get (@link app.Geo.Location} from cache * @param {string} point - a geolocation * @param {string} location - description * @private * @memberOf app.Geo */ function _addToCache(point, location) { _LOC_CACHE.entries.push({ loc: location, point: point, }); if (_LOC_CACHE.entries.length > _LOC_CACHE.maxSize) { // FIFO _LOC_CACHE.entries.shift(); } } /** * Make sure point is in fixed point notation * @param {string} point - 'lat lng' may have exponential notation * @returns {string} 'lat,lng' fixed point notation * @private * @memberOf app.Geo */ function _cleanPoint(point) { let ret = point; try { const stringArray = point.split(' '); if (stringArray.length === 2) { const lat = parseFloat(stringArray[0]).toFixed(8); const lng = parseFloat(stringArray[1]).toFixed(8); ret = `${lat},${lng}`; } } catch (ex) { Chrome.Utils.noop(); } return ret; } return { /** * Get the location string * @param {string} point - 'lat,long' * @returns {Promise<string>} geolocation as string * @memberOf app.Geo */ get: function(point) { if (!Chrome.Storage.getBool('showLocation')) { return Promise.reject(new Error('showLocation is off')); } else if (Chrome.Utils.isWhiteSpace(point)) { return Promise.reject(new Error('point is empty or null')); } // replace any exponential notation const pt = _cleanPoint(point); // check cache const cache = _getFromCache(pt); if (cache) { // retrieve from cache return Promise.resolve(cache.loc); } // get from api - it will translate based on the browser language const url = `${_GEOCODE_API}?latlng=${pt}`; const conf = Chrome.JSONUtils.shallowCopy(Chrome.Http.conf); conf.maxRetries = 2; return Chrome.Http.doGet(url, conf).then((response) => { let location = ''; if ((response.status === 'OK') && response.results && (response.results.length > 0)) { location = response.results[0].formatted_address; // cache it _addToCache(pt, location); } return Promise.resolve(location); }); }, }; })();