Skip to content
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

Handles firing closeOnClick before another listener #10926

Merged
merged 9 commits into from Aug 12, 2021

Conversation

avpeery
Copy link
Contributor

@avpeery avpeery commented Aug 11, 2021

This PR closes #10029.

Previous bug required double click to open a popup in new area when using the same popup as the closeOnClick event listener fired after opening the popup event listener. This change moves the closeOnClick listener to be fired first in the case that there are multiple listeners for an event.

You can manually test this with debug/popup.html and using this code to create the popup:
const popup = new mapboxgl.Popup(); popup.setHTML("Hello world"); map.on("click", (e) => popup.setLngLat(e.lngLat).addTo(map));

WIP: this doesn't consider the use-case if a user were to click on the same target intending to close a popup, and would prefer moving into helper function without having the index hard-coded in the logic.

Functionality before the change:

Screen.Recording.2021-08-11.at.11.06.04.AM.mov

Functionality after the change:

Screen.Recording.2021-08-11.at.11.03.34.AM.mov

Launch Checklist

  • briefly describe the changes in this PR
  • include before/after visuals or gifs if this PR includes visual changes
  • write tests for all new functionality
  • post benchmark scores
  • manually test the debug page
  • apply changelog label ('bug', 'feature', 'docs', etc) or use the label 'skip changelog'
  • add an entry inside this element for inclusion in the mapbox-gl-js changelog: Handles firing closeOnClick before another click listener by implementing a preclick event

@avpeery avpeery marked this pull request as draft August 11, 2021 18:28
@@ -124,6 +124,12 @@ export class Evented {

// make sure adding or removing listeners inside other listeners won't cause an infinite loop
const listeners = this._listeners && this._listeners[type] ? this._listeners[type].slice() : [];

// Check if onClose is an event listener and move to front of list to fire first
if (listeners.length > 1 && listeners[1].name === "bound _onClose") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may work for this specific use case, but this solution is brittle, with possible cases where it breaks and it's very hard to debug — for example, what if a user puts multiple click listeners on a popup? Then _onClose will not be the second, but later in the array. What if a user adds a listener with the same name? What if a different class in GL JS (not popup) uses the same method name (_onClose) and the execution order is swapped unexpectedly?

I think we should find a solution that's more explicit and can't produce unexpected side effects — e.g. firing a preclick event before click here and then subscribing to it for Popup closeOnClick. This is how Leaflet handles it as seen here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for the feedback! Yes I wasn't confident on this initial approach. I appreciate sending over the resources and example from leaflet. I implemented a preclick that works manually with the debug file but is breaking some of the unit tests in test/unit/ui/map_events.test.js that I'm looking into now.

@@ -38,8 +38,13 @@ export class MapEventHandler {
this._map.fire(new MapMouseEvent(e.type, this._map, e));
}

preclick(e: MouseEvent) {
this._map.fire(new MapMouseEvent(e.type, this._map, e));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.type will be equal to click here (propagating from the DOM event of the same name) so looks like it'll fire click twice — I think we want to explicitly specify preclick here instead.

Copy link
Member

@mourner mourner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great to me now, nice work! Let's try adding a unit test for the new behavior, and once it's in it's good to merge.

@mourner
Copy link
Member

mourner commented Aug 12, 2021

Not sure what's going on with the render tests, the changes don't seem to have anything that would cause so many failures so it might be something unrelated to the PR entirely...

@mourner
Copy link
Member

mourner commented Aug 12, 2021

test-render-prod completed successfully so it seems like a temporary fluke, triggered a rerun of the failed render-test job now.

@avpeery
Copy link
Contributor Author

avpeery commented Aug 12, 2021

@mourner thanks so much for your help! FYI - it says per the unit tests that the expectation for the default behavior for closeOnClick should be true, but it was set as false (which I just changed in the recent commit), I also added the extra documentation in src/ui/map.js but wondering if that is unneeded and should I remove? Yes, I'm working on a unit test right now! .... Edited to add: Guess I must have changed the default behavior of closeOnClick myself and forgot as it's not showing up in changes, oops!

@mourner
Copy link
Member

mourner commented Aug 12, 2021

I also added the extra documentation in src/ui/map.js but wondering if that is unneeded and should I remove?

That was a good call, let's keep it — you never know when a user might find something like this useful, and preclick is exposed in Leaflet (and has been for years) so there's a positive precedent.

@avpeery avpeery requested a review from mourner August 12, 2021 20:08
@avpeery avpeery self-assigned this Aug 12, 2021
@avpeery avpeery marked this pull request as ready for review August 12, 2021 20:08
Copy link
Member

@mourner mourner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

@avpeery avpeery merged commit 9c1e1a0 into main Aug 12, 2021
@avpeery avpeery deleted the avpeery/close-on-click branch August 12, 2021 20:23
@SnailBones SnailBones added this to the v2.4.2 milestone Sep 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

closeOnClick behaviour fires before 'click' event
3 participants