diff --git a/appinfo/routes.php b/appinfo/routes.php index e9f7b5363..e4948c65d 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -22,6 +22,7 @@ ['name' => 'photos#getPhotosFromDb', 'url' => '/photos', 'verb' => 'GET'], ['name' => 'photos#getNonLocalizedPhotosFromDb', 'url' => '/photos/nonlocalized', 'verb' => 'GET'], ['name' => 'photos#placePhotos', 'url' => '/photos', 'verb' => 'POST'], + ['name' => 'photos#resetPhotosCoords', 'url' => '/photos', 'verb' => 'DELETE'], // contacts ['name' => 'contacts#getContacts', 'url' => '/contacts', 'verb' => 'GET'], diff --git a/css/style.css b/css/style.css index 6eab6cbfd..09fc793bd 100644 --- a/css/style.css +++ b/css/style.css @@ -19,7 +19,7 @@ } #search-term { margin-right: 0px !important; - width: 200px; + width: 294px; } #timeRangeSlider { @@ -96,8 +96,11 @@ max-width: 50vw; } +#opening-hours-table td { + padding: 0 5px 0 5px; +} #opening-hours-table { - margin-left: 25px; + width: 100%; display: none; } @@ -234,14 +237,25 @@ tr.selected td { border-radius: 50%; } +.leaflet-marker-contact.contact-marker:after { + bottom: 18px; + border-width: 12px 8px 0; +} +.leaflet-marker-device.device-marker:after { + bottom: 18px; + border-width: 12px 7px 0; +} .leaflet-marker-nonLocalizedPhoto.nonLocalizedPhoto-marker:after, +.leaflet-marker-photo.photo-marker:after { + bottom: 17px; + border-width: 11px 8px 0; +} .leaflet-marker-contact.contact-marker:after, .leaflet-marker-device.device-marker:after, +.leaflet-marker-nonLocalizedPhoto.nonLocalizedPhoto-marker:after, .leaflet-marker-photo.photo-marker:after { content:""; position: relative; - bottom: 16px; - border-width: 10px 10px 0; border-style: solid; border-color: var(--color-main-background) transparent; display: block; @@ -304,9 +318,14 @@ tr.selected td { padding: 3px; } +.leaflet-marker-favorite-tooltip, +.leaflet-marker-device-tooltip, +.leaflet-marker-track-tooltip, .leaflet-marker-contact-tooltip, .leaflet-marker-photo-tooltip { opacity: 1 !important; + background-color: var(--color-main-background); + color: var(--color-main-text); } .leaflet-marker-photo-tooltip { padding: 1px; @@ -356,10 +375,6 @@ tr.selected td { line-height: 1.7; font-size: 20px; } -#dummylogo { - display: none; - content: url("images/.png"); -} .easy-button-button img { width: 100%; height: 100%; @@ -494,6 +509,9 @@ tr.selected td { text-align: center; } /* Overriden routing/geocoder style */ +.leaflet-routing-geocoder-result tr { + line-height: 35px; +} /* hide button if placeholder is shown i.e. if field is empty */ .leaflet-routing-geocoder > input:placeholder-shown + span { display: none; @@ -520,7 +538,7 @@ tr.selected td { .leaflet-routing-remove-waypoint::after { right: 6px !important; width: 18px !important; - height: 10px !important; + height: 5px !important; background-color: var(--color-main-background) !important; } .leaflet-routing-remove-waypoint:hover:after { @@ -528,6 +546,7 @@ tr.selected td { } .leaflet-routing-alt table { white-space: normal; + width: 100%; } .leaflet-routing-alt td:nth-child(2), .leaflet-routing-alt td:nth-child(3) { @@ -584,3 +603,26 @@ tr.selected td { word-wrap: break-word; white-space: normal; } +.searchCompleteIcon { + background-color: inherit; + border: 0px; + height: 35px; + padding-top: 15px; +} +.searchCompleteLink { + line-height: 35px; +} +.search-add-favorite { + margin-left: auto; + margin-right: auto; + display: block; +} +.search-result-popup { + width: 250px; +} +.search-result-popup .leaflet-popup-content { + line-height: 25px !important; +} +.ui-autocomplete { + z-index: 9999; +} diff --git a/js/contactsController.js b/js/contactsController.js index 265a8c5ff..8a1206954 100644 --- a/js/contactsController.js +++ b/js/contactsController.js @@ -1,5 +1,6 @@ function ContactsController (optionsController, timeFilterController) { this.contact_MARKER_VIEW_SIZE = 40; + this.contactLayer = null; this.contactsDataLoaded = false; this.contactsRequestInProgress = false; this.optionsController = optionsController; @@ -217,7 +218,7 @@ ContactsController.prototype = { var avatar = this.generateAvatar(marker.data.photo) || this.getUserImageIconUrl(); var img = '' + '

