Can Javascript get information on any window? - javascript

A little bit ago I asked this question about if a child can get information on its parent. But now I realize that I have a followup question that belongs on its own, rather than in comments: Can Javascript find out if any window is open?
I have a window A which can either be called from window B or window C. However, when I close A, I want certain things in the onUnload only to happen if window C is closed. Now, A may not have been opened by C, so I can't rely on window.opener. Is there any way I can find out information on arbitrary windows? I thought about checking window.opener.location but that still requires that C have been the opener, which it may not have been. The names of all the windows are known, so if I could search by those, I'd be golden.
(as for the why: A is a chat console, B is the main menu, C is the queue monitor. When someone is in the queue monitor, they're marked as available for chat. But to actually chat, they have to load up the chat console to do so. Normally, when you close the chat console, an onUnload tries to mark you unavailable, but I don't want to that to happen if the queue monitor is still open.)

The only way to be able to do this is if the parent window that launched the child windows remains open throughout the process. Windows with similar "ancestry" can use the common parent as a relay point. Code on the common parent would probably be required (or at least desirable) to assist.
I suppose it's possible for the common parent to hand each child an object with references to other child windows; I can't imagine any reason for that to fail. Of course, that won't help if one child is launched from one incarnation of the main window, and another launched from a separate one. In that case, even though the windows share a domain, they really have no way of finding each other.
Anyway if you have a reference to a window, the .closed property will tell you if it's closed or not.

Related

Implications of using multiple interactive popup windows

