Chapter 23

Client-Side Scripting


CONTENTS


One clear way to extend the power of the HTTP protocol is by increasing the processing power of the client. If the client's Web browser was able to interpret logical instructions (program code) as well as render HTML, for example, such tasks as form input validation might be accomplished on the client side without a roundtrip to the server. This is quite a bit different than the CGI paradigm, where any client data submission must travel to the server, which then spawns a CGI process to handle the client data. If the client can interpret program instructions and execute logic local to the client machine, the server load can be lessened and the overall flow of data from client to server made more efficient. Both Netscape Communications Corporation, with its JavaScript product, and Microsoft, with its VBScript product, offer this type of HTML extension. The program code is embedded in the HTML masquerading as a comment-hopefully so that noncompliant browsers will ignore the code altogether. The concept is that compliant browsers will run the logical code with built-in interpreters. Listing 23.1 shows what JavaScripts look like.


Listing 23.1. A general JavaScript template.
<HTML>
<HEAD>
<TITLE> My Script Page </TITLE>
</HEAD>
<BODY>
<SCRIPT LANGUAGE = JavaScript>
<!--  put this comment here to try to protect from noncompliant browsers
... script code here   ...
//  -->
</script>
</body>
</html>

We also see scripts that are embedded in the <HEAD> section; in fact, scripts can be embedded in both the <HEAD> and the <BODY> sections.

The same is true for VBScript; just replace the word JavaScript in Listing 23.1 with VBScript (or VBS, in earlier incarnations of the product).

Warning
By including proprietary script code in an HTML page, the developer is making a de facto assumption that the benefits of the clientside logic outweigh the risks of the code behaving erratically on a semicompliant rival browser, breaking on a noncompliant browser, or breaking on a more advanced version of the optimal browser.

Note the fundamental paradox: The Web bills itself as an interoperable environment, where clients in an architecture-neutral manner can interact with servers. Yet, vendors must compete for market share by developing proprietary (non-interoperable) tools.(See note) Thus, I see many pages on the Web that state something like "Netscape Now!" or "Best Experienced with Free Microsoft Internet Explorer"-rather obvious brand differentiation, which is standard fare in a Marketing MBA class. The truth, necessarily, is that vendors are gambling with first-mover developments; a script language that runs on one vendor's browser is either going to not run at all or run erratically on another vendor's browser. We thus move away from the openness envisioned by the HTTP protocol developers and start to get into the sticky ground of market share competition. Worse, within the same vendor, upgrades to a browser may well not be backward-compatible to prior versions of the script interpreter. Thus, scripts that run in Netscape 3.x products might well require the 3.x browser and not run on Netscape 2.x, for example. Developers then are placed in the awkward position of coding explicit logic to check for the version number-not an optimal state of affairs. Having said this, it is still important to cover JavaScript and VBScript because, although they choose to go their own way, they still are quite prevalent on the Net, and their object-oriented flavor is instructive to examine.

This chapter is not meant to be an exhaustive treatise on the syntax of JavaScript or VBScript. Instead, I present a broad comparison of the two products, examine two sample applications in each language, and return at the end to a broad discussion of the advantages and disadvantages of incorporating client-side scripts into an HTML page.

Client-Side Scripting and Security

