Hi, stupid popup question

R

Richard Cornford

I have a web photo gallery that lets users choose any of
three image sizes to view. By default, you get small images
(suitable for an 800x600 external browser window size).
I've been looking through a Javascript book to see if
there might be a way to make an educated guess about what
image size would be best to display. But this may be a
hopeless endeavor, judging from what Richard says. Would
anyone care to offer an opinion as to whether I should
stick with the small images by default or try to do
something more clever?

By "something more clever" I assume you meant something like detecting
the user's screen dimensions and using that to determine the size of
image to send. Certainly the screen size would have some relationship to
the size that is appropriate for an image, but not a clear and well
defined relationship. Other factors may include the browser widow size,
for which the question; does the size of the window represent the size
that the user prefers the window to be, implying that they would want
images sized to suite the window, or would the user re-size the browser
(assuming there is room) to suite the images provided, if they were too
big for its current size? Another factor might be the speed/bandwidth of
the user's connection to the internet, with the users on slower
connections maybe preferring to trade image size off against download
time regardless of screen/browser dimensions.

Is it clear that a client side script is going to be hard pressed to
make these decisions for the user? The user's brain is the best decision
making mechanism available to address these questions. So the clever
approach to the problem is to offer the user an informed choice of the
size of image they would prefer and an easy mechanism for switching
between them if they reconsidered their decision.

Richard.
 
D

DU

Richard said:
I wasn't thinking of any particular browsers, I know that there are
still plenty about that don't mind if a script attempts to position a
window off screen but I didn't want to disagree with Michael on the
point that they really shouldn't. As we were discussing centring windows
on the screen (presumably with the intention that they be visible) I was
more interested in demonstrating that a script with that intention might
still place a new window out of site and not be in a position to know
that it had done so, rather than getting into whether a script could
deliberately put a new window where it couldn't be seen.

Ok.



You cannot view two browser tabs side by side. But that is what I was
getting at. If a design suggests that it would be suitable to have two
windows side by side but it is not possible to know with certainty that
two windows will be the outcome on the client then rather than worrying
about the best way of attempting to open windows (and inevitably
accepting that it is just not going to happen reliably) it might be
better to re-consider that design and attempt to come up with something
that would be meaningful in any browser.

There is no absolute certainty in any other areas either. window.open
calls may have more pitfalls and problems though (bugs, popup blocking
softwares, limitations, browser incompatibilities)
As I see it, a design that want's to open a second window has to take
into account the possibility that the second window does not open (or is
immediately closed by an external pop-up blocker, detect those condition
and falling back), navigates within the current window and opens in a
tab instead of a distinct window, in addition to the desired outcome of
opening in a new window. So a design that suggests the opening of a new
window implies the need to cope with at least three distinct UI styles
and to come up with a script that can detect, and sensibly respond to,
the failure of the window.open call due to pop-up blockers, etc.
(something that, so far, has never been demonstrated to be possible).

That is exactly how I feel and how I address this issue. If you're going
to go with window.open, then consider that
- javascript is/might be turn off; nevertheless a new secondary window
could (or should) still be created (via the html target attribute), at
least a fallback measure insuring access to content should be provided
- the user right-clicks the link and, from the contextmenu, opens the
referenced resource in a tab (the user should be able to do such)
- the user right-clicks the link and, from the contextmenu, opens the
referenced resource in an unnamed new window (the user should be able to
do such; in fact, he should be able to open "n" new secondary windows
that way if that is what he wants to do)
- the user just does a normal left-button click triggering the
window.open call
- the requested popup loses focus and the user clicks again the link in
the opener expecting the requested popup to gain back focus (since the
window already exists); no need to delete the window and then re-create
it entirely all over again. This scenario often happens and throws the
user off.
- the user clicks another link which should just load the referenced
resource into the already existing secondary window

I would say that 99.9% of all websites relying on window.open can not do
more than 2 of the above items.
If opening a new window implies an exponential increase in UI complexity
and necessitates a script that has never been written (and I, for one,
believe to be impossible)

It's possible to create a script which will deal with all the given
listed issues. The item of popup blocker software blocking even
requested popups (rare IMO but possible) is more or less the same as
preventing/neutralizing target="_blank" and opening the referenced
resource into the same window. Again, there is nothing to do really
against that, no fallback mechanism to cater for: the content of the
referenced resource will (should) still be accessible and that is what
really matters, so no biggie.
E.g.: MS WebTV does not support window.open() calls: what it does - and
this is perfectly acceptable in my mind - is it appends the referenced
resource at the end of the current document.


then maybe it would be more effective to
abandon multi-window designs and instead see how much can be achieved
within a single browser window.

[snip]

Of course, working on a single browser instance is far more simple. I'm
absolutely against multiple windows design involving more than 2
windows. And usability studies back this up.

DU
 
W

Warren Sarle

Richard Cornford said:
..
Is it clear that a client side script is going to be hard pressed to
make these decisions for the user? The user's brain is the best decision
making mechanism available to address these questions. So the clever
approach to the problem is to offer the user an informed choice of the
size of image they would prefer and an easy mechanism for switching
between them if they reconsidered their decision.

Thanks for the advice.
 
L

Lasse Reichstein Nielsen

Richard Cornford said:
But the MDI interface does not constrain its inner window size (when not
maximised)

Neither does the normal screen. You can create windows larger than the
available screen resolution, and they are certain to be partly off-screen.
I just created a 2000x1500 pixles window in IE 6.
Mozilla FB does restrict the new window to the available screen size
(only 1600x1200), but I bet that is configurable.
and the MDI window is freely re-sizeable.

But if your window is visible when it is created, then the user will
be able to notice that he hides it by resizing the MDI application.
I.e., it is the user's responsibility once the window has been opened
in plain sight.
Neither of which are a problem as such but centring windows based on
the MDI window size would still be problematic because people never
check to see if ((screen.availWidth - newWindowWidth)/2) is
negative, which it often would be when the MDI window is small,

So would it if the screen has a low resolution. My MDI window is ~800
pixels wide. I sometimes get new windows that are too wide. They would
also be too wide for someone with an 800x600 resolution screen and
non-MDI windows.
and negative values are treated as if they are positive so the
centred window would still be offset down and right, maybe to the
pint of being out of site in a small MDI window. Which is exactly
the same situation is exists now.

Exactly. If they don't check that there is room for their window, it
will overflow, no matter how much information you make available to
them.

If they do check, even the ones that doesn't think about MDI will
check screen.availWidth.
Another problem is the people who use screen size to redirect to a page
"tailored" to the screen size, a small MDI window might be redirected to
PDA or smaller desktop content when the user would prefer to re-size the
MDI window to suite larger content, or with less considerate scripts the
site might attempt to reject the browser because it thought the screen
was too small.

Bad design will break at any size :)
I would expect most of them to switch on application name instead of
screen size.
Of course fluid page design removes the necessity for the scripts that
impose the second problem, but abandoning efforts to position new
windows renders the values reported by the screen object irrelevant
anyway.

