]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index_modules/new_note.js
Split maplibre/dom_util.js into two better named files
[rails.git] / app / assets / javascripts / index_modules / new_note.js
1 export default function (map) {
2   const noteLayer = map.noteLayer,
3         content = $("#sidebar_content"),
4         page = {},
5         control = $(".control-note"),
6         addNoteButton = control.find(".control-button");
7   let newNoteMarker,
8       halo,
9       errorPanel,
10       errorPanelDetail;
11
12   function createNote(location, text) {
13     return fetch("/api/0.6/notes.json", {
14       method: "POST",
15       headers: { ...OSM.oauth },
16       body: new URLSearchParams({
17         lat: location.lat,
18         lon: location.lng,
19         text
20       })
21     })
22       .then(resp => {
23         if (resp.ok) return resp.json();
24         throw new Error(`Got response with status ${resp.status} ${resp.statusText}`);
25       });
26   }
27
28   function addCreatedNoteMarker(feature) {
29     const marker = L.marker(feature.geometry.coordinates.reverse(), {
30       icon: OSM.noteMarkers[feature.properties.status],
31       opacity: 0.9,
32       interactive: true
33     });
34     marker.id = feature.properties.id;
35     marker.addTo(noteLayer);
36   }
37
38   function addHalo(latlng) {
39     if (halo) map.removeLayer(halo);
40
41     halo = L.circleMarker(latlng, {
42       weight: 2.5,
43       radius: 20,
44       fillOpacity: 0.5,
45       color: "#FF6200"
46     });
47
48     map.addLayer(halo);
49   }
50
51   function removeHalo() {
52     if (halo) map.removeLayer(halo);
53     halo = null;
54   }
55
56   function addNewNoteMarker(latlng) {
57     if (newNoteMarker) map.removeLayer(newNoteMarker);
58
59     newNoteMarker = L.marker(latlng, {
60       icon: OSM.noteMarkers.new,
61       opacity: 0.9,
62       draggable: true
63     });
64
65     newNoteMarker.on("dragstart", removeHalo);
66     newNoteMarker.on("dragend", function () {
67       removeHalo();
68       addHalo(newNoteMarker.getLatLng());
69     });
70
71     newNoteMarker.addTo(map);
72     addHalo(newNoteMarker.getLatLng());
73
74     newNoteMarker.on("dragend", function () {
75       content.find("textarea").trigger("focus");
76     });
77   }
78
79   function removeNewNoteMarker() {
80     removeHalo();
81     if (newNoteMarker) map.removeLayer(newNoteMarker);
82     newNoteMarker = null;
83   }
84
85   function moveNewNoteMarkerToClick(e) {
86     if (newNoteMarker) newNoteMarker.setLatLng(e.latlng);
87     if (halo) halo.setLatLng(e.latlng);
88     content.find("textarea").trigger("focus");
89   }
90
91   function updateControls() {
92     const zoomedOut = addNoteButton.hasClass("disabled");
93     const withoutText = content.find("textarea").val() === "";
94
95     content.find("#new-note-zoom-warning").prop("hidden", !zoomedOut);
96     content.find("input[type=submit]").prop("disabled", zoomedOut || withoutText);
97     if (newNoteMarker) newNoteMarker.setOpacity(zoomedOut ? 0.5 : 0.9);
98   }
99
100   page.pushstate = page.popstate = function (path) {
101     OSM.loadSidebarContent(path, function () {
102       page.load(path);
103     });
104   };
105
106   page.load = function (path) {
107     control.addClass("active");
108
109     map.addLayer(noteLayer);
110
111     const params = new URLSearchParams(path.substring(path.indexOf("?")));
112     let markerLatlng;
113
114     if (params.has("lat") && params.has("lon")) {
115       markerLatlng = { lat: params.get("lat"), lng: params.get("lon") };
116     } else {
117       markerLatlng = map.getCenter();
118     }
119
120     map.panInside(markerLatlng, {
121       padding: [50, 50]
122     });
123
124     addNewNoteMarker(markerLatlng);
125
126     content.find("textarea")
127       .on("input", updateControls)
128       .attr("readonly", "readonly") // avoid virtual keyboard popping up on focus
129       .trigger("focus")
130       .removeAttr("readonly");
131
132     content.find("input[type=submit]").on("click", function (e) {
133       const location = newNoteMarker.getLatLng().wrap();
134       const text = content.find("textarea").val();
135
136       errorPanel = content.find(".new-note-error");
137       errorPanel.addClass("d-none");
138       errorPanelDetail = errorPanel.find(".new-note-error-detail");
139
140       e.preventDefault();
141       $(this).prop("disabled", true);
142       newNoteMarker.options.draggable = false;
143       newNoteMarker.dragging.disable();
144
145       createNote(location, text)
146         .then(feature => {
147           if (typeof OSM.user === "undefined") {
148             const anonymousNotesCount = Number(OSM.cookies.get("_osm_anonymous_notes_count")) || 0;
149             OSM.cookies.set("_osm_anonymous_notes_count", anonymousNotesCount + 1, { expires: 14 });
150           }
151           content.find("textarea").val("");
152           addCreatedNoteMarker(feature);
153           OSM.router.route("/note/" + feature.properties.id);
154         })
155         .catch(err => {
156           errorPanel.removeClass("d-none");
157           errorPanelDetail.text(err.message || err);
158           updateControls();
159         });
160     });
161
162     map.on("click", moveNewNoteMarkerToClick);
163     addNoteButton.on("disabled enabled", updateControls);
164     updateControls();
165
166     return map.getState();
167   };
168
169   page.unload = function () {
170     map.off("click", moveNewNoteMarkerToClick);
171     addNoteButton.off("disabled enabled", updateControls);
172     removeNewNoteMarker();
173     control.removeClass("active");
174   };
175
176   return page;
177 }