views:

979

answers:

3

In a web app I'm working on, I'm capturing onBeforeUnload to ask the user whether he really wants to exit.

Now, if he decides to stay, there are a number of things I'd like to do. What I'm trying to figure out is that he actually chose to stay.

I can of course declare a SetTimeout for "x" seconds, and if that fires, then it would mean the user is still there (because we didn't get unloaded). The problem is that the user can take any time to decide whether to stay or not...

I was first hoping that while the dialog was showing, SetTimeout calls would not fire, so I could set a timeout for a short time and it'd only fire if the user chose to stay. However, timeouts do fire while the dialog is shown, so that doesn't work.

Another idea I tried is capturing mouseMoves on the window/document. While the dialog is shown, mouseMoves indeed don't fire, except for one weird exception that really applies to my case, so that won't work either.

Can anyone think of other way to do this?

Thanks!


(In case you're curious, the reason capturing mouseMove doesn't work is that I have an IFrame in my page, containing a site from another domain. If at the time of unloading the page, the focus is within the IFrame, while the dialog shows, then I get the MouseMove event firing ONCE when the mouse moves from inside the IFrame to the outside (at least in Firefox). That's probably a bug, but still, it's very likely that'll happen in our case, so I can't use this method).

A: 

Why not just use the method that StackOverflow does, where you get a popup box that lets you make the choice:

Are you sure you want to navigate away from this page?

You have started writing or editing a post.

Press OK to continue, or Cancel to stay on the current page

Then it doesn't matter how long they take. If they click one button, they leave. If they click the other, they stay.

Chad Birch
I AM doing that. But I want to do some stuff once they stayed, ONLY IF they stayed. I'm basically letting the server know that they did stay, which means that the unload was caused by something trying to get out of an IFrame, and not by them closing the window. This lets me log possible causes for the unload, which I can later do stuff about. But I only want to do this IF they stayed, I want to be sure that they stayed before notifying the server.
Daniel Magliola
So use the "I want to stay" button-click in the popup to trigger the execution of the "stuff". Maybe I'm not understanding the problem.
Chad Birch
Hmmm, the "i want to stay" button belongs to the browser, not to me. I can't touch it or do anything to it, it's a standard dialog that I can't interact with at all.And as far as I know, there is no specific event in the window/document that triggers when the user decides to stay.
Daniel Magliola
Well, assuming it's a confirm() dialog like SO uses, you can use the return value of the confirm() call to determine which button they clicked. I'm not 100% sure offhand, but I believe if they click "OK", you get a return of true, and if they click "Cancel" it returns false. So you can then process that to take your actions.
Chad Birch
If it's a confirm() dialog, then it's not what i'm using. Basically, the only way to keep the page from unloading it to return some string in the onBeforeUnload event, and that string will be shown to the user in a custom dialog.I guess i *could* show a confirm() dialog, but whatever they answer there wouldn't stop the page from being unloaded...
Daniel Magliola
Hmm, maybe you can do some digging into SO's javascript to see how they're using that dialog. It's seemed to work well all the times I've tried to leave/close the page when I've already started writing something. And they obviously have some way to stop you from leaving the page if you click Cancel.
Chad Birch
+1  A: 

What I ended up doing was hooking into the click event for my document, and once I received a click I considered the user had stayed.

It's not a good solution, in most cases (if you are a DiggBar) you'll have lots of false negatives (people will have stayed and you'll never know it), but in our case it made perfect sense, because people interact heavily with our site, not only with the framed sites.

Esentially, my code does this...

function OnBeforeUnload() {
    Event.observe(document, "click", UserStayed);
    if (IConsiderTheIFrameMightBeTryingToPopOut) {
        return "The site is trying to escape. Do you want to stay?";
    }
}

function UserStayed() {
Event.stopObserving(document, "click", UserStayed);
    // New we know the user is still with us for sure.
}
Daniel Magliola
A: 

I want to know exactly how to do the same thing after a form.submit() is fired.

I have to try/catch the form.submit, because sometimes in some browsers, an "unspecified" exception may be thrown if the user cancels.

Basically what is needed is an onnotunloaded event, but there is not one. This is causing me big problems.

Also, if you are returning a string from onunbeforeunload to generate the question, each browser presents the dialogue box differently. IE and Firefox add a question after your message, Chrome does not (and offers yes no buttons), so you may want to use something like:

return 'You have unsaved changes.' + ((navigator.userAgent.toLowerCase().indexOf('chrome') == -1) ? '' : '\n\nDo you really want to leave this page?');

One final irritation is that, in my case, if the script detects there are no unsaved changes, it just uses return so no dialogue is presented. My IDE warns of inconsistent return statements (one with, one without a value)

Steve Waring