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