diff --git a/www/js/app.js b/www/js/app.js index bfb9c484e036898af47ab1bd1374cb7a84a7bffe..d5682e660087311dfa8219cf66353d16d9a8dde0 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -137,6 +137,9 @@ angular.module('cesium', ['ionic', 'ionic-material', 'ngMessages', 'pascalprecht } // endRemoveIf(device) + // Must be done before any other $stateChangeStart listeners + csPlatform.disableChangeState(); + // removeIf(android) // removeIf(ios) // removeIf(firefoxos) @@ -274,7 +277,7 @@ angular.module('cesium', ['ionic', 'ionic-material', 'ngMessages', 'pascalprecht } // Make sure platform is started - return csPlatform.start(); + return csPlatform.ready(); }); }) ; diff --git a/www/js/platform.js b/www/js/platform.js index f126da8e19aa4ba53174731f4698b0e4820af195..2c9d9e1ef3328952987f647575058965584d6a45 100644 --- a/www/js/platform.js +++ b/www/js/platform.js @@ -10,11 +10,12 @@ angular.module('cesium.platform', ['cesium.config', 'cesium.services']) defaultSettingsNode, started = false, startPromise, - readyDeffered, listeners, removeChangeStateListener; function disableChangeState() { + if (removeChangeStateListener) return; // make sure to call this once + var remove = $rootScope.$on('$stateChangeStart', function (event, next, nextParams, fromState) { if (!event.defaultPrevented && next.name !== 'app.home' && next.name !== 'app.settings') { event.preventDefault(); @@ -87,10 +88,7 @@ angular.module('cesium.platform', ['cesium.config', 'cesium.services']) function ready() { if (started) return $q.when(); - if (startPromise) return startPromise; - if (readyDeffered) return readyDeffered.promise; - readyDeffered = $q.defer(); - return readyDeffered.promise; + return startPromise || start(); } function restart() { @@ -102,7 +100,6 @@ angular.module('cesium.platform', ['cesium.config', 'cesium.services']) } function start() { - enableChangeState(); // Avoid change state disableChangeState(); @@ -134,8 +131,6 @@ angular.module('cesium.platform', ['cesium.config', 'cesium.services']) addListeners(); startPromise = null; started = true; - if (readyDeffered) readyDeffered.resolve(); - readyDeffered = null; }) .catch(function(err) { startPromise = null; @@ -143,8 +138,6 @@ angular.module('cesium.platform', ['cesium.config', 'cesium.services']) if($state.current.name !== 'app.home') { $state.go('app.home', {error: 'peer'}); } - if (readyDeffered) readyDeffered.reject(err); - readyDeffered = null; throw err; }); @@ -167,6 +160,7 @@ angular.module('cesium.platform', ['cesium.config', 'cesium.services']) } return { + disableChangeState: disableChangeState, isStarted: isStarted, ready: ready, restart: restart, diff --git a/www/plugins/es/js/services/geo-services.js b/www/plugins/es/js/services/geo-services.js index b92660f9a9feb6d33d480ed34527afe1d7f3305e..c2e77408cd79de42fa33968879912e7a4d02a0be 100644 --- a/www/plugins/es/js/services/geo-services.js +++ b/www/plugins/es/js/services/geo-services.js @@ -22,17 +22,15 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser searchByQuery: csHttp.get('nominatim.openstreetmap.org', 443, '/search.php?format=json') }, google: { + apiKey: csConfig.plugins && csConfig.plugins.es && csConfig.plugins.es.googleApiKey, search: csHttp.get('maps.google.com', 443, '/maps/api/geocode/json') }, searchByIP: csHttp.get('freegeoip.net', 80, '/json/:ip') }; - function _fallbackSearchPositionByString(err, address) { + function googleSearchPositionByString(address) { - console.debug('[ES] [geo] Search position failed on [OSM]. Trying [google] service'); - var apiKey = csConfig.plugins && csConfig.plugins.es && csConfig.plugins.googleApiKey; - - return that.raw.google.search({address: address, key: apiKey}) + return that.raw.google.search({address: address, key: that.raw.google.apiKey}) .then(function(res) { if (!res || !res.results || !res.results.length) return; return res.results.reduce(function(res, hit) { @@ -44,10 +42,17 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser lon: hit.geometry && hit.geometry.location && hit.geometry.location.lng }); }, []); - }) - .catch(function() { + }); + } + + function _fallbackSearchPositionByString(osmErr, address) { + + console.debug('[ES] [geo] Search position failed on [OSM]. Trying [google] service'); + + return googleSearchPositionByString(address) + .catch(function(googleErr) { console.debug('[ES] [geo] Search position failed on [google] service'); - throw err; // throw first error (OMS error) + throw osmErr || googleErr; // throw first OMS error if exists }); } @@ -126,6 +131,12 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser current: getCurrentPosition, searchByAddress: searchhPositionByQuery, searchByIP: searchPositionByIP + }, + google: { + hasApiKey : function() { + return !!that.raw.google.apiKey; + }, + searchByAddress: googleSearchPositionByString } }; }); diff --git a/www/plugins/map/js/controllers/wot-controllers.js b/www/plugins/map/js/controllers/wot-controllers.js index 65e415ab663c304907bc705bed08f0ab58db3651..391cf86def6600ccc160493f4c44f8dccf203d29 100644 --- a/www/plugins/map/js/controllers/wot-controllers.js +++ b/www/plugins/map/js/controllers/wot-controllers.js @@ -159,7 +159,7 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser $scope.loading = true; // Load wot data - return mapWot.load({bounds: $scope.map.bounds}) + return mapWot.load() .then(function(res) { if (res && res.length) { @@ -192,7 +192,7 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser focus: false, message: markerTemplate }; - var id = hit.uid ? (hit.uid + ':' + hit.pubkey) : hit.pubkey; + var id = (hit.uid ? (hit.uid + ':' + hit.pubkey) : hit.pubkey).replace(/-/g, '_'); var wasExisting = !!$scope.map.markers[id]; $scope.map.markers[id] = marker; @@ -235,7 +235,6 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser // Update the browser location, to be able to refresh the page $scope.$on("centerUrlHash", function(event, centerHash) { if (!$scope.loading) { - $scope.load(); return $timeout(function() { $scope.updateLocationHref(centerHash); diff --git a/www/plugins/map/js/services/wot-services.js b/www/plugins/map/js/services/wot-services.js index e38f4ba5c3f9dd38d23eb9cdedc9c060b8926251..a4f71a2c65926861be1cad72014bcab8e023efe3 100644 --- a/www/plugins/map/js/services/wot-services.js +++ b/www/plugins/map/js/services/wot-services.js @@ -1,7 +1,7 @@ angular.module('cesium.map.wot.services', ['cesium.services']) -.factory('mapWot', function($q, csHttp, esHttp, csWot, BMA) { +.factory('mapWot', function($q, csHttp, esHttp, csWot, BMA, esGeo) { 'ngInject'; var @@ -10,7 +10,7 @@ angular.module('cesium.map.wot.services', ['cesium.services']) DEFAULT_LOAD_SIZE: 1000 }, fields = { - profile: ["title", "geoPoint", "avatar._content_type", "city", "description"] + profile: ["title", "geoPoint", "avatar._content_type", "address", "city", "description"] }; that.raw = { @@ -20,29 +20,38 @@ angular.module('cesium.map.wot.services', ['cesium.services']) }; function createFilterQuery(options) { + options = options || {}; var query = { - bool: { - must: [ - {exists: {field: "geoPoint"}} - ] - } + bool: {} }; + // Limit to profile with geo point + if (esGeo.google.hasApiKey()) { + query.bool.should = [ + {exists: {field: "geoPoint"}}, + {exists: {field: "address"}}, + {exists: {field: "city"}} + ]; + } + else { + query.bool.must= [ + {exists: {field: "geoPoint"}} + ]; + } + // Filter on bounding box // see https://www.elastic.co/guide/en/elasticsearch/reference/2.4/geo-point.html - if (options && options.bounds) { - - query.bool.filter = { - "geo_bounding_box" : { - "geoPoint" : { - "top_left" : { - "lat" : Math.max(Math.min(options.bounds.northEast.lat, 90), -90), - "lon" : Math.max(Math.min(options.bounds.southWest.lng, 180), -180) - }, - "bottom_right" : { - "lat" : Math.max(Math.min(options.bounds.southWest.lat, 90), -90), - "lon" : Math.max(Math.min(options.bounds.northEast.lng, 180), -180) - } + if (options.bounds && options.bounds.northEast && options.bounds.southWest) { + query.bool.should = query.bool.should || {}; + query.bool.should.geo_bounding_box = { + "geoPoint" : { + "top_left" : { + "lat" : Math.max(Math.min(options.bounds.northEast.lat, 90), -90), + "lon" : Math.max(Math.min(options.bounds.southWest.lng, 180), -180) + }, + "bottom_right" : { + "lat" : Math.max(Math.min(options.bounds.southWest.lat, 90), -90), + "lon" : Math.max(Math.min(options.bounds.northEast.lng, 180), -180) } } }; @@ -98,23 +107,32 @@ angular.module('cesium.map.wot.services', ['cesium.services']) // Transform profile hits var commaRegexp = new RegExp('[,]'); - res = res.hits.hits.reduce(function(res, hit) { + var noPositionItems = []; + var items = res.hits.hits.reduce(function(res, hit) { var pubkey = hit._id; var uid = uids[pubkey]; var item = uid && {uid: uid} || memberships[pubkey] || {}; item.pubkey = pubkey; + // City & address + item.city = hit._source.city; + item.fullAddress = item.city && ((hit._source.address ? hit._source.address+ ', ' : '') + item.city); + // Set geo point item.geoPoint = hit._source.geoPoint; - if (!item.geoPoint || !item.geoPoint.lat || !item.geoPoint.lon) return res; - - // Convert lat/lon to float (if need) - if (item.geoPoint.lat && typeof item.geoPoint.lat === 'string') { - item.geoPoint.lat = parseFloat(item.geoPoint.lat.replace(commaRegexp, '.')); + if (!item.geoPoint || !item.geoPoint.lat || !item.geoPoint.lon) { + if (!item.fullAddress) return res; // no city: exclude this item + noPositionItems.push(item); } - if (item.geoPoint.lon && typeof item.geoPoint.lon === 'string') { - item.geoPoint.lon = parseFloat(item.geoPoint.lon.replace(commaRegexp, '.')); + else { + // Convert lat/lon to float (if need) + if (item.geoPoint.lat && typeof item.geoPoint.lat === 'string') { + item.geoPoint.lat = parseFloat(item.geoPoint.lat.replace(commaRegexp, '.')); + } + if (item.geoPoint.lon && typeof item.geoPoint.lon === 'string') { + item.geoPoint.lon = parseFloat(item.geoPoint.lon.replace(commaRegexp, '.')); + } } // Avatar @@ -130,13 +148,33 @@ angular.module('cesium.map.wot.services', ['cesium.services']) // Description item.description = esHttp.util.trustAsHtml(hit._source.description); - // City - item.city = hit._source.city; - - return res.concat(item); + return item.geoPoint ? res.concat(item) : res; }, []); - return csWot.extendAll(res, 'pubkey'); + // Resolve missing positions by addresses (only if google API enable) + if (noPositionItems.length && esGeo.google.hasApiKey()) { + var now = new Date().getTime(); + console.log('[map] [wot] Search positions of {0} addresses...'.format(noPositionItems.length)); + var counter = 0; + + return $q.all(noPositionItems.reduce(function(res, item) { + return res.concat(esGeo.google.searchByAddress(item.fullAddress) + .then(function(res) { + if (!res || !res.length) return; + item.geoPoint = res[0]; + delete item.fullAddress; + items.push(item); + counter++; + }) + .catch(function() {/*silent*/})); + }, [])) + .then(function(){ + console.log('[map] [wot] Resolved {0}/{1} addresses in {2}ms'.format(counter, noPositionItems.length, new Date().getTime()-now)); + return items; + }); + } + + return items; }); }