Positioning windows is bound to fail in some setups, and basing it on
the screen size just increases the risk.

However, until people stop trying, the least the browser can do is to
give usable information.

(It would be better if they just ignored the positioning part of the
window.open configuration argument).
There has got to be a reasonable argument for an object called "screen"
to provide information related to the screen.

But the value of screen.availWidth doesn't depend on the screen as
much as on the *available* screen space. That can be, and often is,
smaller than the entire screen. There is no reason why it couldn't be
exactly the size of the MDI viewport. It is not how it traditionally
works, but traditionally, browsers aren't MDI applications. Even the
inferior tabs are a relatively new invention, and isn't supported
by the majority of browsers in use (i.e., IE).
It just might be necessary for script authors to recognise that the
screen is not really relevant to them.

Absolutely. Until that happens, I would prefer Opera, or any other MDI
browser (if there are any), to report the *available* screen space in
screen.avail{Width,Height}, i.e., the size of window one can create
without overflowing the visible area.

/L
 
M

Michael Winter

on 14/11/2003:

If you're going to go with window.open, then consider that
- javascript is/might be turn off; nevertheless a new secondary window
could (or should) still be created (via the html target attribute), at
least a fallback measure insuring access to content should be provided
- the user right-clicks the link and, from the contextmenu, opens the
referenced resource in a tab (the user should be able to do such)
- the user right-clicks the link and, from the contextmenu, opens the
referenced resource in an unnamed new window (the user should be able to
do such; in fact, he should be able to open "n" new secondary windows
that way if that is what he wants to do)
- the user just does a normal left-button click triggering the
window.open call
- the requested popup loses focus and the user clicks again the link in
the opener expecting the requested popup to gain back focus (since the
window already exists); no need to delete the window and then re-create
it entirely all over again. This scenario often happens and throws the
user off.
- the user clicks another link which should just load the referenced
resource into the already existing secondary window

I would say that 99.9% of all websites relying on window.open can not do
more than 2 of the above items.

I'm quite proud to say that my designs always meet most of those
issues. Now that you've brought them to my attention, I could
probably meet every one of them.

It's simple really: allow two completely different navigation paths,
one HTML, the other JS with HTML. The biggest problem I would have is
with pop-up blocker detection. I recently read about Netscape's
built-in blocker model, and it's a sensible method:

Block all onload, global script, and timeout and interval pop-ups
Allow direct action pop-ups (i.e. those driven by user input) *
Return null when window.open fails

However, not all blockers will follow this model. Some won't signal a
failure. Some block every window.open call (Richard referred to
removing calls entirely in the "Defeating pop-up stoppers please?"
thread). Any suggestions?

* This allows the blocker to be compromised if the site designer is
willing to add pop-up windows to every, or most, links.
It's possible to create a script which will deal with all the given
listed issues. The item of popup blocker software blocking even
requested popups (rare IMO but possible) is more or less the same as
preventing/neutralizing target="_blank" and opening the referenced
resource into the same window. Again, there is nothing to do really
against that, no fallback mechanism to cater for: the content of the
referenced resource will (should) still be accessible and that is what
really matters, so no biggie.

Just a small point: the 'target' attribute is illegal in all but
frameset documents**. That is, all documents that use the Frameset
DTD. However, how many sites do you see that actually conform to the
HTML specification? Most designers (including some 'professionals')
don't even include a declaration, probably don't know they even
should, and therefore make the legality of the rest of the document
irrelevant.

Another question: how many developers that use intrinsic events
actually specify the default scripting language using a META element?
There is, after all, no such thing as a default, default scripting
language - most browsers just guess that's going to be JavaScript,
because that's the most used. Using "javascript:..." isn't actually
valid in intrinsic events as "javascript:" is a URL protocol. Only
using

<META http-equiv="Content-Script-Type" content="text/javascript">

is the correct way.

Of course, the same can be said for style sheets and actually
specifying the document's encoding, but that's off-topic here.

** I'm ignoring the Transitional DTD by itself, because there's no
real need for it any more (most, if not all, browsers now in use and
production should support CSS which replaces the depreciated
formatting elements). Shame that the current Frameset DTD isn't
Strict plus frames (rather than Transitional plus frames).

Mike
 
R

Richard Cornford

There is no absolute certainty in any other areas either.
window.open calls may have more pitfalls and problems though
(bugs, popup blocking softwares, limitations, browser
incompatibilities)

True, but a sufficiently cautions script written to enhance an otherwise
fully usable HTML should have a reasonable expectation of being able to
test its environment for support of the required features and, if
unsupported, follow a continuous path of controlled fall-back and
degradation, possibly retreating all of the way back to the pure HTML
version that users without JavaScript would have received. Unfortunately
one of the pitfalls that a call to window.open introduces is the
apparent inability to determine the failure of the call in the face of
some pop-up blocking techniques, and that leaves an unbridgeable gap in
the path of controlled degradation.

It is certainly the case that with some pop-up blockers drawing a
distinction between requested and unrequested pop-ups the problems
diminish, but they never disappear entirely.

... . If you're going
to go with window.open, then consider that

I would say that 99.9% of all websites relying on window.open
can not do more than 2 of the above items.

A lot of that appears to be down to the availability of cut and paste
scripts (and the like) that steadfastly ignore all of the issues around
the opening of new windows, giving the impression that there aren't any.

It's possible to create a script which will deal with all
the given listed issues.
The item of popup blocker software blocking even requested
popups (rare IMO but possible) is more or less the same as
preventing/neutralizing target="_blank" and opening the
referenced resource into the same window. Again, there is
nothing to do really against that, no fallback mechanism to
cater for: the content of the referenced resource will
(should) still be accessible and that is what really matters,
so no biggie.
<snip>

I don't see the neutralising of target attributes as even similar to
pop-up blockers blocking all windows. Without target attributes a
referenced resource will be shown in the current window, but with pop-up
blockers the resource will not be shown unless the script is capable of
detecting the failure of the window.open call and actively navigating
the current window to the resource.

Richard.
 
R

Richard Cornford

It's simple really: allow two completely different navigation
paths, one HTML, the other JS with HTML. The biggest problem
I would have is with pop-up blocker detection. I recently read
about Netscape's built-in blocker model, and it's a sensible
method:
Block all onload, global script, and timeout and interval
pop-ups Allow direct action pop-ups (i.e. those driven by
user input) * Return null when window.open fails

