0

It seems that when working with pointer events, a contextmenu event will lead to pointerout, pointercancel and pointerleave events, but subsequent pointerups and pointermoves will be ignored.

This becomes quite a problem on touch devices where a long press causes contextmenu to be fired. It makes long pointer movements abort early if they happen to linger too long in one spot.

I find advice on how to ignore the contextmenu event. But is it possible to completely disable it such that it never fires at all? And in particular, such that it does not obstruct the flow of pointer events?

Or can the 'length' of a long press be customized?

EDIT Some code that demonstrates this effect, building off Axionatic's:

<!DOCTYPE html>
<html>
<body>
<div id="noContextMenu" style="height:150px; background-color:#ffaaaa;">
  <h2>No right-clicking allowed!</h2>
</div>
<script>
  const noContext = document.getElementById('noContextMenu');
  noContext.addEventListener('contextmenu', e => {
    console.log('contextmenu');
    e.preventDefault();
  });
  noContext.addEventListener('pointerdown', e => console.log('pointerdown'));
  noContext.addEventListener('pointerup', e => console.log('pointerup'));
  noContext.addEventListener('pointercancel', e => console.log('pointercancel'));
  noContext.addEventListener('pointerout', e => console.log('pointerout'));
  noContext.addEventListener('pointerleave', e => console.log('pointerleave'));
  noContext.addEventListener('pointermove', e => console.log('pointermove'));
  noContext.addEventListener('touchstart', e => console.log('touchstart'));
  noContext.addEventListener('touchmove', e => console.log('touchmove'));
  noContext.addEventListener('touchend', e => console.log('touchend'));
  noContext.addEventListener('touchcancel', e => console.log('touchcancel'));
</script>
</body>
</html>

Open this in the browser's touch device emulation mode, then try to do a long press and then further pointer movements without releasing the touch. You should get output like this:

pointerdown
touchstart
contextmenu
pointercancel
pointerout
pointerleave
touchcancel

But no further pointermove or pointerup or touchmove or touchend events.

Josh Hansen
  • 917
  • 1
  • 9
  • 20

2 Answers2

1

Well, I think I found an answer:

noContext.addEventListener('touchstart', e => e.preventDefault());

After that, the context menu is never triggered by a long touch, and continuous pointermove and touchmove events become available, and pointerup and touchend events still fire at the end.

Josh Hansen
  • 917
  • 1
  • 9
  • 20
0

You may prevent a contextmenu event (or any other event) from taking effect by listening for it and cancelling with preventDefault.

Per the MDN Web Docs:

<div id="noContextMenu" style="height:150px; background-color:#ffaaaa;">
  <h2>No right-clicking allowed!</h2>
</div>
<script>
  const noContext = document.getElementById('noContextMenu');
  noContext.addEventListener('contextmenu', e => {
    e.preventDefault();
  });
</script>

This will capture the contextmenu event and prevent it from doing anything when fired within the id="noContextMenu" div.

Axionatic
  • 591
  • 4
  • 7
  • It prevents the default action (showing the context menu) but it doesn't prevent the cancellation of pointer events. At least that's what I'm seeing. That's why I'm interested in preventing `contextmenu` from firing in the first place. – Josh Hansen Aug 12 '21 at 04:56
  • 1
    Are you able to share your code, and what you're trying to achieve? It might be that you have to work with touch events instead. – Axionatic Aug 12 '21 at 05:09
  • I'm building a numberline widget for a math application. I want the user to be able to tap on a number/increment then drag left or right to create a greater than or less than inequality on the numberline. I built off your code here to give a better illustration of the issue, see the updated main entry. – Josh Hansen Aug 12 '21 at 05:35
  • 1
    Thanks for the updated info, and glad you found an answer! – Axionatic Aug 12 '21 at 05:56