Fix add note
[rails.git] / app / assets / javascripts / index / notes.js.erb
1 //= require templates/notes/show
2 //= require templates/notes/new
3
4 function initializeNotes(map) {
5   var params = OSM.mapParams(),
6       noteLayer = map.noteLayer,
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.on("layeradd", function (e) {
29     if (e.layer == noteLayer) {
30       loadNotes();
31       map.on("moveend", loadNotes);
32     }
33   }).on("layerremove", function (e) {
34     if (e.layer == noteLayer) {
35       map.off("moveend", loadNotes);
36       noteLayer.clearLayers();
37       notes = {};
38     }
39   }).on("popupclose", function (e) {
40     if (newNote && e.popup == newNote._popup) {
41       $(newNote).oneTime(10, "removenote", function () {
42         map.removeLayer(newNote);
43         newNote = null;
44       });
45     }
46   }).on("popupopen", function (e) {
47     if (!('ontouchstart' in document.documentElement)) {
48       $(e.popup._container).find(".comment").focus();
49     }
50   });
51
52   if (OSM.STATUS != 'api_offline' && OSM.STATUS != 'database_offline') {
53     if (params.notes || params.layers.indexOf('N') >= 0) map.addLayer(noteLayer);
54     if (params.note) {
55       $.ajax({
56         url: "/api/" + OSM.API_VERSION + "/notes/" + params.note + ".json",
57         success: function (feature) {
58           var marker = updateMarker(notes[feature.properties.id], feature);
59           notes[feature.properties.id] = marker;
60           map.addLayer(noteLayer);
61           marker.openPopup();
62         }
63       });
64     }
65   }
66
67   function updateMarker(marker, feature) {
68     if (marker) {
69       marker.setIcon(noteIcons[feature.properties.status]);
70       marker.setPopupContent(createPopupContent(
71         marker, feature.properties,
72         $(marker._popup._content).find("textarea").val()
73       ));
74     } else {
75       marker = L.marker(feature.geometry.coordinates.reverse(), {
76         icon: noteIcons[feature.properties.status],
77         opacity: 0.9
78       });
79       marker.addTo(noteLayer).bindPopup(
80         createPopupContent(marker, feature.properties),
81         popupOptions()
82       );
83     }
84     return marker;
85   }
86
87   var noteLoader;
88
89   function loadNotes() {
90     var bounds = map.getBounds();
91     var size = bounds.getSize();
92
93     if (size <= OSM.MAX_NOTE_REQUEST_AREA) {
94       var url = "/api/" + OSM.API_VERSION + "/notes.json?bbox=" + bounds.toBBoxString();
95
96       if (noteLoader) noteLoader.abort();
97
98       noteLoader = $.ajax({
99         url: url,
100         success: success
101       });
102     }
103
104     function success(json) {
105       var oldNotes = notes;
106       notes = {};
107       json.features.forEach(updateMarkers);
108
109       function updateMarkers(feature) {
110         var marker = oldNotes[feature.properties.id];
111         delete oldNotes[feature.properties.id];
112         notes[feature.properties.id] = updateMarker(marker, feature);
113       }
114
115       for (id in oldNotes) {
116         noteLayer.removeLayer(oldNotes[id]);
117       }
118
119       noteLoader = null;
120     }
121   };
122
123   function popupOptions() {
124     var mapSize = map.getSize();
125
126     return {
127       minWidth: 320,
128       maxWidth: mapSize.y * 1 / 3,
129       maxHeight: mapSize.y * 2 / 3,
130       offset: new L.Point(0, -40),
131       autoPanPadding: new L.Point(60, 40)
132     };
133   }
134
135   function createPopupContent(marker, properties, comment) {
136     var content = $(JST["templates/notes/show"]({ note: properties }));
137
138     content.find("textarea").on("input", function (e) {
139       var form = e.target.form;
140
141       if ($(e.target).val() == "") {
142         $(form.close).val(I18n.t("javascripts.notes.show.resolve"));
143         $(form.comment).prop("disabled", true);
144       } else {
145         $(form.close).val(I18n.t("javascripts.notes.show.comment_and_resolve"));
146         $(form.comment).prop("disabled", false);
147       }
148     });
149
150     content.find("input[type=submit]").on("click", function (e) {
151       e.preventDefault();
152       var data = $(e.target).data();
153       updateNote(marker, e.target.form, data.method, data.url);
154     });
155
156     if (comment) {
157       content.find("textarea").val(comment).trigger("input");
158     }
159
160     return content[0];
161   }
162
163   var addNoteButton = $(".control-note .control-button");
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       addNoteButton.removeClass("disabled");
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   addNoteButton.on("click", function (e) {
221     e.preventDefault();
222     e.stopPropagation();
223
224     if (addNoteButton.hasClass("disabled")) return;
225
226     addNoteButton.addClass("disabled");
227
228     map.addLayer(noteLayer);
229
230     var mapSize = map.getSize();
231     var markerPosition;
232
233     if (mapSize.y > 800) {
234       markerPosition = [mapSize.x / 2, mapSize.y / 2];
235     } else if (mapSize.y > 400) {
236       markerPosition = [mapSize.x / 2, 400];
237     } else {
238       markerPosition = [mapSize.x / 2, mapSize.y];
239     }
240
241     newNote = L.marker(map.containerPointToLatLng(markerPosition), {
242       icon: noteIcons["new"],
243       opacity: 0.9,
244       draggable: true
245     });
246
247     var popupContent = $(JST["templates/notes/new"]());
248
249     popupContent.find("textarea").on("input", disableWhenBlank);
250
251     function disableWhenBlank(e) {
252       $(e.target.form.add).prop("disabled", $(e.target).val() === "");
253     }
254
255     popupContent.find("input[type=submit]").on("click", function (e) {
256       e.preventDefault();
257       createNote(newNote, e.target.form, '/api/0.6/notes.json');
258     });
259
260     newNote.addTo(noteLayer).bindPopup(popupContent[0], popupOptions()).openPopup();
261
262     newNote.on("remove", function (e) {
263       addNoteButton.removeClass("disabled");
264     }).on("dragstart", function (e) {
265       $(newNote).stopTime("removenote");
266     }).on("dragend", function (e) {
267       e.target.openPopup();
268     });
269   });
270 }