]> git.openstreetmap.org Git - rails.git/commitdiff
Merge remote-tracking branch 'upstream/pull/5952'
authorTom Hughes <tom@compton.nu>
Sun, 27 Apr 2025 09:52:40 +0000 (10:52 +0100)
committerTom Hughes <tom@compton.nu>
Sun, 27 Apr 2025 09:52:40 +0000 (10:52 +0100)
app/assets/favicons/manifest.json.erb
app/assets/javascripts/index.js
app/assets/javascripts/osm.js.erb
config/application.rb
config/initializers/new_framework_defaults_8_0.rb [deleted file]
test/javascripts/osm_test.js

index 2e97cebc3247e3f4ac25aa90401d67dec766422c..6950a24a1f3c5d68c5bc1227ee63299613b752bf 100644 (file)
@@ -7,12 +7,18 @@
                        type: "image/png",
                        density: res.to_f / 48
                } }.push({
-                       src: image_path("../images/osm_logo.svg"),
+                       src: image_path("osm_logo.svg"),
                        sizes: "any",
                        type: "image/svg+xml"
                }).to_json %>,
        "start_url": "/",
        "theme_color": "#7ebc6f",
        "background_color": "#fff",
-       "display": "minimal-ui"
+       "display": "minimal-ui",
+       "protocol_handlers": [
+               {
+                       "protocol": "geo",
+                       "url": "/?geouri=%s"
+               }
+       ]
 }
