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