Detect if window.close() will work before using it (JavaScript) - javascript

According to many rules and security features, window.close() will only work in specific cases:
From the latest working spec for window.close():
The close() method on Window objects should, if all the following conditions are met, close the browsing context A:
The corresponding browsing context A is script-closable.
The browsing context of the incumbent script is familiar with the browsing context A.
The browsing context of the incumbent script is allowed to navigate the browsing context A.
A browsing context is script-closable if it is an auxiliary browsing context that was created by a script (as opposed to by an action of the user), or if it is a browsing context whose session history contains only one Document.
I have a web application that allows users to close new windows and it works fine, except when the rules above are not respected.
What I am looking for is to detect when the close() function will work and only show the close button in such case.
I found information talking about window.opener that returns a reference from the window that opened it. But it doesn't work.
if(window.opener != null){
//show button
}
Maybe this is because the new window was opened using "right click -> open in new tab" and not a script. When tabs are opened in this fashion window.close() works, I just want to detect when window.close() will work.
Any ideas?

According to the docs, the window is script-closable also if session history of the given context is of length 1 (which is exactly what happens when you open a link in a new tab/window). You need to add that to your checker.
if(window.opener != null || window.history.length == 1){
//show button
}

As I understand it, there isn't a native way to do this. It is possible to check if window.close() has failed after the fact by checking if window.closed is false to detect an error. See here.
Your only option is to offer the functionality to close every window, or try to in all cases, and ask the user to close it manually if it fails - otherwise it cannot be closed by you, or any of your code, by definition. There isn't a way around that unfortunately. One option that might be worth trying would be to redirect them somewhere if the window cannot be closed programmatically, which you can verify easily after every attempt.

Related

window.close fails when clicking links within opened window

I am opening a new window with window.open(). If I do NOTHING else on this page, and click the "close window" link, the window closes. This works perfectly; however, if I navigate between pages(all under the same domain) window.close() no longer works.
Is there a way to fix this?
Here is how I am opening pages in this example...
<a href="###" target="_blank">
Here is my close link:
close
I use 2 methods of changing pages within the opened windows.
<select onchange="if (this.value) window.location.href=this.value"> AND STANDARD <a href="####"> tag
Do I need to navigate links within this window a certain way to still maintain my window.close() ability?
You should favour using window.open() to open a new window if you want to close it using window.close(). E.g.
<script>
function newWindow() {
window.open('foo.html', 'myWindow');
return false;
}
</script>
link
From MDN:
The Window.close() method closes the current window, or the window on which it was called. This method can only be called on windows that were opened by a script using the Window.open() method. If the window was not opened by a script, an error similar to this one appears in the console: Scripts may not close windows that were not opened by script.
I understand the behaviour you're describing where you can close the window as long as you don't navigate. I can replicate this in Google Chrome.
I believe this is because (from the spec):
A browsing context is script-closable if it is an auxiliary browsing context that was created by a script (as opposed to by an action of the user), or if it is a top-level browsing context whose session history contains only one Document.
Your new window is considered a "top-level browsing context", not an "auxilliary browsing context". Up until the point that you navigate, the history contains one document, so can be closed using window.close(). As soon as you navigate, the history has more than one document so it's not valid to close the window.
You should also have a read about window.opener and the security risks it poses.
window.opener provides a reference to the window object that opened the current window.
Recent advice is to use rel="noopener" on all links that open in new windows. Again, this is because setting window.opener without knowing what you're doing poses a security risk. Have a read about it here:
Links to cross-origin destinations are unsafe
Browsers are now starting to treat all target="_blank" links as if rel="noopener" had been set, even if you as a developer don't set it. You can see that this is now in most major browsers.
Therefore, you could use link (explicitly setting window.opener) and I think you'd get the behaviour you want. However, this might not be reliable across browsers, and also has security implications as described in the web.dev article.

iPad Chrome only 1st Tab fail with window.close

