feathersui-openfl icon indicating copy to clipboard operation
feathersui-openfl copied to clipboard

Scroller: allow `preventDefault()`

Open player-03 opened this issue 2 years ago • 2 comments

The Scroller class deliberately prevents scroll events from bubbling in an attempt to disable preventDefault(). But as far as I'm aware*, there's no benefit to disabling preventDefault().

In fact, preventDefault() is required to make the HTML5 target usable. There, if you fail to call it, the webpage will scroll every time the user tries to scroll the component.

*It's possible there was a platform-specific benefit, as I've only tested on a few platforms. But in that case, this needs to be inside a conditional compilation block.

player-03 avatar Mar 13 '22 02:03 player-03

So what's happening here is the Scroller wants to handle the mouse wheel event, and it needs to prevent other Scroller instances that may be in the parent chain from handling it at the same time. You don't want two scrollers, where one contains the other, scrolling at the same time. One of them needs to take precedence with the mouse wheel.

Normally, I try very hard to avoid preventing propagation of any event. I want people to have access to lower level events to be able to override the default behavior in Feathers UI. So, the fact that I'm stopping propagation here is kind of a big deal. It means that I felt that I had no other choice.

The comment "can't use preventDefault(), so don't let it bubble" is actually saying that I wanted to use preventDefault() and isDefaultPrevented() instead of stopImmediatePropagation(), but that preventDefault() didn't work as expected for some reason. I did not try to disable the ability to call preventDefault() here. I was trying to call it myself, and something bad happened when I did. It just turned out that my workaround had the side effect of making it harder to use preventDefault() externally.

I should have explained exactly which behavior with preventDefault() was undesirable, but alas, I overlooked that. I suspect that it's because preventDefault() had some secondary effect. It very well could have been that it prevented the html5 target from scrolling the document in some circumstances where it should have scrolled. The comment above is what made me think of that:

we need to handle the event, even if the position doesn't technically change

It may be that when "the position doesn't technically change" the HTML document should be allowed to scroll. I don't recall exactly, and I should probably revisit this after the 1.0 stable release.

Anyway, as a workaround for now, you should try listening for the mouse wheel event during capture phase. That should allow you to handle the event before the Scroller stops propagation.

joshtynjala avatar Mar 14 '22 17:03 joshtynjala

Ah, that explains a lot.

As for a proper solution... I searched Lime and OpenFL for references to isDefaultPrevented, and found only one that applies to scroll events. This calls window.onMouseWheel.cancel(), which is only ever checked by HTML5Window.

Therefore, the only side-effect of preventDefault() is canceling the page scroll event in HTML5. Which is exactly the sort of thing we would want to cancel when Scroller._scrolling is true.

Edit: I accidentally found the hotkey for "close with comment." Oops.

player-03 avatar Mar 14 '22 17:03 player-03