reptile7's JavaScript blog
Saturday, March 10, 2007
 
Super Resize Me, Part 1
Blog Entry #69

In Blog Entry #15, we discussed the properties of the 'client-side' image object. For that entry, I put together a demo that uses onClick event handlers to write a thumbnail image's width, height, hspace, vspace, and border properties. (The W3C states here that these properties have all been deprecated; however, the width and height properties are listed in the HTML 4.01 Strict DTD.) Since then, our image concerns have focused on writing the image src property in various image-flipping contexts: an animation, a random banner display, etc.

In the next few posts, we return the spotlight to the image width and height properties as we look over HTML Goodies' JavaScript Script Tips #45, #46, #47, and #48, which together address a script that allows a user to scale proportionally an image's dimensions. The user first selects an image file from a local disk or from the Web and then chooses a new height or width for the image; for its part, the script calculates a corresponding width or height, respectively, based on the image's intrinsic dimensions, and then resizes the image accordingly. For the user's convenience, the resized image is displayed in a new window.

The Script Tips #45-48 Script can be found in HTML Goodies' /legacy/beyond/javascript/stips/ subdirectory here and is reproduced in the div below:

<!-- The following creates the prompt and displays the image. -->

<script language="javascript">

var path = prompt("Where will I find the image? Put in full URL or Hard Drive Path and Image Name For example: C:/directory/image.jpg","Only image name required if in same directory");

if (path == "Only image name required if in same directory")
{
alert('Come on, put in an image name');
javascript:location.reload( );
}

if (path == null)
{
alert('Do not click Cancel');
javascript:location.reload( );
}

else
{document.write("<img name=thepic src=" +path+ ">");}

</script>


<!-- The following contains the two resize functions and two new window functions. -->

<script language="javascript">

var high = document.thepic.height;
var wide = document.thepic.width;

function newW( )
{
a = high;
b = wide;
c = document.calc.h2.value;
d = (b*c)/a;
document.calc.width2.value = Math.round(d);
}

function newH( )
{
a = high;
b = wide;
e = document.calc.wb2.value;
f = (a*e)/b;
document.calc.height2.value = Math.round(f);
}

function newWin( )
{
var OpenWindow=window.open("", "newwin", "height=500,width=500");
OpenWindow.document.write("<html>");
OpenWindow.document.write("<title>Image</title>");
OpenWindow.document.write("<body bgcolor='000000'>");
OpenWindow.document.write("<center>");
OpenWindow.document.write("<img src=" +path+ " height=" +c+ " width=" +d+ ">");
OpenWindow.document.write("</center>");
OpenWindow.document.write("</html>");
}

function newWin2( )
{
var OpenWindow=window.open("", "newwin2", "height=500,width=500");
OpenWindow.document.write("<html>");
OpenWindow.document.write("<title>Image</title>");
OpenWindow.document.write("<body bgcolor='000000'>");
OpenWindow.document.write("<center>");
OpenWindow.document.write("<img src=" +path+ " height=" +f+ " width=" +e+ ">");
OpenWindow.document.write("</center>");
OpenWindow.document.write("</html>");
}

</script>

<!-- The following contains the two tables that appear on the page. -->

<h2>Resize It</h2>

<form name="calc">

<table border="12" cellspacing="0" cellpadding="4" bgcolor="#fdf99d">

<tr>
    <td align="center">Height:<br><script language="javascript">document.write("<b>"+high+"</b>")</script></td>
    <td align="center">Width:<br><script language="javascript">document.write("<b>"+wide+"</b>")</script></td>
    <td align="center">Enter New Height:<br><input type="text" size="5" name="h2"></td>
    <td align="center"><input type="button" value="Solve" onclick="newW( );"></td>
    <td align="center">New Width Equals<br><input type="text" name="width2" size="10"></td>
    <td align="center"><input type="button" onclick="newWin( );" value="Let Me See It"></td>
</tr>

</table>

<table border="12" cellspacing="0" cellpadding="4" bgcolor="#fdf99d">

<tr>
    <td align="center">Height:<br><script language="javascript">document.write("<b>"+high+"</b>")</script></td>
    <td align="center">Width:<br><script language="javascript">document.write("<b>"+wide+"</b>")</script></td>
    <td align="center">Enter New Width:<br><input type="text" size="5" name="wb2"></td>
    <td align="center"><input type="button" value="Solve" onclick="newH( );"></td>
    <td align="center">New Height Equals<br><input type="text" name="height2" size="10"></td>
    <td align="center"><input type="button" onClick="newWin2( );" value="Let Me See It"></td>
</tr>

</table>

</form>

Joe provides for the Script Tips #45-48 Script a demo that acts on an "angel.jpg" image:

This is the script's demo image, angel.jpg.

Importantly, the demo page's source contains a body element start-tag not present in the script itself; in my attempts to run the script, I find, at least when using Netscape 7.02, that a <body> tag is in fact a necessary inclusion (this isn't the first situation in which I've observed the supposedly "optional" <body> tag to be, uh, not so optional).

Prompt( ) possibilities and the image file name

When the user follows the "See it in Action" link to the demo page, then a prompt( ) box initially pops up soliciting the user for an image file name:

Prompt( ) box for the image file name