Inserting logic into an HTML page is quite a powerful and quite a dangerous idea. Consider the malicious author (let's call this person the attacker), who is seeking a way to interfere with the client (user) computer's proper operation. This broad danger might manifest itself specifically as issuing surreptitious commands from the user's computer, deleting or changing files on the user's local disk drive(s), or tracking the user's keystrokes (an invasion of privacy). Now consider the architects of a generic scripting engine; let's call them the builders. They must build an engine to interpret their scripting language and couch this interpreter inside a specific browser (a JavaScript interpreter inside Netscape, for example, or a VBScript Interpreter inside Microsoft's Internet Explorer). We can model this as a war; the builders come out with an interpreter-let's call it Version 1.0-and claim they have removed all unsafe operations from the interpreter. In other words, the attacker is foiled at every turn by the interpreter at runtime. Wait! A good citizen, posing as an attacker, demonstrates how the interpreter can be duped or circumvented into allowing an attack. The builders fix the publicly circulated problem in a bug-fix release-let's say Version 1.1. The problem with the security model here is that there is no model! Instead, there is an endless cycle of attack and defense against a runtime interpreter. The user places infinite trust in the builders to circumvent attacks now and into the future; such trust is not and cannot be watertight.

It is important to contrast this with the quite different security model of Sun Microsystems' distributed programming language-Java. In Java, source code is compiled by a special compiler into bytecode and the compiler checks for unsafe operations (this is known as algorithmic security). Many unsafe operations stem from the programmer trying to access unknown memory segments with pointers. The Java compiler disallows these attempts. Only bytecode passed by the compiler can be sent across TCP/IP from the server to the client. The bytecode, which runs in a Java virtual machine, is essentially architecture neutral and the client can run the program on various platforms. The theoretical basis of Java security has not been defeated; some clever researchers have discovered flaws in the implementation of the model, but the underpinnings (a safe compiler) remain intact. On the other hand, runtime interpreter engines invite attack both on the browser version number and the operating system platform on which they are running. The power of the Java programming model is well advertised by the fact that Microsoft has announced plans to add Java support to its NT operating system kernel.

An Introduction to JavaScript

JavaScript, an invention of Netscape Communication Corporation, takes its name from the immensely popular Sun Microsystems' language Java, yet the two have very little in common. Java, as mentioned earlier, is bytecode compiled by a safe compiler and then distributed from the server to the client. JavaScript is logic embedded into an HTML page that runs immediately on the client machine. JavaScript's first incarnation was LiveScript, but Netscape decided to cash in on Java's popularity and renamed the product. The fact that JavaScript contains the term Java has caused boundless confusion on the Net. I recommend that the reader logically decouple the two products.

JavaScript is object-based. An HTML form has methods, buttons have methods, and images have methods, for example. It's simplest to think in terms of actions you can do to an object in addition to attributes of the object; both actions and attributes can be exploited by script logic. However, keep in mind that Java is a fully object-oriented language. Everything in Java must be expressed in terms of a class. Not so in JavaScript; scripts might simply be a series of expressions or alert dialog boxes and not reference any objects. Detractors have criticized JavaScript since its inception as LiveScript as a quick hack, but Netscape continues to enhance the feature set, and it will be interesting to see how it can integrate elements of the language into Web standards' initiatives.

Security and JavaScript

My earlier discussion of the weakness of JavaScript's approach to security can be mapped directly into well-publicized attacks on the JavaScript engine. John Robert LoVerso at the OSF Research Institute,(See note) for example, has had a lot of fun writing malicious JavaScripts to exploit holes in various Netscape browser versions.

John has written scripts to stay resident even after the user has left the scripted HTML page, for example, which is a problem through Version 2.01. He also has been able to transmit to himself the user's URL history (where he or she has been) without the user's knowledge (an attack that persists until the user exits the browser altogether). John also has demonstrated that he indeed can write to the client's local file system (contrary to product claims), although this does pop up a dialog box and is not transparent. He also has been able to explore drives (including remote mounts) and directories on client machines. All bugs have been reported to Netscape, and John in fact was awarded a $1,000 Netscape bug bounty prize. The history file (the user's URL cache) was acquired via such an exploration.

JavaScript and Interoperability

Netscape is quite busy enhancing JavaScript from one browser release to the next. Netscape 3, for example, saw a substantial increase in the number of methods that can be applied to various HTML objects. The changes are in no way backward compatible; Netscape 2.x browsers will show strange and ugly foreground error messages with many JavaScript 3.x function calls. Although I will be showing code logic that detects browser versions, the problem also extends to operating system platforms and other vendors' browsers. How can a competitor (such as Microsoft) fully support JavaScript the instant a new Netscape browser comes out, for example? Such support is unrealistic to expect. Of course, Netscape cannot support Microsoft VBScript for the same reasons. The vendors, in their fight for market share, want to steer the user community into using a browser that understands their scripts and their "cool features"; by ignoring the standards process, the entire Internet community suffers to some degree. Furthermore, in a corporate multiplatform (or even multiversion!) environment, proprietary script solutions cannot be justified; they are not production quality. The flip side is that some developers simply don't care about Netscape's competitors. They are willing to assume that their user community uses a compliant browser. Even if this assumption is unpalatable, the following samples should be of interest: the quirky JavaScript syntax still is interesting and does afford visually appealing functionality on Netscape browsers. Netscape is pushing forward with JavaScript innovations. Netscape 3.0 beta 5, for example, uses the NOSCRIPT ... </NOSCRIPT> tag pair to wrap HTML that will run if JavaScript is turned off in the Netscape preferences, or if the client has an incompatible browser. Another feature to improve HTML readability and script modularity is the optional SRC attribute at the script's start. For example,

<SCRIPT LANGUAGE=JavaScript SRC=test.js>

runs the JavaScript contained in the file test.js.

For more information, consult Netscape's Web pages (although, recently, it has some JavaScript off-line). Jerry Currie has created an MS-Windows Help resource for JavaScript at http://www.jchelp.com.

JavaScript Application Samples and Code Discussion

As promised, I'm not going to present an exhaustive (an exhausting!) syntax guide to JavaScript. Instead, I will show a few interesting small applications and discuss selected code techniques so that you can get a feel for the language.

Image-Handling with JavaScript

The first JavaScript application you'll look at shows HTML form interaction with JavaScript and the capability of JavaScript to instantiate a new window with customized properties.(See note)

Figure 23.1 shows the introductory screen of the application. Note how users have two choices. They can use the upper pull-down selection box to choose a GIF image to appear in a new window, or they can use the lower pull-down selection to view an inline GIF image.

Figure 23.1 : The user can elect to show a GIF image in a new window or render it inline.

You can look at an image in a new window. Figure 23.2 shows what happens if Palm Trees is selected from the pull-down selection box.

Figure 23.2 : JavaScript instantiates a new window to contain the GIF--a window without status bars or other frills. Multiple image windows can be opened.

It's also possible to display the images inline running a Netscape 3.x or better browser; this is the second pull-down selection box on-screen, as illustrated in Figure 23.3.

Figure 23.3 : The script has a separate function to display images inline.

Now it's time to examine the code and understand how the script accommodates the image handling shown in Figures 23.2 and 23.3. Listing 23.2 shows the JavaScript and the attached HTML code.


Listing: 23.2. A JavaScript image previewer demo.
<HTML>
<HEAD>

<SCRIPT>
    // JavaScript Image Preview Demo
    // by Paul Colton

    function display_image(form) {
        selectionname = form.imagename.options[form.imagename.selectedIndex].text;
        selection = form.imagename.options[form.imagename.selectedIndex].value;
        myWindow = window.open("", "Preview", "toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=0,resizable=0, copyhistory=0,width=200,height=255");
        myWindow.document.open();
        myWindow.document.write("<HTML><HEAD>");
        myWindow.document.write("<TITLE>Preview</TITLE>");
        myWindow.document.write("</HEAD><BODY BGCOLOR=FFFFFF TEXT=000000>");
        myWindow.document.write("<FORM><CENTER><B><FONT SIZE=+1>" +
            selectionname + "</FONT></B><HR>");
        myWindow.document.write("<IMG HSPACE=0 VSPACE=0 HEIGHT=150 WIDTH=150 " +
// SET THE FOLLOWING ADDRESS TO YOUR MACHINE
            "SRC='http://jrc.livesoftware.com/ip/" + selection + "'>");
        myWindow.document.write("<HR><FORM><INPUT TYPE='button' VALUE='Close' " +
            "onClick='window.close()'></FORM>");
        myWindow.document.write("</CENTER>");
        myWindow.document.write("</BODY></HTML>");
        myWindow.document.close();
   }

function changeImage(form)

{
   selection = form.imagename.options[form.imagename.selectedIndex].value;
   document.images[2].src = "http://jrc.livesoftware.com/ip/" + selection;
}


</SCRIPT>
<TITLE>JavaScript Image Previewer Demo</TITLE>
</HEAD>



<BODY BGCOLOR=FFFFFF TEXT=000000>

<CENTER>

<IMG WIDTH=346 HEIGHT=34 SRC="previewertitle.gif"><BR>
<IMG WIDTH=108 HEIGHT=26 SRC="../images/previewercredit.gif">
</CENTER>


Please select an image from the following image list.
To preview additional images, just move the preview window
to the side and select another image from the list. You do
not need to close the preview window.<p>

<FORM>
<CENTER>
<select NAME="imagename" onChange="display_image(this.form)">
<option value="image0.gif">Select An Image
<option value="image1.gif">Palm Trees
<option value="image2.gif">Sunset
</select>
</CENTER>
</FORM>

<HR WIDTH=75%>
<CENTER>
<H3>Netscape 3.0 Demo Using On-Screen Image Updating</H3>
<FORM>
<CENTER>
<TABLE>


<TR>
<TD valign=center align=center>
<IMG SRC="image0.gif">
</TD>
<TD valign=center align=center>
<SELECT SIZE=1 NAME="imagename" onChange="changeImage(this.form)">
<option value="image0.gif">Select An Image
<option value="image1.gif">Palm Trees
<option value="image2.gif">Sunset
</SELECT>


</TD>
</TR>
</TABLE>
</CENTER>
</FORM>

<HR>
<CENTER>
<FONT SIZE=-2>
Comments to <A HREF="mailto:contact@livesoftware.com">Live Software</A>
</FONT>
</CENTER>
</BODY>
</HTML>

Consider the results of Figure 23.2 first. The user picked Palm Trees from the form. If you look at Listing 23.2, you see that the typical HTML form has been augmented:

<select NAME="imagename" onChange="display_image(this.form)">
<option value="image0.gif">Select An Image
<option value="image1.gif">Palm Trees
<option value="image2.gif">Sunset
</select>

In other words, the script detects a change in this form setting (the onChange method); this corresponds to the user selecting an image. The function display_image then is called with the current ("this") form as an argument. That function is embedded in the <HEAD> section near the top of the HTML; it uses the image selected by the user and it instantiates (in object-oriented terminology) a new window with the myWindow assignment. The window.open method defines the characteristics of myWindow when it is opened. As you can see, it is going to be a plain vanilla window without menubars, scrollbars, and so on; this is ideal for an image viewer. The next line, myWindow.document.open(), is the actual machine operation to start the new window, and then a series of write statements fill the window with HTML content.

The syntax construction certainly will look odd to readers who are not used to object-oriented languages. With the immense popularity of Perl 5 and Java, however, it is clearly time to start getting used to the modular world of classes, objects, and methods.

Now turn to Figure 23.3. The user has picked an image from the second pull-down list, and you see from the HTML code

<SELECT SIZE=1 NAME="imagename" onChange="changeImage(this.form)">
<option value="image0.gif">Select An Image
<option value="image1.gif">Palm Trees
<option value="image2.gif">Sunset
</SELECT>

that, once again, the onChange method is used to call the function changeImage if the form variable imagename changes. Examine the code of the function changeImage:

selection = form.imagename.options[form.imagename.selectedIndex].value;
document.images[2].src = "http://jrc.livesoftware.com/ip/" + selection;

This looks ominous, but it's really quite simple: the first line assigns a variable, selection, to the value of the image selected by the user. This might be image0.gif, image1.gif, or image2.gif. The second line assigns the second GIF image on this HTML page (the Live Software logo you see in Fig. 23.1) with the image selected by the user, prepended by the virtual path to that GIF. If I wanted to take this code and run it on my server, I would only have to (probably) change the GIF offset from 2 to a value appropriate for me, change the URL prefix to my GIFs, and change the names of the GIFs in the HTML form.

Browser Detection and the OnMouse_Over Method

The next JavaScript application we'll look at shows browser detection techniques and also illustrates the mouse_over method. When the user passes the mouse over an image, an action can be taken (in this case, substituting another image for a certain time interval and then reverting to the original image).(See note) See Figure 23.4 for the screen appearance before I pass my mouse over the Test GIF.

Figure 23.4 : The Test image is highlighted for two seconds when the user passes the mouse over it.

If I pass my mouse over the Test image, it lights up for two seconds and then reverts to its inactive (grayed out) state. How is this done? Let's look at the code shown in Listing 23.3.


Listing 23.3. Preloading Images and the onMouseOver method.
<HTML>
<HEAD>
<TITLE>JavaScript Tip of the Week for June 24, 1996: Too Many Browsers? Wrong.</TITLE>
<SCRIPT LANGUAGE = "JavaScript">
var version = 0;

        if(navigator.appName.indexOf("Netscape") != -1){

                if(
                navigator.userAgent.indexOf("Mozilla/3.0b3") != -1 ||
                navigator.userAgent.indexOf("Mozilla/3.0b4") != -1 ||
                navigator.userAgent.indexOf("Mozilla/3.0b5") != -1 ||
                navigator.userAgent.indexOf("Mozilla/3.0b6") != -1 ||
                navigator.userAgent.indexOf("Mozilla/3.0") != -1) {
                version = 3;
                active = new Image(105, 42);
                active.src = "test_active.jpg";
                inactive = new Image(105, 42);
                inactive.src = "test_inactive.jpg";
                        if (navigator.userAgent.indexOf("Macintosh") != -1) {
                        version = 4;
                        }
                }

                else if(
                navigator.userAgent.indexOf("Mozilla/2.0") != -1 ||
                navigator.userAgent.indexOf("Mozilla/2.01") != -1 ||
                navigator.userAgent.indexOf("Mozilla/2.02") != -1) {
                version = 2;
                }
                
                else version = 2;
        }
                
        else {
        version = 1;
        }


function which_one(){
        if (version == 4) return "Netscape Version 3.0 for Macintosh.";
        if (version == 3) return "Netscape Version 3.0.";
        if (version == 2) return "Netscape Version 2.x.";
        if (version == 1) return "Microsoft Internet Explorer 3.0.";
        }

function change_button() {
        document.images[1].src = active.src;
        setTimeout( "document.images[1].src = inactive.src", 2000);
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR = "#FFFFFF" TEXT = "#000000" LINK = "#B8860B" ALINK = "#8B0000" VLINK = "#B8860B">
<A HREF = "http://www.gis.net/~carter/therest/tip_week.html">
<IMG BORDER = 0 VSPACE = 5 HEIGHT = 137 WIDTH = 172 SRC = "../../menus/tip_week.gif" ALT = "JavaScript Tip of the Week"></A>
<BLOCKQUOTE>
<FONT SIZE = 4>for June 24, 1996: Part 1. Determining Which Browser is Being Used</FONT>
<BR><BR><BR>
<SCRIPT LANGUAGE = "JavaScript">
        if (version == 3 || version == 4) {
        document.write("<A HREF = \"JavaScript:alert(\'You are using \' + which_one\(\)\)\" onMouseOver = \"change_button\(\);return true\"><IMG HEIGHT = 42 WIDTH = 105 BORDER = 0 SRC = \"test_inactive.jpg\"></A><BR>" + "<BR><BR><BR>Try moving the mouse over the \"Test\" button, then click. As you can see, the button changes color, I\'ll show you <A HREF = \"part02.html\">how</A> this is done later on. " + "But that\'s not the point. Normally, if you were using Netscape 2.x, you would have gotten a whole bunch of error messages " + "when you moved the mouse over the button.");
        }
        
        else {
        document.write("<A HREF = \"JavaScript:alert(\'You are using \' + which_one\(\)\)\"><IMG HEIGHT = 42 WIDTH = 105 BORDER = 0 SRC = \"test_active.jpg\"></A>" + "<BR><BR><BR>If you have Netscape 3.0 the \"Test\" button changes color when the mouse is moved over it." + " But since you don\'t have 3.0, you should have gotten a bunch of error messages instead. ");
        }
</SCRIPT>

The code checks the browser and platform. If the user is running various versions of Netscape 3.x, two images are instantiated and defined with this code:

active = new Image(105, 42);
active.src = "test_active.jpg";
inactive = new Image(105, 42);
inactive.src = "test_inactive.jpg";

For lucky users with one of the favored versions of Netscape, the inactive GIF is presented with a mouseOver method associated with it. If the users pass their mouse over the test_inactive.jpg image, the function change_button is called, which has these two source lines:

document.images[1].src = active.src;
setTimeout( "document.images[1].src = inactive.src", 2000);

The confusion dies down as you notice that the function is setting the first GIF on the page (the Test GIF) to its active counterpart and then setting a 2000-millisecond (two-second) delay before the document reverts to the inactive original setting. If you look at the HTML in the <BODY> section again, you see the JavaScript If ... test checking the user's browser version. The unsupported onMouseOver function is bypassed if the browser cannot support it. Notice in passing how long the document.write code lines can get; they are outputting long strings of concatenated HTML. The concepts presented here are clever; they avoid runtime errors for unsupported browsers. There's even a check for the Macintosh operating system. This is a step back from open, distributed computing, however. We're reverting to a tower of Babel, where intra-operating system version numbers have to be checked because the scripting language isn't backward compatible and its feature set is under proprietary development. Furthermore, how will new operating systems handle this code a year or two down the line? New Web browsers? New versions of existing Web browsers? There is no need to stress the point that nonstandard avenues of development will remain oddments and curios.

Fahrenheit-to-Celsius Converter

Let's conclude this section by looking at a feature of JavaScript that came about in Netscape 3.0 beta 5: the capability to evaluate JavaScript expressions on the right side of an HTML name/value attribute pair. As the release notes say, "this allows the attributes of one HTML element to depend on information about previously placed elements on the page." This interesting capability to set up codependency between form elements is shown in James Thiele's neat little Fahrenheit-Celsius Converter JavaScript.(See note)

Listing 23.4 shows James' code. This code is for a Fahrenheit-to-Celsius converter, using the eval function by James Thiele (http://www.eskimo.com/~jet/javascript/convert.html).


Listing 23.4. A JavaScript Fahrenheit-to-Celsius converter.
<html>
<head>
<title>Fahrenheit <-> Centigrade Temperature Conversion</title>
</head>
<body>
<P>
<h1>Temperature Conversion:</h1>
</P>
Enter a number in either field, then
<ul><li>click outside the text box, or
    <li>press the tab key.
</ul>
<form>
F: <input type="text" name="F" value="32"
    onChange="eval('C.value = ' + this.form.C_expr.value)">
   <input type="hidden" name="F_expr" value="(212-32)/100 * C.value + 32 ">
    <br>
C: <input type="text" name="C" value="0"
    onChange="eval('F.value = ' + this.form.F_expr.value)">
   <input type="hidden" name="C_expr" value="100/(212-32) * (F.value - 32 )">
    <br>
   <input type=reset name=reset value=reset>
</form>

Notice how the form has two hidden values corresponding to the Celsius-to-Fahrenheit conversion formula and vice versa. When the user changes the Celsius or the Fahrenheit value, the onChange method is called and the eval function recalculates the values with the conversion formulas.

Figure 23.5 shows the simple user interface.

Figure 23.5 : The Fahrenheit and Celsius input boxes update each other if either one is changed.

Note that this application, of course, is completely tied to the browser release. In most large firms, it is difficult to upgrade all users simultaneously on minor or even major version changes, so a production application of recent JavaScript functions would be most problematic, even in an all-Netscape environment.

An Introduction to VBScript

VBScript, Microsoft's answer to Netscape's JavaScript, looks at an HTML page very much like its rival. It can be embedded in the <HEAD> or the <BODY> portions of the page. If it refers to specific form objects, however, it must follow the <BODY> tag. One cosmetic difference is that VBScript code terminates with a carriage return or a colon (:) character, whereas JavaScript terminates with a semicolon (;). VBScript, like JavaScript, is object-based (not truly object-oriented); there are hierarchies of classes, properties, and methods. This <HEAD> script sets the foreground color of the document to white and the background to black, for example:

<HEAD><TITLE>VBScript Colors</TITLE>

<SCRIPT language="VBScript">
<!--
document.bgcolor = "#000000"
document.fgcolor = "#ffffff"
-->
</SCRIPT></HEAD>

VBScript has no strong data typing. All variables (both string and numeric) fall into a single bucket, or variant, and it's up to the programmer to apply type-conversion functions as needed. For example, if I say

mynum = 10
mytext = "abc"

then

Mymixture = cstr(mynum) + mytext

yields the expected result, 10abc.

As with Visual Basic, VBScript distinguishes procedures (parameterized blocks of code that cannot return data) from functions (also parameterized, but they can return data).

Microsoft is in a fast-paced war with Netscape to extend VBScript; every new release of Internet Explorer sees new capabilities of VBScript. The same objections apply; the development direction has distinctly proprietary overtones and rival browsers do not have very good chances at interpreting the latest and greatest VBScripts.

VBScripts and Security

VBScript has no real underlying security model. It's a subset of the Visual Basic programming tool, and the Web clients trust that Microsoft has removed the dangerous elements of the language to avoid malicious embedded VBScripts. Microsoft has proposed a code-signing initiative that first was implemented in Internet Explorer 3.0 Beta 2, however. At least the client is warned when an unknown control is being transported from the server to the client. The implication is that, over time, clients will view certain vendors as trusted software developers and accept their signed code. Any model of distributed trust is quite shaky, however, and it's much too soon to evaluate how effective or useless it might be in the long run.

VBScripts and Interoperability

Microsoft has done some interesting work to position Internet Explorer (IE) as an extensible program that contains a scripting engine. The idea is that the engine does not need to know a specific scripting language in advance. Thus, IE theoretically can be configured to run JavaScript as well. In practice, though, JavaScript often runs imperfectly or does not run in IE. This is not surprising because the competing vendors have no incentive to collaborate on script enhancements. Any given JavaScript addition to IE therefore might well be out of date soon after it is implemented. The comfort level of supporting VBScript pages on a production basis is again low, just as it is with JavaScript, in a corporate environment with a multiplatform client base. It is true that VBScripts can be masked with HTML comment lines to minimize severe runtime problems; in that case, the noncompliant browsers merely should ignore the embedded code.

Tip
Neither JavaScript nor VBScript can be positioned to deliver production-grade applications in a corporate multiplatform environment. Their proprietary nature and their quirky behavior across vendor browsers makes them interesting tools that lack robustness. Java, a networked programming language with a proven security model and support in both UNIX and Microsoft operating system kernels, is preferable for a large-scale production rollout.

VBScript Sample Applications and Code Discussion

This section steps through some introductory VBScript applications to get a feel for how VBScript can be used to validate forms without server involvement, perform a simple conversion, and embed a Visual Basic control.

Simple Client-Side Form Validation

Often in a Web transaction, the user mistypes an entry. Usually, a CGI process must detect the error and waste bandwidth sending the bad data back to the client.

My first example shows the efficiencies gained from client-side validation. The users are meant to type in the number of pounds they weigh. The first validation step is to check that the input is numeric. After that hurdle is passed, the numeric range is checked; the input range, in this case, is set to between 20 and 2,000 pounds.

Figure 23.6 shows the result of an input in excess of 2,000 pounds.

Figure 23.6 : The user's input exceeds the maximum, and VBScript pops up on alert box. The server is not contacted.

A similar validation check catches input that is less than 20 pounds. If all goes well, the program converts American pounds to the British stone measurement system; one stone is equal to 14 pounds and only the remainder in pounds is stated. Therefore, someone weighing 100 pounds can be said to weigh "7 stone 2" (7¥14 = 98; 98 + 2 = 100).

Figure 23.7 shows the result of a successful entry (numeric, and within the range of 20 to 2,000).

Figure 23.7 : The user's valid input of 142 pounds is converted to 10 stone 2.

Listing 23.5 shows the VBScript that converts pounds to stones. It illustrates a Visual Basic subroutine, form handling, numeric type checking, and simple functions as well. It also shows, in passing, the int function (to take the integer portion of an expression), the mod function (or modulus, to take the remainder of a division), and the type-conversion functions Cint (to integer) and CStr (to string).


Listing 23.5. VBScript Pounds-to-Stones converter.
<HTML>
<!-- Visual Basic Script Simple Demo Mark Ginsburg 7/96 -->
<SCRIPT LANGUAGE="VBScript">

Sub ptostone()

Dim myform
Dim mypounds

Set myform = document.frmMain

if isnumeric(myform.pounds.value) then
else
   msgbox "no good " & myform.pounds.value
   exit sub
end if

mypounds = CInt(myform.pounds.Value)

If mypounds < 20 Then
   MsgBox "Are you old enough to type?"
   Exit Sub
Else
   if mypounds > 2000 then
      MsgBox "I did not know elephants could type!"
      Exit Sub
    End If
End If

stone = sconvert(mypounds)
chstone = CStr(stone)
poundsleftover = pconvert(mypounds)
chlb = CStr(poundsleftover)

MsgBox "You weigh " & chstone & " stone " & chlb & " pounds."
End Sub

Function sconvert(arg)
    sconvert = int(arg / 14)
End Function

Function pconvert(arg)
    pconvert = arg mod 14
End Function

</SCRIPT>
<!--  Regular HTML Begins Here - A Simple Form -->
<H2> Pounds to Stone </H2>
<HR>
<FORM NAME=frmMain>
Enter your weight in Pounds ==> <INPUT NAME=pounds TYPE=TEXT>
<INPUT TYPE=BUTTON NAME=btnPounds Value="How many pounds?" onClick="ptostone()">
</CENTER>
</FORM>
</HTML>

-

Note how, as with JavaScript, the VBScript has a distinct object-based feel to it. I assign the variable myform to the form presented in the HTML, and I have immediate access to the values and variables of that form. I perform the isnumeric check on the input; if it is OK, I go ahead and do a type conversion using the CInt function to perform numerical comparisons. Note how, in VBScript, function names are the same as the variables that return the value. After I've figured out the stone corresponding to the valid input, I output the answer in a MsgBox dialog box.

Drawing a Chessboard

The next application shows how to use VBScript to create a two-dimensional chessboard and uses interesting extended HTML table attributes to manipulate foreground text in a table cell and background cell color. It colors the squares appropriately and numbers them from 1 to 64.

Figure 23.8 shows the output of the program.

Figure 23.8 : A VBScript to output an array as an HTML table. Extended table attributes color the cell background and cell text.

Listing 23.6 shows the code for the chessboard program.


Listing 23.6. The chess.htm program.
<HTML>

<HEAD>
<TITLE>My Beautiful Chessboard</TITLE>
</HEAD>

<BODY>
<h1> My Beautiful Chessboard </h1>
<SCRIPT LANGUAGE="VBScript">
<!--
Dim X
Dim Y
WHITE = "ffffff>"  ' this strange > becomes clear in the concatenation code below
BLU = "0000ff>"
colornum = "         "  ' define this as a string
sqcolor = "     "
Dim CArray(8, 8)    ' a 2-dimensional array for the square numbers.

document.write "<CENTER>"
document.write "<TABLE border=4 padding=2>"

'
'  The only trickiness is the mod (modulus) operator:  if
'  the array number minus the row number is odd, then make
'  the square color black; otherwise make it white.
'
'  Also:  make use of FONT COLOR tag to set color of text
'         within a Table Cell; make use of <TD BGCOLOR...
'         tag to set the background color of the Table Cell.
For X = 1 to 8
   For Y = 1 to 8   ' fill in the values of each square
        CArray(X,Y) = ((X - 1) * 8) + Y
        if ((CArray(X,Y) -X) mod 2 = 1) then
             sqcolor = "000000"
             colornum = "<font color=#" & WHITE & CStr(CArray(X,Y)) & "</font>"
        else
             sqcolor = "ffffff"
             colornum = "<font color=#" & BLU & CStr(CArray(X,Y)) & "</font>"
        end if
   
document.write "<TD bgcolor=#" & sqcolor & ">" & colornum & "</td>"
 
   Next
  
document.write "<tr>"  ' must advance to next row
Next   ' out of loop, just finish up the HTML.
document.write "</TABLE>"
document.write "</CENTER>" & "<hr>"
document.write "Next:  write a chess-playing program."
-->

</SCRIPT></BODY></HTML>

The code demonstrates a double For loop to create the 8¥8 chessboard. It then does some arithmetic to figure out the appropriate number for each square and uses the modulus operator (mod) to color the background of the odd-numbered squares black and the even-numbered squares white. Similarly, the foreground number, which is written on the square, is logically set to white if it's on a black square and blue if it's on a white square. Not all browsers support these advanced table attributes, but as you see in Figure 23.8, it's no problem for Microsoft Internet Explorer.

Fahrenheit to Celsius Revisited: Using ActiveX Controls

VBScript has another strategic advantage that Microsoft is leveraging heavily: it can embed objects that were defined by developers taking advantage of Microsoft's ActiveX controls.(See note) These controls, which can be quite sophisticated, are assigned unique class IDs automatically by the tool that created them (the Internet Control Pack extension to Visual Basic), and their attributes can be altered by the VBScript. The ActiveX Control Pad utility(See note) is another handy way of generating object tags, CLSIDs, and parameter tags. The developer just needs to alter the parameter values to change the appearance of the control on-screen.

Listing 23.7 shows an example of a VBScript application, (See note) again a Fahrenheit-to-Celsius converter, taking advantage of a scroll control and label controls.


Listing 23.7. The scroll.html application.
<BASE HREF="file:///C|/ActiveX Samples/scroll.html">

<HTML>
<HEAD>
<TITLE>VBScript Temperature Converter</TITLE>
</HEAD>
<CENTER>
<H3>VBScript Temperature Converter</H3>
<HR>
<OBJECT ID="LabelF" WIDTH=97 HEIGHT=23
 CLASSID="CLSID:978C9E23-D4B0-11CE-BF2D-00AA003F40D0">
    <PARAM NAME="PicturePosition" VALUE="524294">
    <PARAM NAME="Size" VALUE="2046;494">
    <PARAM NAME="FontEffects" VALUE="1073741825">
    <PARAM NAME="FontHeight" VALUE="240">
    <PARAM NAME="FontCharSet" VALUE="0">
    <PARAM NAME="FontPitchAndFamily" VALUE="2">
    <PARAM NAME="ParagraphAlign" VALUE="3">
    <PARAM NAME="FontWeight" VALUE="700">
</OBJECT>
<OBJECT ID="ScrollBar1" WIDTH=23 HEIGHT=165
 CLASSID="CLSID:DFD181E0-5E2F-11CE-A449-00AA004A803D">
    <PARAM NAME="Size" VALUE="494;3493">
    <PARAM NAME="Min" VALUE="-1000">
    <PARAM NAME="Max" VALUE="1000">
</OBJECT>
<OBJECT ID="LabelC" WIDTH=97 HEIGHT=23
 CLASSID="CLSID:978C9E23-D4B0-11CE-BF2D-00AA003F40D0">
    <PARAM NAME="Size" VALUE="2046;494">
    <PARAM NAME="FontEffects" VALUE="1073741825">
    <PARAM NAME="FontHeight" VALUE="240">
    <PARAM NAME="FontCharSet" VALUE="0">
    <PARAM NAME="FontPitchAndFamily" VALUE="2">
    <PARAM NAME="ParagraphAlign" VALUE="3">
    <PARAM NAME="FontWeight" VALUE="700">
</OBJECT>
</CENTER>

<SCRIPT LANGUAGE="VBS">
Sub ConvTemp()
    Dim CTemp

    CTemp = CInt((ScrollBar1.Value - 32) * (5 / 9))     ' Celsius Value
    LabelF.Caption = CStr(ScrollBar1.Value) & " F"      ' Scroll Value is Farenheit
    LabelC.Caption = CStr(CTemp) & " C"

End Sub

Sub ScrollBar1_Scroll()
    ConvTemp()
End Sub

Sub ScrollBar1_Change()
    ConvTemp()
End Sub
</SCRIPT>

<BODY onLoad="ConvTemp">

</BODY>

</HTML>

The actual logic is very simple; the bulk of the code is to set up the objects and their parameters. When the user moves the scroll slider, the function ConvTemp() is called and the two labels, corresponding to the Fahrenheit and Celsius values, are recalculated. Figure 23.9 shows one instant in time of this application.

Figure 23.9 : A scroll object is embedded on an HTML page.

Embeddable objects inside HTML are a recent focus of the World Wide Web Consortium (W3C) and Microsoft has changed its CLSId syntax to conform with W3C guidelines. It will be interesting to see how Microsoft markets its VBScript applications and its vision of embedded objects to the W3C standards body.

Client-Side Scripting Check


Footnotes

Larry Masinter pointed out this interesting paradox at the fifth World Wide Web Conference, Paris, France, May 1996.
A synopsis of Loverso's creative attacks can be found on-line at http://www.osf.org/~loverso/javascript/track-me.html.
Many thanks to Paul Colton for liberal use of his JavaScript code, courtesy of Live Software. Look for Paul's book, Java Unleashed, published by Sams.net. All code samples at Paul's site, http://jrc.livesoftware.com/, have been updated to work with Netscape 3.0.
Thanks to Nick Heinle for providing this interesting code for discussion. His JavaScript Tip of the Week site is located at http://www.gis.net/~carter/therest/tip_week.html.
Thanks to James Thiele; his application is on-line at http://www.eskimo.com/~jet/javascript/convert.html.
More information is available at http://www.microsoft.com/activex/controls/, and information on general Microsoft Internet initiatives can be found at http://www.microsoft.com/intdev/. Microsoft's on-line Visual Basic reference guide is at http://www.microsoft.com/vbscript/us/vbslang/vbstoc.htm.
Information on the ActiveX Control Pad is at http://207.68.137.35/workshop/author/cpad/.
Thanks to Joe La Valle for the Temperature Scrollbar Visual Basic application code.