' + escapeHTML(basename(markerData.name)) + '

'; - marker.bindTooltip(img, {permanent: false, className: "leaflet-marker-contact-tooltip"}); + marker.bindTooltip(img, {permanent: false, className: 'leaflet-marker-contact-tooltip', direction: 'top', offset: L.point(0, -25)}); markers.push(marker); } return markers; @@ -488,5 +489,25 @@ ContactsController.prototype = { this.showLayer(); }, + + getAutocompData: function() { + var that = this; + var mData; + var data = []; + if (this.map.hasLayer(this.contactLayer)) { + this.contactLayer.eachLayer(function (l) { + mData = l.data; + data.push({ + type: 'contact', + label: mData.name, + value: mData.name, + lat: mData.lat, + lng: mData.lng + }); + }); + } + return data; + }, + }; diff --git a/js/devicesController.js b/js/devicesController.js index aa0dfcd89..27a0e7611 100644 --- a/js/devicesController.js +++ b/js/devicesController.js @@ -56,6 +56,11 @@ DevicesController.prototype = { var id = $(this).parent().parent().parent().parent().attr('device'); that.toggleDeviceLine(id, true); }); + $('body').on('click', '.contextToggleLine', function(e) { + var id = $(this).parent().parent().attr('devid'); + that.toggleDeviceLine(id, true); + that.map.closePopup(); + }); // toggle devices $('body').on('click', '#navigation-devices > a', function(e) { that.toggleDevices(); @@ -78,6 +83,11 @@ DevicesController.prototype = { var id = $(this).parent().parent().parent().parent().attr('device'); that.askChangeDeviceColor(id); }); + $('body').on('click', '.contextChangeDeviceColor', function(e) { + var id = $(this).parent().parent().attr('devid'); + that.askChangeDeviceColor(id); + that.map.closePopup(); + }); $('body').on('change', '#devicecolorinput', function(e) { that.okColor(); }); @@ -334,15 +344,9 @@ DevicesController.prototype = { else { imgurl = OC.generateUrl('/svg/core/clients/phone?color='+color.replace('#', '')); } - var rgbc = hexToRgb(color); - var textcolor = 'black'; - if (rgbc.r + rgbc.g + rgbc.b < 3 * 80) { - textcolor = 'white'; - } $('').appendTo('body'); // subgroup layer @@ -781,7 +776,10 @@ FavoritesController.prototype = { var fav = this._map.favoritesController.favorites[favid]; var cat = fav.category ? fav.category.replace(' ', '-') : this._map.favoritesController.defaultCategory.replace(' ', '-'); var favTooltip = this._map.favoritesController.getFavoriteTooltipContent(fav); - e.target.bindTooltip(favTooltip, {className: 'tooltipfav-' + cat}); + e.target.bindTooltip(favTooltip, { + className: 'leaflet-marker-favorite-tooltip tooltipfav-' + cat, + direction: 'top' + }); e.target.openTooltip(); }, @@ -1145,5 +1143,32 @@ FavoritesController.prototype = { OC.Notification.showTemporary(t('maps', 'Failed to import favorites')); }); }, + + getAutocompData: function() { + var that = this; + var fav, favid; + var data = []; + if (that.map.hasLayer(that.cluster)) { + for (var cat in this.categoryLayers) { + layer = this.categoryLayers[cat]; + if (this.map.hasLayer(layer)) { + layer.eachLayer(function (l) { + fav = that.favorites[l.favid]; + if (fav.name) { + data.push({ + type: 'favorite', + label: fav.name, + value: fav.name, + lat: fav.lat, + lng: fav.lng + }); + } + }); + } + } + } + return data; + }, + } diff --git a/js/nonLocalizedPhotosController.js b/js/nonLocalizedPhotosController.js index 29f3eb5ce..576aa902e 100644 --- a/js/nonLocalizedPhotosController.js +++ b/js/nonLocalizedPhotosController.js @@ -321,9 +321,9 @@ NonLocalizedPhotosController.prototype = { return OC.generateUrl('core') + '/preview.png?file=' + encodeURI(filename) + '&x=32&y=32'; }, - /* Preview size 375x211 is used in files details view */ + /* Preview size 341x256 is commonly found in preview folder */ generatePreviewUrl: function (fileId) { - return OC.generateUrl('core') + '/preview?fileId=' + fileId + '&x=349&y=349&a=1'; + return OC.generateUrl('core') + '/preview?fileId=' + fileId + '&x=341&y=256&a=1'; }, getImageIconUrl: function() { diff --git a/js/photosController.js b/js/photosController.js index 51bd89211..5aea796cf 100644 --- a/js/photosController.js +++ b/js/photosController.js @@ -11,6 +11,8 @@ function PhotosController (optionsController, timeFilterController) { this.photoMarkersLastVisible = -1; this.timeFilterBegin = 0; this.timeFilterEnd = Date.now(); + + this.movingPhotoPath = null; } PhotosController.prototype = { @@ -51,6 +53,19 @@ PhotosController.prototype = { $(this).parent().parent().parent().find('>.app-navigation-entry-menu').addClass('open'); } }); + $('body').on('click', '.movephoto', function(e) { + var ul = $(this).parent().parent(); + var filePath = ul.attr('filepath'); + that.movingPhotoPath = filePath; + that.enterMovePhotoMode(); + that.map.closePopup(); + }); + $('body').on('click', '.resetphoto', function(e) { + var ul = $(this).parent().parent(); + var filePath = ul.attr('filepath'); + that.resetPhotoCoords([filePath]); + that.map.closePopup(); + }); // expand navigation $('body').on('click', '#navigation-photos', function(e) { if (e.target.tagName === 'LI' && $(e.target).attr('id') === 'navigation-photos') { @@ -201,12 +216,65 @@ PhotosController.prototype = { var img = '' + '