However, not all blockers will follow this model. Some
won't signal a failure. Some block every window.open call
(Richard referred to removing calls entirely in the "Defeating
pop-up stoppers please?" thread). Any suggestions?
<snip>

So you want to have a go at writing a reliable pop-up blocker detecting
script? Or to be more precise, a script that can tell when a call to
window.open will fail or has failed (in the sense that the user will not
be seeing a new window as a result of the call). It is a worthwhile
exercise as the result will either be an extremely useful script if
successful, or you will convince yourself that it is impossible (which
was my conclusion when I attempted it).

The first task of such a script (before the pop-up blockers come into
play) is to verify that the browser in question has a window.open
function, so a test like - if(typeof window.open != 'undefined'){
.... } - or - if(window.open){ ... } - would seem like a good idea.
Unfortunately, pocket IE (which cannot open new windows) does not like
this code and errors at any test of window.open. There is not a lot that
can be done about that but the test is still worthwhile as it does
produce meaningful results on other browsers incapable of opening new
windows.

Having verified that a window.open function exists, called it and
assigned the result to a variable, the next task is to determine whether
the call was successful. Obviously if the browser returns a null value
instead of a window reference then the failure of a simple -
if(winRef){ ... } - test will facilitate fall-back. From then on it is
time to start checking for the influence of pop-up blockers.

There are broadly two general approaches to pop-up blocking software,
content inserting/re-writing proxies (such as Proximatron) that modify
incoming HTML pages before they get to the browser, and external pop-up
blockers that watch for new instances of the browser and automatically
close them (via the operating system).

It is the content inserting proxies that act by replacing the
window.open function with a version of their own. They insert a script
section into the top incoming HTML page, pre-empting any other script on
the page. I have seen about 6 versions of this type of window.open
replacing script, they have common features and features that differ.
This is an example of one (the first I could fine, but not a great
example):-

<!-- BEGIN Popup Blocker -->
<script language='javascript'>
NS_ActualOpen=window.open;
function NS_NullWindow(){this.window;}
function NS_NewOpen(url,nam,atr){return(new NS_NullWindow());}
window.open=NS_NewOpen;
</script>
<!-- END Popup Blocker -->
<!--Copyright streamingsuccess.com. All Rights Reserved.-->

You may notice that the return value from the replacement window.open
call is a normal JavaScript object with no non-undefined properties.
The - this.window; - statement in the - NS_NullWindow is almost
certainly an error on the part of the code's author as it is essentially
futile. But the returned object is, in this case, easy to identify as it
lacks any of the features that could reasonably be expected of a new
window, a reasonable test might be:-

if(typeof winRef.closed == 'boolean'){
// window reference looks good so far
...
}else{
// window reference looks bogus.
}

It is, however, and example of a pop-up blocker that will never open a
new window (requested of otherwise).

Proximatron is a little more sophisticated as it provides 3 pop-up
modification filters (by default. Others may also be used). The first
filter simply blocks all window.open calls by replacing the window.open
function with a function that will only open pop-ups under circumstances
that will not occur. The second filter needs to be used with the first
and provides a "requested pop-up only" facility by getting user click
events to initiate the circumstances under which the replacement
window.open function will open a new window. The final filter is just
used to prevent scripts that are to be allowed to open new windows from
specifying the removal of window chrome.

Proximatron's first filter uses this JS code:-

var PrxLC=new Date(0);
var PrxModAtr=0;
var PrxInst;
if(!PrxInst++) PrxRealOpen=window.open;

function PrxOMUp(){PrxLC=new Date();}
function PrxNW(){return(this.window);}

function PrxOpen(url,nam,atr){
if(PrxLC){
var cdt=new Date();
cdt.setTime(cdt.getTime()-PrxLC.getTime());
if(cdt.getSeconds()<2){
return(PrxRealOpen(url,nam,PrxWOA(atr)));
}
}
return(PrxNW());
}

function PrxWOA(atr){
var xatr="location=yes,status=yes,resizable=yes,'+
'toolbar=yes,scrollbars=yes";
if(!PrxModAtr) return(atr);
if(atr){
var hm;
hm=atr.match(/height\=[0-9]+/i);
if(hm) xatr+="," + hm;
hm=atr.match(/width\=[0-9]+/i);
if(hm) xatr+="," + hm;
}
return(xatr);
}
window.open=PrxOpen;

When this script blocks a new window the object returned from the call
to window.open is a reference to the current window. That is also
relatively easy to test for with - if(winRef != window){ ... } -.

Generally these pop-up blockers return an object that (more or less)
attempts to be indistinguishable form a real window reference, probably
to prevent the script author from hassling the user about the fact that
they are running a pop-up blocker. The first example did this badly,
Proximatron returns an object indistinguishable from a window reference,
because it is a window reference but it can still be identified as not
being a reference to a unique window. In between, a content inserting
proxy's replacement window.open function may return an object like an
instance of the following:-

function WindowDummy(url){
this.self = this.window = this.parent =
this.frames = this.top = this;
this.opener = window;
this.open = window.open;
this.closed = false;
this.location = new LocationDummy(url);
this.document = new DocumentDummy(this.location);
this.length = 0;
this.focus = forDummys;
this.close = function(){this.closed = true;};
this.navigator = window.navigator;
}
function LocationDummy(url){
this.href = url;
this.toString = function(){return this.href;};
this.refresh = this.replace = forDummys;
}
function DocumentDummy(loc){
this.location = loc;
this.body = this.documentElement = {};
this.close = this.open = this.write = this.writeln = forDummys;
this.links = this.anchors = this.forms = this.images = [];
}
var forDummys = function(){return;};

- not a real window reference but something that is going to take a bit
of work to separate from a reference to a real window. The content
inserting proxies don't suffer from any practical limitations in code
size as they are local on the client so download time is not a
consideration at that stage and they are also in a position to know
which browser they are acting with (because the user can tell them) so
the object returned could be more finely tailored to imitate a window in
that browser. That code is an example of what could be done, to date I
have not seen a content inserting proxy that was that went that far, but
the only thing stopping them from using that type of return object is
the skill of the person authoring the pop-up blocker code and a
perception of the need.

The implied need to carry out a detailed examination of an object
reference returned from a call to window.open to distinguish a real
window reference for a reference to an object that was deliberately
impersonating a window may suffer from the real window reference being
returned before the DOM in the new window was fully configured.
Certainly a real window reference could not be expected to contain the
DOM for the document it was downloading. That may itself be the basis
for a discriminating test as the JavaScript object that attempted to
impersonate a window object would be static while a real window
reference would contain a DOM that would be expected to change during
the period after its creation (particularly the contents of the document
as the HTML arrived from the server).

The second type of pop-up blocker is an external process that monitors
for additional instances of the browser and automatically closes them.
These also provide some facilities to allow pop-ups. I have seen
examples that allow pop-ups with particular (user configured) title
texts, allow URLs/domains to be listed as allowed to open windows and
have read descriptions of one that blocks all new browser instances
unless the user is holding down the Ctrl key as the window opens. Which
is one definition of a user-requested pop-up, though it requires that
the page author tips the reader off that a particular action is going to
attempt to open a new window so they know to hold the key down. Other
external pop-up blockers claim to make their pop-up blocking decisions
based on AI (probably marketing waffle but it does mean that the
criteria used are not publicly declared).

With these external processes, from the point of view of the browser a
new window was opened, so the window reference returned from the
window.open call will be a real reference to a window object. The
browser will just have the impression that the newly opened window was
closed (as it would if the user closed it manually). That means that
testing the winRef.closed property should indicate that the window has
been closed. Unfortunately there are timing issues with this as the
external pop-up blocker will not necessarily be able to close the new
window immediately (especially if it is interested in the URL or title
text).

That means that testing winRef.closed immediately after the call to
window.open will not necessarily provide the required information and
the real status of the new window would have to be re-checked at
intervals. Deciding what the interval of testing should be, and how long
to keep testing before the new window was assumed to be safe would not
be easy as there would be many unknowable factors involved.

In addition, following that style of testing makes fall back very
complex. For example, if a window opening script was going to be
triggered with the onclick event handling function for a link element,
such that the return value form a function call was used to cancel the
navigation specified in the link's HREF. The function called could carry
out the required tests and return a value based on the success of the
window.open call, so that the browser could navigate within the current
window if the pop-up was known to have been blocked. However, if the
winRef checking code has to initialise a setTimout/Interval process to
repeatedly check that the window is still open how do you handle the
fall-back if that script discovered that the new window had been closed?
The onclick function has already returned (presumably false) at that
point so the fall back has to be actively triggered by the periodic
checking function, meaning that it needs to keep track of where it is
expected to navigate to.

There is one reasonably easy technique that can positively indicate the
success of a call to window.open: Having the onload event handler in the
resource loaded into that window call-back into its opener and
announce/flag its arrival. Logically a positive indicator of the success
of a call to window.open is also a positive indicator of the failure of
the call if it is absent. The problem being that the resource loaded
into the new window cannot announce its arrival until it arrives. Given
that the interval between a request for a resource and its arrival back
at the browser is subject to many variable factors it is going to be
necessary to give the resource quite a long period in which to arrive
before it would be valid to assume that the fact that it had not yet
shown up indicated the actions of a pop-up blocker (necessitating the
fall back). It is a practical test but what sort of UI is designed to
take a couple of minutes to react to user actions?

That should give you an adequate starting point when attempting to
address the issues around the actual call to window.open in the face of
the existence of pop-up blockers. I look forward to seeing your solution
(or anyone else's).

Richard.
 
Y

Yann-Erwan Perio

Richard said:
So you want to have a go at writing a reliable pop-up blocker detecting
script? Or to be more precise, a script that can tell when a call to
window.open will fail or has failed
There are broadly two general approaches to pop-up blocking software,
content inserting/re-writing proxies (such as Proximatron) that modify
incoming HTML pages before they get to the browser, and external pop-up
blockers that watch for new instances of the browser and automatically
close them (via the operating system).


I'm still absorbing the analysis you've provided in your post, but ISTM
that content-inserting proxies share a simple conception problem.
They're replacing the window.open function, but "window" only refers to
the current window object, no other window objects. Therefore, a
possible way to defeat these blockers would be to call another
"window.open", eg something like:


var MyWinOpen=function(){
var fName="frame"+(new Date().getTime());
document.write(
"<iframe name=\""+fName+"\" "+
"width=\"0\" "+
"height=\"0\" "+
"style=\"visibility:hidden\""+//cannot use display for O7
"><\/iframe>"
);

function cp(url, name, features){ //create popup
var ref=null;
if(frames[fName]){
with(frames[fName].document){
open();
write(
"<script type=\"text\/javascript\">"+
"window.onload=function(evt){"+
"if(parent.MyWinOpen){"+
"parent.MyWinOpen._ref=window.open("+
"\""+url+"\""+
(name ?
(",\""+name+"\""):
(",\"win"+(new Date().getTime())+"\"")
)+
(features?(",\""+features+"\""):(""))+
");"+
"}"+
"}"+
"<\/script>"
);
close();
}
ref=MyWinOpen._ref;
}
return ref;
}

return function (url, name, features) {
return cp(url, name, features);
}
}();


Of course, this approach has several issues:
- it requires good iframes support, and not all agents might provide it
(at least for now),
- the reference returned isn't correct due to timing problems (an onload
handler inside the popup would however, as you've pointed out, be an
appropriate response).

Still, this would probably work in most browsers, which makes me think
that the only valid approach for popup-blocking is the external popup
blocker approach, and preferrably included in the browser.


Cheers,
Yep.
 
A

Adam i Agnieszka Gasiorowski FNORD

DU said:
Richard said:
[...]
The existence of tabbed browsers does bring into question the validity
of designing sites to use multiple windows. Most of the justifications
for such a design vanish completely on such a browser (and they do
include browsers based entirely on IE).

I don't agree. There are cases where having 2 browser window is more
suitable than having 2 browser tabs. I can have 2 browser instances, 2
browser windows side by side. How can you view 2 browser tab side by side?

In Opera, you can. You can have tiled pages
with tabbed interface, for example.
 
L

Lasse Reichstein Nielsen

Adam i Agnieszka Gasiorowski FNORD said:
In Opera, you can. You can have tiled pages
with tabbed interface, for example.

That is because Opera doesn't use tabs. It has full MDI windows. Tabs
is but a pale imitation of the glory that is Opera :)

