]> git.openstreetmap.org Git - rails.git/commitdiff
Add parseGeoURI function and tests
authorMarwin Hochfelsner <50826859+hlfan@users.noreply.github.com>
Thu, 10 Apr 2025 10:30:57 +0000 (12:30 +0200)
committerMarwin Hochfelsner <50826859+hlfan@users.noreply.github.com>
Fri, 25 Apr 2025 17:41:14 +0000 (19:41 +0200)
app/assets/javascripts/osm.js.erb
test/javascripts/osm_test.js

index 31f92da84a846644e9e99fe2c653dc18bc983a9b..31997e303f9db393af2f37f04fcba14a6c73e1c6 100644 (file)
@@ -121,6 +121,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 10d562959f39bd5a0d9a7284a5b8a1a5764b5162..cac209c0f3c411be9fd3ac6e29d4dcd47d857d61 100644 (file)
@@ -130,6 +130,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");