2 $(document).on("click", "a[href='#versions-navigation-active-page-item']", function (e) {
3 scrollToActiveVersion();
4 $("#versions-navigation-active-page-item a.page-link").trigger("focus");
8 OSM.Element = function (map, type) {
10 let scrollStartObserver, scrollEndObserver;
12 page.pushstate = page.popstate = function (path, id, version) {
13 OSM.loadSidebarContent(path, function () {
14 initVersionsNavigation();
15 page._addObject(type, id, version);
19 page.load = function (path, id, version) {
20 initVersionsNavigation();
21 page._addObject(type, id, version, true);
24 page.unload = function () {
26 scrollStartObserver?.disconnect();
27 scrollStartObserver = null;
28 scrollEndObserver?.disconnect();
29 scrollEndObserver = null;
32 page._addObject = function () {};
33 page._removeObject = function () {};
35 function initVersionsNavigation() {
36 scrollToActiveVersion();
38 const $scrollableList = $("#versions-navigation-list-middle");
39 const [scrollableFirstItem] = $scrollableList.children().first();
40 const [scrollableLastItem] = $scrollableList.children().last();
42 if (scrollableFirstItem) {
43 scrollStartObserver = createScrollObserver("#versions-navigation-list-start", "2px 0px");
44 scrollStartObserver.observe(scrollableFirstItem);
47 if (scrollableLastItem) {
48 scrollEndObserver = createScrollObserver("#versions-navigation-list-end", "-2px 0px");
49 scrollEndObserver.observe(scrollableLastItem);
53 function createScrollObserver(shadowTarget, shadowOffset) {
54 const threshold = 0.95;
55 return new IntersectionObserver(([entry]) => {
56 const floating = entry.intersectionRatio < threshold;
58 .css("box-shadow", floating ? `rgba(0, 0, 0, 0.075) ${shadowOffset} 2px` : "")
59 .css("z-index", floating ? "5" : ""); // floating z-index should be larger than z-index of Bootstrap's .page-link:focus, which is 3
66 OSM.MappedElement = function (map, type) {
67 const page = OSM.Element(map, type);
69 page._addObject = function (type, id, version, center) {
70 const hashParams = OSM.parseHash();
71 map.addObject({ type: type, id: parseInt(id, 10), version: version && parseInt(version, 10) }, function (bounds) {
72 if (!hashParams.center && bounds.isValid() &&
73 (center || !map.getBounds().contains(bounds))) {
74 OSM.router.withoutMoveListener(function () {
75 map.fitBounds(bounds);
81 page._removeObject = function () {
88 function scrollToActiveVersion() {
89 const [scrollableList] = $("#versions-navigation-list-middle");
91 if (!scrollableList) return;
93 const [activeStartItem] = $("#versions-navigation-list-start #versions-navigation-active-page-item");
94 const [activeScrollableItem] = $("#versions-navigation-list-middle #versions-navigation-active-page-item");
96 if (activeStartItem) {
97 scrollableList.scrollLeft = 0;
98 } else if (activeScrollableItem) {
99 scrollableList.scrollLeft = Math.round(activeScrollableItem.offsetLeft - (scrollableList.offsetWidth / 2) + (activeScrollableItem.offsetWidth / 2));
101 scrollableList.scrollLeft = scrollableList.scrollWidth - scrollableList.offsetWidth;