How to hide a custom context menu when over a button or element

Issue

I am looking for a simple way to hide the custom context menu unless over a button or element. Here is a simple example I coded up containing a custom context menu and a button I wish to have it attached to. I am thinking maybe there could be an event listener that looks out for an on hover over the element, or maybe a function that toggles it on or off when needed? Also i was wondering if the button or element wasn’t defined with a class or ID is there still a way to know when you are over it maybe via coordinates (Not necessary just curious if possible)? The idea is there will be multiple elements that will require the context menu but the general space around the elements in the body should not show the custom menu.

function view() {

    const contextMenu = document.getElementById('context-menu');
    const scope = document.querySelector("body");

    //body

    var listLength = contextMenu.children.length;
    for (i = 0; i < listLength; i++)
        contextMenu.removeChild(contextMenu.children[0]);

    contextMenuadd(contextMenu, "line 1 of context menu", 1);
    contextMenuadd(contextMenu, "line 2 of context menu", 2);
    contextMenuadd(contextMenu, "line 3 of context menu", 3);
    contextMenuadd(contextMenu, "line 4 of context menu", 4);

    scope.addEventListener("contextmenu", (event) => {
        event.preventDefault();

        const {
            clientX: mouseX,
            clientY: mouseY
        } = event;

        contextMenu.style.top = `${mouseY}px`;
        contextMenu.style.left = `${mouseX}px`;
        contextMenu.classList.add('visible');
        contextMenu.style.display = 'block';
        contextMenu.style.zIndex = 20000;
        contextMenu.style.position = 'fixed';
        contextMenu.style.width = "360px";
        contextMenu.style.borderRadius = "5px";


    });

    scope.addEventListener("click", (e) => {
        if (e.target.offsetParent != contextMenu) {
            contextMenu.style.display = 'none';
        }
    });

};

document.addEventListener('DOMContentLoaded', view);

function contextMenuadd(contextMenu, menustring, count) {
    var action = function(e) {
        //menuLink;
        let currentRow = $(event.target)[0].parentElement;
        var index = parseInt(currentRow.row);
        var value = currentRow.textContent;
        en(href, '_self');

    };


    var menuitem = document.createElement('LI');
    menuitem.addEventListener('click', action);
    menuitem.classList.add("hotspot__item");
    menuitem.innerHTML = '<a href="#">' + menustring + '</a>';
    menuitem.row = count;


    contextMenu.appendChild(menuitem);

};

document.addEventListener('click', function(e) {
    let inside = (e.target.closest('#container'));
    if (!inside) {
        let contextMenu = document.getElementById('contextMenuId');
        contextMenu.setAttribute('style', 'display:none');
    }
});
#context-menu {
    position: fixed;
    z-index: 10000;
    width: 180px;
    background: #ffaaaa;
    border-radius: 5px;
    display: none;
}

#context-menu.item {
    padding: 2px 4px;
    font-size: 12px;
    color: #eee;
    cursor: pointer;
    border-radius: inherit;
}
<body id="allofit">
    <header>
        <h2>Context Menu Example</h2>
    </header>

    <!-- <gm:figure-group> -->

    <div id='sdi_canvas1' style="width:400px; height:400px">

        <button id="container"> this is data in my DIV</button>

    </div>
    <div id="context-menu" class="context-menu" 
        oncontextmenu="ShowMenu('contextMenu',event)" style="display:none">
        <div class="item">Option 1</div>
        <div class="item">Option 2</div>
    </div>

</body>

Here’s a fiddle for reference JSFiddle

Solution

  • You can add a class to all the elements that will show the custom
    context menu.
  • And oncontextmenu, you check if the element contains the class then toggle the context menu accordingly.

Try this

document.addEventListener('DOMContentLoaded', () => {
    const scope = document.querySelector("body");
    const contextMenu = document.getElementById('context-menu');

    scope.addEventListener("contextmenu", (event) => {
        event.preventDefault();

        if( event.target.classList.contains('has-content-menu') || 
            event.target.closest('.has-content-menu') !== null 
        ){
            contextMenu.style.top     = event.clientY + 'px';
            contextMenu.style.left    = event.clientX + 'px';
            contextMenu.style.display = 'block';
        }else{
            contextMenu.style.display = 'none';
        }
    });

    scope.addEventListener("click", (event) => {
        contextMenu.style.display = 'none';
    });
});
*, ::after, ::before {
    box-sizing: border-box;
}

body, html {
    height: 100%;
}

#context-menu {
    position: fixed;
    z-index: 10000;
    width: 180px;
    background: #ffaaaa;
    border-radius: 5px;
    display: none;
    z-index: 20000;
}

#context-menu.item {
    padding: 2px 4px;
    font-size: 12px;
    color: #eee;
    cursor: pointer;
    border-radius: inherit;
}
<button class="has-content-menu">  this is data in my DIV</button>
<div id="context-menu">
    <div class="item">Option 1</div>
    <div class="item">Option 2</div>
</div>

Answered By – ruleboy21

Answer Checked By – Pedro (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.