]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index/history.js
Merge remote-tracking branch 'upstream/pull/5823'
[rails.git] / app / assets / javascripts / index / history.js
1 //= require jquery-simulate/jquery.simulate
2
3 OSM.History = function (map) {
4   const page = {};
5
6   $("#sidebar_content")
7     .on("click", ".changeset_more a", loadMore)
8     .on("mouseover", "[data-changeset]", function () {
9       highlightChangeset($(this).data("changeset").id);
10     })
11     .on("mouseout", "[data-changeset]", function () {
12       unHighlightChangeset($(this).data("changeset").id);
13     });
14
15   const group = L.featureGroup()
16     .on("mouseover", function (e) {
17       highlightChangeset(e.layer.id);
18     })
19     .on("mouseout", function (e) {
20       unHighlightChangeset(e.layer.id);
21     })
22     .on("click", function (e) {
23       clickChangeset(e.layer.id, e.originalEvent);
24     });
25
26   group.getLayerId = function (layer) {
27     return layer.id;
28   };
29
30   function highlightChangeset(id) {
31     const layer = group.getLayer(id);
32     if (layer) layer.setStyle({ fillOpacity: 0.3, color: "#FF6600", weight: 3 });
33     $("#changeset_" + id).addClass("selected");
34   }
35
36   function unHighlightChangeset(id) {
37     const layer = group.getLayer(id);
38     if (layer) layer.setStyle({ fillOpacity: 0, color: "#FF9500", weight: 2 });
39     $("#changeset_" + id).removeClass("selected");
40   }
41
42   function clickChangeset(id, e) {
43     $("#changeset_" + id).find("a.changeset_id").simulate("click", e);
44   }
45
46   function displayFirstChangesets(html) {
47     $("#sidebar_content .changesets").html(html);
48   }
49
50   function displayMoreChangesets(div, html) {
51     const sidebar = $("#sidebar")[0];
52     const previousScrollHeightMinusTop = sidebar.scrollHeight - sidebar.scrollTop;
53
54     const oldList = $("#sidebar_content .changesets ol");
55
56     div.replaceWith(html);
57
58     const prevNewList = oldList.prevAll("ol");
59     if (prevNewList.length) {
60       prevNewList.next(".changeset_more").remove();
61       prevNewList.children().prependTo(oldList);
62       prevNewList.remove();
63
64       // restore scroll position only if prepending
65       sidebar.scrollTop = sidebar.scrollHeight - previousScrollHeightMinusTop;
66     }
67
68     const nextNewList = oldList.nextAll("ol");
69     if (nextNewList.length) {
70       nextNewList.prev(".changeset_more").remove();
71       nextNewList.children().appendTo(oldList);
72       nextNewList.remove();
73     }
74   }
75
76   function update() {
77     const data = new URLSearchParams();
78     const params = new URLSearchParams(location.search);
79
80     if (location.pathname === "/history") {
81       data.set("bbox", map.getBounds().wrap().toBBoxString());
82       const feedLink = $("link[type=\"application/atom+xml\"]"),
83             feedHref = feedLink.attr("href").split("?")[0];
84       feedLink.attr("href", feedHref + "?" + data);
85     }
86
87     data.set("list", "1");
88
89     if (params.has("before")) {
90       data.set("before", params.get("before"));
91     }
92     if (params.has("after")) {
93       data.set("after", params.get("after"));
94     }
95
96     fetch(location.pathname + "?" + data)
97       .then(response => response.text())
98       .then(function (html) {
99         displayFirstChangesets(html);
100         updateMap();
101       });
102   }
103
104   function loadMore(e) {
105     e.preventDefault();
106     e.stopPropagation();
107
108     const div = $(this).parents(".changeset_more");
109
110     $(this).hide();
111     div.find(".loader").show();
112
113     $.get($(this).attr("href"), function (html) {
114       displayMoreChangesets(div, html);
115       updateMap();
116     });
117   }
118
119   let changesets = [];
120
121   function updateBounds() {
122     group.clearLayers();
123
124     for (const changeset of changesets) {
125       const bottomLeft = map.project(L.latLng(changeset.bbox.minlat, changeset.bbox.minlon)),
126             topRight = map.project(L.latLng(changeset.bbox.maxlat, changeset.bbox.maxlon)),
127             width = topRight.x - bottomLeft.x,
128             height = bottomLeft.y - topRight.y,
129             minSize = 20; // Min width/height of changeset in pixels
130
131       if (width < minSize) {
132         bottomLeft.x -= ((minSize - width) / 2);
133         topRight.x += ((minSize - width) / 2);
134       }
135
136       if (height < minSize) {
137         bottomLeft.y += ((minSize - height) / 2);
138         topRight.y -= ((minSize - height) / 2);
139       }
140
141       changeset.bounds = L.latLngBounds(map.unproject(bottomLeft),
142                                         map.unproject(topRight));
143     }
144
145     changesets.sort(function (a, b) {
146       return b.bounds.getSize() - a.bounds.getSize();
147     });
148
149     for (const changeset of changesets) {
150       const rect = L.rectangle(changeset.bounds,
151                                { weight: 2, color: "#FF9500", opacity: 1, fillColor: "#FFFFAF", fillOpacity: 0 });
152       rect.id = changeset.id;
153       rect.addTo(group);
154     }
155   }
156
157   function updateMap() {
158     changesets = $("[data-changeset]").map(function (index, element) {
159       return $(element).data("changeset");
160     }).get().filter(function (changeset) {
161       return changeset.bbox;
162     });
163
164     updateBounds();
165
166     if (location.pathname !== "/history") {
167       const bounds = group.getBounds();
168       if (bounds.isValid()) map.fitBounds(bounds);
169     }
170   }
171
172   page.pushstate = page.popstate = function (path) {
173     OSM.loadSidebarContent(path, page.load);
174   };
175
176   page.load = function () {
177     map.addLayer(group);
178
179     if (location.pathname === "/history") {
180       map.on("moveend", update);
181     }
182
183     map.on("zoomend", updateBounds);
184
185     update();
186   };
187
188   page.unload = function () {
189     map.removeLayer(group);
190     map.off("moveend", update);
191     map.off("zoomend", updateBounds);
192   };
193
194   return page;
195 };