index 7ff8a40d1474905b9d706968e75c35b90b22149f..9bce95798c73c96e3860120f0356877369f42946 100644 (file)
@@ -211,7 +211,9 @@ $(function () {
     map.setView([params.lat, params.lon], params.zoom);
   }
 
-  if (params.marker) {
+  if (params.marker && params.mrad) {
+    L.circle([params.mlat, params.mlon], { radius: params.mrad }).addTo(map);
+  } else if (params.marker) {
     L.marker([params.mlat, params.mlon]).addTo(map);
   }
 
index 31f92da84a846644e9e99fe2c653dc18bc983a9b..c7887b63dcbb35bd89855c32d6d1de8368f37587 100644 (file)
@@ -56,12 +56,20 @@ OSM = {
 
   mapParams: function (search) {
     const params = new URLSearchParams(search || location.search),
+          geoURI = OSM.parseGeoURI(params.get("geouri")),
           mapParams = {};
 
     if (params.has("mlon") && params.has("mlat")) {
       mapParams.marker = true;
       mapParams.mlon = parseFloat(params.get("mlon"));
       mapParams.mlat = parseFloat(params.get("mlat"));
+      mapParams.mrad = parseFloat(params.get("mrad"));
+    }
+    if (geoURI) {
+      mapParams.marker = true;
+      mapParams.mlon = geoURI.coords.lng;
+      mapParams.mlat = geoURI.coords.lat;
+      mapParams.mrad = geoURI.uncertainty;
     }
 
     // Old-style object parameters; still in use for edit links e.g. /edit?way=1234
@@ -93,6 +101,12 @@ OSM = {
       mapParams.lon = params.get("mlon");
       mapParams.lat = params.get("mlat");
       mapParams.zoom = params.get("zoom") || 12;
+    } else if (geoURI?.uncertainty > 0 && !("zoom" in geoURI)) {
+      mapParams.bounds = geoURI.coords.toBounds(geoURI.uncertainty * 4);
+    } else if (geoURI) {
+      mapParams.lon = geoURI.coords.lng;
+      mapParams.lat = geoURI.coords.lat;
+      mapParams.zoom = geoURI.zoom || 12;
     } else if (loc) {
       [mapParams.lon, mapParams.lat, mapParams.zoom] = loc;
     } else if (OSM.home) {
@@ -121,6 +135,29 @@ OSM = {
     return mapParams;
   },
 
+  parseGeoURI: function (geoURI) {
+    let url;
+    try {
+      url = new URL(geoURI);
+    } catch (e) { return; }
+    if (!url?.pathname || url.protocol !== "geo:") return;
+    const [path, ...params] = url.pathname.split(";");
+    let coords;
+    try {
+      coords = L.latLng(path.split(","));
+    } catch (e) { return; }
+    if (!coords) return;
+    const searchParams = new URLSearchParams(params.join("&").toLowerCase());
+    const crs = searchParams.get("crs");
+    if (crs && crs !== "wgs84") return;
+    const uncertainty = parseFloat(searchParams.get("u"));
+    const zoom = parseFloat(url.searchParams.get("z"));
+    const out = { coords };
+    if (uncertainty >= 0) out.uncertainty = uncertainty;
+    if (zoom >= 0) out.zoom = zoom;
+    return out;
+  },
+
   parseHash: function (hash = location.hash) {
     const args = {};
 
index 05d7fb41d664ff4226ac4ee1c28b486e83917630..463561eef72b42426587ba0b5caecdc06b9bbab9 100644 (file)
@@ -9,7 +9,7 @@ Bundler.require(*Rails.groups)
 module OpenStreetMap
   class Application < Rails::Application
     # Initialize configuration defaults for originally generated Rails version.
-    config.load_defaults 7.2
+    config.load_defaults 8.0
 
     # Please, add to the `ignore` list any other `lib` subdirectories that do
     # not contain `.rb` files, or that should not be reloaded or eager loaded.
diff --git a/config/initializers/new_framework_defaults_8_0.rb b/config/initializers/new_framework_defaults_8_0.rb
deleted file mode 100644 (file)
index 92efa95..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# Be sure to restart your server when you modify this file.
-#
-# This file eases your Rails 8.0 framework defaults upgrade.
-#
-# Uncomment each configuration one by one to switch to the new default.
-# Once your application is ready to run with all new defaults, you can remove
-# this file and set the `config.load_defaults` to `8.0`.
-#
-# Read the Guide for Upgrading Ruby on Rails for more info on each option.
-# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
-
-###
-# Specifies whether `to_time` methods preserve the UTC offset of their receivers or preserves the timezone.
-# If set to `:zone`, `to_time` methods will use the timezone of their receivers.
-# If set to `:offset`, `to_time` methods will use the UTC offset.
-# If `false`, `to_time` methods will convert to the local system UTC offset instead.
-#++
-# Rails.application.config.active_support.to_time_preserves_timezone = :zone
-
-###
-# When both `If-Modified-Since` and `If-None-Match` are provided by the client
-# only consider `If-None-Match` as specified by RFC 7232 Section 6.
-# If set to `false` both conditions need to be satisfied.
-#++
-# Rails.application.config.action_dispatch.strict_freshness = true
-
-###
-# Set `Regexp.timeout` to `1`s by default to improve security over Regexp Denial-of-Service attacks.
-#++
-# Regexp.timeout = 1
index 10d562959f39bd5a0d9a7284a5b8a1a5764b5162..8f4471140d21e59e8002f6fc596af464d9d03389 100644 (file)
@@ -73,6 +73,33 @@ describe("OSM", function () {
       expect(params).to.have.property("zoom", 16);
     });
 
+    it("parses geoURIs", function () {
+      const params = OSM.mapParams("?geouri=geo%3A57.6247%2C-3.6845");
+      expect(params).to.have.property("lat", 57.6247);
+      expect(params).to.have.property("lon", -3.6845);
+      expect(params).to.have.property("mlat", 57.6247);
+      expect(params).to.have.property("mlon", -3.6845);
+      expect(params).to.have.property("zoom", 12);
+    });
+
+    it("parses zoom in geoURIs", function () {
+      const params = OSM.mapParams("?geouri=geo%3A57.6247%2C-3.6845%3Fz%3D16");
+      expect(params).to.have.property("lat", 57.6247);
+      expect(params).to.have.property("lon", -3.6845);
+      expect(params).to.have.property("mlat", 57.6247);
+      expect(params).to.have.property("mlon", -3.6845);
+      expect(params).to.have.property("zoom", 16);
+    });
+
+    it("parses uncertainty in geoURIs", function () {
+      const params = OSM.mapParams("?geouri=geo%3A57.6247%2C-3.6845%3Bu%3D100");
+      const expected = L.latLngBounds([57.62290336944585, -3.6878552857327764], [57.62649663055414, -3.6811447142672233]);
+      expect(params).to.have.property("mlat", 57.6247);
+      expect(params).to.have.property("mlon", -3.6845);
+      expect(params).to.have.property("mrad", 100);
+      expect(params).to.have.property("bounds").deep.equal(expected);
+    });
+
     it("parses lat/lon/zoom from the hash", function () {
       location.hash = "#map=16/57.6247/-3.6845";
       const params = OSM.mapParams("?");
@@ -130,6 +157,99 @@ describe("OSM", function () {
     });
   });
 
+  describe(".parseGeoURI", function () {
+    it("parses basic geoURIs", function () {
+      let params = OSM.parseGeoURI("geo:57.6247,-3.6845");
+      expect(params.coords).to.deep.equal(L.latLng(57.6247, -3.6845));
+      expect(params.zoom).to.be.undefined;
+      expect(params.uncertainty).to.be.undefined;
+      params = OSM.parseGeoURI("GEO:57.6247,-3.6845");
+      expect(params.coords).to.deep.equal(L.latLng(57.6247, -3.6845));
+    });
+    it("parses only geoURIs", function () {
+      let params = OSM.parseGeoURI("latlng:57.6247,-3.6845");
+      expect(params).to.be.undefined;
+      params = OSM.parseGeoURI("geo57.6247,-3.6845");
+      expect(params).to.be.undefined;
+    });
+    it("rejects geoURIs with less than 2 coordinates", function () {
+      const params = OSM.parseGeoURI("geo:57.6247");
+      expect(params).to.be.undefined;
+    });
+    it("parses geoURIs with altitude", function () {
+      const params = OSM.parseGeoURI("geo:57.6247,-3.6845,100");
+      expect(params.coords).to.deep.equal(L.latLng(57.6247, -3.6845, 100));
+    });
+    it("rejects geoURIs with more than 3 coordinates", function () {
+      const params = OSM.parseGeoURI("geo:123,57.6247,-3.6845,100");
+      expect(params).to.be.undefined;
+    });
+    it("ignores non-numeric coordinates", function () {
+      let params = OSM.parseGeoURI("geo:57.6247,-3.6845,abc");
+      expect(params.coords.lat).to.equal(57.6247);
+      expect(params.coords.lng).to.equal(-3.6845);
+      expect(isNaN(params.coords.alt)).to.be.true;
+      params = OSM.parseGeoURI("geo:57.6247,abc");
+      expect(params).to.be.undefined;
+    });
+    it("parses geoURIs with crs", function () {
+      let params = OSM.parseGeoURI("geo:57.6247,-3.6845;crs=wgs84");
+      expect(params.coords).to.deep.equal(L.latLng(57.6247, -3.6845));
+      params = OSM.parseGeoURI("geo:57.6247,-3.6845;CRS=wgs84");
+      expect(params.coords).to.deep.equal(L.latLng(57.6247, -3.6845));
+      params = OSM.parseGeoURI("geo:57.6247,-3.6845;CRS=WGS84");
+      expect(params.coords).to.deep.equal(L.latLng(57.6247, -3.6845));
+    });
+    it("rejects geoURIs with different crs", function () {
+      const params = OSM.parseGeoURI("geo:57.6247,-3.6845;crs=utm");
+      expect(params).to.be.undefined;
+    });
+    it("parses geoURIs with uncertainty", function () {
+      let params = OSM.parseGeoURI("geo:57.6247,-3.6845;u=100");
+      expect(params.uncertainty).to.equal(100);
+      params = OSM.parseGeoURI("geo:57.6247,-3.6845;U=100");
+      expect(params.uncertainty).to.equal(100);
+    });
+    it("ignores negative uncertainty", function () {
+      const params = OSM.parseGeoURI("geo:57.6247,-3.6845;u=-100");
+      expect(params.uncertainty).to.be.undefined;
+    });
+    it("ignores non-numeric uncertainty", function () {
+      const params = OSM.parseGeoURI("geo:57.6247,-3.6845;u=abc");
+      expect(params.uncertainty).to.be.undefined;
+    });
+    it("parses uncertainty 0", function () {
+      const params = OSM.parseGeoURI("geo:57.6247,-3.6845;u=0");
+      expect(params.uncertainty).to.equal(0);
+    });
+    it("ignores uncertainty in the query parameters", function () {
+      const params = OSM.parseGeoURI("geo:57.6247,-3.6845?u=100");
+      expect(params.uncertainty).to.be.undefined;
+    });
+    it("parses geoURIs with zoom", function () {
+      let params = OSM.parseGeoURI("geo:57.6247,-3.6845?z=16");
+      expect(params.zoom).to.equal(16);
+      params = OSM.parseGeoURI("geo:57.6247,-3.6845?Z=16");
+      expect(params.zoom).to.be.undefined;
+    });
+    it("ignores non-numeric zoom", function () {
+      const params = OSM.parseGeoURI("geo:57.6247,-3.6845?z=abc");
+      expect(params.zoom).to.be.undefined;
+    });
+    it("ignores negative zoom", function () {
+      const params = OSM.parseGeoURI("geo:57.6247,-3.6845?z=-100");
+      expect(params.zoom).to.be.undefined;
+    });
+    it("parses geoURIs with zoom level 0", function () {
+      const params = OSM.parseGeoURI("geo:57.6247,-3.6845?z=0");
+      expect(params.zoom).to.equal(0);
+    });
+    it("ignores zoom in the geouri parameters", function () {
+      const params = OSM.parseGeoURI("geo:57.6247,-3.6845;z=16");
+      expect(params.zoom).to.be.undefined;
+    });
+  });
+
   describe(".parseHash", function () {
     it("parses lat/lon/zoom params", function () {
       const args = OSM.parseHash("#map=5/57.6247/-3.6845&layers=M");