/L
 
R

Richard Cornford

... ISTM that content-inserting proxies share a simple
conception problem. They're replacing the window.open function,
but "window" only refers to the current window object, no other
window objects.

I imagine the thinking behind the strategy of replacing the window.open
function assumes that any resource loaded into any given window or frame
will also have to pass through the proxy and thus have its open method
replaced as it loads. But you are right, in practice frame and window
content can originate in the browser and so avoid having the open
function of its frame replaced.
Therefore, a possible way to defeat these
blockers would be to call another "window.open",

As I originally perceived it the problem was to reliably determine the
outcome of the call to window.open, rather than modifying the
reliability of that call. But that is also a completely valid approach
and if the influence of an entire type of pop-up blocker could be
removed without harmful consequences then that should simplify the
remaining problem.
eg something like:

var MyWinOpen=function(){
var fName="frame"+(new Date().getTime());
document.write(
"<iframe name=\""+fName+"\" "+
"width=\"0\" "+
"height=\"0\" "+
"style=\"visibility:hidden\""+//cannot use display for O7

I had a problem with this script on Opera 7.11, which produced an access
denied error when attempting to write to the IFRAME. I suspected that it
was due to cross-domain security restrictions due the IFRAME having a
default "about:blank" (actually "opera:blank") URL and confirmed my
suspicion by including a SRC attribute in the IFRAME opening tag with a
same domain URL, at which point Opera 7.11 happily executed the script.
"><\/iframe>"
);

function cp(url, name, features){ //create popup
var ref=null;
if(frames[fName]){
with(frames[fName].document){
open();
write(
"<script type=\"text\/javascript\">"+
"window.onload=function(evt){"+
"if(parent.MyWinOpen){"+
"parent.MyWinOpen._ref=window.open("+
"\""+url+"\""+
(name ?
(",\""+name+"\""):
(",\"win"+(new Date().getTime())+"\"")
)+
(features?(",\""+features+"\""):(""))+
");"+
"}"+
"}"+
"<\/script>"
);
close();
}
ref=MyWinOpen._ref;
}
return ref;
}

return function (url, name, features) {
return cp(url, name, features);
}
}();

