turbolinks / turbolinks-classic

Classic version of Turbolinks. Now deprecated in favor of Turbolinks 5.
MIT License
3.54k stars 428 forks source link

Touch event 'passes through' to the next page when using the transition cache #646

Closed gregblass closed 8 years ago

gregblass commented 8 years ago

I'm using Turbolinks 3.0 on iOS with Fastclick to remove the 300ms iOS delay, with the transition cache enabled. This provides a really great/instant experience with Rails on mobile devices

I have a link on both pages in the same place, and when I press the link on one page, fastclick+turbolinks loads the next page instantly - but the event passes through to the next page and the link on that page gets clicked too, triggering both links and navigating pages twice.

The event will actually pass through to anything thats in the same place (if I click a link and a form input is on the same place on the next page loaded, it will focus on the input).

I can actually do a 'faster tap' with my finger to prevent it from happening. Its only when the tap is more sluggish (it lasts longer) that it happens.

Any help or insight would be greatly appreciated!

gregblass commented 8 years ago

After tons of depressing debugging and thinking over the past few days, this solution seems to work (but is very hack-ish):

JS:

 $(document).on("page:restore", function() {
   $("body").prepend("<div id='ghost-blocker' onclick='return false;'></div>");
   setTimeout(function() {
     $("#ghost-blocker").remove();
    }, 300);
  });

CSS:

 #ghost-blocker {
   position: absolute;
   left: 0;
   right: 0;
   height: 100%;
   width: 100%;
   z-index: 999;
 }

I basically debugged all the callbacks with alerts and saw that the last thing that happened after loading the page from the cache but before the ghost click fired was the page:restore function. I made a blocker div that covers the whole screen and cancels out any click event, then removed it 300ms later. This does the job, albeit sloppily. The page:restore callback is also a great time to reset the page in any other way that you need, such as resetting loader images that were left over (I'm using ladda).

I'm now going to try to dive deeper and attempt to catch the ghost click event and prevent it from happening instead of manipulating the DOM with a whole div.

I'd love to hear if anyone has any ideas as to how I could cancel out the click that is passing through in a more programatic way instead of shoving a whole blocker div into the dom and then removing it. And I'd really like to hear the opinions on some of the core team here...I think the bigger issue is that most companies are not using turbolinks with the transition cache enabled + fastclick. Github itself is using Turbolinks, but not fastclick...I'd love to hear why. Perhaps this issue?

gregblass commented 8 years ago

It seems like most companies aren't using fastclick in production for their mobile responsive app - or if they are, its not in conjunction with turbolinks.

Most seem to roll out separate hybrid or native apps for a great mobile experience. I guess I'll go the same route. Ionic seems awesome.

gregblass commented 8 years ago

Blahhhhhhhhh.

Just tested on a slower android phone and this hack isn't working.

I am now learning angular/ionic to make real hybrid apps and will disable fastclick completely on the mobile website side due to its compatibility issues with turbolinks.

Eagerly awaiting turbolinks 5!

gregblass commented 8 years ago

This is no longer an issue with Turbolinks 5. Also, fastclick is basically no longer necessary since iOS 9.3 was released yesterday and supports touch-action:manipulation. Overall Turbolinks 5 is amazing IMO, and there is no reason that I can see to still be using 3.