]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index_modules/new_note.js
Merge remote-tracking branch 'upstream/pull/7190'
[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 dragend", function (a) {
66       removeHalo();
67       if (a.type === "dragend") {
68         addHalo(newNoteMarker.getLatLng());
69       }
70     });
71
72     newNoteMarker.addTo(map);
73     addHalo(newNoteMarker.getLatLng());
74
75     newNoteMarker.on("dragend", function () {
76       content.find("textarea").trigger("focus");
77     });
78   }
79
80   function removeNewNoteMarker() {
81     removeHalo();
82     if (newNoteMarker) map.removeLayer(newNoteMarker);
83     newNoteMarker = null;
84   }
85
86   function moveNewNoteMarkerToClick(e) {
87     if (newNoteMarker) newNoteMarker.setLatLng(e.latlng);
88     if (halo) halo.setLatLng(e.latlng);
89     content.find("textarea").trigger("focus");
90   }
91
92   function updateControls() {
93     const zoomedOut = addNoteButton.hasClass("disabled");
94     const withoutText = content.find("textarea").val() === "";
95
96     content.find("#new-note-zoom-warning").prop("hidden", !zoomedOut);
97     content.find("input[type=submit]").prop("disabled", zoomedOut || withoutText);
98     if (newNoteMarker) newNoteMarker.setOpacity(zoomedOut ? 0.5 : 0.9);
99   }
100
101   page.pushstate = page.popstate = function (path) {
102     OSM.loadSidebarContent(path, function () {
103       page.load(path);
104     });
105   };
106
107   page.load = function (path) {
108     control.addClass("active");
109
110     map.addLayer(noteLayer);
111
112     const params = new URLSearchParams(path.substring(path.indexOf("?")));
113     let markerLatlng;
114
115     if (params.has("lat") && params.has("lon")) {
116       markerLatlng = { lat: params.get("lat"), lng: params.get("lon") };
117     } else {
118       markerLatlng = map.getCenter();
119     }
120
121     map.panInside(markerLatlng, {
122       padding: [50, 50]
123     });
124
125     addNewNoteMarker(markerLatlng);
126
127     content.find("textarea")
128       .on("input", updateControls)
129       .attr("readonly", "readonly") // avoid virtual keyboard popping up on focus
130       .trigger("focus")
131       .removeAttr("readonly");
132
133     content.find("input[type=submit]").on("click", function (e) {
134       const location = newNoteMarker.getLatLng().wrap();
135       const text = content.find("textarea").val();
136
137       errorPanel = content.find(".new-note-error");
138       errorPanel.addClass("d-none");
139       errorPanelDetail = errorPanel.find(".new-note-error-detail");
140
141       e.preventDefault();
142       $(this).prop("disabled", true);
143       newNoteMarker.options.draggable = false;
144       newNoteMarker.dragging.disable();
145
146       createNote(location, text)
147         .then(feature => {
148           if (typeof OSM.user === "undefined") {
149             const anonymousNotesCount = Number(OSM.cookies.get("_osm_anonymous_notes_count")) || 0;
150             OSM.cookies.set("_osm_anonymous_notes_count", anonymousNotesCount + 1, { expires: 14 });
151           }
152           content.find("textarea").val("");
153           addCreatedNoteMarker(feature);
154           OSM.router.route("/note/" + feature.properties.id);
155         })
156         .catch(err => {
157           errorPanel.removeClass("d-none");
158           errorPanelDetail.text(err.message || err);
159           updateControls();
160         });
161     });
162
163     map.on("click", moveNewNoteMarkerToClick);
164     addNoteButton.on("disabled enabled", updateControls);
165     updateControls();
166
167     return map.getState();
168   };
169
170   page.unload = function () {
171     map.off("click", moveNewNoteMarkerToClick);
172     addNoteButton.off("disabled enabled", updateControls);
173     removeNewNoteMarker();
174     control.removeClass("active");
175   };
176
177   return page;
178 }