I have one strange issue as below for Chrome in iPad.
There is the web page, which call window.open and window.close to select the user and close. H/w when in 1st Tab page, it can successfully call window.open to open the page to select user, but when click select to call window.close, it does not work without any change, still stay at the current screen to select user.
But if I open the web page in 2nd, 3rd...Tab page, it can both successfully window.open and window.close to complete the user select process.
Meanwhile, if I clear all browsing data and close all tab pages, then the new 1st tab page will works with window.open and window.close.
But if I not only clear all browsing data, but also force close Chrome (double click home button and swipe Chrome out), then the new 1st tab page will fail with window.close.
Another interesting find is that if I open such as google.com at the 1st tab of Chrome, then in 2nd tab still open my web and call window.open and window.close, all of them also works.
May I know if there is any difference about the 1st tab of Chrome or something else wrong with window.close for Chrome in iPad.
Finally I find possibly issue root as opener is null at the 1st tab.
Could you pls help to check and thx a lot!
function doSelect( userid, username )
{
opener.document.`formName`.`fieldPrefix`_ID.value = userid;
opener.document.`formName`.`fieldPrefix`_Name.value = username;
if ( opener.document.`formName`.`fieldPrefix`_SavedName )
{
opener.document.`formName`.`fieldPrefix`_SavedName.value = username;
}
if ( opener.markDirty != null )
{
opener.markDirty();
}
window.close();
}
function chooseUser( prefix, title, filter ){
window.open("/livelink/livelink.exe?func=user.SelectUserDlg&formname=ReportPrompts&fieldprefix=" + prefix + "&title=" + title + filter + "&DisplayUserName","","height=340,width=680,scrollbars=yes,resizable=yes,menubar=no")
Because of abuse in the early days of JavaScript, browsers will only let you window.close() a window that you created via JavaScript or a brand new window.
http://www.w3.org/TR/html51/browsers.html#dom-window-close
The close() method on Window objects should, if all the following
conditions are met, close the browsing context A:
The corresponding browsing context A is script-closable.
The
responsible browsing context specified by the incumbent settings
object is familiar with the browsing context A.
The responsible
browsing context specified by the incumbent settings object is allowed
to navigate the browsing context A.
A browsing context is
script-closable if it is an auxiliary browsing context that was
created by a script (as opposed to by an action of the user), or if it
is a top-level browsing context whose session history contains only
one Document.

Close current web page onclick button using javascript?

I have web page on which there is a button 'start'. Now I want that onclick of that 'start' button this page will be closed. can i do this using javascript?
<input type="button" value="Close" onclick="window.close()" />
<script>window.close();</script>
Going to another page will close the current page (stopping execution of any other scripts on it, etc).
location = "http://duckduckgo.com";
You will need Javascript to do this. Use window.close()
close();
Note: the current window is implied. This is equivalent:
window.close();
or you can specify a different window.
So:
function close_window() {
if (confirm("Close Window?")) {
close();
}
}
with HTML:
close
or:
close
You return false here to prevent the default behavior for the event. Otherwise the browser will attempt to go to that URL (which it obviously isn't).
Now the options on the window.confirm() dialog box will be OK and Cancel (not Yes and No). If you really want Yes and No you'll need to create some kind of modal Javascript dialog box.
Note: there is browser-specific differences with the above. If you opened the window with Javascript (via window.open()) then you are allowed to close the window with javascript. Firefox disallows you from closing other windows. I believe IE will ask the user for confirmation. Other browsers may vary.
You can only use Javascript to close a window that was created via javascript, this is a security feature. Therefore window.close(); is not going to work in most scenarios as some other users have pointed out.
What I'd do is open an new instance of the current window setting the target to _self and then closing this e.g:
window.open(window.location, '_self').close();
Or:
<script type="text/javascript">
function closeWindow(){
window.open(window.location, '_self').close();
}
</script>
<input type="button" id="btnClose" value="Close window" onclick="closeWindow();" />
See the w3.org docs on window.close(). Pay close attention to:
The close() method on Window objects should, if all the following conditions are met, close the browsing context A:
The corresponding browsing context A is script-closable.
The responsible browsing context specified by the incumbent settings
object is familiar with the browsing context A.
The responsible browsing context specified by the incumbent settings object is allowed
to navigate the browsing context A.
In particular:
The corresponding browsing context A is script-closable.
What is "script closable"?
A browsing context is script-closable if it is an auxiliary browsing context that was created by a script (as opposed to by an action of the user), or if it is a top-level browsing context whose session history contains only one Document.
The proposed solution is a bit of a hack though. If compatibility is an issue I would recommend doing whatever it is you're doing in this window inside a pop-up/'script closable' window so that you can guarantee support.

window.open() still returns null

I am using IE8 on Windows 7. Referred to several threads and understand that in IE8 when I am using window.open to popup a new window, the JavaScript window.open is returning null value.
If I run IE as administrator or disable the protected mode, I see the window.open returns the expected object.
I am looking out for a solution apart from the options mentioned above. For such a small feature (opening a popup) I cannot ask customer to run IE as administrator or disable the protected mode.
If there is any work around, please let me know. It will be a great help.
Primarily, I want to make sure that only one window is opened when user clicks multiple times on the link and give the focus to the window which is already open. To achieve this I need to get the object from window.open so that I can check if the window is already open and give the focus to the already opened window. Otherwise open a new window.
For IE10, window.open returns a NULL reference object if Enable Protected Mode is checked under Internet Options->Security->Security Level for this zone and the ZONE is different i.e. in my case local file opening a popup from Intranet.
window.open returns a reference object even if Enable Protected Mode is checked when yoursite.com opens someothersite.com in popup window i.e. Internet->Internet
You can use window.showModalDialog as a alternative or replacement for window.open method.
It is more secure then window.open. It will not allow user clicking the Parent page.
Example Usage:
var myFeatures = "dialogWidth:1060px;dialogHeight:550px;resizable:yes";
window.showModalDialog(url,window,myFeatures);
//Here window is an object, no need to assign or declare.
If you want more detail explanation see Here.
//Fifth Question.

JavaScript close window when opener is closed in IE

For my web application I need to close the child window whenever the parent window is closed. By "closed" I mean that the browser window is actually closed, not just navigated to a new page.
I have seen the "How can I close the child window if the parent window is closed?" question already, but mine is an extension on that. The answer to that question solves the problem of closing the child window on any unload event of the parent. However unload != close (IMO); just clicking on a link triggers the unload event.
Since there isn't an "onclose" event in JS, I decided that the best method is on the parent's unload event setTimeout on the child to see if it's parent still exists and close if not:
var w = window.open("", "Logger", "height=480,width=640,resizeable,scrollbars=yes");
if (w) {
JSEvents.on(window,'unload',function(){
if (w && !w.closed) {
w.setTimeout(function(){
//IE this==w.opener
if (!w.opener || w.opener.closed) {
w.close();
}
},500);
}
});
}
However, I believe that I have pretty conclusively shown that in IE(7) you cannot use setTimeout during the unload event on either the parent or child window. In the above example this == w.opener inside of the setTimeout anonymous function. This test never produces an alert:
JSEvents.on(window, 'unload', function(){
window.setTimeout(function(){alert('HERE');},500);
});
A straight alert without the setTimeout will produce the alert.
Is there a trick to setting a setTimeout on the child from the parent that I can use?
Is there another method for detecting when the parent is closed that I can use?
It is much easier to do in FF, so I am focusing on getting this to work under IE.
Is there a trick to setting a setTimeout on the child from the parent that I can use?
You can't do it with code from the parent in IE. When IE closes a window, the members you defined from code inside it are gone, and references to those members (such as the child's timeout pointing to your function) are left dangling. Depending on what version of IE you've got, maybe nothing will happen, or maybe you'll get a “can't execute code from a freed script” error.
You can do it inside the child. The parent could set a flag on the child onunload (eg. w.parentUnloaded= true) which a setInterval poller on the child could check for, and close itself —
if (window.parentUnloaded && (!window.opener || window.opener.closed))
Is this an IE bug? Well... other browsers react differently to unloaded scripts, certainly. But there is no standard that says what is supposed to happen here. Even within the same browser series, behaviours change as browsers are updated to avoid cross-context scripting issues.
With stuff like this and event timing issues(*), cross-window scripting is much more difficult to get right than it looks. It's generally best avoided; if you can put your ‘pop-ups’ in divs in the main page, it is usually better to do that.
(*: there are cases(**) where an event can be fired in one window and execute whilst JavaScript in another window is still in the process of running. So window ‘a’ could call a method on window ‘b’ and have that execute whilst other code in window ‘b’ is still in progress. This can dramatically confuse the scripts in window ‘b’, if they are written under the normal JavaScript assumption that there is only one thread of execution active at once. This is why I suggest using the poller in the child rather than having the parent explicitly call the child. In the future we will use HTML5's postMessage method to avoid these problems.)
(**: You could very well argue that this should never happen, and it certainly is weird, but it does happen in many browsers, in particular when modal dialogues are involved or some versions of the IE Sun Java plugin are in use.)
You can't just leave pop-up windows lying around after the application is closed; it's just not polite.
Some would say the impoliteness was opening the pop-ups in the first place. ;-)
It would seem to me that it would make sense to close any child windows when the parent is left, regardless of whether the user was closing the window, or just navigating back to his home page, or a bookmark, or typing an address, or something. Personally I'd probably want to lose the child windows on a refresh too, if I'm trying to ‘reset’ the application to a beginning state.
If you have multiple documents the parent is going to be navigating between which are all part of the same application and should not close the children, you're making things really hard for yourself! :-) However you could adapt the above ‘child window if’ approach to try to sniff the opener.location and see if that's within your application to decide whether to close or not. The trick is if the opener had been navigated to a different domain, the access would throw a security exception, so you'd have to wrap the location access up in a try...catch block that also closed the windows if the opener location was unreadable.
bucabay wrote (and Anthony something similar):
The browser considers the window closed once you refresh or close the window. So as far as the child is concerned, it's opener is gone once you refresh the parent.
That's very sensible and logical. Browsers probably should have one ‘window’ per document like that. But try it — they don't. A child pop-up retains access to its opener (and, as long as that opener is a document in the same security context, the contents of the opener), over a refresh of the opener, in IE/FF/Op/Saf/Chr.
In pop up window: (this works if the opener is closed OR changes domains)
var int = window.setInterval(function(){
// On opener domain change, all browsers throw an error. Lets use that error to our advantage using try/catch:
try
{
if(opener && typeof opener.document != 'undefined')
{
// Adding this variable fixes IE8. Why? Because F U thats why.
var openerRef = window.opener.location.host;
}
else{
// Loads the survey when opener is closed
window.location = 'exit-survey.jsp';
}
}
// Loads the survey if an error throws (error throws when opener changes domain)
catch(err)
{
window.location = 'exit-survey.jsp';
}
}, 500);
})
Have you tried creating the function inside the opened window like this:
window.closeWithParent = function() {
if (!window.opener || window.opener.closed) {
window.close();
}
};
window.parentClosing = function() {
window.setTimeout(window.closeWithParent, 500);
};
Then from your parent window:
JSEvents.on(window,'unload', function() {
if (w.parentClosing) w.parentClosing();
});
I'm not sure, but I think that interfacing with the window object across windows might be causing the problem you are seeing. Also, this way the setTimeout is called in the child windows scope (hopefully) instead of your parent window, which is being unloaded (this losing any timeouts).
The problem is from the browsers perspective a window is a concept which is created to display the content of a document. When you navigate from that document to another that window is closed and a new one is created.
The fact that the browsers conceptual windows are hosted by an actual client window owned by the browser and that client window may be re-used to display subsequent documents isn't actually any of your business (if you don't mind the phrase).
Its how the browser chooses to display the content, that window having a close button that may be potentially clicked by the user is outside of what most browsers consider that any host document needs to know.
Hence any trick you might invent to circumvent this now, if it works at all, may be closed by tighter security in later versions of a browser.
My advice would be to drop this requirement.
The browser considers the window closed once you refresh or close the window. So as far as the child is concerned, it's opener is gone once you refresh the parent.
So you cannot test if a window just refreshed, or opened another instance on that same domain using JavaScript references. (such as window.opener)
You can however create indirect references to other windows and save them in any browser storage that is cross window, or even server storage. Having the storage reflect the state of the window will allow other windows to observe that window even though they do not have a reference.
You could use cookies, or DOM Storage etc. I have a library that uses cookies (it was written a year ago when DOM storage was not supported - FF2+, IE8+ I think). If you want to see it as an example, I can do that.
Anyway, what you can do is keep a piece of data that represents the parent window. Keep it updated at regular intervals, and poll it from the child.
Example with cookies:
// parent
setInterval(function() { setCookie('parent_alive', new Date()) }, 1000);
// child
setInterval(function() { if (readCookie('parent_alive') < new Date()-5000) window.close() }, 1000)
Here the child will close 5 seconds after the parent does not update the cookie "parent_alive". The main problem is that internet connection may prevent a page from loading for 5 seconds, by which the child thinks it was closed. So it is a balancing act.
Note the polling is quite efficient if you use session cookies since they stay in memory. However, if you use persistent cookies you will probably be hitting the disk which would suck.
It seems that the correct way to add a script into the child window's scope is to use the DOM to create the script tag. The following code works to check if the parent window is open still a quarter second after it unloads in IE.
var w = window.open("", "Logger", "height=480,width=640,resizeable,scrollbars=yes");
if (w) {
JSEvents.on(window,'unload',function(){
if (w && !w.closed) {
var srpt = w.document.createElement('script');
srpt.type = 'text/javascript';
srpt.text = 'window.setTimeout(function(){if(!window.opener||window.opener.closed){window.close();}},250);';
w.document.body.appendChild(srpt);
}
});
}
Thanks for everyone's help in pointing me in this direction. The solution was just figuring out how to dynamically insert a new script tag with text content instead of a src.

Categories