window.onbeforeunload not working on the iPad? - javascript

Does anyone know if the onbeforeunload event is supported on the iPad and/or if there's a different way to use it?
I've tried pretty much everything, and it seems like the onbeforeunload event is never triggered on the iPad (Safari browser).
Specifically, this is what I've tried:
window.onbeforeunload = function(event) { event.returnValue = 'test'; }
window.onbeforeunload = function(event) { return 'test'; }
(both of the above together)
window.onbeforeunload = function(event) { alert('test')'; }
(all of the above functions but inside <body onbeforeunload="...">
All of these work on FF and Safari on the PC, but not on the iPad.
Also, I've done the following just after loading the page:
alert('onbeforeunload' in window);
alert(typeof window.onbeforeunload);
alert(window.onbeforeunload);
Respectively, the results are:
true
object
null
So, the browser does have the property, but for some reason it doesn't get fired.
The ways I try to navigate away from the page are by clicking the back and forward buttons, by doing a google search in the top bar, by changing location in the address bar, and by clicking on a bookmark.
Does anyone have any idea about what's going on? I'd greatly appreciate any input.
Thanks

This bit of JavaScript works for me on Safari and Chrome on ipad and iphone, as well as desktop/laptop/other browsers:
var isOnIOS = navigator.userAgent.match(/iPad/i)|| navigator.userAgent.match(/iPhone/i);
var eventName = isOnIOS ? "pagehide" : "beforeunload";
window.addEventListener(eventName, function (event) {
window.event.cancelBubble = true; // Don't know if this works on iOS but it might!
...
} );

I have found that the onunload() event does fire. It's behavior is somewhat odd; whatever you have in your callback function attached to the event is actually run after the new page has loaded in the background (You can't tell it's loaded yet, but server logging will show that it has).
More oddly, if you have a confirm() call in your onunload(), and the user has clicked a link to go somewhere else, you are in business. If, however, the user closes the iPad Safari browser tab, the onunload() event will fire, but your confirm() will have an implicit cancel as response.

Only Apple would know for sure, but my guess is that they purposely did not enable that functionality in mobile Safari because it is most often used by shady characters to get you to stay on their site or pop up lots of porn/advertising windows.

There's a known bug in WebKit with onbeforeunload. I believe it's fixed in the latest beta of Chrome 5, but it's quite possible the iPad's browser is made from a version of WebKit that doesn't have the fix.
Related Chrome bug report.

beforeunload event is not supported by Mobile Safari. You can see the list of all supported events here: Handling Events Apple documentation
And the beforeunload is not in the list!

https://code.google.com/p/chromium/issues/detail?id=97035
see hear.
alerts are no longer allowed during page dismissal events (beforeunload, unload, pagehide).
I think alerts, prompt, confirm, and other actions like these are also no longer allowed.

Here's a solution that should work on all modern browsers:
var unloaded = false;
window.addEventListener("beforeunload", function(e)
{
if (unloaded)
return;
unloaded = true;
console.log("beforeUnload");
});
window.addEventListener("visibilitychange", function(e)
{
if (document.visibilityState == 'hidden')
{
if (unloaded)
return;
unloaded = true;
console.log("beforeUnload");
}
});
Mobile browsers don't tend to not support beforeunload because the browser can go into the background without unloading the page, then be killed by the operating system at any time.
Most desktop browser contain a bug that causes visibilityState to not get called when the document unloads. See: here.
Therefore, it's important to include both events to cover all scenarios.
NB
I have used console.log instead of alert in my example because alert will get blocked by some browsers when called from beforeunload or visibilitychange.

If you just need to know if the page has been left you can use document.unload. It works fine in ios browsers. If you see on Apple documentation you'll find that it's deprecated and they recommend to use document.pagehide

Related

Javascript code inside beforeunload callback not working in Safari

I have added code to change web page color on beforeunload event:
window.onbeforeunload = function (){
$('.navbar-collapse').css({background: 'blue'});
console.log("Hello unload");
return null;
}
This code works properly on Chrome and Firefox but it doesn't work on Safari browser.
However, when I debug this code in Safari, when stepping over each line of code in the callback function, id DOES changes background color.
When I navigate by clicking on an url on page and then click back button on browser, the background color is changed.
Any idea?
window.onbeforenload is "magic" in the sense that it is special and more and more browsers are restricting what it can do.
Some browsers will let you display a custom message, other browers are free to ignore this event entirely.
In short: Don't try to do anything but return a null or non-null value and hope for the best. It is out of your hands.
You might want to see this answer too: window.onbeforeunload and window.onunload is not working in Firefox , Safari , Opera?

Eliminate 300ms delay on click events in mobile Safari

I've read that mobile Safari has a 300ms delay on click events from the time the link/button is clicked to the time the event fires. The reason for the delay is to wait to see if the user intends to double-click, but from a UX perspective waiting 300ms is often undesirable.
One solution to eliminate this 300ms delay is to use jQuery Mobile "tap" handling. Unfortunately I'm not familiar with this framework and don't want to load some big framework if all I need is a line or two of code applying touchend in the right way.
Like many sites, my site has many click events like this:
$("button.submitBtn").on('click', function (e) {
$.ajaxSubmit({... //ajax form submisssion
});
$("a.ajax").on('click', function (e) {
$.ajax({... //ajax page loading
});
$("button.modal").on('click', function (e) {
//show/hide modal dialog
});
and what I'd like to do is to get rid of the 300ms delay on ALL those click events using a single code snippet like this:
$("a, button").on('tap', function (e) {
$(this).trigger('click');
e.preventDefault();
});
Is that a bad/good idea?
Now some mobile browsers eliminate 300 ms click delay if you set the viewport. You don't need to use workarounds anymore.
<meta name="viewport" content="width=device-width, user-scalable=no">
This is currently supported Chrome for Android, Firefox for Android and Safari for iOS
However on iOS Safari, double-tap is a scroll gesture on unzoomable pages. For that reason they can't remove the 300ms delay. If they can't remove the delay on unzoomable pages, they're unlikely to remove it on zoomable pages.
Windows Phones also retain the 300ms delay on unzoomable pages, but they don't have an alternative gesture like iOS so it's possible for them to remove this delay as Chrome has. You can remove the delay on Windows Phone using:
html {
-ms-touch-action: manipulation;
touch-action: manipulation;
}
Source: http://updates.html5rocks.com/2013/12/300ms-tap-delay-gone-away
UPDATE 2015 December
Until now, WebKit and Safari on iOS had a 350ms delay before single taps activate links or buttons to allow people to zoom into pages with a double tap. Chrome changed this a couple of months ago already by using a smarter algorithm to detect that and WebKit will follow with a similar approach. The article gives some great insights how browsers work with touch gestures and how browsers can still get so much smarter than they are today.
UPDATE 2016 March
On Safari for iOS, the 350 ms wait time to detect a second tap has been removed to create a “fast-tap” response. This is enabled for pages that declare a viewport with either width=device-width or user-scalable=no. Authors can also opt in to fast-tap behavior on specific elements by using the CSS touch-action: manipulation as documented here (scroll down to the 'Styling Fast-Tap Behavior' heading) and here.
This plugin -FastClick developed by Financial Times does it perfectly for you!
Make sure though to add event.stopPropagation(); and/or event.preventDefault(); directly after the click function, otherwise it might run twice as it did for me, i.e.:
$("#buttonId").on('click',function(event){
event.stopPropagation(); event.preventDefault();
//do your magic
});
i know this is old but can't you just test to see if "touch" is supported in the browser? Then create a variable that's either "touchend" or "click" and use that variable as the event that gets bound to your element?
var clickOrTouch = (('ontouchend' in window)) ? 'touchend' : 'click';
$('#element').on(clickOrTouch, function() {
// do something
});
So that code sample checks to see if the "touchend" event is supported in the browser and if not then we use the "click" event.
(Edit: changed "touchend" to "ontouchend")
I've come across a hugely popular alternative called Hammer.js (Github page) which I think is the best approach.
Hammer.js is a more full-featured touch library (has many swipe commands) than Fastclick.js (most upvoted answer).
Beware though: scrolling fast on mobile devices tends to really lock up the UI when you use either Hammer.js or Fastclick.js. This is a major problem if your site has a newsfeed or an interface where users will be scrolling a lot (would seem like most web apps). For this reason, I'm using neither of these plugins at the moment.
Somehow, disabling zoom seems to disable this small delay. Makes sense, as double-tap isn't needed anymore then.
How can I "disable" zoom on a mobile web page?
But please be aware of the usability impact this will have. It may be useful for webpages designed as apps, but shouldn't be used for more general-purpose 'static' pages IMHO. I use it for a pet project that needs low latency.
Unfortunately there is no easy way to do this. So just using touchstart or touchend will leave you with other problems like someone starts scrolling when click on on a button for example. We use zepto for a while, and even with this really good framework there are some issues that came up over the time. A lot of them are closed, but it seems is not a field of simple solution.
We have this solution to globally handle clicks on links:
$(document.body).
on('tap', 'a',function (e) {
var href = this.getAttribute('href');
if (e.defaultPrevented || !href) { return; }
e.preventDefault();
location.href= href;
}).
on('click', 'a', function (e) {
e.preventDefault();
});
I searched for an easy way without jquery and without fastclick library. This works for me:
var keyboard = document.getElementById("keyboard");
var buttons = keyboard.children;
var isTouch = ("ontouchstart" in window);
for (var i=0;i<buttons.length;i++) {
if ( isTouch ) {
buttons[i].addEventListener('touchstart', clickHandler, false);
} else {
buttons[i].addEventListener('click', clickHandler, false);
}
}
In jQuery you can bind "touchend" event, witch trigger code inmediatly after tap (is like a keydown in keyboard). Tested on current Chrome and Firefox tablet versions. Don't forget "click" also, for your touch screen laptops and desktop devices.
jQuery('.yourElements').bind('click touchend',function(event){
event.stopPropagation();
event.preventDefault();
// everything else
});
Just to provide some extra information.
On iOS 10, <button>s on my page could not be triggered continuously. There was always a lag.
I tried fastclick / Hammer / tapjs / replacing click with touchstart, all failed.
UPDATE: the reason seems to be that the button is too close to the edge! move it to near the center and lag gone!
You're supposed to explicitly declare passive mode :
window.addEventListener('touchstart', (e) => {
alert('fast touch');
}, { passive : true});

preventDefault blocks right-click menu in Firefox on Mac but not Windows

I have a web application in which I have hooked mouse up and mouse down events; I use them for selection and manipulation of the graphical language for which my application is an editor. To prevent the right-click/context menu supplied by Firefox from showing up, I've placed:
if (evt.preventDefault) {
evt.preventDefault();
}
at the top of each of my mouse up and mouse down event handlers. I don't want to return false; I actually want the event to propagate.
On the Mac, the right-click menu doesn't show up; this is what I expect. On Windows, however, it stubbornly appears, even though Firebug confirms that my call to "preventDefault" is occurring and likewise "defaultPrevented" gets set to true.
Any idea what gives? Has anyone else run across this problem? I'm running Firefox 6.0.2 on both the Mac and Windows.
[Update: more recent versions of Firefox yielded consistent results on Mac and Windows: the context menu failed to be suppressed on both platforms.]
Okay. After putting this aside and returning to it several times, I finally found the solution.
Attempting to deal with the appearance of the context menu in the various mouse listeners appears to be fundamentally flawed. Instead, thanks to code I found here, I was put on the scent of the contextmenu event. That event appears to be the right way to handle things, although the code actually posted on that site didn't do the trick — merely calling "stopPropagation" and returning false was insufficient.
The following worked for me:
element.addEventListener('contextmenu', function(evt) {
evt.preventDefault();
}, false);
This has been tested with Firefox 10.0 on a Mac and Firefox 9.0.1 and 10.0 on Windows 7.
This option is removed in Mozilla's 23rd version.
Go to Tools > Options.
Go to the Content tab.
Click Advanced button next to Enable JavaScript option.
Disable or replace context menus. Check this box and it will magically work again.
There is no way to get around this setting in JavaScript.

window.open no longer works when called in the onunload event handler in IE9

In my web application, I launch a desktop application using a custom url protocol. For example: "fakeproto://" will launch "fakeproto.exe" on your desktop. If you don't know what I'm talking about, read this: Registering an Application to a URL Protocol
I needed a way, though, to make sure "fakeproto.exe" was installed on the user's PC before attempting to launch. It's a bit of a hack, but I got it to work for all the major browsers. IE presented the most problems and had a unique implementation.
In Javascript, I would first try to load the custom url protocol:
window.open('fakeproto://', '_self');
Before this, I actually defined the following onunload event handler:
window.onunload = function()
{
window.open('help.php', '_self');
}
So if the desktop didn't recognize the custom url protocol, IE would simply leave the current page and go to "webpage cannot be displayed". In this event, the onunload event handler would fire and open help.php instead.
This works great in IE7 & IE8, but once I upgraded to IE9, this no longer works? It goes to "webpage cannot be displayed" instead of help.php.
Using a debugger, the onunload event handler is firing and the code is being executed correctly, but for some reason the window.open call isn't working??? I disabled the pop-up blocker as well, to make sure it wasn't that. No luck.
Anyone have any ideas? Anyone hear of IE9 being more strict with window.open? Anyone know of any alternative solutions to the original problem?
BTW, I can get it to work if I open help.php to a new window.
window.onunload = function()
{
window.open('help.php', '_blank');
}
But this only works if any pop-up blockers are disabled. I would like to avoid using this solution.
Yes, IE9 blocks navigations in the onunload handler.

Javascript register window/tab closing event before window/tab close

This has / may have been asked before, but, as far as I remember, the question was not satisfactory answered at that time ^^
How can I register a window or tab closing event with Javascript? I have tried body.onclose and body.onunload, and dozens others whose names I made up myself and thought they might possibly exist, but none of it worked, or, if it did, it only fired after the window or tab has been closed.
Question:
Is there any way to register such an event before the window or tab has been closed? It needn't even be compatible with all browsers, as long as it works with Firefox.
window.onbeforeunload= …;.
window.onbeforeunload = function (e) {
var e = e || window.event;
// For IE and Firefox
if (e) {
e.returnValue = 'Any string';
}
// For Safari
return 'Any string';
};
WE don't have Onclose but we have OnbeforeUnload. Even I am looking for same event but no luck.
Unload and beforeUnload have negative effects on the "page cache" (also known as the "back forward cache"). This is a special cache that preserves some extra state when you navigate away from the page, so that it can be seamlessly resotred when you navigate 'back' (or unclose a tab). If you've ever wondered why some form fields keep their contents when you click back and some don't - this is often part of the reason.
You should probably take a look at the "pageshow" and "pagehide" events in Firefox and
WebKit. IE doesn't have a page cache equivalent, so in that environment you should be fine to use before/unload. Despite Opera's early concerns, pageshow and pagehide made it into the HTML5 Spec

Categories