It is an ingenious method of getting access to an unmodified window.open
function and when it works I don't see any method of defeating it. I did
try putting it in a page with a script that replaced the IFRAME's open
function prior to the call to MyWinOpen but as I expected the re-writing
of the IFRAME contents resets the IFRAME's global object and resorted a
genuine open function to it. So I don't think that there is anything
that could be inserted into a page that would prevent MyWinOpen from
performing to the best of its abilities.

Proxies do have the option of doing a simple (or regular expression)
find and replace on the source code and maybe replacing references to
"open", for example, with some other text, but that would be easy to
discourage ( - window['op'+'en']( ... ) - ) and very likely to have
undesirable side effects that may leave the user convinced that turning
JavaScript off made more sense for them.
Of course, this approach has several issues:
- it requires good iframes support, and not all agents
might provide it (at least for now),

That is quite a big problem at present because (all else being equal)
window.open is more widely supported than executing scripts by writing
their contents into an IFRAME. Obviously Netscape 4 does not understand
IFRAMEs at all, and IceBrowser 5 does not seem to allow writing to
IFRAMES. I also could not get Opera 6 to execute the code written into
the IFRAME.

Then again, if the point of the exercise is to guarantee that the window
opening attempt has an uninterrupted path of controlled fall back when
it fails, it might be worth sacrificing some browser support (and
falling back in those cases) in exchange for getting rid of the problem
of determining whether the window reference returned from the call to
window.open was genuine or just a dummy. With your script, when it
works, the result will always be genuine or null.

With a genuine window reference - winRef.closed == true - would be a
positive indicator of the actions of an external pop-up blocker, and
should be available sooner than waiting for the loaded page to arrive.
That assumes that the external pop-up blocker is not interested in the
contents of the new window but should certainly be useful with the
blockers that just close every new window regardless.
- the reference returned isn't correct due to timing
problems (an onload handler inside the popup would however,
as you've pointed out, be an appropriate response).

As the influence of external pop-up blockers still needs to be
determined I don't see any real problem in having to wait a bit before
using the window reference. I still see the period that it may be
necessary to wait prior to concluding that a resource loaded over the
internet has been blocked and will never be arriving as the biggest
remaining stumbling block in attempting to produce a window opening GUI
that is both usable (sufficiently responsive) and reliable (in the sense
that it always falls back (to navigation within the existing window) in
the face of the failure of the wiondw.open call). But you may have got
that down to a relatively small sub-set of external pop-up blockers.
Still, this would probably work in most browsers, which makes
me think that the only valid approach for popup-blocking is the
external popup blocker approach, and preferrably included in the
browser.

Yes, you have invalidated the strategy of replacing the window.open
function. I wonder if anyone will notice, I can imagine a spate of
pop-ups getting past the proxy based pop-up stoppers and IE users being
forced to switch to using external blockers instead.

When I started this reply (yesterday) I was thinking "that is an
ingenious script, well up to Yep's usual standard, but it doesn't solve
the real problem", but the more I have thought about the consequences of
what you have done the more I have been seeing those unbridgeable gaps
in the path of controlled fall back getting smaller and smaller (and a
lot of them have closed entirely). Probably to the point that it is
worth trying to build a general window opening script (with reasonably
reliable fall-back) around your code. It won't be 100% (the long delay
between the user's action and the final fall-back decision will not
reduce to zero), there is also going to be a strong (and undesirable)
dependence on setTimeout/Interval, and it certainly won't be pretty. But
the result might be good enough and the only way to find out is to write
it and try it with my small collection of external pop-up blockers and
see if it works.

Richard.
 
Y

Yann-Erwan Perio

Richard said:
I did
try putting it in a page with a script that replaced the IFRAME's open
function prior to the call to MyWinOpen but as I expected the re-writing
of the IFRAME contents resets the IFRAME's global object and resorted a
genuine open function to it.

I've tested that too, but actually the test I preferred concerned the
Window.prototype.open method, available in Mozilla - I wanted to see
whether it was shared by all browser instances, but it wasn't (quite
normally, or you could try and interfere with any opened instance).

Still, I dreamt a second on
Window.prototype.open.apply(this, ["foo.html"]);

....certainly easily defeated, but so neat.
So I don't think that there is anything
that could be inserted into a page that would prevent MyWinOpen from
performing to the best of its abilities.

Me neither, and now that we have the real return from window.open, it
should indeed be more feasible to determine more or less reliably
whether the window has been effectively opened.
the more I have been seeing those unbridgeable gaps
in the path of controlled fall back getting smaller and smaller (and a
lot of them have closed entirely). Probably to the point that it is
worth trying to build a general window opening script (with reasonably
reliable fall-back) around your code. It won't be 100% (the long delay
between the user's action and the final fall-back decision will not
reduce to zero), there is also going to be a strong (and undesirable)
dependence on setTimeout/Interval, and it certainly won't be pretty. But
the result might be good enough and the only way to find out is to write
it and try it with my small collection of external pop-up blockers and
see if it works.

I don't have much experience with external popup software, nor with
popups issues, so I wouldn't be sure enough to provide an appropriate
script (I'll try this WE though), but the approach you've described,
checking the reference then the "closed" property/load event at regular
intervals with specific rules to make the fallback decision, sounds
quite solid to me (and maybe not as ugly as you say, the TimedQue
component might give interesting results with the fallback controller).

In the end, it still will be impossible to tell whether a window has
been closed by a software or the user, so navigation rules and fallback
will get even more attention.

Thanks for your whole analysis, it's as always finely conducted, a real
pleasure to read.


Cheers,
Yep.
 
A

Adam i Agnieszka Gasiorowski FNORD

Lasse said:
That is because Opera doesn't use tabs. It has full MDI windows. Tabs
is but a pale imitation of the glory that is Opera :)

Hail To Opera! ;8].
 
R

Richard Cornford

I don't have much experience with external popup software, nor
with popups issues, so I wouldn't be sure enough to provide an
appropriate script (I'll try this WE though), but the approach
you've described, checking the reference then the "closed"
property/load event at regular intervals with specific rules
to make the fallback decision, sounds quite solid to me (and
maybe not as ugly as you say,

Well I have written a version and it seems to work, though it could
probably do with some more testing), but it is ugly (at least I think
so). I have not been feeling very inspired this week so I am sure there
is plenty of room for improvements, but I don't feel like doing any more
with it for at least a day or so. So I am going to post it as it is and
let it be kicked about in public for a bit.
the TimedQue component might give interesting
results with the fallback controller).

