'On scroll underline a menu item based on the id of the portion where the final user is

Here's my problem and my code:

var lastId,
    topMenu = $("#menu-main-menu"),
    topMenuHeight = headerheight+1,
    menuItems = topMenu.find("a"),
    scrollItems = menuItems.map(function() {
        if($(this).parent().hasClass('external')) {
            return;
        }
        var item = $($(this).attr("href"));
        if (item.length) { 
            return item; 
        }
    });

    $(window).on("scroll", function() {

        const fromTop = $(this).scrollTop()+topMenuHeight;
        let cur = scrollItems.map(function() {
            if ($(this).offset().top < fromTop) {
                return this;
            }   
        });
        cur = cur[cur.length-1];

        let id = cur && cur.length ? cur[0].id : "";

        if (lastId !== id) {
            lastId = id;
            menuItems
            .parent().removeClass("underline")
            .end().filter("[href='#"+id+"']").parent().addClass("underline");
        }

    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="navbarNav" class="menu-main-menu-container">
        <ul id="menu-main-menu" class="menu"><li id="menu-item-17" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-17"><a href="#test2">Veelgestelde vragen</a></li>
            <li id="menu-item-18" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-18"><a href="#test1">Test1</a></li>
            <li id="menu-item-19" class="active menu-item menu-item-type-custom menu-item-object-custom menu-item-19"><a href="#test3">Test2</a></li>
            <li id="menu-item-20" class="external menu-item menu-item-type-custom menu-item-object-custom menu-item-20"><a href="http://www.confiban.com">Test3</a></li>
        </ul>
    </div>
    <div class="lazyblock-section" id="section-extra-Z1YeUxc">
        <div id="test1" class="background-color" style="background-size: cover;background-color: #fff; ">
        </div>
    </div>
</body>
</html>

Essentially, I create a menu and, based on another script here on stackoverflow, I created a jquery script to underline the menu item, based on the portion of the screen where the user will scroll.

It works but with a caveat. I will only work if the list is order, for example if the menu will be:

<li id="menu-item-18"><a href="#test1">Test1</a></li>
<li id="menu-item-19"><a href="#test2">Test2</a></li>
<div class="lazyblock-section">
    <div id="test1">
    </div>
</div>
<div class="lazyblock-section">
    <div id="test2">
    </div>
</div>

but if the markup will be:

<li id="menu-item-18"><a href="#test1">Test1</a></li>
<li id="menu-item-19"><a href="#test2">Test2</a></li>
<div class="lazyblock-section">
    <div id="test2">
    </div>
</div>
<div class="lazyblock-section">
    <div id="test1">
    </div>
</div>

The script won't work.

Now the client will have the freedom to order every element of the menu, and I tried to console.log every single variable here finding out that the script is working fun, but not being able to properly debug:

Apparently the only variable that is not clear for me is cur:

cur = cur[cur.length-1];
let id = cur && cur.length ? cur[0].id : "";

I tried to ged rid of the value [cur.length-1] but it is not working as it should.

Any suggestion?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source