ngx-contextmenu icon indicating copy to clipboard operation
ngx-contextmenu copied to clipboard

Added touch compatiblity

Open Gizrah opened this issue 7 years ago • 14 comments

If you're interested, I've added basic touch functionality so it works on phones/tablets.

Gizrah avatar Nov 06 '17 14:11 Gizrah

First, thanks for contributing!

So basically, the context menu shows up when you long press? Is there not a native event for a long press? I'd like to avoid hard coding the time you have to press.

I haven't done much mobile web app development, so your input is appreciated.

isaacplmann avatar Nov 06 '17 14:11 isaacplmann

Hi, thanks for replying so quickly!

Unfortunately there’s no such thing as a native event for long press from what I’ve found so far. There’s four options: touchstart, touchmove, touchcancel (when you receive a call for instance) and touchend that are shared between iOS and Android, according to MDN.

I understand your reluctance against hard-coding anything, I have the same sentiment. Half a second seems long enough to not be a click and short enough not to hamper any other function. I’ve scoured Stack Overflow of course, so this was the median I got to.

Greetings, Auke

Gizrah avatar Nov 06 '17 14:11 Gizrah

Thanks for explaining the long press implementation.

What's the reason for falling back to pageX/pageY? Do mobile browsers not use clientX/clientY?

isaacplmann avatar Nov 06 '17 15:11 isaacplmann

No, the touch event doesn’t even have a clientY/X param. So this was the next, and seemingly only available, thing.

Gizrah avatar Nov 06 '17 15:11 Gizrah

I'm learning this stuff now, but it looks like the right thing to do is to reference the touches property of the TouchEvent and then reference clientX/clientY on that. What should happen if there is more than one Touch in the touches array? Should we only use the first one? Or not open the context menu?

It looks like pageX/pageY is not supported in iOS Safari (TouchEvent inherits from UIEvent)

isaacplmann avatar Nov 06 '17 17:11 isaacplmann

Also, even if the pageX/Y events were supported, they'll position the context menu incorrectly. pageX/Y is relative to the document, clientX/Y is relative to the viewport.

isaacplmann avatar Nov 06 '17 17:11 isaacplmann

That’s odd, I tested it on my iPad. I’ll have to look into it more to answer your questions.

Gizrah avatar Nov 06 '17 17:11 Gizrah

I'm going to see if I can use TouchEvent instead of the current MouseEvent and test it on several android devices, ranging from 4.4.1 to 7. Or whatever is on a Galaxy S8. (Yay for test-material at work)

Gizrah avatar Nov 07 '17 07:11 Gizrah

I've implemented the TouchEvent now, and cancelled out the touchmove event.

However.

I noticed that there's an obvious drag delay now only on the place with the touchmove hostbind, but I can't seem to find a way right now how to prevent this yet. Although I have some ideas.

Gizrah avatar Nov 07 '17 10:11 Gizrah

After some serious testing across devices, I've noticed excessive inconsistencies among the different devices.

Android: Seems to ignore touchmove completely, instead registers a touchcancel on move, and fires the the contextmenu event, without touchend, after the standard duration.

iOS: Uses touchstart, touchend and touchmove. However, the default iOS context menu is opened regardless and seemingly is not part of the touch events available. The contextmenu event is never called.

I'm quite at a loss at the moment how to get this working.

Gizrah avatar Nov 07 '17 13:11 Gizrah

Thanks for working on this. Cross browser/device testing is hard. I've avoided working on the mobile piece because it is so hard. My advice would be to find another library that handles touch events in javascript (not necessarily in Angular) and see how they handle all the device differences. This has to be a problem that other people have tried to solve before.

Let me know if I can help.

isaacplmann avatar Nov 07 '17 13:11 isaacplmann

Here is the jQuery mobile taphold event implementation. And the custom events, vclick etc are defined here.

It looks like they start a timer when touchstart happens and if it hasn't been canceled after 1000ms the taphold event is fired. Timer cancelling happens with a touchmove, touchcancel or touchend.

I'm not planning to work on this myself, but if @Gizrah or someone else wants to pick up here and get something working I'd be glad of any contribution.

isaacplmann avatar Nov 20 '17 18:11 isaacplmann

I think the Angular Material team is using HammerJS to handle longpress events. See the tooltip docs and the code. It looks like the (longpress) event is set up here. Still don't quite understand how it works, but it looks like they've solved this problem.

isaacplmann avatar Dec 14 '17 22:12 isaacplmann

I'll pick this up at a later date, when my current project is on the production environment. I can .. ehm .. sneak work on this in the meantime. Thanks for the documentation links!

Gizrah avatar Jan 16 '18 13:01 Gizrah