From c9d1b074180e9d30a1a73d0a7d808b09366e2b45 Mon Sep 17 00:00:00 2001 From: blavenie <benoit.lavenier@e-is.pro> Date: Wed, 2 Aug 2017 19:13:38 +0200 Subject: [PATCH] [enh] ES settings: allow to define a google API key, for address resolution in maps --- www/index.html | 1 + www/js/config.js | 2 +- www/plugins/es/js/services/geo-services.js | 26 ++++++-- .../es/js/services/settings-services.js | 5 +- .../templates/settings/plugin_settings.html | 5 ++ www/plugins/map/i18n/locale-fr-FR.json | 9 +++ .../js/controllers/settings-controllers.js | 22 +++++++ .../map/js/controllers/wot-controllers.js | 62 ++++++++++--------- www/plugins/map/js/plugin.js | 3 +- www/plugins/map/js/services/wot-services.js | 28 +++++---- .../map/templates/network/view_map.html | 1 + .../settings/es_settings_extend.html | 35 +++++++++++ .../map/templates/wot/popup_marker.html | 2 +- www/plugins/map/templates/wot/view_map.html | 3 + 14 files changed, 155 insertions(+), 49 deletions(-) create mode 100644 www/plugins/map/js/controllers/settings-controllers.js create mode 100644 www/plugins/map/templates/settings/es_settings_extend.html diff --git a/www/index.html b/www/index.html index 99346e3f..8774b6e5 100644 --- a/www/index.html +++ b/www/index.html @@ -198,6 +198,7 @@ <script src="dist/dist_js/plugins/map/js/controllers/wot-controllers.js"></script> <script src="dist/dist_js/plugins/map/js/controllers/network-controllers.js"></script> <script src="dist/dist_js/plugins/map/js/controllers/user-controllers.js"></script> + <script src="dist/dist_js/plugins/map/js/controllers/settings-controllers.js"></script> <!-- RML9 plugin --> <!--<script src="dist/dist_js/plugins/rml9/plugin-01-add_button.js"></script>--> diff --git a/www/js/config.js b/www/js/config.js index 663467b0..8dd35f81 100644 --- a/www/js/config.js +++ b/www/js/config.js @@ -64,4 +64,4 @@ angular.module("cesium.config", []) "newIssueUrl": "https://github.com/duniter/cesium/issues/new?labels=bug" }) -; \ No newline at end of file +; diff --git a/www/plugins/es/js/services/geo-services.js b/www/plugins/es/js/services/geo-services.js index c2e77408..e634e82c 100644 --- a/www/plugins/es/js/services/geo-services.js +++ b/www/plugins/es/js/services/geo-services.js @@ -10,7 +10,7 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser }) - .factory('esGeo', function($q, csConfig, csHttp) { + .factory('esGeo', function($rootScope, $q, csConfig, csSettings, csHttp) { 'ngInject'; var @@ -22,7 +22,7 @@ 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, + apiKey: undefined, search: csHttp.get('maps.google.com', 443, '/maps/api/geocode/json') }, searchByIP: csHttp.get('freegeoip.net', 80, '/json/:ip') @@ -126,6 +126,24 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser }); } + // If no google api key in config: get it from settings + that.raw.google.apiKey = csConfig.plugins && csConfig.plugins.es && csConfig.plugins.es.googleApiKey; + if (!that.raw.google.apiKey) { + csSettings.ready() + .then(function() { + + // Listen settings changed + function onSettingsChanged(data){ + that.raw.google.enable = data.plugins && data.plugins.es && data.plugins.es.enableGoogleApi; + that.raw.google.apiKey = that.raw.google.enable && data.plugins.es.googleApiKey; + } + csSettings.api.data.on.changed($rootScope, onSettingsChanged, this); + + onSettingsChanged(csSettings.data); + }) + } + + return { point: { current: getCurrentPosition, @@ -133,8 +151,8 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser searchByIP: searchPositionByIP }, google: { - hasApiKey : function() { - return !!that.raw.google.apiKey; + isEnable: function() { + return that.raw.google.enable && that.raw.google.apiKey; }, searchByAddress: googleSearchPositionByString } diff --git a/www/plugins/es/js/services/settings-services.js b/www/plugins/es/js/services/settings-services.js index aaeef5d7..1570d704 100644 --- a/www/plugins/es/js/services/settings-services.js +++ b/www/plugins/es/js/services/settings-services.js @@ -40,7 +40,10 @@ angular.module('cesium.es.settings.services', ['cesium.services', 'cesium.es.htt }, invitations: { readTime: true - } + }, + defaultCountry: undefined, + enableGoogleApi: false, + googleApiKey: undefined } } }, {plugins: {es: csConfig.plugins && csConfig.plugins.es || {}}}), diff --git a/www/plugins/es/templates/settings/plugin_settings.html b/www/plugins/es/templates/settings/plugin_settings.html index 20208d92..52c0cecc 100644 --- a/www/plugins/es/templates/settings/plugin_settings.html +++ b/www/plugins/es/templates/settings/plugin_settings.html @@ -64,5 +64,10 @@ </div> </label> + <!-- Allow extension here --> + <cs-extension-point name="common"></cs-extension-point> + + + </ion-content> </ion-view> diff --git a/www/plugins/map/i18n/locale-fr-FR.json b/www/plugins/map/i18n/locale-fr-FR.json index 7433568d..8070a7d0 100644 --- a/www/plugins/map/i18n/locale-fr-FR.json +++ b/www/plugins/map/i18n/locale-fr-FR.json @@ -36,6 +36,15 @@ }, "ERROR": { "LOCALIZE_ME_FAILED": "Impossible de récupérer votre position actuelle" + }, + "SETTINGS": { + "MAP_DIVIDER": "Cartes", + "ENABLE_GOOGLE_API": "Activer les services Google API ?", + "ENABLE_GOOGLE_API_HELP": "Permet l'affichage dans la <b>carte des membres</b> des comptes ayant une adresse mais aucun positionnement GPS.", + "GOOGLE_API_KEY": "Clé d'API Google", + "BTN_GOOGLE_API": "Obtenir une clé", + "BTN_GOOGLE_API_WARNING": "nécessite d'avoir un compte Google", + "GOOGLE_API_KEY_PLACEHOLDER": "Exemple: AIzaqyAgszvWm0tM81x1sMK_ipDHBI7EowLqR7I" } } } diff --git a/www/plugins/map/js/controllers/settings-controllers.js b/www/plugins/map/js/controllers/settings-controllers.js new file mode 100644 index 00000000..a8489331 --- /dev/null +++ b/www/plugins/map/js/controllers/settings-controllers.js @@ -0,0 +1,22 @@ +angular.module('cesium.map.settings.controllers', ['cesium.services']) + + // Configure menu items + .config(function(PluginServiceProvider, csConfig) { + 'ngInject'; + + var enable = csConfig.plugins && csConfig.plugins.es; + if (enable) { + // Extend settings via extension points + PluginServiceProvider.extendState('app.es_settings', { + points: { + 'common': { + templateUrl: "plugins/map/templates/settings/es_settings_extend.html" + } + } + }); + } + }) + +; + + diff --git a/www/plugins/map/js/controllers/wot-controllers.js b/www/plugins/map/js/controllers/wot-controllers.js index 391cf86d..ecd7d0c8 100644 --- a/www/plugins/map/js/controllers/wot-controllers.js +++ b/www/plugins/map/js/controllers/wot-controllers.js @@ -102,19 +102,8 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser if ($scope.loading) { // Load the map (and init if need) - $scope.loadMap().then(function(map) { - - // Load indicator - map.fire('dataloading'); - - // Load data - return $scope.load() - - // Hide loading indicator - .then(function() { - map.fire('dataload'); - }); - }); + $scope.loadMap() + .then($scope.load); } else { // Make sur to have previous center coordinate defined in the location URL @@ -127,16 +116,24 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser return leafletData.getMap($scope.mapId).then(function(map) { if (!$scope.map.loading) return map; // already loaded + // Add a refresh button + if (!UIUtils.screen.isSmall()) { + L.easyButton('icon ion-refresh', function(btn, map){ + return $scope.load(map); + }, + {position: 'topright'} + ).addTo(map); + } + // Add loading control - var loadingControl = L.Control.loading({ + L.Control.loading({ position: 'topright', separate: true - }); - loadingControl.addTo(map); + }).addTo(map); // Add localize me control - var localizeMe = MapUtils.control.localizeMe(); - localizeMe.addTo(map); + MapUtils.control.localizeMe() + .addTo(map); // Add search control var searchTip = $interpolate($templateCache.get('plugins/map/templates/wot/item_search_tooltip.html')); @@ -155,25 +152,28 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser }; // Load markers data - $scope.load = function() { + $scope.load = function(map) { + if (!map) { + return leafletData.getMap($scope.mapId).then(function(map) { + return $scope.load(map); // loop with the map object + }); + } + $scope.loading = true; + // Show loading indicator + map.fire('dataloading'); // Load wot data return mapWot.load() .then(function(res) { + var markers = {}; + var existingMarkerIds = _.keys($scope.map.markers); if (res && res.length) { var formatPubkey = $filter('formatPubkey'); var markerTemplate = $templateCache.get('plugins/map/templates/wot/popup_marker.html'); - // Sort with member first - /*res = _.sortBy(res, function(hit) { - var score = 0; - score += (!hit.uid) ? 100 : 0; - return -score; - });*/ - _.forEach(res, function (hit) { var type = hit.pending ? 'pending' : (hit.uid ? 'member' : 'wallet'); var shortPubkey = formatPubkey(hit.pubkey); @@ -193,11 +193,10 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser message: markerTemplate }; var id = (hit.uid ? (hit.uid + ':' + hit.pubkey) : hit.pubkey).replace(/-/g, '_'); - var wasExisting = !!$scope.map.markers[id]; - $scope.map.markers[id] = marker; + markers[id] = marker; // Create a search marker (will be hide) - if (!wasExisting) { + if (!existingMarkerIds[id]) { var searchText = hit.name + ((hit.uid && hit.uid != hit.name) ? (' | ' + hit.uid) : '') + ' | ' + shortPubkey; var searchMarker = angular.merge({ type: type, @@ -215,8 +214,11 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser } }); } - + $scope.map.markers = markers; $scope.loading = false; + + // hide loading indicator + map.fire('dataload'); }); }; diff --git a/www/plugins/map/js/plugin.js b/www/plugins/map/js/plugin.js index d5bef332..ab125fb9 100644 --- a/www/plugins/map/js/plugin.js +++ b/www/plugins/map/js/plugin.js @@ -6,7 +6,8 @@ angular.module('cesium.map.plugin', [ // Controllers 'cesium.map.wot.controllers', 'cesium.map.network.controllers', - 'cesium.map.user.controllers' + 'cesium.map.user.controllers', + 'cesium.map.settings.controllers' ]) // Configure plugin diff --git a/www/plugins/map/js/services/wot-services.js b/www/plugins/map/js/services/wot-services.js index a4f71a2c..de359673 100644 --- a/www/plugins/map/js/services/wot-services.js +++ b/www/plugins/map/js/services/wot-services.js @@ -26,7 +26,7 @@ angular.module('cesium.map.wot.services', ['cesium.services']) }; // Limit to profile with geo point - if (esGeo.google.hasApiKey()) { + if (options.searchAddress) { query.bool.should = [ {exists: {field: "geoPoint"}}, {exists: {field: "address"}}, @@ -63,6 +63,7 @@ angular.module('cesium.map.wot.services', ['cesium.services']) options = options || {}; options.from = options.from || 0; options.size = options.size || constants.DEFAULT_LOAD_SIZE; + options.searchAddress = esGeo.google.isEnable() && (angular.isDefined(options.searchAddress) ? options.searchAddress : true); var request = { query: createFilterQuery(options), @@ -107,7 +108,7 @@ angular.module('cesium.map.wot.services', ['cesium.services']) // Transform profile hits var commaRegexp = new RegExp('[,]'); - var noPositionItems = []; + var searchAddressItems = []; var items = res.hits.hits.reduce(function(res, hit) { var pubkey = hit._id; @@ -117,13 +118,13 @@ angular.module('cesium.map.wot.services', ['cesium.services']) // 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) { - if (!item.fullAddress) return res; // no city: exclude this item - noPositionItems.push(item); + if (!options.searchAddress || !item.city) return res; // no city: exclude this item + item.searchAddress = item.city && ((hit._source.address ? hit._source.address+ ', ' : '') + item.city); + searchAddressItems.push(item); } else { // Convert lat/lon to float (if need) @@ -152,24 +153,29 @@ angular.module('cesium.map.wot.services', ['cesium.services']) }, []); // Resolve missing positions by addresses (only if google API enable) - if (noPositionItems.length && esGeo.google.hasApiKey()) { + if (searchAddressItems.length) { var now = new Date().getTime(); - console.log('[map] [wot] Search positions of {0} addresses...'.format(noPositionItems.length)); + console.log('[map] [wot] Search positions of {0} addresses...'.format(searchAddressItems.length)); var counter = 0; - return $q.all(noPositionItems.reduce(function(res, item) { - return res.concat(esGeo.google.searchByAddress(item.fullAddress) + return $q.all(searchAddressItems.reduce(function(res, item) { + return !item.searchAddress ? res : res.concat(esGeo.google.searchByAddress(item.searchAddress) .then(function(res) { if (!res || !res.length) return; item.geoPoint = res[0]; - delete item.fullAddress; + // If search on city, add a randomized delta to avoid superposition + if (item.city == item.searchAddress) { + item.geoPoint.lon += Math.random() / 1000; + item.geoPoint.lat += Math.random() / 1000; + } + delete item.searchAddress; // not need anymore 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)); + console.log('[map] [wot] Resolved {0}/{1} addresses in {2}ms'.format(counter, searchAddressItems.length, new Date().getTime()-now)); return items; }); } diff --git a/www/plugins/map/templates/network/view_map.html b/www/plugins/map/templates/network/view_map.html index ff906349..316a454c 100644 --- a/www/plugins/map/templates/network/view_map.html +++ b/www/plugins/map/templates/network/view_map.html @@ -1,5 +1,6 @@ <ion-view left-buttons="leftButtons" class="view-map-network"> <ion-nav-title> + <span class="hidden-xs" translate>MAP.NETWORK.VIEW.TITLE</span> </ion-nav-title> <ion-nav-buttons side="secondary"> diff --git a/www/plugins/map/templates/settings/es_settings_extend.html b/www/plugins/map/templates/settings/es_settings_extend.html new file mode 100644 index 00000000..70f41cc5 --- /dev/null +++ b/www/plugins/map/templates/settings/es_settings_extend.html @@ -0,0 +1,35 @@ + +<span class="item item-divider" translate>MAP.SETTINGS.MAP_DIVIDER</span> + +<label class="item item-toggle dark item-text-wrap"> + <span translate>MAP.SETTINGS.ENABLE_GOOGLE_API</span> + <h4 class="gray" translate>MAP.SETTINGS.ENABLE_GOOGLE_API_HELP</h4> + <div class="toggle toggle-royal"> + <input type="checkbox" ng-model="formData.enableGoogleApi"> + <div class="track"> + <div class="handle"></div> + </div> + </div> +</label> + +<ion-item class="item-input" + ng-if="!$root.config.plugins.es.googleApiKey" + ng-class="{'item-input-error': formData.enableGoogleApi && !formData.googleApiKey}"> + <div class="input-label col-33"> + <span class="" ng-class="{'gray': !formData.enableGoogleApi}"translate>MAP.SETTINGS.GOOGLE_API_KEY</span> + <h4> + <a href="https://console.developers.google.com/apis/credentials/key" target="_system" translate>MAP.SETTINGS.BTN_GOOGLE_API</a> + <span class="gray"> ({{'MAP.SETTINGS.BTN_GOOGLE_API_WARNING'|translate}})</span> + </h4> + </div> + <input type="text" + placeholder="{{'MAP.SETTINGS.GOOGLE_API_KEY_PLACEHOLDER' | translate}}" + ng-model="formData.googleApiKey" + ng-if="formData.enableGoogleApi"> +</ion-item> +<div class="form-errors" + ng-show="formData.enableGoogleApi && !formData.googleApiKey"> + <div class="form-error"> + <span translate="ERROR.FIELD_REQUIRED"></span> + </div> +</div> diff --git a/www/plugins/map/templates/wot/popup_marker.html b/www/plugins/map/templates/wot/popup_marker.html index ec551fee..03564575 100644 --- a/www/plugins/map/templates/wot/popup_marker.html +++ b/www/plugins/map/templates/wot/popup_marker.html @@ -18,6 +18,6 @@ </h4> </div> </div> -<div class="item no-border no-padding item-text-wrap" ng-if="::hit.description"> +<div class="item no-border no-padding item-text-wrap hidden-xs" ng-if="::hit.description"> <small ng-bind-html="::hit.description"></small> </div> diff --git a/www/plugins/map/templates/wot/view_map.html b/www/plugins/map/templates/wot/view_map.html index 15fa1403..939ec7cc 100644 --- a/www/plugins/map/templates/wot/view_map.html +++ b/www/plugins/map/templates/wot/view_map.html @@ -1,8 +1,11 @@ <ion-view left-buttons="leftButtons" class="view-map-wot"> <ion-nav-title> + <span class="hidden-xs" translate>MAP.WOT.VIEW.TITLE</span> </ion-nav-title> <ion-nav-buttons side="secondary"> + <button class="button button-icon button-clear icon ion-loop visible-xs visible-sm" ng-click="load()"> + </button> </ion-nav-buttons> <ion-content data-tap-disabled="true"> -- GitLab