buy prednisone

Popup blocker detection pattern

Have you ever wondered why popup blockers hate certain popup windows, but not others?

The underneath formula is pretty simple: if a window.open() call is not on top of a click event in the call stack, popup blockers would block it unless it’s on the exception list. This can be verified using Firebug or Chrome Developer Tools.

Call stack of window.open() triggered indirectly from a click event
Call stack of window.open() triggered from an Ajax callback

Therefore, the rule of thumb is that you should avoid calling window.open() from anything other than an user-initiated click event.

What if it’s a design requirement, or if it really works better for your application to call window.open() arbitrarily?

We used to be able to easily detect whether a popup window is opened successfully. When a popup window is created using window.open(), it would return an reference object to the new window if it’s successful, and null if something prevents it from opening. This works for all major browsers except the latest versions of Chrome (9 and 10), which always return an object.

This is explained in this Chromium ticket. The popup blocker in Chrome actually just hides the popup window behind the scene instead of blocking it from opening.

Until the Chromium ticket is closed, this is probably the most universal way of detecting popup blockers:

1
2
3
4
5
6
7
8
9
10
// try to create a popup
var popup = window.open(...);

setTimeout(function() {
    if(!popup || popup.closed || parseInt(popup.innerWidth) == 0)
    {
        //POPUP BLOCKED
        alert("Please disable your browser popup blocker in order to continue.");
    }
}, 500);

For most browsers, !popup is sufficient. In case the popup is closed immediately, its closed property would be set to true. For Chrome, the window.open() would return an object, and so detecting its innerWidth (or innerHeight, outerWidth, outerHeight… your choice) after a timeout should work.

Here is my recommended pattern of detecting and solving popup blocker issues:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// For large applications, you probably need a name for the window to prevent multiple window for the same goal
var name_of_popup = 'new_window_123';
// This works just fine unless there is a popup blocker
var popup = window.open(..., name_of_popup, ...);

// Detect popup blocker
setTimeout(function() {
    if(!popup || popup.closed || parseInt(popup.innerWidth) == 0)
    {
        // Close the window that is hidden behind Chrome's popup blocker
        // This is useful because you can then reclaim the name of the window that is being hidden
        // Without this, window.open(..., name_of_popup, ...) will be blocked because it is currently hidden by Chrome
        popup && popup.close();

        // This is just an example. Won't work unless you have popup() defined
        // Use your own alert framework or modal plugin to allow user-initiated window.open()
        popup("Please disable your browser popup blocker in order to continue. You may also <a href="#" id="popup_openbox_blocked">click here to open the window.</a>");

        // Attach click event to the link
        $j('#popup_openbox_blocked').click(function() {
                // window.open() works here because it is initiated by an user's click action
                // We prefer window.open() to the anchor's href action because we want to save the return reference from window.open
                var new_window = window.open(..., name_of_popup, ...);
                popup.close(); // Close the custom alert. Won't work unless you have popup() defined
                return false;
        });
    }
}, 500);
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
3 Responses
  1. giovanni says:

    sorry. don’t work in chrome

  2. David says:

    Chrome has probably changed since I wrote the post 2 years ago. I will find some time to revise it…

  3. Stefan says:

    In Chrome, use outerWidth instead of innerWidth and you’re good to go.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>