Skip to content

Instantly share code, notes, and snippets.

@kylebarrow
Created June 23, 2011 06:30
Show Gist options
  • Select an option

  • Save kylebarrow/1042026 to your computer and use it in GitHub Desktop.

Select an option

Save kylebarrow/1042026 to your computer and use it in GitHub Desktop.
Prevent links in standalone web apps opening Mobile Safari
<!DOCTYPE html>
<head>
<title>Stay Standalone</title>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<script src="stay_standalone.js" type="text/javascript"></script>
</head>
<body>
<ul>
<li><a href="http://google.com/">Remote Link (Google)</a></li>
<li><a href="javascript:alert('Awesome script is awesome')">JavaScript Link</a></li>
<li><a href="/">Local Link</a></li>
<li><a href="#amp">Local Anchor</a></li>
</ul>
</body>
// Mobile Safari in standalone mode
if(("standalone" in window.navigator) && window.navigator.standalone){
// If you want to prevent remote links in standalone web apps opening Mobile Safari, change 'remotes' to true
var noddy, remotes = false;
document.addEventListener('click', function(event) {
noddy = event.target;
// Bubble up until we hit link or top HTML element. Warning: BODY element is not compulsory so better to stop on HTML
while(noddy.nodeName !== "A" && noddy.nodeName !== "HTML") {
noddy = noddy.parentNode;
}
if('href' in noddy && noddy.href.indexOf('http') !== -1 && (noddy.href.indexOf(document.location.host) !== -1 || remotes))
{
event.preventDefault();
document.location.href = noddy.href;
}
},false);
}
@cseelus

cseelus commented Jan 30, 2018

Copy link
Copy Markdown

@karlingen Awesome, also prevents links where turbolinks="false" is set from opening a new window in those mobile Safari standalone Webapps.

@khovanskiy

khovanskiy commented Mar 16, 2018

Copy link
Copy Markdown

Here is my modification for TypeScript application. Note: The solution supports UI Web View case and target=_blank

static getIOSScope(): string {
    const standalone = (window.navigator as any).standalone;
    const userAgent = window.navigator.userAgent.toLowerCase();
    const safari = /safari/.test(userAgent);
    const ios = /iphone|ipod|ipad/.test(userAgent);
    if (ios) {
        if (!standalone && safari) {
            return 'browser';
        } else if (standalone && !safari) {
            return 'standalone';
        } else if (!standalone && !safari) {
            return 'uiwebview';
        }
    }
    return 'another';
}

static fixIOSLinks() {
    const scope = Utils.getIOSScope();
    if (scope !== 'standalone' && scope !== 'uiwebview') {
        return;
    }
    // _blank links open inside
    const links = document.getElementsByTagName('a');
    for (let i = 0; i < links.length; ++i) {
        if (links[i].getAttribute('target') == '_blank') {
            links[i].removeAttribute('target');
            links[i].setAttribute('data-target', '_blank');
        }
    }
    // not _blank links open outside => iOS is piece of shit
    document.addEventListener('click', function (e) {
        let element: Element = e.target as Element;
        while (!/^(a|html)$/i.test(element.nodeName) && element.parentNode) {
            element = element.parentNode as Element;
        }
        if (element.getAttribute) {
            const href = element.getAttribute('href');
            const target = element.getAttribute('data-target');
            if (target) {
                return;
            }
            const protocol = (element as any).protocol;
            const isHrefDefined = !!href && '#' !== href;
            if (isHrefDefined) {
                const isWebProtocol = !protocol || protocol !== 'tel:';
                const isRelativePath = Utils.isRelativePath(href);
                const pattern = new RegExp("^[a-z][a-z0-9+.-]*:\/\/" + window.document.location.host);
                const isCurrentHost = pattern.test(href);
                if (isWebProtocol && (isRelativePath || isCurrentHost)) {
                    e.preventDefault();
                    window.document.location.assign(href);
                }
            }
        }
    }, false);
}

@ganar

ganar commented May 3, 2018

Copy link
Copy Markdown

@irae @khovanskiy Is there a way to execute on links that load within AJAX content? For instance: I have a featherlight loading AJAX content. Is there a way to prevent links loaded on AJAX to open pdf or XLSX files within the app?

@MovingGifts

Copy link
Copy Markdown

@khovanskiy I think you forgot to include the Utils.isRelativePath(href)function used in your code snippet:

const isRelativePath = Utils.isRelativePath(href);

Can you please include it to complete the solution you were sharing?

@garygrubb

Copy link
Copy Markdown

Could someone please help me with similar code for a HTML form post ?

@aaronhb

aaronhb commented May 10, 2019

Copy link
Copy Markdown

I am trying to find a solution so that i can have it open PDF files or other links open in mobile web browser but all others stay in the PWA. Anyone know how to do this?

I am using the following code

<script>(function(a,b,c){if(c in b&&b[c]){var d,e=a.location,f=/^(a|html)$/i;a.addEventListener("click",function(a){d=a.target;while(!f.test(d.nodeName))d=d.parentNode;"href"in d&&(d.href.indexOf("http")||~d.href.indexOf(e.host))&&(a.preventDefault(),e.href=d.href)},!1)}})(document,window.navigator,"standalone")</script>

@ssfinney

ssfinney commented Jul 1, 2019

Copy link
Copy Markdown

Works for me!

@SarKaa

SarKaa commented Nov 2, 2019

Copy link
Copy Markdown

Is there any way to make this work on iframes. I mean all links opened within the iframe open in the web app?

@justinputney

Copy link
Copy Markdown

This solution appears to launch URLs in a lightbox from the Web App in iOS 13.2. Is anyone else seeing this behavior?

@johnbarratt

Copy link
Copy Markdown

@justinputney Yes, seeing same thing here.

@justinputney

Copy link
Copy Markdown

@johnbarratt Thanks for the confirmation. Let me know if you find a fix where it doesn't trigger a ligthbox.

@johnbarratt

Copy link
Copy Markdown

@justinputney : Just found this, seems to fix it, you just need a bare bones manifest, though it only works for pages added after the manifest was added to the site : https://stackoverflow.com/questions/58210991/peculiar-pwa-bug-on-safari-ios-13-1-2

@justinputney

Copy link
Copy Markdown

@johnbarratt Thanks!

@joe182

joe182 commented Feb 18, 2021

Copy link
Copy Markdown

correct me if I'm wrong, but to prevent links from opening in safari, isn't just the scope the only thing you need to add to your manifest? No javascript, no hacks no nothing just a single line in the json file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment