You are here: irt.org | Articles | JavaScript | Window | Almost complete control of pop-up windows [ previous next ]
Published on: Sunday 27th February 2000 By: Martin Webb
This article addresses a problem that most developers eventually hit - how to keep control of a pop-up window when the main window changes location.
The title of this article "Almost complete control of pop-up windows", suggests that we'll not be able to control our pop-up windows, and this is true in older versions of browsers which don't support the windows closed property or the windows focus() method, both introduced in JavaScript 1.1. For newer browsers that do support closed and focus() we should be able to retain complete control of our popup windows.
Opening a pop-up window is easy (see the previous article The JavaScript Pop-up Window Primer for full details), the following shows three different ways to open the same page in a pop-up window:
<script language="JavaScript"><!-- function open_popup(page) { window.open(page); return false; } open_popup('page1.htm'); //--></script> <p> <a href="page2.htm" onClick="return open_popup('page2.htm')">Open Popup</a> </p> <form action="page3.htm"> <input type="submit" onClick="return open_popup('page3.htm')" value="Open Pop-up"> </form>
To allow non-JavaScript-enabled browsers some degree of navigation - we use normal link href properties, normal submit buttons with normal action attributes, but return false from the open_popup() function so as to cancel out the otherwise normal navigation.
A different window will be opened each and every time, as we haven't specified a window reference or a window name to load the page into. To avoid cluttering the desktop with multiple windows we need to be able to load a page into the same pop-up window each time, regardless of whether the window is already opened or closed. To do this just specify a second parameter to the windows open() method:
<script language="JavaScript"><!-- function open_popup(page) { window.open(page,'popupWindowName'); return false; } //--></script>
Now when a pop-up window is opened, any new request to load a page into a pop-up window will replace the current page in the existing pop-up window named popupWindowName.
If the pop-up window is hidden behind another window you'll not see the change being made to the pop-up windows contents. To all intents and purposes it will look to the user as if nothing has happened. We need to bring the pop-up window to the front of all other windows. To do this we set the current focus to the pop-up window using the window focus() method.
To set the focus to the current window we would use:
window.focus();
To blur the focus from the current window we would use:
window.blur();
But how do we focus or blur the pop-up window? All we have is the window's name, and not its reference (i.e. an object reference) which we need to be able to invoke an object method() on. To do this we need a window reference to the pop-up window. When opening a window using the window open() the method returns an object reference to the newly created window. Now when we want to invoke a method on the pop-up window we can use its reference (window_handle), so that when a new page is loaded into it we can ensure that the pop-up window is visible, using the following amended code:
<script language="JavaScript"><!-- function open_popup(page) { window_handle = window.open(page,'popupWindowName'); window_handle.focus(); return false; } //--></script>
The variable window_handle is used to retain the reference to the pop-up window throughout the life of the current document. As soon as the pop-up window is created, or its contents are requested to be changed, then the focus() method ensures that it is brought to the top of the stack of visible windows.
Well, the above technique does work in browsers that support the window focus() method, i.e. JavaScript 1.1 enabled browsers. In JavaScript 1.0 enabled browsers the use of the non supported focus() method will generate a JavaScript error. To avoid this we can provide two different definitions of the open_pop() function, one that will be used by JavaScript 1.0 browsers, and another that will override the first definition in JavaScript 1.1+ enabled browsers:
<script language="JavaScript"><!-- function open_popup(page) { window_handle = window.open(page,'popupWindowName'); return false; } //--></script> <script language="JavaScript1.1"><!-- function open_popup(page) { window_handle = window.open(page,'popupWindowName'); window_handle.focus(); return false; } //--></script>
This does mean, however, that in JavaScript 1.0 enabled browsers, that the pop-up window could remain hidden behind other windows. A solution would be to close the pop-up window first, before attempting to load another page into it. This does require a simple check to make sure that the window is indeed open before closing a non-open window, thus avoiding yet another JavaScript error message. To do this we test the value of the window_handle. If it is not null then the window is either open, or has been opened but subsequently closed:
<script language="JavaScript"><!-- function open_popup(page) { if (window_handle) window_handle.close(); window_handle = window.open(page,'popupWindowName'); return false; } //--></script> <script language="JavaScript1.1"><!-- function open_popup(page) { window_handle = window.open(page,'popupWindowName'); window_handle.focus(); return false; } //--></script>
Notice how we also use the window_handle as an object reference when invoking the close() method. There is still a possibility that the pop-up window has been opened previously closed. We need to avoid the possible JavaScript error message that might result from attempting to close a closed window. A simple solution is to open it first, then close it, and then open it again:
<script language="JavaScript"><!-- function open_popup(page) { window_handle = window.open(page,'popupWindowName'); window_handle.close(); window_handle = window.open(page,'popupWindowName'); return false; } //--></script> <script language="JavaScript1.1"><!-- function open_popup(page) { window_handle = window.open(page,'popupWindowName'); window_handle.focus(); return false; } //--></script>
It does appear to be an overkill, for what does seem to be a simple error. But, we can now use our existing pop-up window with impunity, with the knowledge that it will jump to the top if it is hidden under a stack of other windows, when we load a new page into it.
Generally there isn't much purpose to opening a pop-up window, unless the pop-up window is used to open pages into the main window (acting like a TV remote control). On modern browsers, this reference is supplied automatically to the pop-up window by the opener reference, which references (from the pop-up window) to the window that opened it. Therefore, one can change the contents of the opener window using:
<a href="example.htm" onClick="opener.location.href='example.htm';return false">example.htm</a>
The previous code works fine, so long as the opener is still open. If not, then the opener reference will be broken and the request will fail. To compensate for this eventuality we can employ the same technique we used to load a page into a possibly closed pop-up window, by using the window open() and the second attribute (the window name) to target the window.
We can target a named frame, or we can target a window, so long as the window has been named. By default he main browser window has a name of "", i.e blank. In JavaScript 1.1 it is possible to set the name of a window using the window name property. So, in the main window the following amended JavaScript code, will enable us to target the main window in JavaScript 1.1 enabled browsers:
<script language="JavaScript"><!-- function open_popup(page) { window_handle = window.open(page,'popupWindowName'); window_handle.close(); window_handle = window.open(page,'popupWindowName'); return false; } //--></script> <script language="JavaScript1.1"><!-- window.name = 'main'; function open_popup(page) { window_handle = window.open(page,'popupWindowName'); window_handle.focus(); return false; } //--></script>
Generally speaking, the pop-up window tends to be smaller than the main window. As there is no real need to set the focus to the main window when changing its contents, we can use a drastically reduced version of the window opening code:
<script language="JavaScript"><!-- function open_main(page) { window_handle = window.open(page,'main'); return false; } //--></script> <a href="example.htm" onClick="return open_main('example.htm')">example.htm</a>
JavaScript 1.1 also introduced the window closed property. Using this property, it is possible to detect if a window has been opened and subsequently closed. We can use this to load a page directly into the opener window if it still open for JavaScript 1.1 enabled browsers:
<script language="JavaScript"><!-- function open_main(page) { window_handle = window.open(page,'main'); return false; } //--></script> <script language="JavaScript1.1"><!-- function open_main(page) { if (opener && !opener.closed) { opener.location.href = page; } else { window_handle = window.open(page,'main'); } return false; } //--></script> <a href="example.htm" onClick="return open_main('example.htm')">example.htm</a>
Note, that we have to test first the opener property, just in case the current window was not opened by another window.
Occasionally we move from one page to another in our main browser window, moving from page in a site to another. When the contents of a window changes, not only is a new page shown, but all the previous JavaScript code, and (more importantly) all the previous JavaScript variables are lost. Therefore, any reference to a pop-up window (window_handle in our examples) is also lost. We now have no reference to the pop-up window to be able to set the focus or open new pages into it or close it. If we attempt to access the pop-up window using the window_handle reference then we'll receive the following JavaScript error:
window_handle has no properties
It may happen, that the user inadvertently closes the main window, leaving us with just the pop-up window. If we then attempt to access the main window throught the pop-up windows opener property we will receive the following JavaScript error:
opener.location has no properties.
This section will present two solutions, one of which we have seen in passing but not discussed, and another that involves frames.
The first solution uses the fact that when opening a window using the name of an existing open window, a new window is not created, but the existing open window has its contents changed instead. At the same time the windows open() method returns the window reference to the existing open window - we have actually seen this in action already. We can use this in two ways, one to solve the problem where we have lost a reference to a pop-up window (in effect re-establishing a reference to a window that we may have lost due to a page change in the main window) and secondly to target the opener window using its window name (in effect ensuring we open a new opener window if it has been inadvertently closed), and then using the returned window reference to set the current windows opener property to the newly created main window.
The following JavaScript code demonstrates how to change the contents of a pop-up windows opener in such a way as to open a new main window if it has been closed, and re-establish an opener window for the pop-up window:
<script language="JavaScript"><!-- var window_handle; var window_page; function open_main(page) { if (opener) opener.location.href = page; else { window.open('frame.htm'); window_page = page; setTimeout('reopen_opener()',100); } return false; } function reopen_opener() { opener = window.open(window_page,'main'); opener.window_handle = self; opener.window_handle.closed = false; } //--></script> <script language="JavaScript1.1"><!-- function open_main(page) { if (opener && !opener.closed) opener.location.href = page; else { window.open('frame.htm'); window_page = page; setTimeout('reopen_opener()',100); } return false; } //--></script> <p> <a href="example.htm" onClick="return open_main('example.htm')">Load example.htm into opener</a> </p>
the most important part of the previous JavaScript code is the setting of the opener to the newly created window in the reopen_opener() method to the window reference returned by open(). This is then used to set the opener window's window_handle to the current pop-up window (i.e. self), and at the same time setting its closed property to false.
The second solution, described at the beginning of this section, uses frames in the main window to provide a location to store intra page variables. As mentioned earlier, whenever a page change occurs, and JavaScript code and JavaScript variables are wiped out, thus losing any references to pop-up windows that may have been created. Using a frameset to hold our pages, provides us with an easy storage location (the top frame) to hold JavaScript variables that will persist through many page changes, and, so long as we remain withint our domain, which remain accessible to us at any time.
The following simple frameset definition will suffice for our purposes:
<html> <head> <title>frame</title> </head> <frameset rows="100%,*"> <frame src="example.htm" frameborder="0" border="0"> </frameset> </html>
It only contains on frame - which fills up the entire window. Although, at the moment, it contains no JavaScript variables, we can, from the example.htm page, use it to hold anything we like. So, for example, to hold a window reference, from the example.htm page:
top.window_handle = open(page,'popupWindowName');
Which will create a window_handle variable in the top most frame, holding a reference to the pop-up window.
Even if the example.htm page is not loaded within the frameset (say someone came directly to example.htm from a search engine) then the above code still works, as then top will actually refer to self - the current window.
Note: if you need to ensure that your page is correctly framed within your own frameset, and not on its own, or within an alien frameset, then see the article Re-directing access within frames - Revisited
We can now make changes to all our existing JavaScript code to reference the top frame of the main (or opener) window. This will ensure that the window_handle persists through page changes in the main window.
The working example uses all the techniques describe within this article to attempt to retain control of your popup windows.
The JavaScript Pop-up Window Primer