I was thinking about a custom setTimeout function but TimedQue does lend
itself to the task in hand very well. I also noticed a slight bug
(commented below) in the earlier versions so using it was useful from
that point of view as well.
In the end, it still will be impossible to tell whether a
window has been closed by a software or the user,

Yes that is a problem, as it proved necessary to keep checking that the
window was still open for a short while after it loaded its page and set
the value in the opener. As it stands, if the user closes the window at
any point prior to the script deciding that the new window is ok and
safe then the fall-back happens, so if the user genuinely changed their
mind about viewing the content then they are going to have to use the
back button to return to the page they started on.
so navigation rules and fallback
will get even more attention.
<snip>

Judging the best values to use for the various repeated tests and timing
intervals is not going to be easy. There are too many unknowns involved
and safe values will make for an unresponsive UI.

My test script:-

<html>
<head>
<title>Pop-up window script with reliable fall-back version 1</title>
<script type="text/javascript">
/* TimedQue takes a function reference as an argument and schedules
the execution of that function at intervals. If the function
returns false when executed it is removed from the queue and not
executed again. If the execution of the function returns true the
function stays in the queue and is executed again following the
interval (until it returns false). (return values will be
type-converted as appropriate.)
*/
var TimedQue = (function(){
var base, timer;
var interval = 40;
var newFncs = null;
function addFnc(next, f){
function t(){
next = next&&next();
if(f()){
return t;
}else{
f = null;
return next;
}
};
t.addItem = function(d){
if(next){
next.addItem(d);
}else{
next = d;
}
return this;
};
t.finalize = function(){
return ((next)&&(next = next.finalize())||(f = null));
};
/* debugging toString function */
//t.toString = function(){return (''+f+
// ((next)?'\n----------------\n'+next:''));};
return t;
};
function tmQue(fc){
if(newFncs){
newFncs = newFncs.addItem(addFnc(null, fc));
}else{
newFncs = addFnc(null, fc);
}
if(!timer){
timer = setTimeout(tmQue.act, interval);
}
};
tmQue.act = function(){
var fn = newFncs, strt = new Date().getTime();
if(fn){
newFncs = null;
if(base){
base.addItem(fn);
}else{
base = fn;
}
}
base = base&&base();
/* I added the following test for newFncs in case one of the
functions executed through this function calls TimedQue and
newFuncs becomes non-null during the - base = base&&base();
- line.
*/
if(base||newFncs){
var t = interval - (new Date().getTime() - strt);
timer = setTimeout(tmQue.act, ((t > 0)?t:1));
}else{
timer = null;
};
};
tmQue.act.toString = function(){
return 'TimedQue.act()';
};
tmQue.finalize = function(){
timer = timer&&clearTimeout(timer);
base = base&&base.finalize();
newFncs = [];
};
return tmQue;
})();

</script>
</head>
<body>

<script type="text/javascript">
/* This function (expression) is executed inline and must be
within the body of the page as it will document.write an
IFRAME element into the page.
*/
(function(){
var global = this;
var readyTest = false, initTestCount = 0;
/* This code is written into the IFRAME to ensure that it
will execute scripts written into it.
*/
var checkAr = [
"<script type=\"text\/javascript\">",
"(function(){",
"if((typeof parent != \'undefined\')&&(parent.winOpen_f)){",
"parent.winOpen_f.ready=true;",
"}",
"})();",
"<\/script>"
];
var ifrmAr = [
"<iframe name=\"",
"",
"\" width=\"0\" height=\"0\" ",
/* Maybe some instructions on IFRAME borders should be
included in the style attribute as Opera 6 displays them.
*/
"style=\"visibility:hidden;\" ",//cannot use display for O7
/* blank.html avoids cross-domain security restrictions on
Opera 7.11 (at least) and is a minimal HTML page:-
<html><head><title></title></head><body></body></html>
*/
"src=\"blank.html\"",
"><\/iframe>"
];
var fName = (ifrmAr[1] = "frame"+getTimeBasedString());
//alert(fName+'\n\n'+ifrmAr.join('\n'))
document.write(ifrmAr.join(''));
/* The following array is the code written into the IFRAME in
order to open a new window (using an unmodified wiondw.open
method).
*/
var outAr = [
"<script type=\"text\/javascript\">",
"(function(){",
/* Check that the window has an open function, if it does
not then the test function will navigate the current
window in 2 seconds as parent.winOpen_f._refSent will
remain false.
*/
"if((this.open)&&(parent.winOpen_f)){",
"parent.winOpen_f._ref[\'",
"", //NAME index 4
"\']=this.open(\'",
"", //URL index 6
"\',\'",
"", //NAME index 8
"\'",
"", //FEATURES ,"..." (including comma and quotes) index 10
");",
"parent.winOpen_f._refSent[\'",
"", //NAME index 13
"\']=true;",
"}",
"})();",
"<\/script>"
];
function getTimeBasedString(){
var rmd, res = '';
var num = (new Date().getTime());
while(num > 0){
rmd = (num % 52)|0;
num = Math.floor(num / 52);
rmd += ((rmd > 25)?71:65);
res = res + String.fromCharCode(rmd);
}
return res;
};
/* This function writes the test script into the IFRAME and sets
readyTest to indicate that it has acted. If it has acted but
the winOpen_f.ready property is not true (within a limited
period) then the IFRAME will not execute scripts written in to
it.
*/
function checkIframe(){
var frm = frames[fName];
if((frm)&&(frm = frm.document)){
frm.open();
frm.write(checkAr.join(''));
frm.close();
readyTest = true;
return false;
}else{
if(initTestCount > 1){
/* If the IFRAME has not been fond by now the chances
are it never will be. So set readyTest to true and let
the rest of the script assume that writing the script
into the IFRAME failed so it can get on with falling
back.
*/
readyTest = true;
}
}
return true;
}
function getTestFunction(name, url){
var startTime = new Date().getTime();
var checkCount = 0;
return (function(){
var interval = new Date().getTime() - startTime;
var winRef;
if(!winOpen_f._refSent[name]){ //window ref not set yet
/*If window.open errors in the IFRAME then
winOpen_f._refSent[name] will never be true.
*/
if(interval > 2000){ //true if tested for more than ...
return setLocation(url);
}
}else{ //win ref is set
if((!(winRef = winOpen_f._ref[name]))||(winRef.closed)){
return setLocation(url);
}else{
if(!winOpen_f._refArived[name]){ //not arrived yet
if(interval > 180000){ //give it 3 minutes to show up
if((winRef)&&(winRef.close))winRef.close();
return setLocation(url);
}
}else{
/* If the window loads quickly it is possible for it
to report its arrival before being closed by the
pop-up blocker so this test is repeated 3 times to
make sure.

Unfortunately, if the user closed the window
within this period the page will be opened in the
current window.
*/
return (++checkCount < 4); //arrived so stop testing?
}
}
}
return true; //keep testing
});
}
function setLocation(url){location = url;return false;};
function cp(url, name, features){ //create popup
if(!name){name = getTimeBasedString();};
if(initTestCount < 6){
TimedQue(function (){ //schedule the window opening function.
var winRef, frm = frames[fName];
if((cp.ready)&&(frm)&&(frm = frm.document)){
/* If a window reference exists under this name then
we may as well re-use it as go to the effort of
re-calling window.open. It is probably also
reasonable to assume that it will not now be
pop-up killed.
*/
if((winRef = cp._ref[name])&&(!winRef.closed)){
winRef.location = url;
/* Mark the page as having arrived (based on the
assumption that it will) so that any unfinished
test functions for the previous page do not
decided to navigate this window.
*/
cp._refArived[name] = true;
if(winRef.focus)winRef.focus();
}else{
cp._refArived[name] = false;
cp._ref[name] = null;
cp._refSent[name] = false;
outAr[6] = url;
outAr[13] = (outAr[4] = (outAr[8] = name));
outAr[10] = (features?(",\'"+features+"\'"):(""));
//alert(outAr.join('\n'))
frm.open();
frm.write(outAr.join(''));
frm.close();
TimedQue(getTestFunction(name, url));
}
}else{
/* Either the initial script written into the IFRAME
failed, or checkIframe has not successfully executed
yet.
*/
++initTestCount;
if((!readyTest)||(initTestCount < 6)){
/* If readyTest is false then keep periodically
executing this function to give checkIframe a
chance to execute. Otherwise give it up to 5
more opportunities to set cp.ready to true.
*/
return true; //continue cheking
}else{ //give up and fall back
setLocation(url);
}
}
/* Allow this function to be dropped from
the TimedQue queue by returning false.
*/
return false;
});
}else{
/* Didn't initialise (or IFRAME cannot be located, or it
doesn't contain a document object) so give up.
*/
setLocation(url);
}
return false; //this function always returns false.
}
if((global.location)&&(global.frames)){
if(global.setTimeout){
cp.ready = false;
cp._ref = {};
cp._refSent = {};
cp._refArived = {};
global.winOpen_f = cp;
TimedQue(checkIframe);
}else{
/* Without a working setTimoeout the best that can be done
is to navigate the current window. (Note that setLocation
returns false to cancel onclick navigation). We also need
a frames collection in order to find the IFRAME.
*/
global.winOpen_f = setLocation;
}
}else{
/* If it doesn't look like winOpen_f will be able to handle the
window opening/fall-back actively then set winOpen_f to a
function that will return true so that its return value can
be used to control onclick event handlers to provide HREF
fall-back.
*/
global.winOpen_f = function(){return true;};
}
})();