' + dateStr + '

' + '

' + escapeHTML(basename(markerData.path)) + '

'; - marker.bindTooltip(img, {permanent: false, className: "leaflet-marker-photo-tooltip"}); + marker.bindTooltip(img, {permanent: false, className: 'leaflet-marker-photo-tooltip', direction: 'right', offset: L.point(0, -30)}); + marker.on('contextmenu', this.photoMouseRightClick); markers.push(marker); } return markers; }, + photoMouseRightClick: function(e) { + var filePath = e.target.data.path; + + e.target.unbindPopup(); + var popupContent = this._map.photosController.getPhotoContextPopupContent(filePath); + e.target.bindPopup(popupContent, { + closeOnClick: true, + className: 'popovermenu open popupMarker', + offset: L.point(-5, 9) + }); + e.target.openPopup(); + }, + + getPhotoContextPopupContent: function(filePath) { + var moveText = t('maps', 'Move'); + var resetText = t('maps', 'Remove geo data'); + var res = + ''; + return res; + }, + + enterMovePhotoMode: function() { + $('.leaflet-container').css('cursor', 'crosshair'); + this.map.on('click', this.movePhotoClickMap); + OC.Notification.showTemporary(t('maps', 'Click on the map to move the photo, press ESC to cancel')); + }, + + leaveMovePhotoMode: function() { + $('.leaflet-container').css('cursor', 'grab'); + this.map.off('click', this.movePhotoClickMap); + this.movingPhotoPath = null; + }, + + movePhotoClickMap: function(e) { + var lat = e.latlng.lat; + var lng = e.latlng.lng; + var filePath = this.photosController.movingPhotoPath; + this.photosController.leaveMovePhotoMode(); + this.photosController.placePhotos([filePath], [lat], [lng]); + }, + updateTimeFilterRange: function() { this.updateMyFirstLastDates(); this.timeFilterController.updateSliderRangeFromController(); @@ -291,9 +359,9 @@ PhotosController.prototype = { return OC.generateUrl('core') + '/preview.png?file=' + encodeURI(filename) + '&x=32&y=32'; }, - /* Preview size 375x211 is used in files details view */ + /* Preview size 341x256 is commonly found in preview folder */ generatePreviewUrl: function (fileId) { - return OC.generateUrl('core') + '/preview?fileId=' + fileId + '&x=349&y=349&a=1'; + return OC.generateUrl('core') + '/preview?fileId=' + fileId + '&x=341&y=256&a=1'; }, getImageIconUrl: function() { @@ -372,5 +440,43 @@ PhotosController.prototype = { }); }, + resetPhotoCoords: function(paths) { + var that = this; + $('#navigation-photos').addClass('icon-loading-small'); + $('.leaflet-container').css('cursor', 'wait'); + var req = { + paths: paths + }; + var url = OC.generateUrl('/apps/maps/photos'); + $.ajax({ + type: 'DELETE', + url: url, + data: req, + async: true + }).done(function (response) { + OC.Notification.showTemporary(t('maps', '{nb} photos reset', {nb: response})); + if (response > 0) { + that.photosDataLoaded = false; + for (var i=0; i < that.photoMarkers.length; i++) { + that.photoLayer.removeLayer(that.photoMarkers[i]); + } + that.photoMarkers = []; + that.photoMarkersOldest = null; + that.photoMarkersNewest = null; + that.photoMarkersFirstVisible = 0; + that.photoMarkersLastVisible = -1; + that.timeFilterBegin = 0; + that.timeFilterEnd = Date.now(); + + that.showLayer(); + } + }).always(function (response) { + $('#navigation-photos').removeClass('icon-loading-small'); + $('.leaflet-container').css('cursor', 'grab'); + }).fail(function(response) { + OC.Notification.showTemporary(t('maps', 'Failed to reset photos coordinates') + ': ' + response.responseText); + }); + }, + }; diff --git a/js/script.js b/js/script.js index db2f1b971..fd998f8f7 100644 --- a/js/script.js +++ b/js/script.js @@ -13,8 +13,10 @@ contactsController.initLayer(mapController.map); mapController.map.contactsController = contactsController; tracksController.initController(mapController.map); + tracksController.map.tracksController = tracksController; devicesController.initController(mapController.map); mapController.map.devicesController = devicesController; + searchController.initController(mapController.map); // once controllers have been set/initialized, we can restore option values from server optionsController.restoreOptions(); @@ -27,39 +29,6 @@ $('#opening-hours-table-toggle-collapse').toggle(); }); - // Search - $('#search-form').submit(function(e) { - e.preventDefault(); - submitSearchForm(); - }); - $('#search-submit').click(function() { - submitSearchForm(); - }); - - function submitSearchForm() { - var str = $('#search-term').val(); - if(str.length < 1) { - return; - } - - searchController.search(str).then(function(results) { - if (results.length === 0) { - return; - } - else if (results.length === 1) { - var result = results[0]; - mapController.displaySearchResult(result); - routingController.control.spliceWaypoints(routingController.control.getWaypoints().length - 1, 1, new L.LatLng(result.lat, result.lon)); - } - else { - console.log('multiple results'); - var result = results[0]; - mapController.displaySearchResult(result); - routingController.control.spliceWaypoints(routingController.control.getWaypoints().length - 1, 1, new L.LatLng(result.lat, result.lon)); - } - }); - } - document.onkeydown = function (e) { e = e || window.event; if (e.key === 'Escape') { @@ -69,6 +38,9 @@ if (contactsController.movingBookid !== null) { contactsController.leaveMoveContactMode(); } + if (photosController.movingPhotoPath !== null) { + photosController.leaveMovePhotoMode(); + } } }; window.onclick = function(event) { @@ -264,7 +236,7 @@ }); var name = result.display_name; var popupContent = searchController.parseOsmResult(result); - this.searchMarker.bindPopup(popupContent); + this.searchMarker.bindPopup(popupContent, {className: 'search-result-popup'}); this.searchMarker.addTo(this.map); this.searchMarker.openPopup(); this.map.flyTo([result.lat, result.lon], 15, {duration: 1}); @@ -452,7 +424,7 @@ $('.leaflet-control-layers').toggle(); // main layers buttons - var esriImageUrl = $('#dummylogo').css('content').replace('url("', '').replace('")', '').replace('.png', 'esri.jpg'); + var esriImageUrl = OC.filePath('maps', 'css/images', 'esri.jpg'); this.esriButton = L.easyButton({ position: 'bottomright', states: [{ @@ -464,7 +436,7 @@ } }] }); - var osmImageUrl = $('#dummylogo').css('content').replace('url("', '').replace('")', '').replace('.png', 'osm.png'); + var osmImageUrl = OC.filePath('maps', 'css/images', 'osm.png'); this.osmButton = L.easyButton({ position: 'bottomright', states: [{ @@ -746,24 +718,37 @@ if (!routingController.enabled) { routingController.toggleRouting(); } - var control = routingController.control; - control.spliceWaypoints(0, 1, e.latlng); + routingController.setRouteFrom(e.latlng); }, contextRouteTo: function(e) { if (!routingController.enabled) { routingController.toggleRouting(); } - var control = routingController.control; - control.spliceWaypoints(control.getWaypoints().length - 1, 1, e.latlng); + routingController.setRouteTo(e.latlng); }, contextRoutePoint: function(e) { if (!routingController.enabled) { routingController.toggleRouting(); } - var control = routingController.control; - routingController.control.spliceWaypoints(control.getWaypoints().length - 1, 0, e.latlng); + routingController.addRoutePoint(e.latlng); + }, + + setRouteFrom: function(latlng) { + this.control.spliceWaypoints(0, 1, latlng); + }, + + setRouteTo: function(latlng) { + this.control.spliceWaypoints(this.control.getWaypoints().length - 1, 1, latlng); + }, + + setRoutePoint: function(i, latlng) { + this.control.spliceWaypoints(i, 1, latlng); + }, + + addRoutePoint: function(latlng) { + this.control.spliceWaypoints(this.control.getWaypoints().length - 1, 0, latlng); }, }; @@ -953,19 +938,245 @@ timeFilterController.connect(); var searchController = { - isGeocodeabe: function(str) { + map: null, + SEARCH_BAR: 1, + ROUTING_FROM: 2, + ROUTING_TO: 3, + ROUTING_POINT: 4, + currentLocalAutocompleteData: [], + initController: function(map) { + this.map = map; + var that = this; + // Search + $('#search-form').submit(function(e) { + e.preventDefault(); + that.submitSearchForm(); + }); + $('#search-submit').click(function(e) { + e.preventDefault(); + that.submitSearchForm(); + }); + $('#search-term').on('focus', function(e) { + $(this).select(); + that.setSearchAutocomplete(that.SEARCH_BAR); + }); + $('body').on('focus', '.leaflet-routing-geocoder input', function(e) { + var inputs = $('.leaflet-routing-geocoder input'); + var nbInputs = inputs.length; + var index = inputs.index($(this)); + if (index === 0) { + that.setSearchAutocomplete(that.ROUTING_FROM); + } + else if (index === nbInputs - 1) { + that.setSearchAutocomplete(that.ROUTING_TO); + } + else { + that.setSearchAutocomplete(that.ROUTING_POINT, index); + } + }); + $('body').on('keyup', '.leaflet-routing-geocoder input', function(e) { + // if we press enter => disable autocomplete to let nominatim results dropdown appear + if (e.key === 'Enter') { + $(this).autocomplete('close'); + $(this).autocomplete('disable'); + } + // if any other key (except arrows up/down) is pressed => enable autocomplete again + else if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') { + $('.leaflet-routing-geocoder-result').removeClass('leaflet-routing-geocoder-result-open'); + $(this).autocomplete('enable'); + $(this).autocomplete('search'); + } + }); + // replace JQuery ui autocomplete matching function + // to make 'one three' match 'one two three' for example. + // search terms in the same order + $.ui.autocomplete.filter = function (array, terms) { + arrayOfTerms = terms.split(' '); + var term = $.map(arrayOfTerms, function (tm) { + return $.ui.autocomplete.escapeRegex(tm); + }).join('.*'); + var matcher = new RegExp(term, 'i'); + return $.grep(array, function (value) { + return matcher.test(value.label || value.value || value); + }); + }; + // search result add favorite + $('body').on('click', '.search-add-favorite', function(e) { + var lat = parseFloat($(this).attr('lat')); + var lng = parseFloat($(this).attr('lng')); + var name = $(this).parent().find('.location-header').text(); + favoritesController.addFavoriteDB('', lat, lng, name); + that.map.closePopup(); + }); + }, + + setSearchAutocomplete: function(field, routingPointIndex=null) { + var fieldElement; + if (field === this.SEARCH_BAR) { + fieldElement = $('#search-term'); + } + else if (field === this.ROUTING_FROM) { + fieldElement = $('.leaflet-routing-geocoder input').first(); + } + else if (field === this.ROUTING_TO) { + fieldElement = $('.leaflet-routing-geocoder input').last(); + } + else if (field === this.ROUTING_POINT) { + fieldElement = $('.leaflet-routing-geocoder input').eq(routingPointIndex); + } + var that = this; + var data = []; + // get favorites + var favData = favoritesController.getAutocompData(); + data.push(...favData); + // get contacts + var contactData = contactsController.getAutocompData(); + data.push(...contactData); + // get devices + var devData = devicesController.getAutocompData(); + data.push(...devData); + if (navigator.geolocation && window.isSecureContext) { + data.push({ + type: 'location', + label: t('maps', 'My location'), + value: t('maps', 'My location') + }); + } + that.currentLocalAutocompleteData = data; + fieldElement.autocomplete({ + source: data, + select: function (e, ui) { + var it = ui.item; + if (it.type === 'favorite') { + that.map.setView([it.lat, it.lng], 15); + } + else if (it.type === 'contact') { + that.map.setView([it.lat, it.lng], 15); + } + else if (it.type === 'device') { + devicesController.zoomOnDevice(it.id); + } + else if (it.type === 'address') { + if (field === that.SEARCH_BAR) { + mapController.displaySearchResult(it.result); + } + } + else if (it.type === 'location') { + navigator.geolocation.getCurrentPosition(function (position) { + var lat = position.coords.latitude; + var lng = position.coords.longitude; + if (field === that.SEARCH_BAR) { + that.map.setView([lat, lng], 15); + } + if (field === that.SEARCH_BAR || field === that.ROUTING_TO) { + routingController.setRouteTo(L.latLng(lat, lng)); + } + else if (field === that.ROUTING_FROM) { + routingController.setRouteFrom(L.latLng(lat, lng)); + $('.leaflet-routing-geocoder input').last().focus(); + } + else if (field === that.ROUTING_POINT) { + routingController.setRoutePoint(routingPointIndex, L.latLng(lat, lng)); + $('.leaflet-routing-geocoder input').last().focus(); + } + }); + return; + } + if (field === that.SEARCH_BAR || field === that.ROUTING_TO) { + routingController.setRouteTo(L.latLng(it.lat, it.lng)); + } + else if (field === that.ROUTING_FROM) { + routingController.setRouteFrom(L.latLng(it.lat, it.lng)); + $('.leaflet-routing-geocoder input').last().focus(); + } + else if (field === that.ROUTING_POINT) { + routingController.setRoutePoint(routingPointIndex, L.latLng(it.lat, it.lng)); + $('.leaflet-routing-geocoder input').last().focus(); + } + } + }).data('ui-autocomplete')._renderItem = function(ul, item) { + var iconClass = 'icon-link'; + if (item.type === 'favorite') { + iconClass = 'icon-favorite'; + } + else if (item.type === 'contact') { + iconClass = 'icon-group'; + } + else if (item.type === 'device') { + if (item.subtype === 'computer') { + iconClass = 'icon-desktop'; + } + else { + iconClass = 'icon-phone'; + } + } + else if (item.type === 'location') { + iconClass = 'icon-address'; + } + // shorten label if needed + var label = item.label; + if (label.length > 35) { + label = label.substring(0, 35) + '...'; + } + var listItem = $('
  • ') + .data('item.autocomplete', item) + .append(' ' + label + '') + .appendTo(ul); + return listItem; + }; + }, + + submitSearchForm: function() { + var that = this; + var str = $('#search-term').val(); + if (str.length < 1) { + return; + } + + this.search(str).then(function(results) { + if (results.length === 0) { + return; + } + else if (results.length === 1) { + var result = results[0]; + mapController.displaySearchResult(result); + routingController.setRouteTo(L.latLng(result.lat, result.lon)); + } + else { + var result = results[0]; + var newData = []; + newData.push(...that.currentLocalAutocompleteData); + for (var i=0; i < results.length; i++) { + newData.push({ + type: 'address', + label: results[i].display_name, + value: results[i].display_name, + result: results[i], + lat: results[i].lat, + lng: results[i].lon + }); + } + $('#search-term').autocomplete('option', {source: newData}); + $('#search-term').autocomplete('search'); + } + }); + }, + + isGeocodeable: function(str) { var pattern = /^\s*\d+\.?\d*\,\s*\d+\.?\d*\s*$/; return pattern.test(str); }, search: function(str) { - var searchTerm = str.replace(' ', '%20'); // encode spaces - var apiUrl = 'https://nominatim.openstreetmap.org/search/'+searchTerm+'?format=json&addressdetails=1&extratags=1&namedetails=1&limit=8'; + var searchTerm = encodeURIComponent(str); + var apiUrl = 'https://nominatim.openstreetmap.org/search/' + searchTerm + '?format=json&addressdetails=1&extratags=1&namedetails=1&limit=8'; return $.getJSON(apiUrl, {}, function(response) { return response; }); }, geocode: function(latlng) { - if(!this.isGeocodeabe(latlng)) return; + if (!this.isGeocodeable(latlng)) { + return; + } var splits = latlng.split(','); var lat = splits[0].trim(); var lon = splits[1].trim(); @@ -977,64 +1188,87 @@ parseOsmResult: function(result) { var add = result.address; var road, postcode, city, state, name; - if(add.road) { + if (add.road) { road = add.road; - if(add.house_number) road += ' ' + add.house_number; + if (add.house_number) { + road += ' ' + add.house_number; + } + } + if (add.postcode) { + postcode = add.postcode; } - if(add.postcode) postcode = add.postcode; - if(add.city || add.town || add.village) { - if(add.city) city = add.city; - else if(add.town) city = add.town; - else if(add.village) city = add.village; - if(add.state) { + if (add.city || add.town || add.village) { + if (add.city) { + city = add.city; + } + else if (add.town) { + city = add.town; + } + else if (add.village) { + city = add.village; + } + if (add.state) { state = add.state; } } var details = result.namedetails; - if(details.name) name = details.name; + if (details.name) { + name = details.name; + } var unformattedHeader; - if(name) unformattedHeader = name; - else if(road) unformattedHeader = road; - else if(city) unformattedHeader = city; + if (name) { + unformattedHeader = name; + } + else if (road) { + unformattedHeader = road; + } + else if (city) { + unformattedHeader = city; + } var unformattedDesc = ''; var needSeparator = false; // add road to desc if it is not heading and exists (isn't heading, if 'name' is set) - if(name && road) { + if (name && road) { unformattedDesc = road; needSeparator = true; } - if(postcode) { - if(needSeparator) { + if (postcode) { + if (needSeparator) { unformattedDesc += ', '; needSeparator = false; } unformattedDesc += postcode; } - if(city) { - if(needSeparator) { + if (city) { + if (needSeparator) { unformattedDesc += ', '; needSeparator = false; - } else if(unformattedDesc.length > 0) { + } + else if (unformattedDesc.length > 0) { unformattedDesc += ' '; } unformattedDesc += city; } - if(state && add && add.country_code == 'us') { // assume that state is only important for us addresses - if(unformattedDesc.length > 0) { + if (state && add && add.country_code == 'us') { // assume that state is only important for us addresses + if (unformattedDesc.length > 0) { unformattedDesc += ' '; } unformattedDesc += '(' + state + ')'; } var header = '

    ' + unformattedHeader + '

    '; - if(result.icon) header = '
    ' + header + '
    '; + if (result.icon) { + header = '
    ' + header + '
    '; + } var desc = '' + unformattedDesc + ''; + desc += ''; // Add extras to parsed desc var extras = result.extratags; - if(extras.opening_hours) { + if (extras.opening_hours) { desc += '
    '; var oh = new opening_hours(extras.opening_hours, result); var isCurrentlyOpen = oh.getState(); @@ -1042,18 +1276,24 @@ var currentDt = new Date(); var dtDiff = changeDt.getTime() - currentDt.getTime(); dtDiff = dtDiff / 60000; // get diff in minutes - if(oh.getState()) { // is open? - desc += 'Open'; - if(dtDiff <= 60) { - desc += ', closes in ' + dtDiff + ' minutes'; - } else { - desc += ' until ' + changeDt.toLocaleTimeString() + ''; + if (oh.getState()) { // is open? + desc += '' + t('maps', 'Open') + ' '; + if (dtDiff <= 60) { + desc += ', ' + t('maps', 'closes in {nb} minutes', {nb: dtDiff}) + ''; } - } else { - desc += 'Closed'; - desc += 'opens at ' + changeDt.toLocaleTimeString() + ''; + else { + desc += ' ' + t('maps', 'until {date}', {date: changeDt.toLocaleTimeString()}) + ''; + } + } + else { + desc += '' + t('maps', 'Closed') + ' '; + desc += '' + t('maps', 'opens at {date}', {date: changeDt.toLocaleTimeString()}) + ''; } - desc += '
    '; + desc += ''; var todayStart = currentDt; todayStart.setHours(0); todayStart.setMinutes(0); @@ -1064,17 +1304,21 @@ var intervals = oh.getOpenIntervals(todayStart, sevDaysEnd); desc += ''; // intervals should be 7, if 8, then first entry is interval after 00:00:00 from last day - if(intervals.length == 8) { + if (intervals.length == 8) { // set end time of last element to end time of first element and remove it intervals[7][1] = intervals[0][1]; intervals.splice(0, 1); } - for(var i=0; i'; var startTime = from.toLocaleTimeString(); var endTime =to.toLocaleTimeString(); @@ -1083,13 +1327,13 @@ } desc += '
    '; } - if(extras.website) { + if (extras.website) { desc += '
    ' + helpers.beautifyUrl(extras.website) + '
    '; } - if(extras.phone) { + if (extras.phone) { desc += '
    ' + extras.phone + '
    '; } - if(extras.email) { + if (extras.email) { desc += '
    ' + extras.email + '
    '; } diff --git a/js/tracksController.js b/js/tracksController.js index 034d22462..751cae1a5 100644 --- a/js/tracksController.js +++ b/js/tracksController.js @@ -56,6 +56,11 @@ TracksController.prototype = { var id = parseInt($(this).parent().parent().parent().parent().attr('track')); that.removeTrackDB(id); }); + $('body').on('click', '.contextRemoveTrack', function(e) { + var id = parseInt($(this).parent().parent().attr('trackid')); + that.removeTrackDB(id); + that.map.closePopup(); + }); // remove all tracks $('body').on('click', '#remove-all-tracks', function(e) { that.removeAllTracksDB(); @@ -121,6 +126,12 @@ TracksController.prototype = { var id = $(this).parent().parent().parent().parent().attr('track'); that.askChangeTrackColor(id); }); + // context menu event + $('body').on('click', '.contextChangeTrackColor', function(e) { + var id = parseInt($(this).parent().parent().attr('trackid')); + that.askChangeTrackColor(id); + that.map.closePopup(); + }); $('body').on('change', '#trackcolorinput', function(e) { that.okColor(); }); @@ -128,6 +139,11 @@ TracksController.prototype = { var id = $(this).attr('track'); that.showTrackElevation(id); }); + $('body').on('click', '.contextShowElevation', function(e) { + var id = parseInt($(this).parent().parent().attr('trackid')); + that.showTrackElevation(id); + that.map.closePopup(); + }); $('body').on('click', '.showTrackElevation', function(e) { var id = $(this).parent().parent().parent().parent().attr('track'); that.showTrackElevation(id); @@ -653,7 +669,13 @@ TracksController.prototype = { icon: this.trackDivIcon[id] } ); - mm.bindTooltip(brify(name, 20), {className: coloredTooltipClass}); + mm.bindTooltip(brify(name, 20), { + className: coloredTooltipClass + ' leaflet-marker-track-tooltip', + direction: 'top', + offset: L.point(0, -15) + }); + mm.trackid = id; + mm.on('contextmenu', this.trackMouseRightClick); var popupText = this.getWaypointPopupText(id, name, lat, lon, cmt, desc, ele, linkText, linkUrl, sym); mm.bindPopup(popupText); @@ -903,7 +925,11 @@ TracksController.prototype = { if (this.tracks[id].file_name !== name) { tooltipText = tooltipText + '
    ' + escapeHTML(name); } - l.bindTooltip(tooltipText, {sticky: true, className: coloredTooltipClass}); + l.bindTooltip(tooltipText, { + sticky: true, + className: coloredTooltipClass + ' leaflet-marker-track-tooltip', + direction: 'top' + }); // border layout var bl; bl = L.polyline(latlngs, @@ -924,17 +950,64 @@ TracksController.prototype = { }); bl.on('mouseout', function() { }); - bl.bindTooltip(tooltipText, {sticky: true, className: coloredTooltipClass}); + bl.bindTooltip(tooltipText, { + sticky: true, + className: coloredTooltipClass + ' leaflet-marker-track-tooltip', + direction: 'top' + }); l.on('mouseover', function() { that.trackLayers[id].bringToFront(); }); l.on('mouseout', function() { }); + l.trackid = id; + l.on('contextmenu', this.trackMouseRightClick); + bl.trackid = id; + bl.on('contextmenu', this.trackMouseRightClick); return date; }, + trackMouseRightClick: function(e) { + var id = e.target.trackid; + + e.target.unbindPopup(); + var popupContent = this._map.tracksController.getTrackContextPopupContent(id); + e.target.bindPopup(popupContent, { + closeOnClick: true, + className: 'popovermenu open popupMarker', + offset: L.point(-4, 5) + }); + e.target.openPopup(e.latlng); + e.preventDefault(); + }, + + getTrackContextPopupContent: function(id) { + var colorText = t('maps', 'Change track color'); + var elevationText = t('maps', 'Show track elevation'); + var removeText = t('maps', 'Remove'); + var res = + ''; + return res; + }, + zoomOnTrack: function(id) { if (this.mainLayer.hasLayer(this.mapTrackLayers[id])) { this.map.fitBounds(this.mapTrackLayers[id].getBounds(), {padding: [30, 30]}); @@ -990,15 +1063,9 @@ TracksController.prototype = { setTrackCss: function(id, color) { $('style[track='+id+']').remove(); - var rgbc = hexToRgb(color); - var textcolor = 'black'; - if (rgbc.r + rgbc.g + rgbc.b < 3 * 80) { - textcolor = 'white'; - } $('