Imagine you have to provide support for some really old web application. The app has one main window and pop-up windows that show some sensitive information (for example payroll list). Client wants to ensure that all pop-ups are closed when user leaves main window or clicks “logout” button in this window...
So... how to close all the windows opened with window.open?
On the web this question comes up very often. Unfortunately, most common answer is really naive. Proposed solution is based on keeping references to opened pop-ups and subsequent invocation of close method:
var popups = [];
function openPopup() {
var wnd = window.open('Home/Popup', 'popup' + popups.length, 'height=300,width=300');
popups.push(wnd);
}
function closePopups() {
for (var i = 0; i < popups.length; i++) {
popups[i].close();
}
popups = [];
}
In practice this doesn’t work because the array of references is cleared at full page reload (for example after clicking on a link or upon postback)...
Other suggested solution is to give the pop-up a unique name (using the second parameter of the open method) and later acquisition of a reference to the window:
var wnd = window.open('', 'popup0');
wnd.close();
This is based on the fact, that window.open method works in two modes:
- If a window with a given name doesn’t exist, it is created.
- If a window with a given name does exist, it will not be recreated, instead a reference to that window will be returned (if non empty URL is passed to the open method pop-up will be reloaded).
The problem lies at point no. 1. If pop-up window with given name wasn’t previously opened, the call to open and close methods will cause the pop-up to be briefly visible. It sucks…
But maybe a reference to pop-up can be retained between page reloads?
If there is no need to support older browsers (unlikely for the old application) we can try to put reference to the pop-up window into localStorage. However, this will not work:
var popup = window.open('http://morzel.net', 'test');
localStorage.setItem('key', JSON.stringify(popup));
TypeError: Converting circular structure to JSON
Old tricks for keeping page state between reloads that are based on cookies or window.name will not work too.
So… what to do?
Even if you can’t afford to have a major change such as introducing frames, don’t give up :)
Pop-up windows have opener property that points to parent window (that is the window in which the call to window.open was placed). Pop-ups can therefore periodically check whether the main window still remains open. Additionally, pop-ups can also access variables from parent window. This can be used to enforce pop-ups closure when main window is closed or when user clicks on “logout” button in parent window. When user is logged-in (and only then!), a marker variable (i.e. loggedIn) should be set in main window.
Here is the JS code that should be placed on a page displayed in a pup-up:
window.setInterval(function () {
try {
if (!window.opener || window.opener.closed === true || window.opener.loggedIn !== true) {
window.close();
}
} catch (ex) {
window.close(); // FF may throw security exception when you try to access loggedIn (for external site)
}
}, 1000);
Checking variable from the opener window has another advantage. If user moves away from our application in main window (for example by clicking back button or a link to an external website), then the pop-up window will detect the lack of monitored variable in window.opener and close automatically.
Well, it's not the kind of code you enjoy to write but it achieves the desired result despite the painful gaps in the browsers API. If only they provide us with window.exists('name') method...