3

I can't get the pointerup event to fire on a link (an A tag with a href attribtue set) for event.pointerType == 'mouse' if the mouse was moved between pointerdown and pointerup.

I have the following scenario:

var lastEvent = false;
var handler = function (e) {
  if (lastEvent != e.type) {
    e.target.innerHTML += e.type + ' with ' + e.pointerType + '<br/>';
    e.target.scrollTo(0, e.target.scrollHeight);
  }
  lastEvent = e.type;
}
document.querySelector('a').addEventListener('pointerdown', handler);
document.querySelector('a').addEventListener('pointermove', handler);
document.querySelector('a').addEventListener('pointerup', handler);
div {
  height: 100vh;
  display: flex;
}
a {
  height: 60vh;
  width: 75vw;
  margin: auto;
  background-color: red;
  display: inline-block;
  user-select: none;
  touch-action: none;
  overflow-y: scroll;
}
<div>
    <a href="#"></a>
</div>

If I press a mouse button, keeps it pressed for a while and then releases it, I get this sequence:

  1. pointerdown with mouse
  2. pointerup with mouse

However if I press my mouse button, keeps it pressed and moves the mouse pointer around, and then releases it, I get this sequence:

  1. pointerdown with mouse
  2. pointermove with mouse

Problem: pointerup never fires.

I guess it is the built-in click-or-drag features in the browser (I have tested in Chrome) which blocks the pointerup event from firing, because If do this on a span or removes the href from the anchor link it works with this sequence:

  1. pointerdown with mouse
  2. pointermove with mouse
  3. pointerup with mouse

Also, it works flawlessly for touch-driven PointerEvents:

  1. pointerdown with touch
  2. pointermove with touch
  3. pointerup with touch

I guess there is a clever css property to set on the element to disable this pointerup prevention. Something like a { pointer-actions: click; }, but I haven't been able to find what.

Xyz
  • 5,955
  • 5
  • 40
  • 58

1 Answers1

6

D'oh! I stated the answer in the question, basically. It was the drag action which prevented the pointerup event from firing. Simply adding the draggable="false" attribute on the link element fixed this issue.

<a href="#" draggable="false"></a>

Proof of concept:

var lastEvent = false;
var handler = function (e) {
  if (lastEvent != e.type) {
    e.target.innerHTML += e.type + ' with ' + e.pointerType + '<br/>';
    e.target.scrollTo(0, e.target.scrollHeight);
  }
  lastEvent = e.type;
}
document.querySelector('a').addEventListener('pointerdown', handler);
document.querySelector('a').addEventListener('pointermove', handler);
document.querySelector('a').addEventListener('pointerup', handler);
div {
  height: 100vh;
  display: flex;
}
a {
  height: 60vh;
  width: 75vw;
  margin: auto;
  background-color: red;
  display: inline-block;
  user-select: none;
  touch-action: none;
  overflow-y: scroll;
}
<div>
    <a href="#" draggable="false"></a>
</div>

The only downside is that with draggable set to false, all mousedown-mousemove-mouseup will trigger a click event. But this can be prevented by checking if the difference for clientX/clientY between pointerdown and pointerup event is greater than a certain amount of pixels, store that in a variable and add an click event handler which runs e.preventDefault(); e.stopPropagation(); in this case.

Xyz
  • 5,955
  • 5
  • 40
  • 58