-
-
Save kylebarrow/1042026 to your computer and use it in GitHub Desktop.
<!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); | |
} |
Did a simple test and it still work in IOS 11.2 Beta. Thanks!
Here is a modification for rails applications wanting their data-remote="true"
links to work as well. In coffeescript:
$(document).ready ->
# For iOS Web apps, so they do not open in new window
if 'standalone' of window.navigator and window.navigator.standalone
# If you want to prevent remote links in standalone web apps opening Mobile Safari, change 'remotes' to true
noddy = undefined
remotes = false
document.addEventListener 'click', ((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' and noddy.nodeName != 'HTML'
noddy = noddy.parentNode
if 'href' of noddy and noddy.href.indexOf('http') != -1 and (noddy.href.indexOf(document.location.host) != -1 or remotes)
event.preventDefault()
# do not redirect page on data-remote links
(document.location.href = noddy.href) unless $(noddy).data('remote') == true
return
), false
@karlingen Awesome, also prevents links where turbolinks="false"
is set from opening a new window in those mobile Safari standalone Webapps.
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);
}
@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?
@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?
Could someone please help me with similar code for a HTML form post ?
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>Works for me!
Is there any way to make this work on iframes. I mean all links opened within the iframe open in the web app?
This solution appears to launch URLs in a lightbox from the Web App in iOS 13.2. Is anyone else seeing this behavior?
@justinputney Yes, seeing same thing here.
@johnbarratt Thanks for the confirmation. Let me know if you find a fix where it doesn't trigger a ligthbox.
@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
@johnbarratt Thanks!
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.
Example Link:
<a onclick="return confirm('Really want to proceed?')" href="/reservation/cancel/1">Cancel</a>
Any idea to solve it?