7

I've got a game that runs in the web browser (as a plugin) and what I'm trying to do is:

  1. Detect if the user has decided to close the browser (Alt+F4, hitting the 'X' button etc)

  2. Prevent the browser from closing whilst we fire a call to our web services to log that the user has closed the browser

  3. Once we receive the response from the web services, release the lock and allow the browser to close as requested.

The main reason we want to do this is we're having some concurrency problems and going through our logs we want to isolate people logging out / closing the browser from genuine instances where the plugin has crashed.

I looked into doing this with JQuery (for X-Browser compatability - Opera won't work but we don't have any users on Opera anyway thankfully):

$(window).bind('beforeunload', function(e) {
    e.preventDefault();
    // make AJAX call
});

The problem is that this displays a confirmation dialog to the user ('Are you sure you want to leave this page') which the user might confirm before the AJAX call is sent.

So the question is, is there a way of preventing the browser from closing until the response is received? Also 'beforeunload' fires when the page is changed as well - is there a way of distinguishing clicking on a link from actually clicking close?

Grateful for any help wrt to this!

csdev86
  • 83
  • 1
  • 1
  • 5
  • Just out of curiosity... is there any difference if you swap the "preventDefault" and the "make ajax call" parts? – hugomg Jan 05 '12 at 13:34

4 Answers4

7

Its tricky business to avoid the browser window from beeing closed. Actually, there is no way to do that, beside returning a non-undefined value from the onbeforeunload event, like you described.

There is one possible suggestion I can make, that is creating a synchronized ajax request within the onbeforeunload event. For instance

window.onbeforeunload = function() {
    $.ajax({
        url: '/foo',
        type: 'GET',
        async: false,
        timeout: 4000
    });
};

In theory, this will block the browser for a maximum of 4 seconds. In reality, browsers will treat this differently. For instance, Firefox (I tested it on 9), will indeed not close the window immediately, but it also does not respect the timeout value there. I guess there is an internal maximum of like 2 seconds before the request is canceled and the window/tab gets closed. However, that should be enough in most cases I guess.

Your other question (how to distinguish between clicking a link), is fairly simple. As described above, onbeforeunload looks what is getting returned from its event handlers. So lets assume we have a variable which is global for our application, we could do something like

var globalIndicator = true;

// ... lots of code

window.onbeforeunload = function() {
    return globalIndicator;
};

At this point, we would always receive a confirmation dialog when the window/tab is about to get closed. If we want to avoid that for any anchor-click, we could patch it like

$( 'a[href^=http]' ).on('click', function() {
    globalIndicator = undefined;
});
jAndy
  • 231,737
  • 57
  • 305
  • 359
  • Thanks Andreas for your input; so there's actually no way of preventing the browser from closing until a response is received... the problem is if the player is on a slow connection; 2 secs might not be long enough to make the call. Thanks for the explanation for distinguishing between clicking a link - most helpful – csdev86 Jan 05 '12 at 14:44
  • If you think about how it could be used, it's pretty clear that no browser would allow a page to block for an arbitrarily long time before closing. If it were possible, someone could, e.g., make a popup ad that a user could never close. – smorgan Jan 05 '12 at 15:11
1

You can use below code to prevent the browser from getting closed:-

window.onbeforeunload = function() {

//Your code goes here.

    return "";
} 

Now when user closes the browser then he gets the confirmation dialogue because of return ""; & waits for user's confirmation & this waiting time makes the request to reach the server.

MrSmith
  • 370
  • 4
  • 22
1

As for the first part of your question, there is no reliable way of preventing the browser from closing other than using window.onbeforeunload. The browser is there to serve the user and if the user chooses to close his browser then it will do so.

For your second question, it is reasonably easy to distinguish a click on a link from other events triggering an onbeforeunload event by jQuery:

$('a').click(function(e) {...});

You could use this, for example, to make sure a click will not trigger unbeforeunload:

$('a').click(function(e) {window.onbeforeunload = null});
NobRuked
  • 593
  • 4
  • 12
0

I'm pretty sure that what you want isn't possible using JavaScript. But since you have a browser plugin, shouldn't you be able to check whether your plugin object was cleaned up correctly? I'm not sure if you're using ActiveX, NPAPI or something like Firebreath, but these frameworks all have lifecycle methods that will be called on your plugin in the event of a normal shutdown, so you should be able to write something to the logs at this point. If the plugin crashes, these won't be called.

tinyd
  • 952
  • 6
  • 9
  • The fact we couldn't make the call from the plugin reliably was the reason why started to look at doing it from the web browser. – csdev86 Jan 05 '12 at 14:59