Question

I'm trying to write a web app which replaces the context menu (right-click menu) with my own customized ones. I want it so that when the user clicks on a table row, they get one certain context menu and when they click on the background of the page, they get a different one.

I have already written the menus and gotten them working. The problem comes in when trying to figure out how to get the background's menu to show ONLY when clicking on the background and how to get the table row's menu to show when that is clicked.

I tried using document.body.oncontextmenu for the body and and setting the oncontextmenu function for each table row, but the body's oncontextmenu function overrides the row's so I get the wrong menu. The menu for the table rows DOES work if I stop using the body's menu, so that's not the issue.

I could be using the wrong events, so is there a different event for just the background (and not the elements on top of the background)? Or a way to "prioritize" the events so the table row's function takes precedence? Thanks!

This is how the code looks:

var tableMenu;
var bodyMenu;

window.onload = function()
{
    bodyMenu = new rightClickMenu("bodyMenu");
    document.body.oncontextmenu = function() { bodyMenu.show(); tableMenu.hide(); }
    bodyMenu.add("Add Entry", function()
    {
        alert("ADD");
    });

    tableMenu = new rightClickMenu("tableMenu", "tblSims");

    simRows = getElementsByClassName("trSimRow");
    for (var i in simRows)
        simRows[i].oncontextmenu = function() { tableMenu.show(this.id.substring(2)); bodyMenu.hide(); }

    tableMenu.add("Delete Entry", function(mac)
    {
        alert("DELETE");
    });

    document.body.onclick = function()
    {
        bodyMenu.hide();
        tableMenu.hide();
    };
}
Was it helpful?

Solution

You have to work with the Javascript Event Propagation model. What happens is that your click event is automatically passed down the layers of objects on a page that have been registered as event listeners, unless you explicitly tell it to stop, try something like this:

function setupClickHandlers()
{
    document.getElementsByTagName('body')[0].onclick = doBodyMenu;
    document.getElementById('tableID').onclick = doTableMenu;
}

function doBodyMenu()
{
    //do whatever it does
}

function doTableMenu(e)
{
    //do whatever it does

    //stop the event propagating to the body element
    var evt = e ? e : window.event;

    if (evt.stopPropagation) {evt.stopPropagation();}
    else {evt.cancelBubble=true;}
    return false;
}

This should deal with the way each browser handles events.

OTHER TIPS

You can capture the target element, e.g.:

$('*').click(function(e) {
    alert(e.target);
    alert(e.target.tagName);
    if(e.target.tagName == 'html') {
        // show background menu
    }
});

$( document ).ready(function() {

    var childClicked = false;
    
    // myContainer is the nearest container div to the clickable elements 
    $("#myContainer").children().click(function(e) {
        console.log('in element');
        childClicked = true;
    });

    $("#myContainer").click(function(e){
        if(!childClicked) {
            console.log('in background');
            e.preventDefault();
            e.stopPropagation();
        }
        childClicked = false;
    });
});
#myContainer {
width:200px;
height:200px;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="myContainer" style="">

<a href="#">link</a>

<div style="width:50px;height:50px;background-color: white;">
<a href="#">another link</a>
</div>

</div>

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top