Okay, here's some bizarre Safari behavior.
Summary:
Suppose I want to disable the context menu on my webpage. However, when the user right-clicks on the blue square, I want to run openSpecialMenu()
. In order to match this desired behavior, I have:
- An
contextmenu
event listener on the document that callsevent.preventDefault()
. This prevents the context menu from appearing. - An
contextmenu
event listener on the blue square that callsopenSpecialMenu()
.
Now, suppose my special menu closes itself on click
events, as most popup menus do.
I re-created this scenario in the following snippet:
document.addEventListener('contextmenu', function(event) {
event.preventDefault();
console.log('document contextmenu prevented');
});
document.getElementById("thing").addEventListener('contextmenu', function(event) {
console.log('blue square contextmenu');
// This opens my special menu.
// openSpecialMenu();
});
document.getElementById("thing").addEventListener('click', function(event) {
console.log('blue square click');
// My special menu closes if this is run.
});
document.getElementById("thing").addEventListener('mouseup', function(event) {
console.log('blue square mouseup');
// My special menu closes if this is run.
});
#thing {
height: 100px;
width: 100px;
background: blue;
}
<div id="thing"></div>
Take a look on Safari. Using CTRL + click, "right-click" on the blue square in the Codepen output with the console open. Notice that events are fired in the following order:
blue square contextmenu
document contextmenu prevented
blue square click
This mostly looks okay... except for this blue square click
event. You might be wondering why a click
event is being fired on Safari when CTRL is being held... shouldn't the contextmenu
event eat that?
Now comment out the event.preventDefault()
and try again. Notice that this time, the blue square click
console log doesn't appear. What's happening?
My dumb, intuitive theory:
Preventing the contextmenu
event with preventDefault
causes Safari to treat the event as a click
event. AFAIK, this is behavior only with Safari, have not been able to repro on Chrome, Edge, FF.
Why is this a problem?
If click
events are being fired here, then my special menu is closed immediately after it is opened. My function openSpecialMenu()
is correctly called, but then a click
event is triggered immediately after, and the special menu closes again.
My questions:
- Is this a known bug with Safari? Is this even a bug?
- How can I work around this? I can write some hacky solution where I check the browser and check to see if
click
events are fired quickly aftercontextmenu
events... but I'm looking for something more robust.