]> git.openstreetmap.org Git - rails.git/blobdiff - app/assets/javascripts/leaflet.map.js
Collect map layer credits into a data structure
[rails.git] / app / assets / javascripts / leaflet.map.js
index ffb2d7a2140f52199e28e4521cea68b5f6ed65c1..fe4b139d14f41e9ff017ee83f10a0395bb6b1274 100644 (file)
@@ -15,25 +15,69 @@ L.OSM.Map = L.Map.extend({
   initialize: function (id, options) {
     L.Map.prototype.initialize.call(this, id, options);
 
-    var copyright = I18n.t("javascripts.map.copyright", { copyright_url: "/copyright" });
-    var donate = I18n.t("javascripts.map.donate_link_text", { donate_url: "https://donate.openstreetmap.org" });
-    var terms = I18n.t("javascripts.map.terms", { terms_url: "https://wiki.osmfoundation.org/wiki/Terms_of_Use" });
-    var cyclosm = I18n.t("javascripts.map.cyclosm", { cyclosm_url: "https://www.cyclosm.org", osmfrance_url: "https://openstreetmap.fr/" });
-    var thunderforest = I18n.t("javascripts.map.thunderforest", { thunderforest_url: "https://www.thunderforest.com/" });
-    var memomaps = I18n.t("javascripts.map.opnvkarte", { memomaps_url: "https://memomaps.de/" });
-    var hotosm = I18n.t("javascripts.map.hotosm", { hotosm_url: "https://www.hotosm.org/", osmfrance_url: "https://openstreetmap.fr/" });
+    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: copyright + " ♥ " + donate + ". " + terms,
+      attribution: makeAttribution("mapnik"),
       code: "M",
       keyid: "mapnik",
       name: I18n.t("javascripts.map.base.standard")
     }));
 
     this.baseLayers.push(new L.OSM.CyclOSM({
-      attribution: copyright + ". " + cyclosm + ". " + terms,
+      attribution: makeAttribution("cyclosm"),
       code: "Y",
       keyid: "cyclosm",
       name: I18n.t("javascripts.map.base.cyclosm")
@@ -41,7 +85,7 @@ L.OSM.Map = L.Map.extend({
 
     if (OSM.THUNDERFOREST_KEY) {
       this.baseLayers.push(new L.OSM.CycleMap({
-        attribution: copyright + ". " + thunderforest + ". " + terms,
+        attribution: makeAttribution("thunderforest"),
         apikey: OSM.THUNDERFOREST_KEY,
         code: "C",
         keyid: "cyclemap",
@@ -49,7 +93,7 @@ L.OSM.Map = L.Map.extend({
       }));
 
       this.baseLayers.push(new L.OSM.TransportMap({
-        attribution: copyright + ". " + thunderforest + ". " + terms,
+        attribution: makeAttribution("thunderforest"),
         apikey: OSM.THUNDERFOREST_KEY,
         code: "T",
         keyid: "transportmap",
@@ -57,15 +101,18 @@ L.OSM.Map = L.Map.extend({
       }));
     }
 
-    this.baseLayers.push(new L.OSM.OPNVKarte({
-      attribution: copyright + ". " + memomaps + ". " + terms,
-      code: "O",
-      keyid: "opnvkarte",
-      name: I18n.t("javascripts.map.base.opnvkarte")
-    }));
+    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")
+      }));
+    }
 
     this.baseLayers.push(new L.OSM.HOT({
-      attribution: copyright + ". " + hotosm + ". " + terms,
+      attribution: makeAttribution("hotosm"),
       code: "H",
       keyid: "hot",
       name: I18n.t("javascripts.map.base.hot")
@@ -79,8 +126,7 @@ L.OSM.Map = L.Map.extend({
 
     this.gpsLayer = new L.OSM.GPS({
       pane: "overlayPane",
-      code: "G",
-      name: I18n.t("javascripts.map.base.gps")
+      code: "G"
     });
 
     this.on("layeradd", function (event) {
@@ -88,6 +134,51 @@ L.OSM.Map = L.Map.extend({
         this.setMaxZoom(event.layer.options.maxZoom);
       }
     });
+
+    function makeAttribution(id) {
+      const layerCredit = layerCredits[id];
+      let attribution = "";
+
+      attribution += I18n.t("javascripts.map.copyright_text", {
+        copyright_link: $("<a>", {
+          href: "/copyright",
+          text: I18n.t("javascripts.map.openstreetmap_contributors")
+        }).prop("outerHTML")
+      });
+
+      attribution += layerCredit.donate ? " &hearts; " : ". ";
+      attribution += makeCredit(layerCredit);
+      attribution += ". ";
+
+      attribution += $("<a>", {
+        href: "https://wiki.osmfoundation.org/wiki/Terms_of_Use",
+        text: I18n.t("javascripts.map.website_and_api_terms")
+      }).prop("outerHTML");
+
+      return attribution;
+    }
+
+    function makeCredit(credit) {
+      const children = {};
+      for (const childId in credit.children) {
+        children[childId] = makeCredit(credit.children[childId]);
+      }
+      const text = I18n.t(`javascripts.map.${credit.id}`, children);
+      if (credit.href) {
+        const link = $("<a>", {
+          href: credit.href,
+          text: text
+        });
+        if (credit.donate) {
+          link.addClass("donate-attr");
+        } else {
+          link.attr("target", "_blank");
+        }
+        return link.prop("outerHTML");
+      } else {
+        return text;
+      }
+    }
   },
 
   updateLayers: function (layerParam) {
@@ -242,42 +333,70 @@ L.OSM.Map = L.Map.extend({
       interactive: false
     };
 
+    var haloStyle = {
+      weight: 2.5,
+      radius: 20,
+      fillOpacity: 0.5,
+      color: "#FF6200"
+    };
+
     this.removeObject();
 
-    var map = this;
-    this._objectLoader = $.ajax({
-      url: OSM.apiUrl(object),
-      dataType: "xml",
-      success: function (xml) {
-        map._object = object;
-
-        map._objectLayer = new L.OSM.DataLayer(null, {
-          styles: {
-            node: objectStyle,
-            way: objectStyle,
-            area: objectStyle,
-            changeset: changesetStyle
-          }
-        });
+    if (object.type === "note") {
+      this._objectLoader = {
+        abort: function () {}
+      };
 
-        map._objectLayer.interestingNode = function (node, ways, relations) {
-          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;
-            }
-          } else {
-            return false;
-          }
-        };
+      this._object = object;
+      this._objectLayer = L.featureGroup().addTo(this);
 
-        map._objectLayer.addData(xml);
-        map._objectLayer.addTo(map);
+      L.circleMarker(object.latLng, haloStyle).addTo(this._objectLayer);
 
-        if (callback) callback(map._objectLayer.getBounds());
+      if (object.icon) {
+        L.marker(object.latLng, {
+          icon: object.icon,
+          opacity: 1,
+          interactive: true
+        }).addTo(this._objectLayer);
       }
-    });
+
+      if (callback) callback(this._objectLayer.getBounds());
+    } else { // element or changeset handled by L.OSM.DataLayer
+      var map = this;
+      this._objectLoader = $.ajax({
+        url: OSM.apiUrl(object),
+        dataType: "xml",
+        success: function (xml) {
+          map._object = object;
+
+          map._objectLayer = new L.OSM.DataLayer(null, {
+            styles: {
+              node: objectStyle,
+              way: objectStyle,
+              area: objectStyle,
+              changeset: changesetStyle
+            }
+          });
+
+          map._objectLayer.interestingNode = function (node, ways, relations) {
+            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;
+              }
+            } else {
+              return false;
+            }
+          };
+
+          map._objectLayer.addData(xml);
+          map._objectLayer.addTo(map);
+
+          if (callback) callback(map._objectLayer.getBounds());
+        }
+      });
+    }
   },
 
   removeObject: function () {
@@ -300,12 +419,17 @@ L.OSM.Map = L.Map.extend({
   },
 
   setSidebarOverlaid: function (overlaid) {
+    var sidebarWidth = 350;
     if (overlaid && !$("#content").hasClass("overlay-sidebar")) {
       $("#content").addClass("overlay-sidebar");
-      this.invalidateSize({ pan: false })
-        .panBy([-350, 0], { animate: false });
+      this.invalidateSize({ pan: false });
+      if ($("html").attr("dir") !== "rtl") {
+        this.panBy([-sidebarWidth, 0], { animate: false });
+      }
     } else if (!overlaid && $("#content").hasClass("overlay-sidebar")) {
-      this.panBy([350, 0], { animate: false });
+      if ($("html").attr("dir") !== "rtl") {
+        this.panBy([sidebarWidth, 0], { animate: false });
+      }
       $("#content").removeClass("overlay-sidebar");
       this.invalidateSize({ pan: false });
     }