Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stay in iOS Safari's standalone mode when navigating

When in iOS' standalone web app modus, and you click a link, that link is opened in Mobile Safari instead of staying in the standalone modus. This makes no sense to me (at least for internal links).

The only way I can think of fixing this is adding a click handler to the document node, and manually navigating like this:

if (window.navigator.standalone) {
  document.addEventListener('click', (e) => {
    if (e.target.tagName === 'A') {
      e.preventDefault();
      window.location = e.target.getAttribute('href');
  });
}

Is there a less hacky way of obtaining this behavior? This really hurt my eyes.

like image 627
Kris Selbekk Avatar asked Apr 30 '17 21:04

Kris Selbekk


1 Answers

Unfortunate something along those lines is the standard way to do it. irae on GitHub has put together a script called Stay Standalone that will handle all the dirty work for you and is tested on a variety of edge cases. Although the script is a bit older, it does work on modern version of iOS.

It might be a bit ugly, but the code is resilient and can be included in a general Javascript bundle. It won't change the behavior for other scenarios. This is just speculation, but the reason I think Apple opted for this behavior is that standalone web apps have no forward or back buttons and clicking a link could put the app in an "unusable" state and for websites not full intended to be apps. This is probably the most desirable behavior in the general case for the end user.

Here is a copy of the Javascript:

(function(document,navigator,standalone) {
    // prevents links from apps from oppening in mobile safari
    // this javascript must be the first script in your <head>
    if ((standalone in navigator) && navigator[standalone]) {
        var curnode, location=document.location, stop=/^(a|html)$/i;
        document.addEventListener('click', function(e) {
            curnode=e.target;
            while (!(stop).test(curnode.nodeName)) {
                curnode=curnode.parentNode;
            }
            // Condidions to do this only on links to your own app
            // if you want all links, use if('href' in curnode) instead.
            if(
                'href' in curnode && // is a link
                (chref=curnode.href).replace(location.href,'').indexOf('#') && // is not an anchor
                (   !(/^[a-z\+\.\-]+:/i).test(chref) ||                       // either does not have a proper scheme (relative links)
                    chref.indexOf(location.protocol+'//'+location.host)===0 ) // or is in the same protocol and domain
            ) {
                e.preventDefault();
                location.href = curnode.href;
            }
        },false);
    }
})(document,window.navigator,'standalone');

You can see the tests here.

like image 52
Alec Gorge Avatar answered Nov 11 '22 14:11

Alec Gorge