]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index/notes.js.erb
Refactor layer persistence
[rails.git] / app / assets / javascripts / index / notes.js.erb
1 //= require templates/notes/show
2 //= require templates/notes/new
3
4 $(document).ready(function () {
5   var params = OSM.mapParams(),
6       noteLayer = new L.LayerGroup({code: 'N'}),
7       notes = {},
8       newNote;
9
10   var noteIcons = {
11     "new": L.icon({
12       iconUrl: "<%= image_path 'new_note_marker.png' %>",
13       iconSize: [25, 40],
14       iconAnchor: [12, 40]
15     }),
16     "open": L.icon({
17       iconUrl: "<%= image_path 'open_note_marker.png' %>",
18       iconSize: [25, 40],
19       iconAnchor: [12, 40]
20     }),
21     "closed": L.icon({
22       iconUrl: "<%= image_path 'closed_note_marker.png' %>",
23       iconSize: [25, 40],
24       iconAnchor: [12, 40]
25     })
26   };
27
28   map.noteLayer = noteLayer;
29
30   map.on("layeradd", function (e) {
31     if (e.layer == noteLayer) {
32       loadNotes();
33       map.on("moveend", loadNotes);
34     }
35   }).on("layerremove", function (e) {
36     if (e.layer == noteLayer) {
37       map.off("moveend", loadNotes);
38       noteLayer.clearLayers();
39       notes = {};
40     }
41   }).on("popupclose", function (e) {
42     if (newNote && e.popup == newNote._popup) {
43       $(newNote).oneTime(10, "removenote", function () {
44         map.removeLayer(newNote);
45         newNote = null;
46       });
47     }
48   }).on("popupopen", function (e) {
49     if (!('ontouchstart' in document.documentElement)) {
50       $(e.popup._container).find(".comment").focus();
51     }
52   });
53
54   if (OSM.STATUS != 'api_offline' && OSM.STATUS != 'database_offline') {
55     if (params.notes || params.layers.indexOf('N') >= 0) map.addLayer(noteLayer);
56     if (params.note) {
57       $.ajax({
58         url: "/api/" + OSM.API_VERSION + "/notes/" + params.note + ".json",
59         success: function (feature) {
60           var marker = updateMarker(notes[feature.properties.id], feature);
61           notes[feature.properties.id] = marker;
62           map.addLayer(noteLayer);
63           marker.openPopup();
64         }
65       });
66     }
67   }
68
69   function updateMarker(marker, feature) {
70     if (marker) {
71       marker.setIcon(noteIcons[feature.properties.status]);
72       marker.setPopupContent(createPopupContent(
73         marker, feature.properties,
74         $(marker._popup._content).find("textarea").val()
75       ));
76     } else {
77       marker = L.marker(feature.geometry.coordinates.reverse(), {
78         icon: noteIcons[feature.properties.status],
79         opacity: 0.9
80       });
81       marker.addTo(noteLayer).bindPopup(
82         createPopupContent(marker, feature.properties),
83         popupOptions()
84       );
85     }
86     return marker;
87   }
88
89   var noteLoader;
90
91   function loadNotes() {
92     var bounds = map.getBounds();
93     var size = bounds.getSize();
94
95     if (size <= OSM.MAX_NOTE_REQUEST_AREA) {
96       var url = "/api/" + OSM.API_VERSION + "/notes.json?bbox=" + bounds.toBBoxString();
97
98       if (noteLoader) noteLoader.abort();
99
100       noteLoader = $.ajax({
101         url: url,
102         success: success
103       });
104     }
105
106     function success(json) {
107       var oldNotes = notes;
108       notes = {};
109       json.features.forEach(updateMarkers);
110
111       function updateMarkers(feature) {
112         var marker = oldNotes[feature.properties.id];
113         delete oldNotes[feature.properties.id];
114         notes[feature.properties.id] = updateMarker(marker, feature);
115       }
116
117       for (id in oldNotes) {
118         noteLayer.removeLayer(oldNotes[id]);
119       }
120
121       noteLoader = null;
122     }
123   };
124
125   function popupOptions() {
126     var mapSize = map.getSize();
127
128     return {
129       minWidth: 320,
130       maxWidth: mapSize.y * 1 / 3,
131       maxHeight: mapSize.y * 2 / 3,
132       offset: new L.Point(0, -40),
133       autoPanPadding: new L.Point(60, 40)
134     };
135   }
136
137   function createPopupContent(marker, properties, comment) {
138     var content = $(JST["templates/notes/show"]({ note: properties }));
139
140     content.find("textarea").on("input", function (e) {
141       var form = e.target.form;
142
143       if ($(e.target).val() == "") {
144         $(form.close).val(I18n.t("javascripts.notes.show.resolve"));
145         $(form.comment).prop("disabled", true);
146       } else {
147         $(form.close).val(I18n.t("javascripts.notes.show.comment_and_resolve"));
148         $(form.comment).prop("disabled", false);
149       }
150     });
151
152     content.find("input[type=submit]").on("click", function (e) {
153       e.preventDefault();
154       var data = $(e.target).data();
155       updateNote(marker, e.target.form, data.method, data.url);
156     });
157
158     if (comment) {
159       content.find("textarea").val(comment).trigger("input");
160     }
161
162     return content[0];
163   }
164
165   function createNote(marker, form, url) {
166     var location = marker.getLatLng();
167
168     marker.options.draggable = false;
169     marker.dragging.disable();
170
171     $(form).find("input[type=submit]").prop("disabled", true);
172
173     $.ajax({
174       url: url,
175       type: "POST",
176       oauth: true,
177       data: {
178         lat: location.lat,
179         lon: location.lng,
180         text: $(form.text).val()
181       },
182       success: noteCreated
183     });
184
185     function noteCreated(feature) {
186       $(marker._popup._content).find("textarea").val("");
187
188       notes[feature.properties.id] = updateMarker(marker, feature);
189       newNote = null;
190
191       $("#createnoteanchor").removeClass("disabled").addClass("geolink");
192     }
193   }
194
195   function updateNote(marker, form, method, url) {
196     $(form).find("input[type=submit]").prop("disabled", true);
197
198     $.ajax({
199       url: url,
200       type: method,
201       oauth: true,
202       data: {
203         text: $(form.text).val()
204       },
205       success: function (feature) {
206         if (feature.properties.status == "hidden") {
207           noteLayer.removeLayer(marker);
208
209           delete notes[feature.properties.id];
210         } else {
211           var popupContent = createPopupContent(marker, feature.properties);
212
213           marker.setIcon(noteIcons[feature.properties.status]);
214           marker.setPopupContent(popupContent);
215         }
216       }
217     });
218   }
219
220   $(".leaflet-control-attribution").on("click", "#createnoteanchor", function (e) {
221     e.preventDefault();
222
223     if ($(e.target).hasClass("disabled")) return;
224
225     $(e.target).removeClass("geolink").addClass("disabled");
226
227     map.addLayer(noteLayer);
228
229     var mapSize = map.getSize();
230     var markerPosition;
231
232     if (mapSize.y > 800) {
233       markerPosition = [mapSize.x / 2, mapSize.y / 2];
234     } else if (mapSize.y > 400) {
235       markerPosition = [mapSize.x / 2, 400];
236     } else {
237       markerPosition = [mapSize.x / 2, mapSize.y];
238     }
239
240     newNote = L.marker(map.containerPointToLatLng(markerPosition), {
241       icon: noteIcons["new"],
242       opacity: 0.9,
243       draggable: true
244     });
245
246     var popupContent = $(JST["templates/notes/new"]({
247         create_url: $(e.target).attr("href")
248     }));
249
250     popupContent.find("textarea").on("input", disableWhenBlank);
251
252     function disableWhenBlank(e) {
253       $(e.target.form).prop("disabled", $(e.target).val() === "");
254     }
255
256     popupContent.find("input[type=submit]").on("click", function (e) {
257       e.preventDefault();
258       createNote(newNote, e.target.form, $(e.target).data("url"));
259     });
260
261     newNote.addTo(noteLayer).bindPopup(popupContent[0], popupOptions()).openPopup();
262
263     newNote.on("remove", function (e) {
264       $("#createnoteanchor").removeClass("disabled").addClass("geolink");
265     }).on("dragstart", function (e) {
266       $(newNote).stopTime("removenote");
267     }).on("dragend", function (e) {
268       e.target.openPopup();
269     });
270   });
271 });