I'm coming up with the idea of detaching elements onto popup windows. Make a popup with window.open(), set up some elements in that document and add event listeners to serve the original purpose, but as a popup window component. All of this works, and it seems that the created window is handled by the same thread.
Is this "technique" bug-prone by any chance? I.g: If I create a canvas in the popup window and get a WebGL context from it, will it work flawlessly? If I set a bunch of event listeners there, will I get callbacks from them without any delay?
I couldn't do my research on this one because almost no one does this. Through my life, I've seen many sites use popup windows for user inputs but not for interactive or real timey stuff. I'm building a web app that's complex that utilising multiple monitors would benefit in user experience. You know, at least I know how painful it is to have two monitors and be unable to use both of them because all the component of the app is cramped in a single window. Just imagine using an MDI version of Photoshop where all the toolbox is within the MDI area and you can't get them out of the app window. A web page is exactly that.
Although this is non-conventional it definitely seems to suit the requirement you mentioned. I don't see any issues when it comes to the browser support for handling rendition or communication across the windows, it's just that you will need to be more careful with your code. Something like make frequent checks in case user has closed one of your pop-ups(or register a window close callback so that you can make necessary adjustments).
Eventing across the windows should also be fine. Refer http://help.dottoro.com/ljrwrqew.php which has exactly same example of attaching the event callback from one window to another.
Another good read is http://www.infimum.dk/HTML/JSwindows.html
One possible drawback could be that the popup can be blocked by the browser popup blocker (but yes, you could inform the user to don't block the popup coming from your web application)
Another one could be that the dimensions of the popup that you specify on your javascript code could be not respected (this is at the discretion of the browser), so for example one browser could open anytime the popup in a new tab or a new maximized window.
Here you will find some ready made experiments with multi-window: https://experiments.withgoogle.com/chrome?tag=Multi-Window
For data sharing between your main window and your popup you shouldn't have any problem.
Something to keep in mind is that not every browser use the same threading model, so you must do some performance tests as well on all the browser you will want to support and see the differences.

how does javascript execution context work in firefox extensions with multiple windows?

I am writing what should be a fairly straightforward firefox extension. But this is my first firefox-extension and my first javascript program, and I'm used to C and assembly-language where nothing is hidden, so I'm having a difficult time understanding what to expect.
My question will be about multiple execution contexts (or the [partial] lack thereof) in multiple windows my extension creates with window.open() or window.openDialog(). But first let me describe what my extension is doing, in case that matters.
My extension is essentially simple in that it does not change the firefox browser window in any way. It doesn't add any new GUI elements, doesn't add, remove or modify any menu items, it isn't invoked by operating any of the widgets or controls or menus in the firefox browser.
What my extension does do is detect when the mouse cursor pauses, and when the mouse pauses over a text-node, my extension calls window.open() or window.openDialog() to display a tiny, borderless, "clarify window" just above the term the mouse cursor paused over.
The "clarify window" looks alot like a tooltip window, except being a tiny firefox browser its content is HTML [with javascript if desired], so it can look much nicer and richer than a tooltip. The "clarify window" also contains a few buttons. One button creates and displays a larger "elaborate window" that contains more elaborate information about the term under the mouse cursor. Another button creates and displays an "option window" that lets the operator control how various aspects of my extension works. These windows are also created by my extension calling window.open() or window.openDialog(), so they are both firefox browser windows that display HTML [with javascript if desired].
ALL the global/shared variables in my extension are inside a single structure that is defined and initialized at the top of the javascript program that is my extension.
So, once my extension is installed, when someone (the "operator") opens a firefox browser, my extension is running in the browser no matter what HTML page the firefox browser loads. When the mouse cursor pauses over a text node, my extension finds the term (word, phrase, acronym) under the mouse cursor, creates an HTML file that describes that term, then calls window.open() or window.openDialog() to create the "clarify window" and displays that HTML file (nominally "clarify.html").
Since this tiny, borderless "clarify window" is also a firefox browser (even though displayed without any UI elements), my extension is also part of the "clarify window". So if the operator pauses the mouse cursor over a term in the "clarify window", the same kind of action occurs again. Originally my extension code displayed yet another "clarify window" above the first, and this process worked recursively. This worked, and was kind of cute and elegant, but eventually I decided this behavior was "too much". So I changed the code to check whether the mouse paused over a term in the "clarify window", and if so, just update the contents of the one "clarify window".
My question applies to either of these ways of operation, but both these successes imply to me that somehow or other, the extension executing in the "clarify window" is essentially independent of the extension executing in the original firefox browser window... mostly because the code works as expected and I assumed the two instances were independent when I wrote the code.
Okay, now for the "difficult case" that makes me need to understand how the "execution context" of the multiple javascript programs/extensions are related (or not).
When the mouse pauses over the term, my extension inserts some simple markup around the term to "highlight" the term by changing the text color (which doesn't change the size of the term, and therefore never causes text reflow). If the operator moves the mouse cursor into the "clarify window", the execution context switches to the extension javascript in the "clarify window", and the extension javascript in the original browser window no longer receives events (like "mousemove", "mouseover", "mouseout" and so forth) --- the execution context of the "clarify window" receives all those events (installed by addEventHandler()).
It almost seemed this would not present a problem. But it does. The first case I noticed was the following. When the operator moves the mouse cursor to the end of the "clarify window", then beyond the end and outside the "clarify window", the execution javascript receives a "mouseout" event as it should. However, if the mouse cursor is then over the desktop or a window created by some completely unrelated application, then... nothing further occurs.
When this happens, the "clarify window" can destroy itself when it receives the "mouseout" event to assure the abandoned "clarify window" does not become stranded over the original firefox browser.
However, the term is still highlighted in the original firefox browser Woops. Big problem!
This is where the nature-of and relationships-between "execution contexts" becomes crucial.
Here are two possible solutions that I imagine, but I have no idea whether either SHOULD work, much less ACTUALLY work, and what reliability issues might exists as new browser versions are released.
Both solutions call window.openDialog() instead of window.open() to open the "clarify window". The key difference is, window.openDialog() allows extra (arbitrary) arguments to be passed, which can then be accessed by the extension running in the created window. I can imagine two solutions:
#1: pass [the address of] the term_highlight_remove() function into window.openDialog(). This function, and indeed all functions in my extension are just members of that global/shared structure, but I don't think that matters in any way (though I certainly don't know, given that javascript is a total freaking mystery to me given my low-level, C-oriented mindset).
#2: pass [the address of] the entire global/shared structure into window.openDialog(). Then the extension javascript in the "clarify window" context MAYBE has access to all variables in that structure, and could execute its own term_highlight_remove() function but modify the variables that belong to the extension javascript in the original browser.
I have a feeling that #2 will not work, but #1 might. The reason I am skeptical #2 works is the following. One thing the term_highlight_remove() function does is to remove an attribute that is something like style="color:#FFFF60" from around the term in the original browser. I rather suspect that executing term_highlight_remove() in the context of the "clarify window" cannot possibly modify HTML in the original browser window.
Which leaves approach #1. The following is how I fantasize this works.
When the [address of] the term_highlight_remove() function is passed in an extra argument of window.openDialog(), I would hope that somehow this not only passes the address of the term_highlight_remove() function in the execution context of the original browser, but also that somehow javascript keeps track of the execution context of that function [address].
If so, then hopefully when the extension javascript in the "clarify window" calls the passed-in term_highlight_remove() function, the act of calling that function somehow magically switches from the execution context of the "clarify window" to the execution context of the original browser window.
If this does happen, then the term_highlight_remove() function it calls should (I hope) access variables from the global/shared structure that belongs to the original browser window AND should (I hope) access and modify the HTML elements from that structure to modify the HTML in the original browser.
Whew!
So the question is... how do these execution contexts work (in the situation described above)?
And does either #1 or #2 above work? And if neither does, how to I achieve the results I require?
Can you upload your code to github, it would be easier to understand. Also why use window and why not a panel? You can put an iframe inside the panel? Anyways you aren't receiving pointer-events below the window because its covered. Try putting in the window css pointer-events:none; on the clarify window. However because you are using window.open it probably won't work, what you need to do is use Services.ww so like:
var {utils, Cu} = Components;
Cu.import('resource://gre/modules/Services.jsm');
var win = Services.ww.openWindow(null, "YOUR_CLARIFY.HTML_URL_HERE", "_blank", "chrome", null);
when this window opens set the style of it to pointer-events:none
Now to make it not work inside the calrifyWindow, just add to the top of your code:
if (document.location.indexOf('clarify.html') > -1) {
return;
}

In Javascript, how to reuse a window previously opened by another page

I have a window which uses javascript to open another child window, in the standard window.open("http://foobar","name") manner. If I open again with the same name, it reuses the window. This is great and exactly what I want.
However, if the original window is closed, I would like to be able to reopen it and have its window.open go to the previously opened child window. Unfortunately, because it is a new parent window it will open another child window (which it will happily and correctly reuse).
Does anybody here know of a way to get hold of that previous child window so I can avoid making more windows than necessary?
Behind the scenes, the driver of this question is this: I have a java program which will periodically open different websites and I do not want to force a plethora of tabs or windows. Command-line options do not let you reuse windows or declare targets; javascript lets you declare a target. I figured I would write a small javascript page which opened a page in a specifically-named window and then close itself. Anytime you want to see a new page, hit that page passing in your new page.... Much to my dismay, though, targets seem specific to the window which creates them.
So if you have ideas which are relevant to my actual problem I'm interested too.
Embedding a browser took less time than trying various ways of controlling browsers.

Why does Firefox lose focus on page reload?

I have two instances of Firefox running simultaneously next to each other. One window is in the front and the other one in the background. Both instances use the same target URL.
Whenever I do a page reload in one of my instance the other instance loses the focus and gets minimized to the Windows taskbar.
Has anyone ever experienced this effect?
I've found the problem. Some buggy jQuery code returned a window reference rather than a DOM Element. The call to $(element).blur() ( element is a window reference ) now explains the strange behaviour.
Could be a buggy 'onunload' handler. If both windows are open to the same page, then doing a reload in one will trigger onunload, which eventually calls window.blur(). If both windows are child windows of the same parent page (ie: created via window.open(), or regular link with target="somename"), they could be assigned the same name.
I don't know what FF"s priorities are on conflicting window names in JavaScript, but you could try opening the two windows in various orders, and reloading one or the other and see which one minimizes (if at all).

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