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