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
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) {
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 = {};
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("?");
});
});
+ 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");