</script>


<a href="popUp.jsp?delay=3"
onclick="return winOpen_f(this.href, 'cc')">test window open 3</a><br>
<a href="popUp.jsp?delay=4"
onclick="return winOpen_f(this.href, 'cc')">test window open 4</a><br>
<script type="text/javascript">
/* The following line tests the inline creation of an unrequested
pop-up, (with requested pop-ups blocked by the browser it
should navigate the current window, not very useful).
*/
//winOpen_f("popUp.jsp?delay=5", 'cc');
</script>
</body>
</html>

The page that is being loaded in the pop-up (popUp.jsp) is a Java Server
Page. I was using that so I could simulate slow responses from the
server by having the Java thread that would return the page sleep for an
interval before sending anything back. And setting the length of the
delay with a query string on the URLs in the HTML for convenience. The
important part of the page for testing (assuming no Java application
server is available) is the JavaScript that sets the value in the opener
to announce that the page has arrived.

------------------------popUp.jsp-----------------
<%@ page language="java" %><%
String delayString = request.getParameter("delay");
long delayValue;
if(delayString != null){
try{
delayValue = Long.parseLong(delayString);
}catch(Exception e){
delayValue = 1;
}
}else{
delayValue = 1;
}
try{
Thread.sleep(delayValue);
}catch(InterruptedException ignore){
; //just carry on.
}
%><html>
<head>
<title>XXXX XXXX</title>
<script type="text/javascript">
if((this.name)&&(opener)&&(!opener.closed)&&
(opener.parent)&&(opener.parent.MyWinOpen)&&
(opener.parent.MyWinOpen._refArived)){
opener.parent.MyWinOpen._refArived[this.name] = true;
}
</script>
</head>
<body>
delay = <%= delayValue %>
</body>
</html>

I am not convince that this is good enough to solve the pop-up window
reliability problems (at least not yet) and I don't think that may of
the people who think that 5 or 6 lines of cut and paste code is all that
is required to create a new window are going to like the prospect of
replacing that with 200+ lines. There is also still (although there
always was) the problem of having to design the UI for both multi-window
use and one-window use, but at least it is getting closer to just those
two alternatives rather than having a script think it has a new window
when in fact it doesn't.

Richard.
 
R

Richard Cornford

function checkIframe(){
var frm = frames[fName];
if((frm)&&(frm = frm.document)){
frm.open();
frm.write(checkAr.join(''));
frm.close();
readyTest = true;
return false;
}else{
if(initTestCount > 1){
/* If the IFRAME has not been fond by now the chances
are it never will be. So set readyTest to true and let
the rest of the script assume that writing the script
into the IFRAME failed so it can get on with falling
back.
*/
readyTest = true;

return false;

Opps, this needs a slight modification, the addition of the - return
false; - after the above - readyTest = true; - line so that TimedQue
will stop executing checkIframe at intervals. It didn't show up in
testing because the browsers I was testing it with all happily report
the IFRAME as a named member of the frames collection. But Netscape 4
(at least) will need this.

Richard.

}
}
return true;
}
<snip>
 
Y

Yann-Erwan Perio

Richard Cornford wrote:

[about a popup script with reliable fallback]

First sorry fot the late answer, too much work this week; I have now
just spent a couple hours on your script (it deserved at least that).
Well I have written a version and it seems to work, though it could
probably do with some more testing), but it is ugly (at least I think
so).

Why ugly? To me you've adressed all possible issues, and the technical
conception is quite interesting. It might indeed be difficult to read at
first (closures aspects, TimedQue calls' stack and return values), but
in the end it proves to be very satisfactory.
I was thinking about a custom setTimeout function but TimedQue does lend
itself to the task in hand very well.

I can only agree here, the ability for a function to remove itself from
the queue is admirably exploited with the fallback mechanism, the
fallback decision remains encapsulated within the controllers, this is
really nice (though I'm still hesitating whether it would have been
better to have the config vars as private static members - a minor point).
rmd = (num % 52)|0;

Why the "|0" ?
I am not convince that this is good enough to solve the pop-up window
reliability problems (at least not yet) and I don't think that may of
the people who think that 5 or 6 lines of cut and paste code is all that
is required to create a new window are going to like the prospect of
replacing that with 200+ lines. There is also still (although there
always was) the problem of having to design the UI for both multi-window
use and one-window use, but at least it is getting closer to just those
two alternatives rather than having a script think it has a new window
when in fact it doesn't.

I concur; and to me you've perfectly addressed the issue, far better
than I could have done it. Not only is the logic very strong, but the
technical aspects are also neatly handled. The use you've made of
closures, particularly, is IMHO clearly in the spirit of javascript
(prototyping being of course another branch) - unfortunately scripts
expressing what js really is are so rare!

I'll keep on reading the code until I'm able to re-use techniques and
conceptions proposed there, and will let you know any further
comments/questions. Again, thanks for your contribution :)


