From 01f7448201d11139ae3a31745b7f26965c7282e7 Mon Sep 17 00:00:00 2001 From: Dave Arter Date: Mon, 12 Feb 2018 09:52:46 +0000 Subject: Populate `usrn` field with USRN of clicked asset, if available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some cobrands require reports to include the USRN of the clicked road. This commit allows an asset layer to be added and designated as a 'USRN provider' by setting its `usrn_field` property when calling fixmystreet.assets.add. Initially this feature used OpenLayers' getFeatureFromEvent method, however that doesn't work if the layer isn't topmost. This is because it uses the clicked element in the DOM to determine which feature was clicked. This doesn't work if the layer you're trying to get the feature from wasn't actually the DOM element that was clicked. Instead, we add a new method, OpenLayers.Layer.Vector.getFeatureAtPoint method which takes a Point object and iterates through the features' geometries to find the matching point. To make things a little more user-friendly, if an asset isn't clicked directly we find the closest to the clicked point and use that for the USRN. To accomplish this, this commit factors out the ‘select nearest asset’ code into a new method OpenLayers.Layer.Vector.getNearestFeature, which takes a Point and a distance threshold and finds the nearest feature. --- web/js/map-OpenLayers.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 0f6cca2b5..5ebb9a18e 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -40,19 +40,32 @@ $.extend(fixmystreet.utils, { }; $.extend(fixmystreet.maps, { - // This function might be passed either an OpenLayers.LonLat (so has - // lon and lat), or an OpenLayers.Geometry.Point (so has x and y). update_pin: function(lonlat) { + // This function might be passed either an OpenLayers.LonLat (so has + // lon and lat), or an OpenLayers.Geometry.Point (so has x and y). + if (lonlat.x !== undefined && lonlat.y !== undefined) { + // It's a Point, convert to a LatLon + lonlat = new OpenLayers.LonLat(lonlat.x, lonlat.y); + } + var transformedLonlat = lonlat.clone().transform( fixmystreet.map.getProjectionObject(), new OpenLayers.Projection("EPSG:4326") ); - var lat = transformedLonlat.lat || transformedLonlat.y; - var lon = transformedLonlat.lon || transformedLonlat.x; + var lat = transformedLonlat.lat; + var lon = transformedLonlat.lon; document.getElementById('fixmystreet.latitude').value = lat; document.getElementById('fixmystreet.longitude').value = lon; + + // This tight coupling isn't ideal. A better solution would be for the + // asset code to register an event handler somewhere, but the correct + // place isn't apparent. + if (fixmystreet.assets) { + fixmystreet.assets.select_usrn(lonlat); + } + return { 'url': { 'lon': lon, 'lat': lat }, 'state': { 'lon': lonlat.lon, 'lat': lonlat.lat } -- cgit v1.2.3 From 3cd4bb6e70d193f678e482835688f53c6ec68632 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Mon, 12 Mar 2018 16:52:44 +0000 Subject: Update some tight JS coupling to use events. Remove 'hooks' functions, and Split out USRN handling to its own object. --- web/js/map-OpenLayers.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 5ebb9a18e..0a1c947a0 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -59,12 +59,7 @@ $.extend(fixmystreet.utils, { document.getElementById('fixmystreet.latitude').value = lat; document.getElementById('fixmystreet.longitude').value = lon; - // This tight coupling isn't ideal. A better solution would be for the - // asset code to register an event handler somewhere, but the correct - // place isn't apparent. - if (fixmystreet.assets) { - fixmystreet.assets.select_usrn(lonlat); - } + $(fixmystreet).trigger('maps:update_pin', [ lonlat ]); return { 'url': { 'lon': lon, 'lat': lat }, -- cgit v1.2.3 From 3b82cc190589cbc712ec35e28efa1dd0af2f0d82 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Fri, 23 Mar 2018 18:09:04 +0000 Subject: Fix race condition making a new report. If you started a new report by clicking the map before the server had responded with the map list pins, when they did arrive they would replace the new report pin. --- web/js/map-OpenLayers.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 0a1c947a0..ec4f8bc3d 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -96,6 +96,7 @@ $.extend(fixmystreet.utils, { fixmystreet.markers.features[0].move(lonlat); } else { var markers = fixmystreet.maps.markers_list( [ [ lonlat.lat, lonlat.lon, fixmystreet.pin_new_report_colour ] ], false ); + fixmystreet.bbox_strategy.layer.protocol.abort(fixmystreet.bbox_strategy.response); fixmystreet.bbox_strategy.deactivate(); fixmystreet.markers.removeAllFeatures(); fixmystreet.markers.addFeatures( markers ); @@ -578,6 +579,9 @@ $.extend(fixmystreet.utils, { }); fixmystreet.markers.events.register( 'loadstart', null, fixmystreet.maps.loading_spinner.show); fixmystreet.markers.events.register( 'loadend', null, fixmystreet.maps.loading_spinner.hide); + OpenLayers.Request.XMLHttpRequest.onabort = function() { + fixmystreet.markers.events.triggerEvent("loadend", {response: null}); + }; var markers = fixmystreet.maps.markers_list( fixmystreet.pins, true ); fixmystreet.markers.addFeatures( markers ); -- cgit v1.2.3 From 925ebbebe7e41a89c80cf0ee93405378cb17d44a Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Thu, 22 Mar 2018 17:14:12 +0000 Subject: Fix issues with new report pin, improve cursor. The "coerce pin ID to integer" behaviour to fix a previous issue was coercing undefined to NaN, which then caused other problems with the new report pin, such as fading out when hovered, and being the wrong size. Also improve the cursor handling, showing the grab/ grabbing cursors where available. --- web/js/map-OpenLayers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index ec4f8bc3d..7d0f9076e 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -126,7 +126,7 @@ $.extend(fixmystreet.utils, { fixmystreet.map.getProjectionObject() ); } - var id = +pin[3]; + var id = pin[3] === undefined ? pin[3] : +pin[3]; var marker_size = (id === window.selected_problem_id) ? selected_size : size; var marker = new OpenLayers.Feature.Vector(loc, { colour: pin[2], -- cgit v1.2.3 From eb0dff66c47f91f345ecbda223d67c32569148af Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Mon, 30 Apr 2018 11:31:56 +0100 Subject: Drop unused copy of function. This is already defined in fixmystreet.utils further up. --- web/js/map-OpenLayers.js | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 7d0f9076e..1e763d91f 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -330,20 +330,6 @@ $.extend(fixmystreet.utils, { fixmystreet.markers.refresh({force: true}); } - function parse_query_string() { - var qs = {}; - if (!location.search) { - return qs; - } - location.search.substring(1).split(/[&;]/).forEach(function(i) { - var s = i.split('='), - k = s[0], - v = s[1] && decodeURIComponent(s[1].replace(/\+/g, ' ')); - qs[k] = v; - }); - return qs; - } - function replace_query_parameter(qs, id, key) { var value = $('#' + id).val(); if (value) { -- cgit v1.2.3 From 36c382ed12ba6da3164e256dd3e4ae97fa7235ea Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Mon, 30 Apr 2018 17:04:36 +0100 Subject: Some IE8/old JS workarounds. --- web/js/map-OpenLayers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 1e763d91f..a96e65953 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -8,7 +8,7 @@ $.extend(fixmystreet.utils, { if (!location.search) { return qs; } - location.search.substring(1).split(/[;&]/).forEach(function(i) { + $.each(location.search.substring(1).split(/[;&]/), function(n, i) { var s = i.split('='), k = s[0], v = s[1] && decodeURIComponent(s[1].replace(/\+/g, ' ')); -- cgit v1.2.3 From 89b38145e0783cd9fb4c020b6c174bc4521ac3b8 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Thu, 31 May 2018 10:18:35 +0100 Subject: Improve handling of loading spinner display. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Going back to /around from /report/new can trigger loadend (and the spinner hiding function) twice (if the strategy activation starts a read), with triggerRead aborting that read and triggering the event itself. This means the spinner is not displayed, as the count falls below 0. We could pin the count above 0, but instead let’s log each layer ID while ‘active’ and switch off when they’re all gone. --- web/js/map-OpenLayers.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index a96e65953..2e62336ed 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -1,3 +1,15 @@ +if (!Object.keys) { + Object.keys = function(obj) { + var result = []; + for (var prop in obj) { + if (Object.prototype.hasOwnProperty.call(obj, prop)) { + result.push(prop); + } + } + return result; + }; +} + var fixmystreet = fixmystreet || {}; fixmystreet.utils = fixmystreet.utils || {}; @@ -247,18 +259,18 @@ $.extend(fixmystreet.utils, { * the spinner in the DOM. */ loading_spinner: { - count: 0, + count: {}, show: function() { - fixmystreet.maps.loading_spinner.count++; - if (fixmystreet.maps.loading_spinner.count > 0) { + fixmystreet.maps.loading_spinner.count[this.id] = 1; + if (Object.keys(fixmystreet.maps.loading_spinner.count).length) { // Show the loading indicator over the map $('#loading-indicator').removeClass('hidden'); $('#loading-indicator').attr('aria-hidden', false); } }, hide: function() { - fixmystreet.maps.loading_spinner.count--; - if (fixmystreet.maps.loading_spinner.count <= 0) { + delete fixmystreet.maps.loading_spinner.count[this.id]; + if (!Object.keys(fixmystreet.maps.loading_spinner.count).length) { // Remove loading indicator $('#loading-indicator').addClass('hidden'); $('#loading-indicator').attr('aria-hidden', true); -- cgit v1.2.3 From de36c49d1ff2bf7858c8cc8762c4c7b9d05c9cb3 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Tue, 5 Jun 2018 12:23:59 +0100 Subject: Fix pointer event issue selecting pin on map. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a mobile device that implements pointer events, there are two events that can happen on an /around page – touching the map starts a new report (or goes back to the map if already on a report page); touching a pin pulls in that report’s page. The map touch, which uses an OpenLayers.Handler.Click, operates on click, whereas the pin touch, which uses an OpenLayers.Handler.Feature, operates on touchstart. Neither event cancels the other, which means you can end up either starting a new report, and then it tries to pull in an undefined pin ID report and errors, or the pin report loads and then you instantly go back to the map page. In order to work around this, we disable the map click control when the feature control event starts, and reactivate once the report data has been loaded. --- web/js/map-OpenLayers.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 2e62336ed..868e2333e 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -311,6 +311,9 @@ $.extend(fixmystreet.utils, { return; } + // clickFeature operates on touchstart, we do not want the map click taking place on touchend! + fixmystreet.maps.click_control.deactivate(); + // All of this, just so that ctrl/cmd-click on a pin works?! var event; if (typeof window.MouseEvent === 'function') { @@ -720,7 +723,7 @@ $.extend(fixmystreet.utils, { } if (document.getElementById('mapForm')) { - var click = new OpenLayers.Control.Click(); + var click = fixmystreet.maps.click_control = new OpenLayers.Control.Click(); fixmystreet.map.addControl(click); click.activate(); } -- cgit v1.2.3