If you want to make use of the webapp mode on ios you have to make sure you don't follow normal links otherwise safari will open. Of course there are more reasons to make an application singlepage but this was our main motivation.
Updating URLs
Updating the URLs is a key problem. We still wanted normal URLs to work for copy & paste, crawlers, facebook sharing etc. In desktop browsers we also want the locationbar to update but we didn't like hashes so we only use ajax / singlepage if pushState is available.
On Mobile devices you want to turn off URL updates, because if the user creates a homescreen bookmark you want him to be in your application and not on some deeplink. More on that later.
Using delegates
We never want safari to open except for external links for that we use a delegate to catch all links. In the callback we check what type of link it is, if it's on our page we preventDefault otherwise we let it trough and safari opens.
The code looks something like this:
Y.delegate('click', function (e) { var link = e.currentTarget; if (link.hasClass('singlepageContent')) { e.preventDefault(); singlepage.loadContent(link.getAttribute('href')); } else if (link.hasClass('singlepageLayout')) { e.preventDefault(); singlepage.loadFullpage(link.getAttribute('href')) } else if ('_blank' === link.getAttribute('target')) { //Let it trough… } else { e.preventDefault(); //You have some uncatched links that you should log. } }, 'a');
In the script loading the content we append a queryparameter to the URL so it's easy to identify what type of request it is, but you could also just check if it's an XMLHttpRequest if content replacing is enough for you.
Delivering the content
From the example above you see that we have different options to deliver content. We use classes on the link to decide what to do:
- Replace only the content – used about 90% of the time to show a detailpage etc.
- Replace the whole layout – this is what we do for special pages where the navigation etc. has to be something else than normal.
- Open Safari – Only used for external links identified by
target="_blank"
. - Uncatched link – you should somehow log those so you can fix them asap.
In the templates we check what type of request it is and use a different base template so only the relevant thing get delivered.
Remembering the state
Unfortunately iOS does not support backgrounding for webapps. Everytime the user switches to a different app and comes back it will be loaded from scratch. You want to make sure that you startup fast and that you remember the last state. We just remember the last URL in the localStorage and load it again if the user resumes.
Scripts and Events
On a singlepage you have to take care of freeing memory and detaching events to some extent. Whenever we load a new page we emmit an event so the current page can clean itself up. What we do is:
- Detach global events like window resize
- Destroy unecessary objects so they can get garbage collected
- Purge the DOM