From cc9daefea2db16fc07901129fd4106dda38bca5c Mon Sep 17 00:00:00 2001
From: Jan-Hendrik Willms <tleilax+studip@gmail.com>
Date: Tue, 16 Apr 2024 08:20:46 +0000
Subject: [PATCH] fixes #4005

Closes #4005

Merge request studip/studip!2860
---
 .../assets/javascripts/lib/header_magic.js    |  2 +-
 resources/assets/javascripts/lib/scroll.js    | 59 ++++++++++---------
 .../responsive/ResponsiveNavigation.vue       |  3 +
 3 files changed, 36 insertions(+), 28 deletions(-)

diff --git a/resources/assets/javascripts/lib/header_magic.js b/resources/assets/javascripts/lib/header_magic.js
index f465e7e95b8..a581107ee5d 100644
--- a/resources/assets/javascripts/lib/header_magic.js
+++ b/resources/assets/javascripts/lib/header_magic.js
@@ -17,7 +17,7 @@ const scroll = function(scrolltop) {
 const HeaderMagic = {
     enable() {
         fold = $('#navigation-level-1').height();
-        Scroll.addHandler('header', scroll);
+        Scroll.addHandler('header', scroll, true);
     },
     disable() {
         Scroll.removeHandler('header');
diff --git a/resources/assets/javascripts/lib/scroll.js b/resources/assets/javascripts/lib/scroll.js
index a4d24d5d55f..f4ffc66e335 100644
--- a/resources/assets/javascripts/lib/scroll.js
+++ b/resources/assets/javascripts/lib/scroll.js
@@ -6,49 +6,54 @@
  * Updates/calls to the callback are synchronized to screen refresh by using
  * the animation frame method (which will fallback to a timer based solution).
  */
-var handlers = {};
-var animId = false;
+const handlers = {};
+let animId = false;
 
-var lastTop  = null;
-var lastLeft = null;
-
-function scrollHandler() {
-    var scrollTop = $(document).scrollTop();
-    var scrollLeft = $(document).scrollLeft();
-
-    if (scrollTop !== lastTop || scrollLeft !== lastLeft) {
-        $.each(handlers, function(index, handler) {
-            handler(scrollTop, scrollLeft);
-        });
-
-        lastTop  = scrollTop;
-        lastLeft = scrollLeft;
-    }
-
-    animId = false;
-
-    engageScrollTrigger();
-}
+let lastTop = null;
+let lastLeft = null;
 
 function refresh() {
-    var hasHandlers = !$.isEmptyObject(handlers);
+    const hasHandlers = Object.keys(handlers).length > 0;
     if (!hasHandlers && animId !== false) {
         window.cancelAnimationFrame(animId);
         animId = false;
     } else if (hasHandlers && animId === false) {
-        animId = window.requestAnimationFrame(scrollHandler);
+        animId = window.requestAnimationFrame(() => Scroll.executeHandlers());
     }
 }
 
 function engageScrollTrigger() {
-    $(window).off('scroll.studip-handler');
-    $(window).one('scroll.studip-handler', refresh);
+    window.removeEventListener('scroll', refresh);
+    window.addEventListener('scroll', refresh, {once: true});
 }
 
 const Scroll = {
-    addHandler(index, handler) {
+    executeHandlers(only_these = []) {
+        const scrollTop = document.scrollingElement.scrollTop;
+        const scrollLeft = document.scrollingElement.scrollLeft;
+
+        if (scrollTop !== lastTop || scrollLeft !== lastLeft) {
+            for (const [index, handler] of Object.entries(handlers)) {
+                if (only_these.length === 0 || only_these.includes(index)) {
+                    handler(scrollTop, scrollLeft);
+                }
+            }
+
+            lastTop  = scrollTop;
+            lastLeft = scrollLeft;
+        }
+
+        animId = false;
+
+        engageScrollTrigger();
+    },
+    addHandler(index, handler, immediate = false) {
         handlers[index] = handler;
         engageScrollTrigger();
+
+        if (immediate) {
+            Scroll.executeHandlers([index]);
+        }
     },
     removeHandler(index) {
         delete handlers[index];
diff --git a/resources/vue/components/responsive/ResponsiveNavigation.vue b/resources/vue/components/responsive/ResponsiveNavigation.vue
index 1c07e738a2f..fffce17d77a 100644
--- a/resources/vue/components/responsive/ResponsiveNavigation.vue
+++ b/resources/vue/components/responsive/ResponsiveNavigation.vue
@@ -594,6 +594,9 @@ export default {
                 attributeFilter: ['class']
             })
         });
+
+        // Check initial state after load
+        this.headerMagic = document.querySelector('body').classList.contains('fixed');
     },
     beforeDestroy() {
         this.classObserver.disconnect();
-- 
GitLab