const page = {};
$("#sidebar_content")
- .on("click", ".changeset_more a", loadMore)
+ .on("click", ".changeset_more a", loadMoreChangesets)
.on("mouseover", "[data-changeset]", function () {
highlightChangeset($(this).data("changeset").id);
})
return layer.id;
};
+ let changesetIntersectionObserver;
+
+ function disableChangesetIntersectionObserver() {
+ if (changesetIntersectionObserver) {
+ changesetIntersectionObserver.disconnect();
+ changesetIntersectionObserver = null;
+ }
+ }
+
+ function enableChangesetIntersectionObserver() {
+ disableChangesetIntersectionObserver();
+ if (!window.IntersectionObserver) return;
+
+ let ignoreIntersectionEvents = true;
+
+ changesetIntersectionObserver = new IntersectionObserver((entries) => {
+ if (ignoreIntersectionEvents) {
+ ignoreIntersectionEvents = false;
+ return;
+ }
+
+ let closestTargetToTop,
+ closestDistanceToTop = Infinity,
+ closestTargetToBottom,
+ closestDistanceToBottom = Infinity;
+
+ for (const entry of entries) {
+ if (entry.isIntersecting) continue;
+
+ const distanceToTop = entry.rootBounds.top - entry.boundingClientRect.bottom;
+ const distanceToBottom = entry.boundingClientRect.top - entry.rootBounds.bottom;
+ if (distanceToTop >= 0 && distanceToTop < closestDistanceToTop) {
+ closestDistanceToTop = distanceToTop;
+ closestTargetToTop = entry.target;
+ }
+ if (distanceToBottom >= 0 && distanceToBottom <= closestDistanceToBottom) {
+ closestDistanceToBottom = distanceToBottom;
+ closestTargetToBottom = entry.target;
+ }
+ }
+
+ if (closestTargetToTop && closestDistanceToTop < closestDistanceToBottom) {
+ const id = $(closestTargetToTop).data("changeset")?.id;
+ if (id) {
+ OSM.router.replace(location.pathname + "?" + new URLSearchParams({ before: id }) + location.hash);
+ }
+ } else if (closestTargetToBottom) {
+ const id = $(closestTargetToBottom).data("changeset")?.id;
+ if (id) {
+ OSM.router.replace(location.pathname + "?" + new URLSearchParams({ after: id }) + location.hash);
+ }
+ }
+ }, { root: $("#sidebar")[0] });
+
+ $("#sidebar_content .changesets ol").children().each(function () {
+ changesetIntersectionObserver.observe(this);
+ });
+ }
+
function highlightChangeset(id) {
const layer = group.getLayer(id);
if (layer) layer.setStyle({ fillOpacity: 0.3, color: "#FF6600", weight: 3 });
}
}
- function update() {
+ function loadFirstChangesets() {
const data = new URLSearchParams();
const params = new URLSearchParams(location.search);
+ disableChangesetIntersectionObserver();
+
if (location.pathname === "/history") {
data.set("bbox", map.getBounds().wrap().toBBoxString());
const feedLink = $("link[type=\"application/atom+xml\"]"),
.then(response => response.text())
.then(function (html) {
displayFirstChangesets(html);
+ enableChangesetIntersectionObserver();
+
+ if (params.has("before")) {
+ const [firstItem] = $("#sidebar_content .changesets ol").children().first();
+ firstItem?.scrollIntoView();
+ }
+ if (params.has("after")) {
+ const [lastItem] = $("#sidebar_content .changesets ol").children().last();
+ lastItem?.scrollIntoView(false);
+ }
+
updateMap();
});
}
- function loadMore(e) {
+ function loadMoreChangesets(e) {
e.preventDefault();
e.stopPropagation();
$.get($(this).attr("href"), function (html) {
displayMoreChangesets(div, html);
+ enableChangesetIntersectionObserver();
updateMap();
});
}
+ function reloadChangesetsBecauseOfMapMovement() {
+ OSM.router.replace("/history" + window.location.hash);
+ loadFirstChangesets();
+ }
+
let changesets = [];
function updateBounds() {
map.addLayer(group);
if (location.pathname === "/history") {
- map.on("moveend", update);
+ map.on("moveend", reloadChangesetsBecauseOfMapMovement);
}
map.on("zoomend", updateBounds);
- update();
+ loadFirstChangesets();
};
page.unload = function () {
map.removeLayer(group);
- map.off("moveend", update);
+ map.off("moveend", reloadChangesetsBecauseOfMapMovement);
map.off("zoomend", updateBounds);
+ disableChangesetIntersectionObserver();
};
return page;
end
end
+ test "update sidebar when before param is included and map is moved" do
+ changeset1 = create(:changeset, :num_changes => 1, :min_lat => 50000000, :max_lat => 50000001, :min_lon => 50000000, :max_lon => 50000001)
+ create(:changeset_tag, :changeset => changeset1, :k => "comment", :v => "changeset-at-fives")
+ changeset2 = create(:changeset, :num_changes => 1, :min_lat => 50100000, :max_lat => 50100001, :min_lon => 50100000, :max_lon => 50100001)
+ create(:changeset_tag, :changeset => changeset2, :k => "comment", :v => "changeset-close-to-fives")
+ changeset3 = create(:changeset)
+
+ visit "/history?before=#{changeset3.id}#map=17/5/5"
+
+ within_sidebar do
+ assert_link "changeset-at-fives"
+ assert_no_link "changeset-close-to-fives"
+ end
+
+ find("#map [aria-label='Zoom Out']").click(:shift)
+
+ within_sidebar do
+ assert_link "changeset-at-fives"
+ assert_link "changeset-close-to-fives"
+ end
+
+ assert_current_path history_path
+ end
+
private
def create_visible_changeset(user, comment)