]> git.openstreetmap.org Git - rails.git/commitdiff
Merge remote-tracking branch 'upstream/pull/5451'
authorTom Hughes <tom@compton.nu>
Wed, 1 Jan 2025 13:34:16 +0000 (13:34 +0000)
committerTom Hughes <tom@compton.nu>
Wed, 1 Jan 2025 13:34:16 +0000 (13:34 +0000)
Gemfile.lock
app/assets/javascripts/index/new_note.js
app/assets/javascripts/leaflet.note.js
app/views/notes/new.html.erb
test/system/create_note_test.rb

index ab8d9f9d1428f42b5ca152fa810a1f0ab4c2b307..02b1777906596658b49112eabfe646520d31ec29 100644 (file)
@@ -92,8 +92,8 @@ GEM
     autoprefixer-rails (10.4.19.0)
       execjs (~> 2)
     aws-eventstream (1.3.0)
-    aws-partitions (1.1026.0)
-    aws-sdk-core (3.214.0)
+    aws-partitions (1.1029.0)
+    aws-sdk-core (3.214.1)
       aws-eventstream (~> 1, >= 1.3.0)
       aws-partitions (~> 1, >= 1.992.0)
       aws-sigv4 (~> 1.9)
@@ -120,7 +120,7 @@ GEM
       erubi (~> 1.4)
       parser (>= 2.4)
       smart_properties
-    bigdecimal (3.1.8)
+    bigdecimal (3.1.9)
     binding_of_caller (1.0.1)
       debug_inspector (>= 1.2.0)
     bootsnap (1.18.4)
@@ -131,7 +131,7 @@ GEM
     bootstrap_form (5.4.0)
       actionpack (>= 6.1)
       activemodel (>= 6.1)
-    brakeman (6.2.2)
+    brakeman (7.0.0)
       racc
     brotli (0.6.0)
     browser (5.3.1)
@@ -273,7 +273,7 @@ GEM
       faraday (>= 0.8)
     faraday-net_http (3.4.0)
       net-http (>= 0.5.0)
-    ffi (1.17.0)
+    ffi (1.17.1)
     ffi-compiler (1.3.2)
       ffi (>= 1.15.5)
       rake
@@ -340,7 +340,7 @@ GEM
       railties (>= 4.2.0)
       thor (>= 0.14, < 2.0)
     json (2.9.1)
-    jwt (2.9.3)
+    jwt (2.10.1)
       base64
     kgio (2.11.4)
     kramdown (2.5.1)
@@ -383,7 +383,7 @@ GEM
     nap (1.1.0)
     net-http (0.6.0)
       uri
-    net-imap (0.5.2)
+    net-imap (0.5.4)
       date
       net-protocol
     net-pop (0.1.2)
@@ -393,7 +393,7 @@ GEM
     net-smtp (0.5.0)
       net-protocol
     nio4r (2.7.4)
-    nokogiri (1.17.2)
+    nokogiri (1.18.1)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     oauth (1.1.0)
@@ -481,7 +481,7 @@ GEM
       rack (~> 2.2, >= 2.2.4)
     rack-session (1.0.2)
       rack (< 3)
-    rack-test (2.1.0)
+    rack-test (2.2.0)
       rack (>= 1.3)
     rack-uri_sanitizer (0.0.2)
     rackup (1.0.1)
@@ -534,7 +534,7 @@ GEM
     rchardet (1.8.0)
     rdoc (6.10.0)
       psych (>= 4.0.0)
-    regexp_parser (2.9.3)
+    regexp_parser (2.10.0)
     reline (0.6.0)
       io-console (~> 0.5)
     request_store (1.7.0)
@@ -567,7 +567,7 @@ GEM
     rubocop-performance (1.23.0)
       rubocop (>= 1.48.1, < 2.0)
       rubocop-ast (>= 1.31.1, < 2.0)
