]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/user.js
create `OSM.MapLibre.defaultSecondaryMapOptions` to share the map style between the...
[rails.git] / app / assets / javascripts / user.js
1 //= require maplibre.map
2 //= require maplibre.combinedcontrolgroup
3 //= require ./home_location_name-endpoint
4
5 $(function () {
6   let map, marker, deleted_lat, deleted_lon, deleted_home_name, homeLocationNameGeocoder, savedLat, savedLon;
7
8   if ($("#social_links").length) {
9     $("#add-social-link").on("click", function () {
10       const newIndex = -Date.now();
11
12       $("#social_links template").contents().clone().appendTo("#social_links")
13         .find("input").attr("name", `user[social_links_attributes][${newIndex}][url]`).trigger("focus");
14
15       renumberSocialLinks();
16     });
17
18     $("#social_links").on("click", "button", function () {
19       const row = $(this).closest(".row");
20       const [destroyCheckbox] = row.find(".social_link_destroy input[type='checkbox']");
21
22       if (destroyCheckbox) {
23         destroyCheckbox.checked = true;
24         row.addClass("d-none");
25       } else {
26         row.remove();
27       }
28
29       renumberSocialLinks();
30     });
31
32     $(".social_link_destroy input[type='checkbox']:checked").each(function () {
33       $(this).closest(".row").addClass("d-none");
34     });
35
36     renumberSocialLinks();
37   }
38
39   function renumberSocialLinks() {
40     $("#social_links .row:not(.d-none)").each(function (i) {
41       const inputLabel = OSM.i18n.t("javascripts.profile.social_link_n", { n: i + 1 });
42       const removeButtonLabel = OSM.i18n.t("javascripts.profile.remove_social_link_n", { n: i + 1 });
43
44       $(this).find("input[type='text']")
45         .attr("placeholder", inputLabel)
46         .attr("aria-label", inputLabel);
47       $(this).find("button")
48         .attr("title", removeButtonLabel);
49     });
50   }
51
52   if ($("#map").length) {
53     map = new maplibregl.Map(OSM.MapLibre.defaultSecondaryMapOptions);
54
55     savedLat = $("#home_lat").val();
56     savedLon = $("#home_lon").val();
57     homeLocationNameGeocoder = OSM.HomeLocationNameGeocoder($("#home_lat"), $("#home_lon"), $("#home_location_name"));
58
59     const position = $("html").attr("dir") === "rtl" ? "top-left" : "top-right";
60     const navigationControl = new maplibregl.NavigationControl({ showCompass: false });
61     const geolocateControl = new maplibregl.GeolocateControl({
62       positionOptions: {
63         enableHighAccuracy: true
64       },
65       trackUserLocation: true
66     });
67     map.addControl(new OSM.MapLibre.CombinedControlGroup([navigationControl, geolocateControl]), position);
68     map.touchZoomRotate.disableRotation();
69     map.keyboard.disableRotation();
70
71     marker = OSM.MapLibre.getMarker({});
72
73     if (OSM.home) {
74       marker.setLngLat([OSM.home.lon, OSM.home.lat]);
75       marker.addTo(map);
76     }
77
78     map.on("click", function (e) {
79       if (!$("#updatehome").is(":checked")) return;
80
81       const [lat, lon] = OSM.cropLocation(e.lngLat, map.getZoom() + 1);
82
83       $("#home_lat").val(lat);
84       $("#home_lon").val(lon);
85
86       clearDeletedText();
87       respondToHomeLatLonUpdate();
88     });
89     map.on("moveend", function () {
90       const lat = $("#home_lat").val().trim(),
91             lon = $("#home_lon").val().trim();
92       let location;
93
94       try {
95         if (lat && lon) {
96           location = new maplibregl.LngLat(lon, lat);
97         }
98       } catch (error) {
99         // keep location undefined
100       }
101
102       $("#home_show").prop("disabled", !location || isCloseEnoughToMapCenter(location));
103     });
104
105     $("#home_lat, #home_lon").on("input", function () {
106       clearDeletedText();
107       respondToHomeLatLonUpdate();
108     });
109
110     $("#home_location_name").on("input", function () {
111       homeLocationNameGeocoder.autofill = false;
112       clearDeletedText();
113
114       respondToHomeLatLonUpdate(false);
115     });
116
117     $("#home_show").click(function () {
118       const lat = $("#home_lat").val(),
119             lon = $("#home_lon").val();
120
121       map.flyTo({ center: [lon, lat], zoom: OSM.MapLibre.defaultHomeZoom });
122     });
123
124     $("#home_delete").click(function () {
125       const lat = $("#home_lat").val(),
126             lon = $("#home_lon").val(),
127             locationName = $("#home_location_name").val();
128
129       $("#home_lat, #home_lon, #home_location_name").val("");
130       deleted_lat = lat;
131       deleted_lon = lon;
132       deleted_home_name = locationName;
133
134       respondToHomeLatLonUpdate(false);
135       $("#home_undelete").trigger("focus");
136     });
137
138     $("#home_undelete").click(function () {
139       $("#home_lat").val(deleted_lat);
140       $("#home_lon").val(deleted_lon);
141       $("#home_location_name").val(deleted_home_name);
142       clearDeletedText();
143
144       respondToHomeLatLonUpdate(false);
145       $("#home_delete").trigger("focus");
146     });
147   }
148
149   function respondToHomeLatLonUpdate(updateLocationName = true) {
150     const lat = $("#home_lat").val().trim(),
151           lon = $("#home_lon").val().trim(),
152           locationName = $("#home_location_name").val().trim();
153     let location;
154
155     try {
156       if (lat && lon) {
157         location = new maplibregl.LngLat(lon, lat);
158         if (updateLocationName) {
159           if (savedLat && savedLon && $("#home_location_name").val().trim()) {
160             homeLocationNameGeocoder.updateHomeLocationName(false, savedLat, savedLon, () => {
161               savedLat = savedLon = null;
162               homeLocationNameGeocoder.updateHomeLocationName();
163             });
164           } else {
165             savedLat = savedLon = null;
166             homeLocationNameGeocoder.updateHomeLocationName();
167           }
168         }
169       }
170       $("#home_lat, #home_lon").removeClass("is-invalid");
171     } catch (error) {
172       if (lat && isNaN(lat)) $("#home_lat").addClass("is-invalid");
173       if (lon && isNaN(lon)) $("#home_lon").addClass("is-invalid");
174     }
175
176     $("#home_message").toggleClass("invisible", Boolean(location));
177     $("#home_show").prop("hidden", !location);
178     $("#home_delete").prop("hidden", !location && !locationName);
179     $("#home_undelete").prop("hidden", !(
180       (!location || !locationName) &&
181       ((deleted_lat && deleted_lon) || deleted_home_name)
182     ));
183     if (location) {
184       marker.setLngLat([lon, lat]);
185       marker.addTo(map);
186       map.panTo([lon, lat]);
187     } else {
188       marker.remove();
189     }
190   }
191
192   function isCloseEnoughToMapCenter(location) {
193     const inputPt = map.project(location);
194     const centerPt = map.project(map.getCenter());
195
196     return centerPt.dist(inputPt) < 10;
197   }
198
199   function clearDeletedText() {
200     deleted_lat = null;
201     deleted_lon = null;
202     deleted_home_name = null;
203   }
204
205   $("input#user_avatar").on("change", function () {
206     $("#user_avatar_action_new").prop("checked", true);
207   });
208
209   $("#content.user_confirm").each(function () {
210     $(this).hide();
211     $(this).find("#confirm").submit();
212   });
213
214   $("input[name=legale]").change(function () {
215     $("#contributorTerms").html("<div class='spinner-border' role='status'><span class='visually-hidden'>" + OSM.i18n.t("browse.start_rjs.loading") + "</span></div>");
216     fetch(this.dataset.url, { headers: { "x-requested-with": "XMLHttpRequest" } })
217       .then(r => r.text())
218       .then(html => { $("#contributorTerms").html(html); });
219   });
220
221   $("#read_ct").on("click", function () {
222     $("#continue").prop("disabled", !($(this).prop("checked") && $("#read_tou").prop("checked")));
223   });
224
225   $("#read_tou").on("click", function () {
226     $("#continue").prop("disabled", !($(this).prop("checked") && $("#read_ct").prop("checked")));
227   });
228 });