N341 Client Programming |
Modified: |
HTML is basically static, the browser displays the text and graphics and waits for the user to click a link or fill in a form to return data to the server. Any dynamic behavior is limited mainly to clicking a link or submitting a form to a server and receiving more static HTML. Client side programming is designed to add dynamic behavior to the client by executing a program on the browser. There are a number of reasons for client side programming, though the most common are for verifying that data has been correctly entered (e.g. all required fields of a form are filled in) or for extending the capability of the browser (e.g. Shockwave for animation). The most common tools and reasons for using them are:
Pros and Cons of Client Side Programming Tools Type Examples Pros Cons Scripting
LanguageJavaScript
PerlScriptSafe, in theory cannot access client files/hardware.
Common to client and server.Limited, cannot access client files/hardware.
Little interactivity, cannot generate graphics, sound, etc.Scripting
LanguageVBScript Can access client files/hardware, extensible using ActiveX.
Common to client and server.Demands trust, OK perhaps for an intranet.
Requires installation of ActiveX objects on client system.Plug-in Shockwave Can extend browser capabilities. Demands trust that the plug-in is safe. Applet Java Safe, cannot access client files/hardware directly.
General programming language with graphics, user interface, etc.
Program delivered to client on demand by server.Cannot access client files/hardware.
High user interface development time, comparable to C++.Rantings - Generally, scripting languages are light-weight programming languages, which is not intended to be a compliment. It takes a lot of imagination to implement a script with anything more than trivial user interaction. Though basic user interfaces with buttons, menus, etc. can be easily generated, scripting languages lack the ability to directly generate graphics so something as simple as a line graph is not very feasible.
VBScript qualifies as a curse when coupled with ActiveX technology. To offset weak scripting languages, it attempts to provide to the browser client all the power of Visual Basic or any language that can generate DLLs. The curse is that the DLL must reside on the client, has complete access to the client hardware, be uniquely identified, have an entry in the client system registry, only runs on Microsoft systems, and be completely trustworthy since an ill-mannered DLL can access anything on a client machine. Oh yes, it presently only runs on Internet Explorer. Otherwise, this is a wonderful technology. To be fair, it probably is manageable on an intranet where everyone can trust everyone else, the threat of personal abuse does not exist, the software is always completely tested, and every browser is IE. Don't count on ActiveX gaining ground as a client technology.
Plug-ins are fine from the user point of view, they can decide that they want to listen to RealAudio and download the plug-in. However, for implementing a real Web-site, unless it caters to a select group, remember that most users won't have the plug-in and many are not willing to download a plug-in just to see your wonderful stuff. VBScript and other Microsoft scripting language implementations coupled with ActiveX is sort of like plug-ins for the masses, anyone that can write a Visual Basic program and generate a DLL can do much of what plug-in writers do. A neat technology but one with too great of technical demands and security risks to be worthwhile for the masses.
Java applets represent a compromise between power and security risks. Applets are downloaded by the browser and are run within a virtual machine on the browser. An applet is restricted by the browser security which generally, in theory at least, forbids applet access to local hardware directly or establishing a new Internet connection. Otherwise an applet can do most of what a regular Java program can do; real time graphics, threads, etc. Proponents claim that it is a write once, run anywhere language. Reality is that each browser behaves slightly differently, applets that run reliably on one Windows browser may crash the same browser on Linux. The biggest complaints against it are that it is slow (somewhat over 10 times slower that C++, where C++ takes 0.001 seconds an applet takes 0.01 seconds) which is generally not an issue; that the user interface is clunky which is true since it attempts to work on every computer so is tailored to none; and the applet download time which usually includes the startup time of the Java virtual machine (JVM). While not perfect, it boils down to trusting an ActiveX component programmer to not on purpose or accidentally cause harm versus trusting a language design to be safe. Java currently represents the only serious programming language that can be somewhat trusted not to thrash the client computer.
Mixed HTML/Script - Scripting languages are typically mixed with HTML in a single file. The HTML provides a user interface and the script program provide the logic. Consider the following JavaScript that displays Hello World 5 times.
The file, JHelloWorld.htm, consists of a mixture of HTML and JavaScript.
JavaScript and HTML JHelloWorld.htm JavaScript <H1>Hello World JavaScript</H1>
<SCRIPT LANGUAGE="JavaScript">
for( i=1; i<=5; i++)
document.write ("Hello World<br/>");
</SCRIPT>
Exercise 0 - JavaScriptUsing the JavaScript program above as a starting point:
Hint: Trust the C++/Java force, much of JavaScript is the same syntax. JavaScript data is dynamically typed so numbers and strings are interchangeable. |
To distinguish script from HTML. Some possible languages are VBScript, JScript, JavaScript, and PerlScript.
document.write - Provides a way for the script to write to the browser with new HTML.
document.write ("Hello World<br/>");
Generating HTML - The document.write statement generates new HTML for the browser. For example, the following displays the table at right:
<SCRIPT LANGUAGE="JavaScript">
document.writeln("<table border='1' cellspacing='0' cellpadding='0'>");
document.writeln("<caption><center>4x3 Table</center></caption>");
for (row=1;row<=4;row++) {
document.writeln("<tr>");
for (col=1; col<=3; col++)
document.writeln('<td>' + row + ',' + col + '</td>');
document.writeln('</tr>');
}
document.writeln("</table>");
</SCRIPT>
4x3 Table
1,1 1,2 1,3 2,1 2,2 2,3 3,1 3,2 3,3 4,1 4,2 4,3 <table border="1">
<caption><center>
<p>4x3 Table</p>
</center></caption>
<tr>
<td>1,1</td>
<td>1,2</td>
<td>1,3</td>
</tr>
<tr>
<td>2,1</td>
<td>2,2</td>
<td>2,3</td>
</tr>
<tr>
<td>3,1</td>
<td>3,2</td>
<td>3,3</td>
</tr>
<tr>
<td>4,1</td>
<td>4,2</td>
<td>4,3</td>
</tr>
</table>
The user-interface HTML components, such as buttons, can interact with script code.
Consider the following VBScript and JavaScript that displays the current time and the name entered in the text box when the button is clicked. The VBScript example can only be run in IE.
VBScript/JavaScript and HTML VBHello.htm VBScript <SCRIPT LANGUAGE="VBScript">
Sub Button1_onClick
Document.Write ("Hello " & Document.NameForm.Text1.Value & "<br>")
End Sub
</SCRIPT><H1>Hello in VBScript</H1>
<FORM NAME="NameForm">
Enter your name and click button:
<INPUT NAME="Text1" TYPE="TEXT" SIZE="10">
<INPUT NAME="Button1" TYPE="BUTTON" VALUE="Hello">
</FORM><SCRIPT LANGUAGE="VBScript">
Document.Write "Current time: " & time & "<br/>"
</SCRIPT>IE Browser Output
![]()
JHello.htm JavaScript <SCRIPT LANGUAGE="JavaScript">
var now = new Date();
document.write ("Current time: " + now.getHours() + ":" + now.getMinutes())
function Button1_onClick() {
document.write ("Hello " + document.NameForm.Text1.value + "<br/>")
}
</SCRIPT><H1>Hello in JavaScript</H1>
<FORM NAME="NameForm">
Enter your name and click button:
<INPUT NAME="Text1" TYPE="TEXT" SIZE="10">
<INPUT NAME="Button1" TYPE="BUTTON"
VALUE="Hello" onClick="Button1_onClick();">
</FORM>![]()
When a user clicks on a button, passes the mouse over a link, etc. an event is generated that can be used to execute a specific function. The examples above illustrate the onClick event handling, when Button1 is clicked a call is made to the Button1_onClick function.
In JavaScript the event handler (function called) can be any name, in VBScript it must be a concatenation of object _ event similar to VB; Button1_onClick is the Button1 object and the onClick event.
The event to event handler name is automatically created in VBScript but in JavaScript the event handler must be explicitly designated (e.g. onClick="Button1_onClick()" ).
Note that JavaScript does not support all the events of VBScript but only IE supports VBScript.
User interaction occurs through buttons, text boxes, hyperlinks, etc. that can generate events to execute a script function, such as the onClick event. Buttons and text boxes are defined in a HTML form but can be referenced in a scripting language.
To define form ButtonInput with Button1 object as:
<FORM name=ButtonInput> <INPUT NAME="Button1" TYPE="BUTTON" VALUE="Button 1"> </FORM>
Accessing a specific form object can be relatively simple. The following JavaScript changes the value of the Button1 object to "OK":
document.ButtonInput.Button1.value = "OK";
One point of confusion is that:
- If the writing is done while the browser is loading the page, the document.write is intermixed with the HTML of the page.
- If writing is done after the page is loaded (displayed) by the browser, a new page is opened.
The example below illustrates that behavior where any JavaScript outside a function is executed when the page is loaded; any function code is executed only when called, in this case only after the page is loaded and the user clicks the Helllo button:
<H1>Hello in JavaScript</H1>
<FORM NAME="NameForm">
Enter your name and click button:
<INPUT NAME="Text1" TYPE="TEXT" SIZE="10">
<INPUT NAME="Button1" TYPE="BUTTON"
VALUE="Hello" onClick="Button1_onClick()">
</FORM><SCRIPT LANGUAGE="JavaScript">
var now = new Date();
document.write ("Current time: " + now.getHours() + ":" + now.getMinutes());function Button1_onClick() {
document.write ("Hello " + document.NameForm.Text1.value + "<br>");
}
</SCRIPT>
displays the time on the same page with HTML for the form, heading, etc.
The script executed after the page is loaded when the button is clicked causes the browser to open a new page.
function Button1_onClick() {
document.write ("Hello " + document.NameForm.Text1.value + "<br>");
}
All scripting code outside of functions is executed when the form is loaded or refreshed. Function definitions are not executed until called.
Button1_onClick above is never executed until Button1 is clicked. In C++ and Java execution starts with a main function, in JavaScript and VBScript, script execution starts with the first script code encountered outside of a function definition.
Any document.write statements encountered during loading the page are executed and added to the current window; this allows the script to construct the HTML displayed when the page is loaded by the browser.
Any document.write statements encountered after loading the page are executed and overwrite the current window; the effect is to overwrite the loaded HTML with new HTML, erasing the display and rendering the new HTML in the window.
Global variables - Any variable defined or first used outside of a function is globally accessible.
Exercise 1 - JavaScript FormsUsing the JavaScript Hello program above as a starting point:
Hint: Trust the C++ or Java force, much of JavaScript has the same syntax. JavaScript data is dynamically typed so numbers and strings are interchangeable. Yes, you can use recursion in JavaScript. For example, neither sum or i require definitions of type.
|
Passing Values to Script Functions
Values can be passed as function parameters. The following passes the document.TextInput.Text1.value to function Button1_onClick.
Button1_onClick(document.TextInput.Text1.value) The Button1_onClick function accesses the document.TextInput.Text1.value object passed using the parameter name input.
function Button1_onClick(input) Note that the parameter input is the value of document.TextInput.Text1.value or text.
Passing Values <FORM name=TextInput> <INPUT type="text" name=Text1 value="1"> </FORM> <FORM name=ButtonInput> <INPUT NAME="Button1" TYPE="BUTTON" VALUE="Text value" onClick="Button1_onClick(document.TextInput.Text1.value)" > </FORM> <SCRIPT language="JavaScript"> function Button1_onClick(input) { document.write("Value entered: <b>" + input + "</b>"); } </SCRIPT>
Value entered: Hello
Passing Objects to Script Functions
Objects (references) can be explicitly accessed, as above, or passed as function parameters.
Passing Objects <FORM name=TextInput> <INPUT type="text" name=Text1 value="1"> </FORM> <FORM name=ButtonInput> <INPUT NAME="Button1" TYPE="BUTTON" VALUE="Text object" onClick="Button1_onClick(document.TextInput.Text1)" > </FORM> <SCRIPT language="JavaScript"> function Button1_onClick(input) { document.write("Value entered: <b>" + input.value + "</b>"); } </SCRIPT>
Value entered: Hello
The following passes the document.TextInput.Text1 object to function Button1_onClick.
Button1_onClick(document.TextInput.Text1) The Button1_onClick function accesses the document.TextInput.Text1 object passed using the parameter name input.
function Button1_onClick(input) Note that the parameter input is precisely document.TextInput.Text1 so its attributes are only those of a text object.
The following increments the value of the object passed by first evaluating the text to a number then adding 1 (e.g. eval("5")+1 is 5+1 or 6).
input.value = eval(input.value) + 1;
Form Object Access and Passing ClientForm.htm <FORM name=TextInput> <INPUT type="text" name=Text1 value="1"> <INPUT type="text" name=Text2 value="2"> </FORM> <FORM name=ButtonInput> <INPUT NAME="Button1" TYPE="BUTTON" VALUE="Button 1" onClick="Button1_onClick(document.TextInput.Text1)" > </FORM> <SCRIPT language="JavaScript"> function Button1_onClick( input ) { document.TextInput.Text2.value = input.value; input.value = eval(input.value) + 1; document.ButtonInput.Button1.value = "Button " + document.TextInput.Text2.value; } </SCRIPT>
Exercise 2 - JavaScript Objects and FunctionsCopy the JavaScript program above as a starting point, create a simple dice rolling script.
Hint: A random number 1-6 is generated by: Math.round(6*Math.random( ))%6+1; |
The Document Object Model (DOM)
To access HTML objects in JavaScript, it is necessary to understand the hierarchical DOM structure, the model used to represent HTML (and XML, XSL, etc.) documents.
The above example (ClientForm.htm) creates two objects named document.TextInput.Text1 and document.TextInput.Text2 by the following:
<FORM name=TextInput>
<INPUT type="text" name=Text1 value="1">
<INPUT type="text" name=Text2 value="2">
</FORM>The DOM can be thought of as a tree with document at the root. The browser places all HTML tags (e.g. <b>, <FORM>, etc.) into the tree hierarchy for rendering. The above example can be represented as a tree structure as:
Access to the Text1 object is: document.TextInput.Text1
To change the value attribute of Text1 in JavaScript: document.TextInput.Text1.value = "42"
Selection Lists
Pull-down lists limit input choice to users. The following gives choices of Red, Green or Blue colors and displays the associated value. The default selected value is Red with the value 1.
Selection Lists <form name="SelectForm" action> <select name="ColorSelect"> <option selected="selected" value="1">Red</option> <option value="2">Green</option> <option value="3">Blue</option> </select> <input name="print" value="Print Color" type="button" onclick="printColor();"> </form> <script language="JavaScript"> function printColor() { document.write( "Selected value: " + SelectForm.ColorSelect.value ); } </script>
Selected value: 2
Arrays
JavaScript arrays, while similar to VB, C++ or Java arrays, are dynamically typed and created.
var color = ["Red", "Green", "Blue"];
defines an array color with the values:
color[0] = "Red";
color[1] = "Green";
color[2] = "Blue";The following example uses an array to translate the selection value into the entry selected. Note that the selection values are 1-3 but the array indices are 0-2, hence the need to subtract 1 from SelectForm.ColorSelect.value as an index.
Arrays and Selection Lists <form name="SelectForm" action> <select name="ColorSelect"> <option selected="selected" value="1">Red</option> <option value="2">Green</option> <option value="3">Blue</option> </select> <input name="print" value="Print Color" type="button" onclick="printColor();"> </form> <script language="JavaScript"> var color = ["Red", "Green", "Blue"]; function printColor() { document.write( "Selected color: " + color[ SelectForm.ColorSelect.value - 1] ); } </script>
Selected color: Green
An example often used to simulate button presses using a graphic image is the mouseOver and mouseOut events.
The following switches between an image used as a link reference to another page. The name of the HREF (SYLLABUS.HTM in this case) is referenced, that could also be a parameter to the change function. The empty HREF="" and return=false are needed for some browsers, return false prevents processing of the HREF="".
mouseOver.htm <SCRIPT LANGUAGE="JavaScript">
function change(newImage,name) {
name.src=newImage;
}
</SCRIPT><H1>JavaScript Events</H1>
Moving the mouse over the image will switch from one image to another, and back when the mouse is out of the image. Clicking the image will load the page referenced.<A HREF="Syllabus.htm"
onMouseOver ="change('html_1.jpg', document.ONE)"
onMouseOut ="change('html_2.jpg', document.ONE)"
onClick ="change('html_3.jpg', document.ONE)">
<IMG SRC="html_2.jpg" NAME=ONE WIDTH=15 HEIGHT=15 BORDER=0 ALT="SYLLABUS">
</A>
<A HREF=""
onMouseOver ="change('html_3.jpg', document.TWO)"
onMouseOut ="change('html_4.jpg', document.TWO)"
onClick ="change('html_3.jpg', document.TWO); return false;">
<IMG SRC="html_4.jpg" NAME=TWO WIDTH=15 HEIGHT=15 BORDER=0 ALT="Nothing">
</A>JavaScript Events
Moving the mouse over the image will switch from one image to another, and back when the mouse is out of the image. Clicking the image will load the page referenced.
Explanation <SCRIPT LANGUAGE="JavaScript">
function change(newImage,name) {
name.src=newImage;
}
</SCRIPT>Defines the function change but does not execute. When change is called by:
change('html_3.jpg', document.TWO)
the execution is:
document.TWO.src = 'html_3.jpg'
which makes the IMAGE SRC = 'html_3.jpg' for the HREF NAME=TWO.
Explanation <A HREF="Syllabus.htm">
<IMG SRC="html_2.jpg" NAME=ONE WIDTH=15 HEIGHT=15 BORDER=0 ALT="SYLLABUS"></A>just defines a normal HREF link to "Syllabus.htm" that is has an image of "html_2.jpg" and NAME=ONE.
The document.ONE can refer to this particular HREF.
onMouseOver="change('html_1.jpg', document.ONE)"
executes the change function when the mouse is over the "html_2.jpg" image.
Maintaining state is critical for user interaction such as games, shopping carts, etc. but somewhat challenging given that the HTTP protocol of the Web is a stateless protocol. Generally, the server does not automatically maintain user state; with many potential users, keeping track of what each has done would make the server much more complex. A simpler approach is to maintain state by the client and pass current state to the server when needed. We'll examine several ways to maintain state: appending to the URL, client scripts such as JavaScript, and applets. The state of a computation broadly means the values of program variables.
- Global variables - In scripting languages, variables defined outside of a function can be accessed globally throughout the program, importantly keeping the value.
- Local variables - Parameters and variables defined inside a function are local to the function and do not keep value between calls to that function.
In the following example, the button value is incremented each time clicked. The state of the button value is maintained in the variable count and of course the document.ButtonInput.Button1.value itself since it is a global object.
Maintaining State Count.htm <SCRIPT LANGUAGE="JavaScript">
var count = 0; // Globalfunction increment() {
count++;
document.ButtonInput.Button1.value = count;
}
</SCRIPT><FORM name=ButtonInput>
<INPUT NAME="Button1" TYPE="BUTTON" VALUE="0"
onClick="increment()" >
</FORM>
Not Maintaining State NoCount.htm
<SCRIPT LANGUAGE="JavaScript">
var count = 0; // Globalfunction increment() {
var count = 0;
count++;
document.ButtonInput.Button1.value = count;
}
</SCRIPT><FORM name=ButtonInput>
<INPUT NAME="Button1" TYPE="BUTTON" VALUE="0"
onClick="increment()" >
</FORM>
A JavaScript script is executed independent of other JavaScript, that means that variables from one page of the browser are not accessible on other pages. However, state of one script can be passed through the URL by appending the state as a parameter to the URL. For example, a script that is invoked by:
Count.htm?15 passes the value 15 to the Count.htm script as part of the URL. A JavaScript in Count.htm can access the URL parameters. The location.search attribute returns the string "?15" which must be parsed from a string to an integer by:
query = location.search;
n = parseInt(query.substring(1, query.length))+ 1; // Begin parse after "?"One advantage of this method is that no server overhead is required, in fact, no server is needed if the page of the URL is already loaded by the browser. A recursive example to increment a counter each time the link is clicked:
Count.htm <h1>Counting Example using URL parameters</h1><br><Script Language = "JavaScript" > var n, query; query = location.search; if (query.length == 0) { // Initialize when executed by: Count.htm document.write ('<A HREF="Count.htm?0">Count 0</A>'); } else { // Increment counter n = parseInt(query.substring(1, query.length)); // Skip '?' and convert to integer document.write ('<A HREF="Count.htm?' + (n+1) + '">Count ' + (n+1) + '</A>'); } </Script>Points of note:
- The URL loading the page is initially: Count.htm
- location.search - A predefined JavaScript parameter that holds the string passed to the page. If the page were loaded by:
Count.htm?1234
location.search = "1234"
The script tests whether any URL parameters exist by location.search.length == 0, generating a link of <A HREF="Count.htm?0">Count 0</A> if not, or increments the URL parameter and generates a link of <A HREF="Count.htm?5">Count 5</A> after 5 clicks. Note that each link click causes the page to be reloaded by the browser with the URL parameters.
Exercise 5 - Factorial using URL StateModify the above Counter.htm to compute the factorial. Start with an initial value of 1, display as: Factorial 4 = 24 Exercise 6 - URL StateModify Exercise - Link Events and Internal State to use URL state.
<A HREF="URL.htm?0"><img SRC="digit0.gif" height=22 width=18 border=0></A> ) when the digit image is clicked. The value of the digit clicked should be added to the modulus 4 counter and displayed. |
VBScript/JavaScript Differences
At the basic level of functionality the two scripting languages are very similar. The main problem with VBScript is that only IE supports it. This problem will disappear after Microsoft achieves world domination but for now it makes it unwise to use VBScript for client-side programming except where the browser is known to be IE. Try the VBHello.htm in Netscape.
Some VBScript and JavaScript Differences JavaScript VBScript Browser Any IE Safe Yes Maybe Extensible Yes using Java Yes using ActiveX Case Sensitive Yes No Concatentation + & Events handlers Any function name Must be concatentation of object _ event Conclusions? - VBScript can be both a client and server side scripting language, is powerful and, through ActiveX, extensible by the average programmer. As a client scripting language, one grave concern is security since VBScript provides full access to the file system and other resources of the host computer via ActiveX. A simple example illustrates this in a script that deletes a file (c:\delete.me) on the host computer, given below. To be fair, VBScript does generally warn that bad things might happen but this sort of message is unlikely to inspire faith in your clients. As a server-side scripting language on Microsoft server operating systems it seems to have better access to the Microsoft technologies than other scripting languages.
VBScript to Delete a File on Host Delete.htm <SCRIPT LANGUAGE="VBScript">
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
fso.DeleteFile("c:\delete.me")
</SCRIPT>
Three similar TicTacToe examples are given in Java and JavaScript for comparison. Java will be examined more closely later in the course if time permits. In the game, the user always plays X and the computer O. Whenever an empty board position is clicked, an X is placed there. For simplicity, the computer then randomly places an O in any empty position, checking for ties and wins. The board positions are numbered as:
0|1|2 3|4|5 6|7|8Key similarities beyond that in the code are that both can be safely run without installing any software components on the client machine. Try both the JavaScript and Java applet (no apology for the poor computer play).
The example is of interest primarily due to the use of events to signal when and what board position should be changed on the screen. The state of the game is held in a string variable board initialized to "012345678" to indicate that no moves have been taken. If an X is placed in position 2 then board = "01x345678", and an X is placed in the two position. When a position is clicked, a move function is called with the position number and the image object, if the move is valid a graphic for the X is assigned to the image object. The following initially places a blank image named "gameb.gif" for the HREF named ZERO, since it is the first image it is placed in the first position. The empty HREF="" and return=false are needed for Netscape, return false prevents processing of the HREF="".
<A HREF="" onClick ="move(document.ZERO, 0); return false;">
<IMG NAME=ZERO BORDER=0 HEIGHT=32 WIDTH=32 SRC="gameb.gif"></A>
Client Side JavaScript TicTacToe with Events and Internal State ETTT.htm <HTML>
<HEAD> <TITLE>Client-Side TicTacToe JavaScript using Events</TITLE> </HEAD>
<BODY BGCOLOR="White">
<H1>Client-Side<br>TicTacToe<br>JavaScript</H1><Script Language = "JavaScript" >
var board = "012345678"; // Initial boardfunction move(imageName, position) {
newBoard = process(position, board );
if (newBoard != board) { // newBoard different? then valid X move
imageName.src="gamex.gif";
board = newBoard;
}
}function win(player, board) {
var wins = "012345678036147258048246";
for (awin=0; awin<8; awin++) {
i0 = parseInt(wins.charAt(awin*3));
i1 = parseInt(wins.charAt(awin*3+1));
i2 = parseInt(wins.charAt(awin*3+2));
if (board.charAt(i0) == board.charAt(i1) &&
board.charAt(i1) == board.charAt(i2) ) {
document.TicTacToe.Text1.value = player+' wins!';
return true;
}
}
return false;
}function tie(board) {
for (i=0; i<=8; i++)
if (board.charAt(i) != 'x' && board.charAt(i) != 'o')
return false;
document.TicTacToe.elements[1].value = 'Tie!';
return true;
}function place(symbol, move, board) {
i = parseInt(move);
if (i >= 0 && i <= 8)
if (board.substr(i,1) == move)
board = board.substr(0,i) + symbol + board.substr(i+1,9-i);
return board;
}function process(move, oldBoard) { // Check if X move OK, generate O move
var oMove;
newBoard = place('x', move, oldBoard); // Place x moveif (win("X", newBoard) || tie(newBoard) || newBoard==oldBoard) return newBoard;
do { // Random O move
oBoard = place('o', (oMove=(Math.round(Math.random()*10)%9)), newBoard);
} while (!win("O", oBoard) && !tie(oBoard) && oBoard == newBoard);switch (oMove) { // Put an O image at the move
case 0 : document.ZERO.src="gameo.gif"; break;
case 1 : document.ONE.src="gameo.gif"; break;
case 2 : document.TWO.src="gameo.gif"; break;
case 3 : document.THREE.src="gameo.gif"; break;
case 4 : document.FOUR.src="gameo.gif"; break;
case 5 : document.FIVE.src="gameo.gif"; break;
case 6 : document.SIX.src="gameo.gif"; break;
case 7 : document.SEVEN.src="gameo.gif"; break;
case 8 : document.EIGHT.src="gameo.gif"; break;
}
return oBoard;
}
</Script>// Draw the board
<A HREF="" onClick ="move(document.ZERO, 0); return false;">
<IMG NAME=ZERO BORDER=0 HEIGHT=32 WIDTH=32 SRC="gameb.gif"></A>
<IMG HEIGHT=32 WIDTH=4 SRC="gamedv.gif">
<A HREF="" onClick ="move(document.ONE, 1); return false;">
<IMG NAME=ONE BORDER=0 HEIGHT=32 WIDTH=32 SRC="gameb.gif"></A>
<IMG HEIGHT=32 WIDTH=4 SRC="gamedv.gif">
<A HREF="" onClick ="move(document.TWO, 2); return false;">
<IMG NAME=TWO BORDER=0 HEIGHT=32 WIDTH=32 SRC="gameb.gif"></A>
<br><IMG HEIGHT=4 WIDTH=104 SRC="gamedh.gif"><br>
<A HREF="" onClick ="move(document.THREE, 3); return false;">
<IMG NAME=THREE BORDER=0 SRC="gameb.gif"></A>
<IMG HEIGHT=32 WIDTH=4 SRC="gamedv.gif">
<A HREF="" onClick ="move(document.FOUR, 4); return false;">
<IMG NAME=FOUR BORDER=0 SRC="gameb.gif"></A>
<IMG HEIGHT=32 WIDTH=4 SRC="gamedv.gif">
<A HREF="" onClick ="move(document.FIVE, 5); return false;">
<IMG NAME=FIVE BORDER=0 SRC="gameb.gif"></A>
<br><IMG HEIGHT=4 WIDTH=104 SRC="gamedh.gif"><br>
<A HREF="" onClick ="move(document.SIX, 6); return false;">
<IMG NAME=SIX BORDER=0 SRC="gameb.gif"></A>
<IMG HEIGHT=32 WIDTH=4 SRC="gamedv.gif">
<A HREF="" onClick ="move(document.SEVEN, 7); return false;">
<IMG NAME=SEVEN BORDER=0 SRC="gameb.gif"></A>
<IMG HEIGHT=32 WIDTH=4 SRC="gamedv.gif">
<A HREF="" onClick ="move(document.EIGHT, 8); return false;">
<IMG NAME=EIGHT BORDER=0 SRC="gameb.gif"></A>// When New Game submit button clicked, execute the ETTT.htm page again to restart the game.
<form name=TicTacToe action="ETTT.htm">
<input type='submit' value='New Game?'> <br>
<input type='TEXT' NAME=Text1 SIZE=20>
</form>
</HTML>
</BODY>
The example illustrates how an HTML file can reload itself and pass the current state through the URL. The original HTML file is loaded for each X move but with a new starting state appended. The state of the game board is updated with each move and passed back as part of the URL. The first time the file is loaded by:
JTTT.htm Assuming that an X move is made to position 2, the JTT.htm file would be loaded with the URL:
JTTT.htm?2012345678 Assuming an O move to 5 and X to 7, the JTT.htm file would be loaded with:
JTTT.htm?701x34o678 This method actually parallels that used by Web servers operating without state or memory of any previous operation. As we've already seen with the Yahoo! search, parameters can be passed as part of the URL. That is precisely what is being done in this example, it just happens that the HTML file contains a reference to itself; recursion!
The data that is passed in is used to generate HTML as the file is being loaded. For example, the URL JTTT.htm?701x34o678 corresponds to a move to position 7 where position 2 is "x" and 5 is an "o". It would generate the partial HTML of:
<A HREF="JTTT.htm?001x34o6x8"><IMG ALIGN=bottom BORDER=0 SRC="gameb.gif"></A>
<IMG ALIGN=bottom SRC="gamedv.gif">
<A HREF="JTTT.htm?101x34o6x8"><IMG ALIGN=bottom BORDER=0 SRC="gameb.gif"></A>
<IMG ALIGN=bottom SRC="gamedv.gif">
<A HREF="JTTT.htm?201x34o6x8"><IMG ALIGN=bottom BORDER=0 SRC="gamex.gif"></A>
<BR><IMG ALIGN=bottom SRC="gamedh.gif"><BR>
<A HREF="JTTT.htm?301x34o6x8"><IMG ALIGN=bottom BORDER=0 SRC="gameb.gif"></A>which contains the move and current board and, for position 3, uses the X image instead of a blank.
Client Side JavaScript TicTacToe with State Data Passed
JTTT.htm<HTML>
<HEAD> <TITLE>Client-Side TicTacToe JavaScript</TITLE></HEAD>
<BODY BGCOLOR="White">
<H1>Client-Side<br>TicTacToe<br>JavaScript</H1><Script Language = "JavaScript" >
// With graphic ideas borrowed from Stephen Wassell
var board = "??012345678"; // Initial boardif (location.search.length == 11) // ? + Move + board
move (location.search);
else
display(board);function display(board) {
for (i=0; i<=8; i++) {
if (board.charAt(i+2) != 'x' && board.charAt(i+2) != 'o') {
document.write ('<A HREF="JTTT.htm?'
+i+board.substr(2,10)+'">');
document.write('<IMG ALIGN=bottom BORDER=0 ' +
'SRC="gameb.gif"></A>');
}
else
document.write('<IMG ALIGN=bottom ' +
'SRC="game'+board.charAt(i+2)+'.gif">');
if (i == 2 || i == 5)
document.write('<BR><IMG ALIGN=bottom ' +
'SRC="gamedh.gif"><BR>')
else
if (i != 8)
document.write('<IMG ALIGN=bottom SRC="gamedv.gif">')
}
}function move(input) { // Display board with move input
display("??"+process(input.charAt(1), input.substr(2, 10)) );
}function win(player, board) {
var wins = "012345678036147258048246";
for (awin=0; awin<8; awin++) {
i0 = parseInt(wins.charAt(awin*3));
i1 = parseInt(wins.charAt(awin*3+1));
i2 = parseInt(wins.charAt(awin*3+2));
if (board.charAt(i0) == board.charAt(i1) &&
board.charAt(i1) == board.charAt(i2) ) {
document.write('<b>'+player+' wins!</b><br><br>');
return true;
}
}
return false;
}function tie(board) {
for (i=0; i<=8; i++)
if (board.charAt(i) != 'x' && board.charAt(i) != 'o')
return false;
document.write('<b>Tie!</b><br><br>');
return true;
}function place(symbol, move, board) {
i = parseInt(move);
if (i >= 0 && i <= 8)
if (board.substr(i,1) == move)
board = board.substr(0,i) +
symbol + board.substr(i+1,9-i);
return board;
}function process(move, oldBoard) {
newBoard = place('x', move, oldBoard); // Place xif (win("X", newBoard) || tie(newBoard))
return newBoard;do { // Random O move
oBoard = place('o',
(Math.round(Math.random()*10)%9),
newBoard);
} while (!win("O", oBoard) &&
!tie(oBoard) && oBoard == newBoard);return oBoard;
}</Script>
<form name=TicTacToe action="JTTT.htm">
<input type='submit' value='New Game?'>
</form>
</BODY>
</HTML>
Browser client output
Further Information - See Microsoft Development Environment Help index item JScript Tutorial.
The key differences between programming the TicTacToe game in JavaScript and Java applet are:
- JavaScript has limited data types while Java has familiar data types and classes.
- JavaScript is part of an HTML source file so is tightly integrated with the HTML loaded by the browser. JavaScript can output HTML to the browser on the fly using the document.write() method. Java applets are started from an HTML file with an applet tag but have only limited interaction with the HTML loaded by the browser. There is no way (that I know of at least) for a Java applet to generate HTML on the fly to the browser. Though the browser JVM executes the applet, the Java applet is more or less independent of the browser operation.
- The JavaScript can only roughly place graphics on screen, basically graphics appear in the order desired but not a specific screen location (the GIF files appear in the order but placement is handled largely by the browser). Java allows precise control over graphics.
- A key difference in terms of programming demands is how each language supports user interface controls. Generally Java has much more power in GUI development but at a cost in programming complexity. In Example 2, the JavaScript example a limited user interface is implemented where each graphic (blank, X, O) is associated with a reference to a URL. For example, the following displays the gameb.gif and loads the JTTT.htm file when the blank board position 2 image is clicked:
document.write ('<A HREF="JTTT.htm?20x234ooxx">');
document.write ('<IMG ALIGN=bottom BORDER=0 SRC="gameb.gif"></A>');Java also has internal user interface controls for buttons, menus, etc. but the programmer must associate a mouse click with a specific button, menu entry. There are some very good GUI development environments (IBM, Microsoft, Borland) that turn much of the graphical layout into drag-n-drop design. For this example, the HTML form supplied a button that was used to start a new game by reloading the ATTT.htm file. Within the Java applet example, user defined graphic images and strings instead of standard controls are used. The overhead of using non-standard controls is that the program must monitor each mouse click to determine if the mouse was over a board position at the time clicked (see the mouseUp method of the ATTT.java program). Essentially each mouse click must be decoded from a screen x,y coordinate system to something meaningful to the program. Standard user controls of HTML or Java perform this screen to method invocation operation automatically.
Client Side Java Applet TicTacToe ATTT.java import java.awt.*;
import java.applet.*;public class ATTT extends Applet {
String board, message;
Image OImage, XImage, HImage, VImage, BImage;
public void init() {
OImage = getImage(getCodeBase(), "gameo.gif");
XImage = getImage(getCodeBase(), "gamex.gif");
HImage = getImage(getCodeBase(),"gamedh.gif");
VImage = getImage(getCodeBase(),"gamedv.gif");
BImage = getImage(getCodeBase(),"gameb.gif");
}
// Called whenever applet starts (window open, etc.)
public void start() {
board="012345678";
message=" ";
repaint();
}
// Called when mouse button released at (x, y) of screen
public boolean mouseUp(Event evt, int x, int y) {
int width = (OImage.getWidth(null)+VImage.getWidth(null));
int height = (OImage.getHeight(null)+HImage.getHeight(null));
int r = (y/height)-1, c = (x/width)-1;
// Is move over the board?
if (r < 0 || r > 2 || c < 0 || c > 2) return true;
int move = c+r*3;String newBoard = process(move, board);
if (board == newBoard) return true; // Position occupied, ignore.
board = newBoard; // Otherwise redraw board.
repaint();
return true;
}
// Display board
void display(String board, Graphics g) {
g.setColor(Color.black);
int xoff = (OImage.getWidth(null)+VImage.getWidth(null)); ;
int yoff = (OImage.getHeight(null)+HImage.getHeight(null));
int r, c;for (int i=0; i<=8; i++) {
c = i%3+1;
r = i/3+1;
if (board.charAt(i) != 'x' && board.charAt(i) != 'o')
g.drawImage(BImage, c*xoff, r*yoff, this);
else
if (board.charAt(i) == 'x')
g.drawImage(XImage, c*xoff, r*yoff, this);
else
g.drawImage(OImage, c*xoff, r*yoff, this);
if (i == 2 || i == 5)
g.drawImage(HImage, xoff, r*yoff+VImage.getHeight(null), this);
else
if (i != 8)
g.drawImage(VImage, (c+1)*xoff-VImage.getWidth(null),
r*yoff, this);
}
g.drawString(message,xoff,yoff*5); // Display Tie! or Win! message
}
// Called on window events (open, repaint, etc.)
public void paint(Graphics g) {
display(board, g);
}int parseInt(char n) {
return (int)(n-'0');
}boolean tie(String board) {
for (int i=0; i<=8; i++)
if (board.charAt(i) != 'x' && board.charAt(i) != 'o')
return false;
message = "Tie!";
return true;
}boolean win(char player, String board) {
String wins = "012345678036147258048246";
int i0, i1, i2;for (int awin=0; awin<8; awin++) {
i0 = parseInt(wins.charAt(awin*3));
i1 = parseInt(wins.charAt(awin*3+1));
i2 = parseInt(wins.charAt(awin*3+2));
if (board.charAt(i0) == board.charAt(i1) &&
board.charAt(i1) == board.charAt(i2) ) {
message = player + " wins!";
return true;
}
}
return false;
}String place(char symbol, int move, String board) {
int i = move;
if (i >= 0 && i <= 8)
if (board.charAt(i) == (char)(move+'0'))
board = board.substring(0,i) + symbol + board.substring(i+1,9);
return board;
}String process(int move, String oldBoard) {
String oBoard;
String newBoard = place('x', move, oldBoard); // Place x moveif (win('X', newBoard) || tie(newBoard)) return newBoard;
do { // Random O move
oBoard = place('o', (int)(Math.round(Math.random()*10)%9), newBoard);
} while (!win('O', oBoard) && !tie(oBoard) && oBoard == newBoard);return oBoard;
}
}
ATTT.htm <HTML>
<HEAD>
<TITLE>Client-Side TicTacToe Java Applet</TITLE>
</HEAD>
<BODY BGCOLOR="White">
<H1>Client-Side<br>
TicTacToe<br>
Java Applet
</H1>
<applet code="ATTT.class"
name="Applet TicTacToe"
WIDTH="150" HEIGHT="180">
</applet>
<form name=TicTacToe action="ATTT.htm">
<input type='submit' value='New Game?'>
</form>
</HTML>
Browser client output
![]()
Further Information - Java Programming by Joe Wigglesworth, Course Technologies, ISBN 1-85032-922-2
A final note about JavaScript and Java applets. It is possible for JavaScript to invoke a Java applet method. In theory, this provides the ability to extend the functionality of JavaScript, limited only by what a Java applet can do. I personally have not done much with this so cannot comment about important issues such as Java object creation and referencing by JavaScript, thread control, etc. Maybe its the thought of trying to get an application to work reliably that uses three languages: HTML, JavaScript, and Java, on different browser platforms that dampens my enthusiasm.