-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: get hideOn clickout to work on iOS #115
feat: get hideOn clickout to work on iOS #115
Conversation
Hey @necojackarc, thanks for the PR! Note that we add all hide listeners to this._hideListenersOnDocumentByEvent. This prevents memory leaks by allowing us to remove listeners on This will require the hiding method(s) to be named. See the other hide functions for an example, and how we need to bind You can add tests right to the hide-on-click and hide-on-clickout tests. Note how events are triggered manually, so you can simply trigger touch events within the tests themselves. |
3f0b36c
to
89d9d9f
Compare
Hmm, something wrong is happening as one of the tests I added failed only in some environments... |
9c97771
to
905f27b
Compare
@@ -33,6 +33,8 @@ test('hides when an element outside the target is clicked', async function(asser | |||
|
|||
await click('#focus-me'); | |||
|
|||
await waitUntil(() => isVisible(attachment) === false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found that without this waitUntile
, this test case would sometimes fail.
Referring to the existing code, I added it.
@kybishop Okay, I addressed every issue on my PR. |
things have been a little crazy with emberconf coming up and all. Should have some time to look though this very soon |
addon/components/attach-popover.js
Outdated
|
||
// On iOS, `document.addEventListener('click', handler)` doesn't work, | ||
// so simulating click events using touch events. | ||
if (navigator.userAgent && navigator.userAgent.match(/iPhone|iPad|iPod/)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I bet we can make this solution a little less device specific.
I dug a bit into Tippy.js, a super popular tooltip lib that this addon takes inspiration on, and they look at ontouchstart
to see if the device supports touch: https://github.com/atomiks/tippyjs/blob/b755ed52ca93976862974356b09b5811214d4c9f/src/js/core/globals.js#L9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can have a slight perf boost by doing this work only once during the init hook. Basically, we just check if ontouchstart
exists in window
, then set an instance variable. Something like this:
this.clickoutEvent = 'ontouchstart' in window ? 'touchend' : 'click';
Then we can just use the same logic as before here, but use this.clickoutEvent
for the event type and not need a new set of functions either.
addon/components/attach-popover.js
Outdated
document.addEventListener('touchmove', this._disableDocumentClickSimulationOnClickOutOnIos); | ||
|
||
this._hideListenersOnDocumentByEvent.touchend = this._hideOnClickOutOnIos; | ||
document.addEventListener('touchend', this._hideOnClickOutOnIos); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably use just one of these events, I'm leaning towards touchend
since click
is normally fired when the mouse button is released.
Any particular reason we might want to use all three?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm positive your idea #115 (comment) is the simplest solution!
But, what I'm worried about and why I've used these three events are that using only touchend
will change the current behavior of ember-attacher.
Now, on Android devices,
- users can click a button then a tooltip will appear
- users can scroll the screen with the tooltip being visible
because click events won't be triggered when users are scrolling their screen.
However, touchend
events always happen when users lift their fingers off the screen.
Then, users won't be able to scroll with the tooltip being visible.
If you don't mind this change, I think #115 (comment) can be the best!
And I'd like to update the PR following this idea.
How do you feel?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense. Perhaps we should use touchstart
instead of touchend
to share the same behavior of hiding tooltips on scroll?
I'll leave the decision up to you. We can always change it if people think it should be one way or the other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I'll try to keep the current behavior, but will remove the devise specific code following your idea!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense. Perhaps we should use touchstart instead of touchend to share the same behavior of hiding tooltips on scroll?
Not to change the current behavior, we should use all three events to simulate "a click", I think...
touchstart
- a user puts their finger on the screentouchmove
- a user moves the fingertouchend
- a user lifts the finger off
Some try to simulate click events "perfectly" then they're tracking the finger position (e.g. If the finger moved only within Npx, this should be regarded as a click), but it may be too much...
Currently, if users don't move their fingers from beginning to end, I regard it as a click.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see what you mean, if there is a touchmove
, it isn't strictly a "click", the user is scrolling the screen.
I poked at Tippy for inspiration and they use touchend
as the hide event. Thinking through how this would appear to the user, I believe this to be the best solution, but I'm still open to other ways. Here's my thought process:
- If a tooltip is currently being shown, the user might want to move the screen around to see the tooltip in a better position. By using
touchend
, they can still scroll around to see the tooltip in a different position, then have it disappear as soon as they lift their scrolling finger. Theoretically they should be able to move their scrolling finger to the side, allowing them to see the tooltip as they expect. - This is a nice and simple solution that requires minimal complex logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds nice enough! I'll update my PR!
905f27b
to
684d0e6
Compare
@kybishop I adopted the idea to use |
Thanks for the awesome work @necojackarc! I'm just waiting on a fix for ember-decorators before the next release, hopefully very soon :) |
On iOS,
document.addEventListener('click', handler)
dosen't work.It means
hideOn='clickout'
also doesn't work on iOS.Actually, I couldn't close popped up items by tapping outside of them.
This PR will fix this issue using touch events to simulate clicks on iOS.
The algorithm is quite simple - if a touched position doesn't move from start to finish, regard the action as a click then execute
this._hideOnClickOut(event)
handler.Since I have no idea how I can add iOS specific tests, I haven't added any tests...