reptile7's JavaScript blog
Wednesday, July 08, 2009
 
An Image Window, Revisited
Blog Entry #150

In Blog Entry #25, we showed that we can use an image URL for the strUrl parameter of the window.open( ) method

var myWindow = window.open("myPhoto.jpg", "windowName", "width=imageWidth,height=imageHeight");

and thereby display an image in a new window. HTML Goodies' "Remote Image" tutorial, our focus today, presents a script that outlines an alternate, more involved way of displaying an image in a window.open( )-opened window. In brief, the "Remote Image" script places an image in a new HTML document that is opened in a new window*, whose dimensions can be based (or not) on the intrinsic dimensions of the image. Placing the image in a parent document allows us to add some bells and whistles to the display that couldn't be added if we directly assigned the image URL to the window.open( ) strUrl parameter: we can add text and/or user interface elements (e.g., a button), we can align the image per our preference, we can impart a background color to the rest of the document body, etc.
(*We've actually done this once previously: check the newWin( ) and newWin2( ) functions in the script discussed by HTML Goodies' JavaScript Script Tips #45-48.)

The "Remote Image" script is reproduced in the div below:

<script type="text/javascript">

var width, height;
var image, ext;
var cond1, cond2;
function transferview(image, width, height) {
if (width == 0) cond1 = " ";
else cond1 = "width=" + (width + 20) + "";
if (height == 0) { cond2 = " " };
else { cond2 = "height=" + (height + 70) + "" };

var s1 = "<title>Image</title>";
var s15 = "";
var s2 = "<center><img src='" + image + "' border='0' />";
var s3 = "<form><input type='button' value='Close Window'" + " onclick='self.close( );' />";
var s4 = "</form></center>";

ImageWindow = window.open("", "newwin" + width, "toolbar=no,scrollbars=" + scroll + ",menubar=no," + cond1 + "," + cond2);
ImageWindow.document.write(s1 + s15 + s2 + s3 + s4);
ImageWindow.document.close( );
}
</script>

<form><input onclick="javascript:transferview('test.gif', 200, 300);" type="button" value="View Image" /> </form>

Deconstruction

As for the "Quick Window" script, Joe offers no deconstruction for the "Remote Image" script. Joe does provide a script demo that works with MSIE but not with Firefox, Opera, or Safari - more on this below. The demo display is accessed via a button:

<input onclick="javascript:transferview('test.gif', 200, 300);" type="button" value="View Image" />

The onclick attribute is set to a JavaScript URL; however, JavaScript URLs are meant to be paired with the href attribute of the anchor element (you can probably also pair them with the href attribute of the area element). As it is superfluous, you'd think that the javascript: part of the onclick value would throw an error and/or cancel the click action, although it doesn't (at least on my computer), but again, the javascript: doesn't need to be there and IMO should be removed. Anyway, clicking the button calls the script's transferview( ) function

var width, height, image, ext, cond1, cond2;

function transferview(image, width, height) { ... }


and passes thereto three arguments:
(0) arguments[0] (test.gif) is the file name of the image to be displayed in the new window, and is assigned to the variable image.
(1-2) arguments[1] (200) and arguments[2] (300) will be used to set the width and height of the new window, and are accordingly assigned to width and height variables, respectively.

Before moving on: as shown above, six variables, including image, width, and height, are declared globally prior to transferview( )'s declaration. The ext variable is not subsequently used in the script and should be removed from the declaration statement.

The transferview( ) function begins with a strange block of code:

if (width == 0) cond1 = " ";
else cond1 = "width=" + (width + 20) + "";
if (height == 0) { cond2 = " " };
else { cond2 = "height=" + (height + 70) + "" };


These if...else statements set values for the previously declared cond1 and cond2 variables, which will respectively become the width=imageWidth and height=imageHeight features for the window.open( ) command that opens the new window.

The if lines set cond1 or cond2 to a space character if width or height is equal to 0. Above and beyond Mozilla's assertion that the window.open( ) strWindowFeatures parameter must not contain any blank space (this is not true in practice on a Macintosh), there's no reason why width or height should ever be 0 or set to 0 by a transferview( ) function call. If the image image were not available or if we had mistyped its file name in the transferview( ) function call, we would still be feeding non-0 numbers to width and height. If we did not specify arguments[1] and arguments[2] in the transferview( ) function call (onclick="transferview('test.gif');"), then in that case width and height would evaluate to undefined, not 0.

The else lines are meant to set horizontal and vertical 'paddings' for the new window with respect to the image image, i.e., to push the edges of the new window away from the edges of the image. The first else line adds 20 to width, appends the sum (220) to the string width=, curiously appends to the resulting string an empty string**, and lastly assigns width=220 to cond1. In an analogous manner**, the second else line increases height by 70 and assigns height=370 to cond2.

**Perhaps the empty string operands were included to ensure that the width=220 and height=370 strings are not 'unterminated', but the Core JavaScript 1.5 Guide's "Data Type Conversion" section makes clear that this is unnecessary. Relatedly, the parentheses that surround width + 20 and height + 70 are indeed needed; otherwise, cond1 would be width=20020 and cond2 would be height=30070, i.e., the operands are concatenated in a normal left-to-right order.

Notice anything unusual about the second if line and the second else line? Both of these lines are terminated with semicolons that lie outside the if/else closing braces. Firefox, Opera, and Safari all throw syntax errors at this point in the code for the following reason: recalling that the else clause of an if...else statement is optional, these browsers view the second if line and its concluding semicolon as a complete if...else statement, and thus they expect another if clause to precede the second else clause, which cannot appear 'in isolation':

if (height == 0) { cond2 = " " };
if (false) var x = "Add me and everything is OK."; else { cond2 = "height=" + (height + 70) + "" };


There are several simple ways to solve this problem: removing the braces or the semicolon (or both) on the second if line will do it, as will the preceding code.

FYI: Mozilla briefly discusses block statements here in the Core JavaScript 1.5 Guide but says nothing about putting semicolons after them. For its part, MSIE clearly views the second if/else lines as a single if...else statement, even as the MSDN Library's "Writing JScript Code" page avers, Notice that the primitive statements within a block end in semicolons, but the block itself does not.

In sum, there's no need to conditionalize the cond1/cond2 assignments, which can be written much more simply as:

cond1 = "width=" + (width + 20);
cond2 = "height=" + (height + 70);


We next have a series of statements that will be used to build the document that goes in the new window:

var s1 = "<title>Image</title>";
var s15 = "";
var s2 = "<center><img src='" + image + "' border='0' />";
var s3 = "<form><input type='button' value='Close Window'" + " onclick='self.close( );' />";
var s4 = "</form></center>";


Ordinarily the above strings would be plugged directly into document.write( ) commands, but separating them in this way does improve the readability of the script. It's simple enough to see what's going on here:
• The s1 string will specify a title for the new document.
• The s2 string takes care of the image image.
• The s3 string indirectly codes a button for the new window.
• Like the empty strings in the else blocks, the s15 string declaration serves no purpose and can be removed.
Some of this code - namely, the center element spanning the s2-s4 strings and the border attribute of the img element in the s2 string - would be deprecated in a non-script HTML context, and yet strings of this sort, once their </ character sequences have been escaped, will pass through a 'strict' validation because the script element has a CDATA content model.

We're finally ready to open the new window and write its document:

ImageWindow = window.open("", "newwin" + width, "toolbar=no,scrollbars=" + scroll + ",menubar=no," + cond1 + "," + cond2);
ImageWindow.document.write(s1 + s15 + s2 + s3 + s4);
ImageWindow.document.close( );


The new window's object reference will be ImageWindow and its name value will be newwin200. Via the cond1 and cond2 variables in the strWindowFeatures parameter, the ImageWindow viewport will have a width of 220 pixels and a height of 370 pixels. The strWindowFeatures parameter also sets the toolbar and menubar features to no, which is unnecessary because these features are (should be) disabled by default upon setting the width and height features.

Bizarrely, the strWindowFeatures scrollbars feature is set to the value of a scroll variable that does not appear earlier in the script - man, doesn't anyone proofread these things? I have no idea whether the script's author wanted to enable or disable the scrollbars feature, but I myself see no point in enabling it and would throw out the scrollbars/scroll code. More fundamentally, regarding the arguments passed to the transferview( ) function, width and height values for a given image should be chosen such that scrolling is not necessary: you are likely to annoy the user (it would certainly annoy me) if scrolling were needed to see the right/bottom parts of the image.

You'd think that scroll's out-of-the-blue appearance in the window.open( ) command would throw a "scroll is not defined" error: not so. Subsequent investigation has revealed that the browsers on my computer see scroll not as a variable but as a property 'reflection' of the scroll( ) method of the window object, e.g., alert(typeof scroll) displays function on the alert( ) box. As a property, scroll evaluates to function scroll() { [native code] }, which counterintuitively doesn't cause any problems vis-à-vis the strWindowFeatures string and, with respect to enabling/disabling the new window's scrollbars, is evidently converted to no by Firefox and Safari. On the other hand, with or without the scrollbars/scroll code, I find that both MSIE and Opera equip the new window with scrollbars if the new window is smaller than the displayed image.

On to the new document: the s# strings are concatenated and then written to the page via an ImageWindow.document.write( ) command; don't forget to subtract + s15 from the write( ) parameter expression if you deleted the var s15 = ""; line earlier. Per the discussion above, the new document's head has a title and its body contains an image and a button - pretty basic.

The transferview( ) function concludes with an ImageWindow.document.close( ) command, whose presence is optional, as noted in Blog Entry #148.

We'll flesh out other practical aspects of the "Remote Image" script and provide our own demo in the next entry.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)