-
Notifications
You must be signed in to change notification settings - Fork 145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Does not work with Ipad/Iphone #34
Comments
Unfortunately Mobile Safari does not support "beforeunload". The only way I can think of to get partial support would be to "intercept" all possible page exist events on the page (e.g. URL clicks, form submits, etc.) and manually fire off a beforeunload event. There is some discussion on the issue here: Adding code like this to support this I think would run contrary to the project's light-weight goal. I hope Apple offer support for this one day! I'll leave this issue open and see what other ideas/enthusiasm exists. Cheers, Chris |
Hi Chris,
----------------------- Original |
Thanks for the pull-request. I've taken a quick look and can see what you're doing. I'm keen to keep the code very lightweight and adding a workaround/hack for this rubs a little the wrong way. My thinking at the moment is to use a "shim" approach and make the changes outside the main jquery.Are-You-Sure code. What I'm think is that we can write a shim that "emulates" the beforeunload event using the method you've used. You'd enabled this by simply adding an extra script to your page. e.g. <script src="/scripts/jquery.are-you-sure.js"></script>
<script src="/scripts/jquery.are-you-sure.beforeunload-shim.js"></script> The beforeunload-shim would:
Here is some code I've mocked up: New file $(function() {
if (!navigator.userAgent.toLowerCase().match(/iphone|ipod|ipad/)) {
return;
}
$('a').bind('click', function(evt) {
var href = $(evt.target).attr('href');
if (href !== undefined && !(href.match(/^#/) || href.trim() == '')) {
var ret = {};
$.when($(window).trigger('ays-beforeunload', ret))
.done(function() {
if (ret.message) {
var msg = ret.message + "\n\nPress OK to leave the page or Cancel to return."
if (confirm(msg)) {
window.location.href = href;
}
} else {
window.location.href = href;
}
});
return false;
}
});
}) This change that need to be made to the Are-You-Sure main code are very minimal:
e.g. $(window).bind('beforeunload ays-beforeunload', function(evt, ret) {
$dirtyForms = $("form").filter('.' + settings.dirtyClass);
if ($dirtyForms.length > 0) {
if (ret) {
ret.message = settings.message;
}
return settings.message;
}
}); I'd welcome your thoughts. |
In terms of keeping the code lightweight (at least in execution), I doubt that a shim is any faster than inline code. It is unlikely that load or execute times would be much different whether the shim is included or not, especially if the code is minified. I don't have any philosophical problem with an external "shim" and it might be better in terms of separating the code to handle weird browser bugs. However, it's hard to know in advance if you will be running on a platform that needs the shim. An external module would certainly make more sense with large modules, but even with my additions, the total code size is still small and could hardly be called bloated. The reason I needed a solution like yours was due to strange problems we were having with customer-filled forms that were incomplete. For several weeks, we could never duplicate the problem. Finally, I decided to go through the server logs and discovered that we only had problems with customers who were using an Ipad to fill out the form. They swore they filled it out correctly, but apparently they navigated away or never clicked the "Submit" button at the bottom of the page. The current jquery.validate and other jquery code had no way of detecting that they had left, which resulted in incomplete forms. I guess Ipad users expect to use magic widgets which automatically save stuff without ever needing to hit the "Submit" button. We're planning to redo our forms to be mobile-friendly, but until then we need a quick solution to our problem. After testing with users, I added the "doubleConfirm" option. Too many users were confused with the confirm() prompts and would click "OK" when they actually wanted to stay. I also put in the hook for jquery.validate (it works only if jquery.validate is loaded), to prevent them from exiting if there are errors. Your original code was bypassing jquery.validate. In this case, I think an "all-in-one" solution is better. Unless you are running in a closed environment, you cannot know what kind of device or browser that your customer will be using. Whatever you do, please note that you need the My solution is certainly not bulletproof and there are probably other browser quirks that may cause it to fail. But I believe it is a good start, especially when compared to many of the overly-complicated (and many non-working) solutions I found. I tested my code on several Apple mobile devices (Ipad and Iphone) and it seems to work on all of them. If you have an Ipad, I suggest you test things yourself before deciding which way to go. |
Also, I'm not sure if your I'll have to test your code to make sure. |
My reference to "lightweight" is more around code maintainability/simplicity rather than execution speed. My gut-feel is that eventually Apple will fix this in the future and it would be nice to not have this crufty code sitting around! I agree with your point that you can't anticipate the browser people are hitting your form with. You're right. Maybe the shim should live in the plugin's (but still abstracted so it's not cluttering the code). Let me sleep on this for a bit and I'll think about the best way to do it. Also thanks for the tip on the .closest('a'). I never thought about that :-) |
I don't like crufty code either, but sometimes practicality outweighs the desire for elegance. Don't know how long it will take Apple to fix the problem, it appears to have been around for quite a while. All the Apple browsers (Chrome, Dolphin, Safari) I tried must use the same code base, because they all have the same bug. Abstracting the code is fine. I only took a couple hours to merge my fixes, so I didn't have time to fully understand your architecture. I learned about the "closest('a')" after wasting a lot of time trying to make it work with all kinds of links. I was trying to write Javascript to parse the link and extract the href when I discovered the "closest()" method. |
Supported added in 1.7 (currently on 1.7-dev branch) |
I was wondering why on this workaround you are forcing the event to change the window location redirecting to the desired link if you click 'ok' and confirm you want to navigate away from the page. In my application I have a number of links where I prevent the default event, but since this workaround is listening to all A clicks it get fired all times.
Is clear that I'm going to have a custom action on this element, and so I don't want the browser to be redirected to another page, but with your workaround this is ignored and I get redirected when I confirm I want to leave the page, or even worse if the plugin is not even running (f.i. we are in a page without forms). A quick fix is just to remove the last 2 lines from the shim:
This way we are not forcing the redirect, and not stopping the link from doing it's default action. |
Landed here trying to find a solution for this problem, except the use-case I have is forcing a form submission when the user leaves a page (internal company skill assessments) but specifically related to tab closure and native-app webview viewports. Our client would like this application to be accessible from company issued iPads running an off-the-shelf shell app that can load and navigate custom content using webview. But we noticed that the shell app's "back" and "home" buttons will allow navigation away from the assessment pages without either confirmation OR forced submission of a (probably failing) test. The same thing occurs in mobile safari by closing a tab. The only other solution I've run across is window.onpopstate, which also is ignored/skilled by Mobile Safari in this situation. |
It's a hard problem to solve. I haven't really come up with anything better for iOS. Back and Tab-closing actions can't be intercepted and preempted on iOS. It's an Apple design decision. If you're in native code, there may be some ways around this, however this is not an area I have much expertise in. |
Thanks for the reply! |
My usage requirement is slightly different. I would like to save data to isolated storage on before unload. I am going to have a look at the code, but wanted to see if you thought this was possible with your code base. *** Update *** The code does offer some interesting functionality for the defined scenario. Thanks for sharing with the community... |
Has anyone figured out how to make this work with Ipad/Iphone browsers?
They do not handle the 'beforeunload' event properly and I've been beating my head trying to figure out how to issue a message if anything in the form changes. I tried your module and used 'pagehide' instead of 'beforeunload', but it did not work.
The text was updated successfully, but these errors were encountered: