1 OSM.DirectionsEndpoint = function Endpoint(map, input, marker, dragCallback, changeCallback) {
4 endpoint.marker = L.marker([0, 0], {
5 icon: OSM.getMarker(marker),
10 endpoint.enableListeners = function () {
11 endpoint.marker.on("drag dragend", markerDragListener);
12 input.on("keydown", inputKeydownListener);
13 input.on("change", inputChangeListener);
16 endpoint.disableListeners = function () {
17 endpoint.marker.off("drag dragend", markerDragListener);
18 input.off("keydown", inputKeydownListener);
19 input.off("change", inputChangeListener);
22 function markerDragListener(e) {
23 const latlng = L.latLng(OSM.cropLocation(e.target.getLatLng(), map.getZoom()));
25 if (endpoint.geocodeRequest) endpoint.geocodeRequest.abort();
26 delete endpoint.geocodeRequest;
29 setInputValueFromLatLng(latlng);
30 endpoint.value = input.val();
31 if (e.type === "dragend") getReverseGeocode();
32 dragCallback(e.type === "drag");
35 function inputKeydownListener() {
36 input.removeClass("is-invalid");
39 function inputChangeListener(e) {
40 // make text the same in both text boxes
41 const value = e.target.value;
42 endpoint.setValue(value);
45 endpoint.setValue = function (value) {
46 if (endpoint.geocodeRequest) endpoint.geocodeRequest.abort();
47 delete endpoint.geocodeRequest;
48 input.removeClass("is-invalid");
50 const coordinatesMatch = value.match(/^\s*([+-]?\d+(?:\.\d*)?)(?:\s+|\s*[/,]\s*)([+-]?\d+(?:\.\d*)?)\s*$/);
51 const latlng = coordinatesMatch && L.latLng(coordinatesMatch[1], coordinatesMatch[2]);
53 if (latlng && endpoint.cachedReverseGeocode && endpoint.cachedReverseGeocode.latlng.equals(latlng)) {
55 if (endpoint.cachedReverseGeocode.notFound) {
56 endpoint.value = value;
57 input.addClass("is-invalid");
59 endpoint.value = endpoint.cachedReverseGeocode.value;
61 input.val(endpoint.value);
66 endpoint.value = value;
72 setInputValueFromLatLng(latlng);
75 } else if (endpoint.value) {
80 endpoint.clearValue = function () {
81 if (endpoint.geocodeRequest) endpoint.geocodeRequest.abort();
82 delete endpoint.geocodeRequest;
84 delete endpoint.value;
86 map.removeLayer(endpoint.marker);
89 endpoint.swapCachedReverseGeocodes = function (otherEndpoint) {
90 const g0 = endpoint.cachedReverseGeocode;
91 const g1 = otherEndpoint.cachedReverseGeocode;
92 delete endpoint.cachedReverseGeocode;
93 delete otherEndpoint.cachedReverseGeocode;
94 if (g0) otherEndpoint.cachedReverseGeocode = g0;
95 if (g1) endpoint.cachedReverseGeocode = g1;
98 function getGeocode() {
99 const viewbox = map.getBounds().toBBoxString(), // <sw lon>,<sw lat>,<ne lon>,<ne lat>
100 geocodeUrl = OSM.NOMINATIM_URL + "search?" + new URLSearchParams({ q: endpoint.value, format: "json", viewbox });
102 endpoint.geocodeRequest = new AbortController();
103 fetch(geocodeUrl, { signal: endpoint.geocodeRequest.signal })
108 function success(json) {
109 delete endpoint.geocodeRequest;
110 if (json.length === 0) {
111 input.addClass("is-invalid");
112 // eslint-disable-next-line no-alert
113 alert(OSM.i18n.t("javascripts.directions.errors.no_place", { place: endpoint.value }));
117 setLatLng(L.latLng(json[0]));
119 endpoint.value = json[0].display_name;
120 input.val(json[0].display_name);
126 function getReverseGeocode() {
127 const latlng = endpoint.latlng.clone(),
128 { lat, lng } = latlng,
129 reverseGeocodeUrl = OSM.NOMINATIM_URL + "reverse?" + new URLSearchParams({ lat, lon: lng, format: "json" });
131 endpoint.geocodeRequest = new AbortController();
132 fetch(reverseGeocodeUrl, { signal: endpoint.geocodeRequest.signal })
137 function success(json) {
138 delete endpoint.geocodeRequest;
139 if (!json || !json.display_name) {
140 endpoint.cachedReverseGeocode = { latlng: latlng, notFound: true };
144 endpoint.value = json.display_name;
145 input.val(json.display_name);
146 endpoint.cachedReverseGeocode = { latlng: latlng, value: endpoint.value };
150 function setLatLng(ll) {
152 .attr("data-lat", ll.lat)
153 .attr("data-lon", ll.lng);
154 endpoint.latlng = ll;
160 function removeLatLng() {
162 .removeAttr("data-lat")
163 .removeAttr("data-lon");
164 delete endpoint.latlng;
167 function setInputValueFromLatLng(latlng) {
168 input.val(latlng.lat + ", " + latlng.lng);