Cheers,
Yep.
 
R

Richard Cornford

Why ugly? To me you've adressed all possible issues, and
the technical conception is quite interesting.

Ugly is, of course, a subjective judgement and my perception of my
efforts was certainly influenced by some very personal factors. My (by
now well documented) belief that opening new windows is not the best way
of approaching UI creation made me reluctant to work on the script at
all (only outweighed by a desire to maintain personal integrity by
knowing what constituted the best that could be achieved, so I could
honestly judge whether it was good enough). I also wasn't feeling very
inspired last week so the process of writing the script was not very
enjoyable, more of a grind, made worse by the need to constantly stop
and start web browsers, external pop-up blockers and the application
server as I worked thorough the various combinations of configurations
to ensure that everything was covered (plus having to go back and
re-test whenever I encountered something new and had to change the
script to compensate). I think that the result has, at best, some loose
ends that need tidying up.
It might indeed be difficult to read at first (closures
aspects, TimedQue calls' stack and return values), but
in the end it proves to be very satisfactory.

I was thinking about this while reading the most recent discussion of
source code obfuscating. There are some techniques that produce code
that will only be understood by people capable of writing it themselves.
Whiteness the use of nested closures, examples are clearly formatted in
plain text and globally published (sometimes along with quite detailed
discussions) and yet there still doesn't seem to be more than a dozen or
so of us using the techniques.

I can only agree here, the ability for a function to remove
itself from the queue is admirably exploited with the fallback
mechanism, the fallback decision remains encapsulated within
the controllers, this is really nice

TimedQue is proving an extremely useful object. It is also making me
think of other function stack concepts. I have been contemplating trying
to make a stack that could re-order itself so that the functions in the
stack could influence the order in which they were executed. Probably
implementing a valueOf method so that they could be tested with
comparison operators.
(though I'm still hesitating whether it would have been better
to have the config vars as private static members - a minor point).

That is one of the loose ends that needs tidying up. There should also
be a public interface of some sort to allow external scripts to request
references to new window objects by name. That would probably require
that the scripts provide a function reference to be called when an
expected window reference became available. Either that or all of the
pop-up interaction code would have to be incorporated in the existing
script. But then, if the script is going to be falling-back on a regular
basis, designing inter-window interaction becomes quite tricky anyway,
needing a lot of server side fall-back to cover the cases when there is
only one window. Which still means it must be less effort overall to
design only for a single window and maintain the state of the combined
process on the server.
Why the "|0" ?

In context it is a mistake. I copied the while loop from another
function that used Math.floor in that location, but a couple of months
ago I noticed that because any bitwise operation starts with a call to
the internal ToInt32 function they have a side effect that is similar to
Math.floor (if the number is a positive integer that can be expressed as
a 32 bit signed integer). OR zero produces that side effect without
changing the (32 bit) integer result of the ToInt32 call and, at between
4 and 14 times faster than Math.floor, it proved the best bitwise
operation to use if the goal is just to achieve the side effect. For
particular application, such as rounding floating point numbers into
pixel screen co-ordinates, the performance gain seems worth while.

As a result I have been looking out for uses of Math.floor when
revisiting my code and replacing them with OR zero when it is clear that
the number will be within the required range. In this case, if I had
though about it a bit more I may have noticed that because the - num -
variable starts off holding an integer and the next line performs
Math.floor on the result of the division, it is not necessary in
conjunction with - (num % 52) - as the result will also be an integer.
Indeed, now that I have though about it, I should change the original
function to call Math.floor before the start of the while loop and just
use the modulo operation to generate the character code.
I concur; and to me you've perfectly addressed the issue,
far better than I could have done it. ...
<snip>

I wouldn't put money on that. Ultimately the whole thing hangs on your
original IFRAME script, the breakthrough that makes reconsidering the
viability of reliable window opening feasible.

I still don't think I would recommend that anybody use it. I have been
considering picking on some unsuspecting person asking about how to open
a new window by posting them an example of it in action. To try and
scare them off using new windows instead of attempting persuasion, but I
think my time would be better spent working on alternative approaches
that don't require new windows (particularly as UI components).
... - unfortunately scripts
expressing what js really is are so rare!
<snip>

Thank you, and for your invention, collaboration and the review (along
with all your posted code, which remains compulsory, and influential,
reading for me :)

Richard.
 
Y

Yann-Erwan Perio

Richard said:
Ugly is, of course, a subjective judgement and my perception of my
efforts was certainly influenced by some very personal factors.

<snip>

Playing the devil's advocate against one's own feeling cannot be amusing
(I hate doing that myself), and writing the sort of script you've
written can be, in my experience, quite wearing (I was surprised at how
fast you could answer in the thread, especially in regards of the
quality provided). In the end though, the result is significant: apart
from the script beauty in itself, you've demonstrated in a very solid
way how unsafe it would be to base a design on popups.
Whiteness the use of nested closures, examples are clearly formatted in
plain text and globally published (sometimes along with quite detailed
discussions) and yet there still doesn't seem to be more than a dozen or
so of us using the techniques.

Even in c.l.j, most regulars don't seem attracted by these techniques -
it must really look painful and ugly from outside ;-)
I have been contemplating trying
to make a stack that could re-order itself so that the functions in the
stack could influence the order in which they were executed. Probably
implementing a valueOf method so that they could be tested with
comparison operators.

That's an interesting idea, and would certainly be pleasant to write,
but which situations would you use such a priority feature for?
a couple of months
ago I noticed that because any bitwise operation starts with a call to
the internal ToInt32 function they have a side effect that is similar to
Math.floor (if the number is a positive integer that can be expressed as
a 32 bit signed integer). OR zero produces that side effect without
changing the (32 bit) integer result of the ToInt32 call and, at between
4 and 14 times faster than Math.floor, it proved the best bitwise
operation to use if the goal is just to achieve the side effect. For
particular application, such as rounding floating point numbers into
pixel screen co-ordinates, the performance gain seems worth while.

That's well spotted, I've just tested on IE6 (a very fast browser) and
it's indeed faster, so this should effectively be an interesting
technique to use with DHTML animations. Thanks for the tip!


Cheers,
Yep.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top