-    rubocop-rails (2.27.0)
+    rubocop-rails (2.28.0)
       activesupport (>= 4.2.0)
       rack (>= 1.1)
       rubocop (>= 1.52.0, < 2.0)
@@ -580,9 +580,9 @@ GEM
       ffi (~> 1.12)
       logger
     rubyzip (2.3.2)
-    sanitize (6.1.3)
+    sanitize (7.0.0)
       crass (~> 1.0.2)
-      nokogiri (>= 1.12.0)
+      nokogiri (>= 1.16.8)
     sass-embedded (1.64.2)
       google-protobuf (~> 3.23)
       rake (>= 13.0.0)
@@ -630,7 +630,7 @@ GEM
     terser (1.2.4)
       execjs (>= 0.3.0, < 3)
     thor (1.3.2)
-    tilt (2.4.0)
+    tilt (2.5.0)
     timeout (0.4.3)
     turbo-rails (2.0.11)
       actionpack (>= 6.0.0)
index 887ba043b12b00bda5478b4e2dfd3aeec305efd3..885d7d2c994b22f5a35b27d1143b5df3254fa75e 100644 (file)
@@ -5,7 +5,7 @@ OSM.NewNote = function (map) {
       content = $("#sidebar_content"),
       page = {},
       addNoteButton = $(".control-note .control-button"),
-      newNote,
+      newNoteMarker,
       halo;
 
   var noteIcons = {
@@ -35,39 +35,21 @@ OSM.NewNote = function (map) {
     OSM.router.route("/note/new");
   });
 
-  function createNote(marker, form, url) {
-    var location = marker.getLatLng().wrap();
-
-    marker.options.draggable = false;
-    marker.dragging.disable();
-
-    $(form).find("input[type=submit]").prop("disabled", true);
-
+  function createNote(location, text, callback) {
     $.ajax({
-      url: url,
+      url: "/api/0.6/notes.json",
       type: "POST",
       oauth: true,
       data: {
         lat: location.lat,
         lon: location.lng,
-        text: $(form.text).val()
+        text
       },
-      success: function (feature) {
-        noteCreated(feature, marker);
-      }
+      success: callback
     });
-
-    function noteCreated(feature, marker) {
-      content.find("textarea").val("");
-      updateMarker(feature);
-      newNote = null;
-      noteLayer.removeLayer(marker);
-      addNoteButton.removeClass("active");
-      OSM.router.route("/note/" + feature.properties.id);
-    }
   }
 
-  function updateMarker(feature) {
+  function addCreatedNoteMarker(feature) {
     var marker = L.marker(feature.geometry.coordinates.reverse(), {
       icon: noteIcons[feature.properties.status],
       opacity: 0.9,
@@ -75,38 +57,78 @@ OSM.NewNote = function (map) {
     });
     marker.id = feature.properties.id;
     marker.addTo(noteLayer);
-    return marker;
   }
 
-  page.pushstate = page.popstate = function (path) {
-    OSM.loadSidebarContent(path, function () {
-      page.load(path);
+  function addHalo(latlng) {
+    if (halo) map.removeLayer(halo);
+
+    halo = L.circleMarker(latlng, {
+      weight: 2.5,
+      radius: 20,
+      fillOpacity: 0.5,
+      color: "#FF6200"
     });
-  };
 
-  function newHalo(loc, a) {
-    var hasHalo = halo && map.hasLayer(halo);
+    map.addLayer(halo);
+  }
 
-    if (a === "dragstart" && hasHalo) {
-      map.removeLayer(halo);
-    } else {
-      if (hasHalo) map.removeLayer(halo);
+  function removeHalo() {
+    if (halo) map.removeLayer(halo);
+    halo = null;
+  }
 
-      halo = L.circleMarker(loc, {
-        weight: 2.5,
-        radius: 20,
-        fillOpacity: 0.5,
-        color: "#FF6200"
-      });
+  function addNewNoteMarker(latlng) {
+    if (newNoteMarker) map.removeLayer(newNoteMarker);
 
-      map.addLayer(halo);
-    }
+    newNoteMarker = L.marker(latlng, {
+      icon: noteIcons.new,
+      opacity: 0.9,
+      draggable: true
+    });
+
+    newNoteMarker.on("dragstart dragend", function (a) {
+      removeHalo();
+      if (a.type === "dragend") {
+        addHalo(newNoteMarker.getLatLng());
+      }
+    });
+
+    newNoteMarker.addTo(map);
+    addHalo(newNoteMarker.getLatLng());
+
+    newNoteMarker.on("dragend", function () {
+      content.find("textarea").focus();
+    });
   }
 
-  page.load = function (path) {
-    if (addNoteButton.hasClass("disabled")) return;
-    if (addNoteButton.hasClass("active")) return;
+  function removeNewNoteMarker() {
+    removeHalo();
+    if (newNoteMarker) map.removeLayer(newNoteMarker);
+    newNoteMarker = null;
+  }
+
+  function moveNewNotMarkerToClick(e) {
+    if (newNoteMarker) newNoteMarker.setLatLng(e.latlng);
+    if (halo) halo.setLatLng(e.latlng);
+    content.find("textarea").focus();
+  }
+
+  function updateControls() {
+    const zoomedOut = addNoteButton.hasClass("disabled");
+    const withoutText = content.find("textarea").val() === "";
 
+    content.find("#new-note-zoom-warning").prop("hidden", !zoomedOut);
+    content.find("input[type=submit]").prop("disabled", zoomedOut || withoutText);
+    if (newNoteMarker) newNoteMarker.setOpacity(zoomedOut ? 0.5 : 0.9);
+  }
+
+  page.pushstate = page.popstate = function (path) {
+    OSM.loadSidebarContent(path, function () {
+      page.load(path);
+    });
+  };
+
+  page.load = function (path) {
     addNoteButton.addClass("active");
 
     map.addLayer(noteLayer);
@@ -124,44 +146,39 @@ OSM.NewNote = function (map) {
       padding: [50, 50]
     });
 
-    newNote = L.marker(markerLatlng, {
-      icon: noteIcons.new,
-      opacity: 0.9,
-      draggable: true
-    });
-
-    newNote.on("dragstart dragend", function (a) {
-      newHalo(newNote.getLatLng(), a.type);
-    });
-
-    newNote.addTo(noteLayer);
-    newHalo(newNote.getLatLng());
-
-    newNote.on("remove", function () {
-      addNoteButton.removeClass("active");
-    }).on("dragend", function () {
-      content.find("textarea").focus();
-    });
+    addNewNoteMarker(markerLatlng);
 
     content.find("textarea")
-      .on("input", disableWhenBlank)
+      .on("input", updateControls)
       .focus();
 
-    function disableWhenBlank(e) {
-      $(e.target.form.add).prop("disabled", $(e.target).val() === "");
-    }
-
     content.find("input[type=submit]").on("click", function (e) {
+      const location = newNoteMarker.getLatLng().wrap();
+      const text = content.find("textarea").val();
+
       e.preventDefault();
-      createNote(newNote, e.target.form, "/api/0.6/notes.json");
+      $(this).prop("disabled", true);
+      newNoteMarker.options.draggable = false;
+      newNoteMarker.dragging.disable();
+
+      createNote(location, text, (feature) => {
+        content.find("textarea").val("");
+        addCreatedNoteMarker(feature);
+        OSM.router.route("/note/" + feature.properties.id);
+      });
     });
 
+    map.on("click", moveNewNotMarkerToClick);
+    addNoteButton.on("disabled enabled", updateControls);
+    updateControls();
+
     return map.getState();
   };
 
   page.unload = function () {
-    if (newNote) noteLayer.removeLayer(newNote);
-    if (halo) map.removeLayer(halo);
+    map.off("click", moveNewNotMarkerToClick);
+    addNoteButton.off("disabled enabled", updateControls);
+    removeNewNoteMarker();
     addNoteButton.removeClass("active");
   };
 
index 5f801096731793a376ca0c3cdf0f729c2c2312a5..19fc9392c0af65497bf686f8e0c24020cdba3050 100644 (file)
@@ -14,12 +14,19 @@ L.OSM.note = function (options) {
     map.on("zoomend", update);
 
     function update() {
-      var disabled = OSM.STATUS === "database_offline" || map.getZoom() < 12;
+      var wasDisabled = link.hasClass("disabled"),
+          isDisabled = OSM.STATUS === "database_offline" || map.getZoom() < 12;
       link
-        .toggleClass("disabled", disabled)
-        .attr("data-bs-original-title", I18n.t(disabled ?
+        .toggleClass("disabled", isDisabled)
+        .attr("data-bs-original-title", I18n.t(isDisabled ?
           "javascripts.site.createnote_disabled_tooltip" :
           "javascripts.site.createnote_tooltip"));
+
+      if (isDisabled && !wasDisabled) {
+        link.trigger("disabled");
+      } else if (wasDisabled && !isDisabled) {
+        link.trigger("enabled");
+      }
     }
 
     update();
index c9b1275b9493f43c9bca1525341dd9b6910af7d2..f461f60e2313575c9f138f7ea272a6ac37b4b8f7 100644 (file)
@@ -9,6 +9,7 @@
                                          :log_in => link_to(t(".anonymous_warning_log_in"), login_path(:referer => new_note_path)),
                                          :sign_up => link_to(t(".anonymous_warning_sign_up"), user_new_path) %></p>
   <% end %>
+  <p class="alert alert-warning" id="new-note-zoom-warning" hidden><%= t "javascripts.site.createnote_disabled_tooltip" %></p>
   <form action="#">
     <input type="hidden" name="lon" autocomplete="off">
     <input type="hidden" name="lat" autocomplete="off">
index 435233cbe1f80ea15b824912f92d8bd00a69ef3b..5688ec37601dc28ad3d6d3913142317ac8291c3c 100644 (file)
@@ -15,6 +15,60 @@ class CreateNoteTest < ApplicationSystemTestCase
     end
   end
 
+  test "cannot create new note when zoomed out" do
+    visit new_note_path(:anchor => "map=12/0/0")
+
+    within_sidebar do
+      assert_no_content "Zoom in to add a note"
+      assert_button "Add Note", :disabled => true
+
+      fill_in "text", :with => "Some newly added note description"
+
+      assert_no_content "Zoom in to add a note"
+      assert_button "Add Note", :disabled => false
+    end
+
+    find(".control-button.zoomout").click
+
+    within_sidebar do
+      assert_content "Zoom in to add a note"
+      assert_button "Add Note", :disabled => true
+    end
+
+    find(".control-button.zoomin").click
+
+    within_sidebar do
+      assert_no_content "Zoom in to add a note"
+      assert_button "Add Note", :disabled => false
+
+      click_on "Add Note"
+
+      assert_content "Unresolved note ##{Note.last.id}"
+      assert_content "Some newly added note description"
+    end
+  end
+
+  test "can open new note page when zoomed out" do
+    visit new_note_path(:anchor => "map=11/0/0")
+
+    within_sidebar do
+      assert_content "Zoom in to add a note"
+      assert_button "Add Note", :disabled => true
+
+      fill_in "text", :with => "Some newly added note description"
+
+      assert_content "Zoom in to add a note"
+      assert_button "Add Note", :disabled => true
+    end
+
+    find(".control-button.zoomin").click
+
+    within_sidebar do
+      assert_no_content "Zoom in to add a note"
+      assert_button "Add Note", :disabled => false
+    end
+  end
+
   test "cannot create note when api is readonly" do
     with_settings(:status => "api_readonly") do
       visit new_note_path(:anchor => "map=18/0/0")