From 0a9cd466c7fe3b1b34566c051d6b6cb5e811e9c5 Mon Sep 17 00:00:00 2001 From: Anton Khorev Date: Wed, 16 Apr 2025 13:53:06 +0300 Subject: [PATCH] Fix marking changesets outside of viewport on history pages The previous method relied on intersection events for all changeset list items that go from below the viewport to above the viewport or in the opposite direction. But that required the items to enter the viewport in between. This is not guaranteed to happen if the sidebar contents is scrolled fast enough, for example by dragging the scrollbar or pressing Home/End keys. If an item goes from below straight to above without ever being inside the viewport, no intersection event is generated and the changeset is left in an invalid state with wrong color. This fix updates changesets below/above based on changesets inside the viewport. --- .../javascripts/index/history-changesets-layer.js | 6 ++++-- app/assets/javascripts/index/history.js | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/index/history-changesets-layer.js b/app/assets/javascripts/index/history-changesets-layer.js index eafa2f715..97d28ffb2 100644 --- a/app/assets/javascripts/index/history-changesets-layer.js +++ b/app/assets/javascripts/index/history-changesets-layer.js @@ -116,8 +116,10 @@ OSM.HistoryChangesetsLayer = L.FeatureGroup.extend({ const changeset = this._changesets.get(id); if (!changeset) return; - changeset.sidebarRelativePosition = state; - this._updateChangesetStyle(changeset); + if (changeset.sidebarRelativePosition !== state) { + changeset.sidebarRelativePosition = state; + this._updateChangesetStyle(changeset); + } }, getLayerId: function (layer) { diff --git a/app/assets/javascripts/index/history.js b/app/assets/javascripts/index/history.js index 8a3ba28ae..d1bcb20a1 100644 --- a/app/assets/javascripts/index/history.js +++ b/app/assets/javascripts/index/history.js @@ -38,6 +38,7 @@ OSM.History = function (map) { if (!window.IntersectionObserver) return; let keepInitialLocation = true; + let itemsInViewport = $(); changesetIntersectionObserver = new IntersectionObserver((entries) => { let closestTargetToTop, @@ -49,15 +50,16 @@ OSM.History = function (map) { const id = $(entry.target).data("changeset")?.id; if (entry.isIntersecting) { + itemsInViewport = itemsInViewport.add(entry.target); if (id) changesetsLayer.setChangesetSidebarRelativePosition(id, 0); continue; + } else { + itemsInViewport = itemsInViewport.not(entry.target); } const distanceToTop = entry.rootBounds.top - entry.boundingClientRect.bottom; const distanceToBottom = entry.boundingClientRect.top - entry.rootBounds.bottom; - if (id) changesetsLayer.setChangesetSidebarRelativePosition(id, distanceToTop >= 0 ? 1 : -1); - if (distanceToTop >= 0 && distanceToTop < closestDistanceToTop) { closestDistanceToTop = distanceToTop; closestTargetToTop = entry.target; @@ -68,6 +70,15 @@ OSM.History = function (map) { } } + itemsInViewport.first().prevAll().each(function () { + const id = $(this).data("changeset")?.id; + if (id) changesetsLayer.setChangesetSidebarRelativePosition(id, 1); + }); + itemsInViewport.last().nextAll().each(function () { + const id = $(this).data("changeset")?.id; + if (id) changesetsLayer.setChangesetSidebarRelativePosition(id, -1); + }); + changesetsLayer.reorderChangesets(); if (keepInitialLocation) { -- 2.39.5