1 OSM.DirectionsEndpoint = function Endpoint(map, input, iconUrl, dragCallback, changeCallback) {
4 endpoint.marker = L.marker([0, 0], {
10 shadowUrl: OSM.MARKER_SHADOW,
17 endpoint.enableListeners = function () {
18 endpoint.marker.on("drag dragend", markerDragListener);
19 input.on("keydown", inputKeydownListener);
20 input.on("change", inputChangeListener);
23 endpoint.disableListeners = function () {
24 endpoint.marker.off("drag dragend", markerDragListener);
25 input.off("keydown", inputKeydownListener);
26 input.off("change", inputChangeListener);
29 function markerDragListener(e) {
30 const latlng = L.latLng(OSM.cropLocation(e.target.getLatLng(), map.getZoom()));
32 if (endpoint.geocodeRequest) endpoint.geocodeRequest.abort();
33 delete endpoint.geocodeRequest;
36 setInputValueFromLatLng(latlng);
37 endpoint.value = input.val();
38 if (e.type === "dragend") getReverseGeocode();
39 dragCallback(e.type === "drag");
42 function inputKeydownListener() {
43 input.removeClass("is-invalid");
46 function inputChangeListener(e) {
47 // make text the same in both text boxes
48 const value = e.target.value;
49 endpoint.setValue(value);
52 endpoint.setValue = function (value) {
53 if (endpoint.geocodeRequest) endpoint.geocodeRequest.abort();
54 delete endpoint.geocodeRequest;
55 input.removeClass("is-invalid");
57 const coordinatesMatch = value.match(/^\s*([+-]?\d+(?:\.\d*)?)(?:\s+|\s*[/,]\s*)([+-]?\d+(?:\.\d*)?)\s*$/);
58 const latlng = coordinatesMatch && L.latLng(coordinatesMatch[1], coordinatesMatch[2]);
60 if (latlng && endpoint.cachedReverseGeocode && endpoint.cachedReverseGeocode.latlng.equals(latlng)) {
62 if (endpoint.cachedReverseGeocode.notFound) {
63 endpoint.value = value;
64 input.addClass("is-invalid");
66 endpoint.value = endpoint.cachedReverseGeocode.value;
68 input.val(endpoint.value);
73 endpoint.value = value;
79 setInputValueFromLatLng(latlng);
82 } else if (endpoint.value) {
87 endpoint.clearValue = function () {
88 if (endpoint.geocodeRequest) endpoint.geocodeRequest.abort();
89 delete endpoint.geocodeRequest;
91 delete endpoint.value;
93 map.removeLayer(endpoint.marker);
96 endpoint.swapCachedReverseGeocodes = function (otherEndpoint) {
97 const g0 = endpoint.cachedReverseGeocode;
98 const g1 = otherEndpoint.cachedReverseGeocode;
99 delete endpoint.cachedReverseGeocode;
100 delete otherEndpoint.cachedReverseGeocode;
101 if (g0) otherEndpoint.cachedReverseGeocode = g0;
102 if (g1) endpoint.cachedReverseGeocode = g1;
105 function getGeocode() {
106 const viewbox = map.getBounds().toBBoxString(), // <sw lon>,<sw lat>,<ne lon>,<ne lat>
107 geocodeUrl = OSM.NOMINATIM_URL + "search?" + new URLSearchParams({ q: endpoint.value, format: "json", viewbox });
109 endpoint.geocodeRequest = new AbortController();
110 fetch(geocodeUrl, { signal: endpoint.geocodeRequest.signal })
115 function success(json) {
116 delete endpoint.geocodeRequest;
117 if (json.length === 0) {
118 input.addClass("is-invalid");
119 // eslint-disable-next-line no-alert
120 alert(I18n.t("javascripts.directions.errors.no_place", { place: endpoint.value }));
124 setLatLng(L.latLng(json[0]));
126 endpoint.value = json[0].display_name;
127 input.val(json[0].display_name);
133 function getReverseGeocode() {
134 const latlng = endpoint.latlng.clone(),
135 { lat, lng } = latlng,
136 reverseGeocodeUrl = OSM.NOMINATIM_URL + "reverse?" + new URLSearchParams({ lat, lon: lng, format: "json" });
138 endpoint.geocodeRequest = new AbortController();
139 fetch(reverseGeocodeUrl, { signal: endpoint.geocodeRequest.signal })
144 function success(json) {
145 delete endpoint.geocodeRequest;
146 if (!json || !json.display_name) {
147 endpoint.cachedReverseGeocode = { latlng: latlng, notFound: true };
151 endpoint.value = json.display_name;
152 input.val(json.display_name);
153 endpoint.cachedReverseGeocode = { latlng: latlng, value: endpoint.value };
157 function setLatLng(ll) {
159 .attr("data-lat", ll.lat)
160 .attr("data-lon", ll.lng);
161 endpoint.latlng = ll;
167 function removeLatLng() {
169 .removeAttr("data-lat")
170 .removeAttr("data-lon");
171 delete endpoint.latlng;
174 function setInputValueFromLatLng(latlng) {
175 input.val(latlng.lat + ", " + latlng.lng);