]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index/layers/data.js
Merge remote-tracking branch 'upstream/pull/6293'
[rails.git] / app / assets / javascripts / index / layers / data.js
1 OSM.initializeDataLayer = function (map) {
2   let dataLoader, loadedBounds;
3   const dataLayer = map.dataLayer;
4
5   dataLayer.isWayArea = function () {
6     return false;
7   };
8
9   dataLayer.on("click", function (e) {
10     const feature = e.layer.feature;
11     OSM.router.click(e.originalEvent, `/${feature.type}/${feature.id}`);
12   });
13
14   dataLayer.on("add", function () {
15     map.fire("overlayadd", { layer: this });
16     map.on("moveend", updateData);
17     updateData();
18   });
19
20   dataLayer.on("remove", function () {
21     if (dataLoader) dataLoader.abort();
22     dataLoader = null;
23     map.off("moveend", updateData);
24     $("#browse_status").empty();
25     map.fire("overlayremove", { layer: this });
26   });
27
28   function updateData() {
29     const bounds = map.getBounds();
30     if (!loadedBounds || !loadedBounds.contains(bounds)) {
31       getData();
32     }
33   }
34
35   function displayFeatureWarning(num_features, add, cancel) {
36     $("#browse_status").html(
37       $("<div class='p-3'>").append(
38         $("<div class='d-flex'>").append(
39           $("<h2 class='flex-grow-1 text-break'>")
40             .text(OSM.i18n.t("browse.start_rjs.load_data")),
41           $("<div>").append(
42             $("<button type='button' class='btn-close'>")
43               .attr("aria-label", OSM.i18n.t("javascripts.close"))
44               .click(cancel))),
45         $("<p class='alert alert-warning'>")
46           .text(OSM.i18n.t("browse.start_rjs.feature_warning", { num_features })),
47         $("<input type='submit' class='btn btn-primary d-block mx-auto'>")
48           .val(OSM.i18n.t("browse.start_rjs.load_data"))
49           .click(add)));
50   }
51
52   function displayLoadError(message, close) {
53     $("#browse_status").html(
54       $("<div class='p-3'>").append(
55         $("<div class='d-flex'>").append(
56           $("<h2 class='flex-grow-1 text-break'>")
57             .text(OSM.i18n.t("browse.start_rjs.load_data")),
58           $("<div>").append(
59             $("<button type='button' class='btn-close'>")
60               .attr("aria-label", OSM.i18n.t("javascripts.close"))
61               .click(close))),
62         $("<p class='alert alert-warning'>")
63           .text(OSM.i18n.t("browse.start_rjs.feature_error", { message: message }))));
64   }
65
66   function getData() {
67     const bounds = map.getBounds();
68     const url = "/api/" + OSM.API_VERSION + "/map.json?bbox=" + bounds.toBBoxString();
69
70     /*
71      * Modern browsers are quite happy showing far more than 100 features in
72      * the data browser, so increase the limit to 4000.
73      */
74     const maxFeatures = 4000;
75
76     if (dataLoader) dataLoader.abort();
77
78     $("#layers-data-loading").remove();
79
80     const spanLoading = $("<span>")
81       .attr("id", "layers-data-loading")
82       .attr("class", "spinner-border spinner-border-sm ms-1")
83       .attr("role", "status")
84       .html("<span class='visually-hidden'>" + OSM.i18n.t("browse.start_rjs.loading") + "</span>")
85       .appendTo($("#label-layers-data"));
86
87     dataLoader = new AbortController();
88     fetch(url, { signal: dataLoader.signal })
89       .then(response => {
90         if (response.ok) return response.json();
91         const status = response.statusText || response.status;
92         if (response.status !== 400 && response.status !== 509) throw new Error(status);
93         return response.text().then(text => {
94           throw new Error(text || status);
95         });
96       })
97       .then(function (data) {
98         dataLayer.clearLayers();
99
100         const features = dataLayer.buildFeatures(data);
101
102         function addFeatures() {
103           $("#browse_status").empty();
104           dataLayer.addData(features);
105           loadedBounds = bounds;
106         }
107
108         function cancelAddFeatures() {
109           $("#browse_status").empty();
110         }
111
112         if (features.length < maxFeatures) {
113           addFeatures();
114         } else {
115           displayFeatureWarning(features.length, addFeatures, cancelAddFeatures);
116         }
117
118         if (map._objectLayer) {
119           map._objectLayer.bringToFront();
120         }
121
122         dataLoader = null;
123       })
124       .catch(function (error) {
125         if (error.name === "AbortError") return;
126
127         displayLoadError(error?.message, () => {
128           $("#browse_status").empty();
129         });
130
131         dataLoader = null;
132       })
133       .finally(() => {
134         spanLoading.remove();
135       });
136   }
137 };