2

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:

  1. An contextmenu event listener on the document that calls event.preventDefault(). This prevents the context menu from appearing.
  2. An contextmenu event listener on the blue square that calls openSpecialMenu().

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:

  1. Is this a known bug with Safari? Is this even a bug?
  2. 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 after contextmenu events... but I'm looking for something more robust.
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
sir_thursday
  • 5,270
  • 12
  • 64
  • 118

0 Answers0