The user's input is outputted/assigned to the variable path. The Script Tips #45-48 Script's first script element holds the prompt( ) command therefor and also an if...if...else code block for dealing with the user's possible prompt( ) box responses, which Joe discusses in Script Tip #45; in source order:

(1) If the user doesn't enter a file name into the prompt( ) box input field and clicks the "OK" button, then the condition of the first if statement, path=="Only image name required if in same directory", returns true: a "Come on, put in an image name" alert( ) message pops up and the page is reloaded via the following command:

javascript:location.reload( );

This command is in the form of a JavaScript URL, which is unnecessary; location.reload( ) by itself is good enough. The reload( ) method of the location object is treated here in the JavaScript 1.3 Client-Side Reference. A location.reload( ) command is equivalent to a history.go(0) command, which we have used previously to refresh documents.

(2) If the user clicks the prompt( ) box's "Cancel" button, then the condition of the second if statement, path==null, returns true: a "Do not click Cancel" alert( ) message pops up and the page is reloaded as described above. Contra Script Tip #45, null is not a "command" but is syntactically a primitive value/data type.

(3) If the user does enter a file name into the prompt( ) box input field and clicks the "OK" button, and if the file name is correct (i.e., contains no typos), then the else statement writes the image to the page via a document.write( ) command:

else document.write("<img name='thepic' src=" + path + ">");
/*It would be good form to put single quotes around the src attribute value, but I've left them out for clarity.*/

The else statement would ordinarily also be executed if the first if statement's condition is true and the second if statement's condition is false, but this is preempted here by the first if statement's location.reload( ) command.

In practice...
On my computer, Netscape 7.02 handles the if...if...else code block without any problems, but MSIE 5.1.6 will not execute a location.reload( ) command unless it is coordinated with a user event (as noted here in Blog Entry #18, MSIE 5.1.6 places the same restriction on the execution of window.status="Message" statements). It is simple enough, however, to functionize the prompt( )/if...if...else code and trigger it with an onLoad event handler; the code below works with both browsers:

<script type="text/javascript">

var path;

function imageFileDialog( ) {

path = window.prompt("Where will I find the image? Put in full URL or Hard Drive Path and Image Name For example: C:/directory/image.jpg","Only image name required if in same directory.");

document.thepic.src = path;

if (path == "Only image name required if in same directory.") {
window.alert("Come on, put in an image name."); location.reload( ); }

if (path == null) {
window.alert("Do not click Cancel."); location.reload( ); } }

</script>

<body onload="imageFileDialog( );">
<img name="thepic" src="" alt="Here's where the image should be." />

Joe briefly considers a fourth prompt( ) possibility:
The user enters incorrect information.
Solution: I can't predict incorrect info, so that results in a broken image, which gives a 40X40 height and width.

We may not be able to "predict" an incorrect image file name, but we can most certainly intercept it. Towards this end, my first approach was to compare path with a suitable regular expression:

var imageFileName = /^[a-z_]\w*\.(gif|jpg|png)$/i;
if (!imageFileName.test(path)) {
window.alert(path + " is an incorrect image file name - please try again.");
location.reload( ); }

For the imageFileName regexp pattern:
• After the ^ start-of-string anchor, [a-z_] matches a single letter (lowercase or uppercase - note the i flag after the pattern) or underscore character.
\w* matches zero or more letters, numbers, or underscores.
\. matches the period preceding the image file extension - recall that the period is a regexp metacharacter that (outside of square brackets) must be escaped with a backslash.
(gif|jpg|png) matches either the gif, jpg, or png image file extension; the pattern ends with the $ end-of-string anchor.

I don't know what restrictions, if any, the Windows platform puts on image file names; however, the Mac platform doesn't require an image file name to begin with a letter or underscore, or end with a .xyz extension. In any case, the imageFileName pattern contains a fatal, fundamental flaw: it won't catch a simple misspelling. What to do? Fortunately, a more general and effective solution is at hand: if an incorrect file name "results in a broken image," then we can tie this outcome to an alert( ) message and a page reload via the onError event handler, which [e]xecutes JavaScript code when an error event occurs; that is, when the loading of a document or image causes an error, quoting Netscape.

To the above imageFileDialog( ) function, and after its second if statement, we can add:

if (path != "Only image name required if in same directory." && path != null)
document.thepic.onerror = badImage;

After the imageFileDialog( ) function, and in the same script element, we can code the badImage( ) function as:

function badImage( ) {
window.alert(path + " is an incorrect image file name - please try again.");
location.reload( ); }

Although other onError codings are possible, this formulation prevents the alert( ) message in the badImage( ) function from popping up if either of the first two imageFileDialog( ) if conditions is true.

With respect to the W3C's technical reports, the error event is briefly discussed in the "HTML event types" section of the DOM Level 2 Events Specification; however, onerror as an element attribute does not appear in the HTML 4.01 Specification's list of intrinsic events.

We next consider the determination of angel.jpg's intrinsic dimensions, which we'll discuss in detail in the following post.

reptile7

Labels: ,


Comments:
Hey Andy,
Have you ever thought of adding a visitor counter to your blog spot? That way you can keep track of how many hits you get. You probably already know how to add one, but if you don't just shoot me an email and I'll show you how I did.
Later,
Clayton
 
Post a Comment

<< Home

Powered by Blogger

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