{"action":"created","issue":{"url":"https://api.github.com/repos/ftlabs/fastclick/issues/392","labels_url":"https://api.github.com/repos/ftlabs/fastclick/issues/392/labels{/name}","comments_url":"https://api.github.com/repos/ftlabs/fastclick/issues/392/comments","events_url":"https://api.github.com/repos/ftlabs/fastclick/issues/392/events","html_url":"https://github.com/ftlabs/fastclick/issues/392","id":71697208,"number":392,"title":"Fastclick.js causes clicks to be lost in leaflet.js","user":{"login":"erjiang","id":321497,"avatar_url":"https://avatars.githubusercontent.com/u/321497?v=3","gravatar_id":"","url":"https://api.github.com/users/erjiang","html_url":"https://github.com/erjiang","followers_url":"https://api.github.com/users/erjiang/followers","following_url":"https://api.github.com/users/erjiang/following{/other_user}","gists_url":"https://api.github.com/users/erjiang/gists{/gist_id}","starred_url":"https://api.github.com/users/erjiang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/erjiang/subscriptions","organizations_url":"https://api.github.com/users/erjiang/orgs","repos_url":"https://api.github.com/users/erjiang/repos","events_url":"https://api.github.com/users/erjiang/events{/privacy}","received_events_url":"https://api.github.com/users/erjiang/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-04-28T20:40:34Z","updated_at":"2015-10-07T20:35:35Z","closed_at":null,"body":"minimal reproduction example jsfiddle (requires device with touch input): https://jsfiddle.net/y723oet0/2/\r\n\r\nObservations: on normal clicks on the map, `this.targetElement = null` in fastclick.js. If the `<a>` element is tapped quickly, then `this.targetElement = <a>`, which causes `onMouse` to reject the next map click.\r\n\r\nI found that adding `this.targetElement = null` to the end of `onTouchEnd()` avoids this problem. Will that cause other problems? So far it seems to work for our application."},"comment":{"url":"https://api.github.com/repos/ftlabs/fastclick/issues/comments/146320081","html_url":"https://github.com/ftlabs/fastclick/issues/392#issuecomment-146320081","issue_url":"https://api.github.com/repos/ftlabs/fastclick/issues/392","id":146320081,"user":{"login":"arkonan","id":365973,"avatar_url":"https://avatars.githubusercontent.com/u/365973?v=3","gravatar_id":"","url":"https://api.github.com/users/arkonan","html_url":"https://github.com/arkonan","followers_url":"https://api.github.com/users/arkonan/followers","following_url":"https://api.github.com/users/arkonan/following{/other_user}","gists_url":"https://api.github.com/users/arkonan/gists{/gist_id}","starred_url":"https://api.github.com/users/arkonan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/arkonan/subscriptions","organizations_url":"https://api.github.com/users/arkonan/orgs","repos_url":"https://api.github.com/users/arkonan/repos","events_url":"https://api.github.com/users/arkonan/events{/privacy}","received_events_url":"https://api.github.com/users/arkonan/received_events","type":"User","site_admin":false},"created_at":"2015-10-07T20:35:35Z","updated_at":"2015-10-07T20:35:35Z","body":"I've also been seeing lost clicks with Leaflet 0.7.3 and Fastclick 1.0.6 on iOS 8.4 and 9.0 Mobile Safari and UIWebViews.  I'm not sure how best to fix the issue but after some debugging I think this is what is happening:\r\n\r\nWhen Fastclick sees a touchend event that it wants to generate a click event for, it does not always clear `this.targetElement` (https://github.com/ftlabs/fastclick/blob/v1.0.6/lib/fastclick.js#L605-L606), presumably because it expects the browser to generate a click event 300ms later and needs to remember to suppress it.  However from my testing on iOS 8.4 and 9 Mobile Safari and UIWebViews, it appears that calling `preventDefault()` on a touchend event prevents the browser-generated click event.  As a result the `onClick()` handler is not called and `this.targetElement` is not cleared.\r\n\r\nNot clearing `this.targetElement` is normally not a problem because the `onTouchEnd()` call to `preventDefault()` suppresses the browser-generated click events, and forged click events have the `forwardedTouchEvent` property set on them (https://github.com/ftlabs/fastclick/blob/v1.0.6/lib/fastclick.js#L307).  In addition, between touchstart and touchend events, `this.trackingClick` is true (https://github.com/ftlabs/fastclick/blob/v1.0.6/lib/fastclick.js#L437) which causes the `onClick()` handler to short circuit (https://github.com/ftlabs/fastclick/blob/v1.0.6/lib/fastclick.js#L684-L688).  \r\n\r\nUnfortunately Leaflet blocks propagation of touch events on callouts and pins. In some versions it also blocks click events.  Because Fastclick listens for clicks in the event capturing phase and touch events in the event bubbling phase, if you have Fastclick attached to a parent of the map (e.g. `document.body`) it will only see the click events for Leaflet pins and callouts, not the corresponding touchstart and touchend events.\r\n\r\nThe lost clicks occur if there is a touchstart, touchend and click handled by FastClick on an element outside the map, followed by a click event on a map pin or callout.   When the user taps on the map pin/callout, Fastclick's `onClick()` handler will be called with `this.targetElement` still set to the element outside the map.  Fastclick doesn't realize the event is for a different target, sets `this.targetElement` to null (https://github.com/ftlabs/fastclick/blob/v1.0.6/lib/fastclick.js#L699) and returns false, canceling the Leaflet click event.  Because `this.targetElement` is now null, subsequent clicks on the map work.\r\n\r\n\r\nWhat I ended up doing was to add a second touchstart handler on the event capture phase.  This handler behaves basically the same as `onTouchCancel()` and resets `this.targetElement` and `this.trackingClick`.  Because this handler runs on the capture phase it cannot be blocked by Leaflet.  The reason I'm not providing a pull request is that I'm not sure that there isn't a race condition where rapidly tapping on some browsers might result in extra clicks sneaking through.  For my use case that isn't nearly as big a problem as the lost clicks.\r\n\r\nAnother possible approach would be to verify that the click event's `event.target` still corresponds to `this.targetElement`.  However I'm guessing the reason the code doesn't do that already is that the target of the click event isn't reliably the same as the one from the touchstart event on all browsers."}}