]> git.openstreetmap.org Git - rails.git/blobdiff - app/assets/javascripts/leaflet.map.js
Merge branch 'pull/5556'
[rails.git] / app / assets / javascripts / leaflet.map.js
index fe4b139d14f41e9ff017ee83f10a0395bb6b1274..99d5a60503328074457a0921e2000428e57907a3 100644 (file)
@@ -15,109 +15,37 @@ L.OSM.Map = L.Map.extend({
   initialize: function (id, options) {
     L.Map.prototype.initialize.call(this, id, options);
 
-    const layerCredits = {
-      mapnik: {
-        id: "make_a_donation",
-        href: "https://supporting.openstreetmap.org",
-        donate: true
-      },
-      cyclosm: {
-        id: "cyclosm_credit",
-        children: {
-          cyclosm_link: {
-            id: "cyclosm_name",
-            href: "https://www.cyclosm.org"
-          },
-          osm_france_link: {
-            id: "osm_france",
-            href: "https://openstreetmap.fr/"
-          }
-        }
-      },
-      thunderforest: {
-        id: "thunderforest_credit",
-        children: {
-          thunderforest_link: {
-            id: "andy_allan",
-            href: "https://www.thunderforest.com/"
-          }
-        }
-      },
-      tracestrack: {
-        id: "tracestrack_credit",
-        children: {
-          tracestrack_link: {
-            id: "tracestrack",
-            href: "https://www.tracestrack.com/"
-          }
-        }
-      },
-      hotosm: {
-        id: "hotosm_credit",
-        children: {
-          hotosm_link: {
-            id: "hotosm_name",
-            href: "https://www.hotosm.org/"
-          },
-          osm_france_link: {
-            id: "osm_france",
-            href: "https://openstreetmap.fr/"
-          }
-        }
-      }
-    };
-
     this.baseLayers = [];
 
-    this.baseLayers.push(new L.OSM.Mapnik({
-      attribution: makeAttribution("mapnik"),
-      code: "M",
-      keyid: "mapnik",
-      name: I18n.t("javascripts.map.base.standard")
-    }));
-
-    this.baseLayers.push(new L.OSM.CyclOSM({
-      attribution: makeAttribution("cyclosm"),
-      code: "Y",
-      keyid: "cyclosm",
-      name: I18n.t("javascripts.map.base.cyclosm")
-    }));
-
-    if (OSM.THUNDERFOREST_KEY) {
-      this.baseLayers.push(new L.OSM.CycleMap({
-        attribution: makeAttribution("thunderforest"),
-        apikey: OSM.THUNDERFOREST_KEY,
-        code: "C",
-        keyid: "cyclemap",
-        name: I18n.t("javascripts.map.base.cycle_map")
-      }));
-
-      this.baseLayers.push(new L.OSM.TransportMap({
-        attribution: makeAttribution("thunderforest"),
-        apikey: OSM.THUNDERFOREST_KEY,
-        code: "T",
-        keyid: "transportmap",
-        name: I18n.t("javascripts.map.base.transport_map")
-      }));
-    }
+    for (const layerDefinition of OSM.LAYER_DEFINITIONS) {
+      if (layerDefinition.apiKeyId && !OSM[layerDefinition.apiKeyId]) continue;
+
+      let layerConstructor = L.OSM.TileLayer;
+      const layerOptions = {};
+
+      for (const [property, value] of Object.entries(layerDefinition)) {
+        if (property === "credit") {
+          layerOptions.attribution = makeAttribution(value);
+        } else if (property === "nameId") {
+          layerOptions.name = I18n.t(`javascripts.map.base.${value}`);
+        } else if (property === "apiKeyId") {
+          layerOptions.apikey = OSM[value];
+        } else if (property === "leafletOsmId") {
+          layerConstructor = L.OSM[value];
+        } else if (property === "leafletOsmDarkId" && OSM.isDarkMap() && L.OSM[value]) {
+          layerConstructor = L.OSM[value];
+        } else {
+          layerOptions[property] = value;
+        }
+      }
 
-    if (OSM.TRACESTRACK_KEY) {
-      this.baseLayers.push(new L.OSM.TracestrackTopo({
-        attribution: makeAttribution("tracestrack"),
-        apikey: OSM.TRACESTRACK_KEY,
-        code: "P",
-        keyid: "tracestracktopo",
-        name: I18n.t("javascripts.map.base.tracestracktop_topo")
-      }));
+      const layer = new layerConstructor(layerOptions);
+      layer.on("add", () => {
+        this.fire("baselayerchange", { layer: layer });
+      });
+      this.baseLayers.push(layer);
     }
 
-    this.baseLayers.push(new L.OSM.HOT({
-      attribution: makeAttribution("hotosm"),
-      code: "H",
-      keyid: "hot",
-      name: I18n.t("javascripts.map.base.hot")
-    }));
-
     this.noteLayer = new L.FeatureGroup();
     this.noteLayer.options = { code: "N" };
 
@@ -128,15 +56,20 @@ L.OSM.Map = L.Map.extend({
       pane: "overlayPane",
       code: "G"
     });
+    this.gpsLayer.on("add", () => {
+      this.fire("overlayadd", { layer: this.gpsLayer });
+    }).on("remove", () => {
+      this.fire("overlayremove", { layer: this.gpsLayer });
+    });
+
 
-    this.on("layeradd", function (event) {
+    this.on("baselayerchange", function (event) {
       if (this.baseLayers.indexOf(event.layer) >= 0) {
         this.setMaxZoom(event.layer.options.maxZoom);
       }
     });
 
-    function makeAttribution(id) {
-      const layerCredit = layerCredits[id];
+    function makeAttribution(credit) {
       let attribution = "";
 
       attribution += I18n.t("javascripts.map.copyright_text", {
@@ -146,8 +79,8 @@ L.OSM.Map = L.Map.extend({
         }).prop("outerHTML")
       });
 
-      attribution += layerCredit.donate ? " ♥ " : ". ";
-      attribution += makeCredit(layerCredit);
+      attribution += credit.donate ? " ♥ " : ". ";
+      attribution += makeCredit(credit);
       attribution += ". ";
 
       attribution += $("<a>", {
@@ -185,14 +118,18 @@ L.OSM.Map = L.Map.extend({
     var layers = layerParam || "M",
         layersAdded = "";
 
-    for (var i = this.baseLayers.length - 1; i >= 0; i--) {
+    for (let i = this.baseLayers.length - 1; i >= 0; i--) {
+      if (layers.indexOf(this.baseLayers[i].options.code) === -1) {
+        this.removeLayer(this.baseLayers[i]);
+      }
+    }
+
+    for (let i = this.baseLayers.length - 1; i >= 0; i--) {
       if (layers.indexOf(this.baseLayers[i].options.code) >= 0) {
         this.addLayer(this.baseLayers[i]);
         layersAdded = layersAdded + this.baseLayers[i].options.code;
       } else if (i === 0 && layersAdded === "") {
         this.addLayer(this.baseLayers[i]);
-      } else {
-        this.removeLayer(this.baseLayers[i]);
       }
     }
   },
@@ -208,11 +145,14 @@ L.OSM.Map = L.Map.extend({
   },
 
   getMapBaseLayerId: function () {
-    var baseLayerId;
-    this.eachLayer(function (layer) {
-      if (layer.options && layer.options.keyid) baseLayerId = layer.options.keyid;
-    });
-    return baseLayerId;
+    const layer = this.getMapBaseLayer();
+    if (layer) return layer.options.layerId;
+  },
+
+  getMapBaseLayer: function () {
+    for (const layer of this.baseLayers) {
+      if (this.hasLayer(layer)) return layer;
+    }
   },
 
   getUrl: function (marker) {
@@ -342,7 +282,7 @@ L.OSM.Map = L.Map.extend({
 
     this.removeObject();
 
-    if (object.type === "note") {
+    if (object.type === "note" || object.type === "changeset") {
       this._objectLoader = {
         abort: function () {}
       };
@@ -350,18 +290,28 @@ L.OSM.Map = L.Map.extend({
       this._object = object;
       this._objectLayer = L.featureGroup().addTo(this);
 
-      L.circleMarker(object.latLng, haloStyle).addTo(this._objectLayer);
+      if (object.type === "note") {
+        L.circleMarker(object.latLng, haloStyle).addTo(this._objectLayer);
 
-      if (object.icon) {
-        L.marker(object.latLng, {
-          icon: object.icon,
-          opacity: 1,
-          interactive: true
-        }).addTo(this._objectLayer);
+        if (object.icon) {
+          L.marker(object.latLng, {
+            icon: object.icon,
+            opacity: 1,
+            interactive: true
+          }).addTo(this._objectLayer);
+        }
+      } else if (object.type === "changeset") {
+        if (object.bbox) {
+          L.rectangle([
+            [object.bbox.minlat, object.bbox.minlon],
+            [object.bbox.maxlat, object.bbox.maxlon]
+          ], changesetStyle).addTo(this._objectLayer);
+        }
       }
 
       if (callback) callback(this._objectLayer.getBounds());
-    } else { // element or changeset handled by L.OSM.DataLayer
+      this.fire("overlayadd", { layer: this._objectLayer });
+    } else { // element handled by L.OSM.DataLayer
       var map = this;
       this._objectLoader = $.ajax({
         url: OSM.apiUrl(object),
@@ -378,13 +328,11 @@ L.OSM.Map = L.Map.extend({
             }
           });
 
-          map._objectLayer.interestingNode = function (node, ways, relations) {
+          map._objectLayer.interestingNode = function (node, wayNodes, relationNodes) {
             if (object.type === "node") {
               return true;
             } else if (object.type === "relation") {
-              for (var i = 0; i < relations.length; i++) {
-                if (relations[i].members.indexOf(node) !== -1) return true;
-              }
+              return Boolean(relationNodes[node.id]);
             } else {
               return false;
             }
@@ -394,6 +342,7 @@ L.OSM.Map = L.Map.extend({
           map._objectLayer.addTo(map);
 
           if (callback) callback(map._objectLayer.getBounds());
+          map.fire("overlayadd", { layer: map._objectLayer });
         }
       });
     }
@@ -403,6 +352,7 @@ L.OSM.Map = L.Map.extend({
     this._object = null;
     if (this._objectLoader) this._objectLoader.abort();
     if (this._objectLayer) this.removeLayer(this._objectLayer);
+    this.fire("overlayremove", { layer: this._objectLayer });
   },
 
   getState: function () {
@@ -454,6 +404,14 @@ L.extend(L.Icon.Default.prototype, {
   }
 });
 
+OSM.isDarkMap = function () {
+  var mapTheme = $("body").attr("data-map-theme");
+  if (mapTheme) return mapTheme === "dark";
+  var siteTheme = $("html").attr("data-bs-theme");
+  if (siteTheme) return siteTheme === "dark";
+  return window.matchMedia("(prefers-color-scheme: dark)").matches;
+};
+
 OSM.getUserIcon = function (url) {
   return L.icon({
     iconUrl: url || OSM.MARKER_RED,